File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <ctype.h>
0010 #include <errno.h>
0011 #include <fcntl.h>
0012 #include <inttypes.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <sys/types.h>
0017 #include <time.h>
0018 #include <unistd.h>
0019
0020 #include <rtems/shell.h>
0021 #include <rtems/trace/rtems-trace-buffer-vars.h>
0022
0023
0024
0025
0026 typedef int (*rtems_trace_buffering_shell_handler_t) (int argc, char *argv[]);
0027
0028
0029
0030
0031 typedef struct
0032 {
0033 const char* name;
0034 rtems_trace_buffering_shell_handler_t handler;
0035 const char* help;
0036 } rtems_trace_buffering_shell_cmd_t;
0037
0038 static int
0039 rtems_trace_buffering_wrong_number_of_args (void)
0040 {
0041 printf ("error: wrong number of arguments\n");
0042 return 1;
0043 }
0044
0045 static int
0046 rtems_trace_buffering_no_trace_buffer_code (void)
0047 {
0048 printf("No trace buffer generated code in the application; see rtems-tld\n");
0049 return 1;
0050 }
0051
0052 static void
0053 rtems_trace_buffering_banner (const char* label)
0054 {
0055 printf("RTEMS Trace Bufferring: %s\n", label);
0056 }
0057
0058 static void
0059 rtems_trace_buffering_print_timestamp (uint64_t uptime)
0060 {
0061 uint32_t hours;
0062 uint32_t minutes;
0063 uint32_t seconds;
0064 uint32_t nanosecs;
0065 uint64_t up_secs;
0066
0067 up_secs = uptime / 1000000000LLU;
0068 minutes = up_secs / 60;
0069 hours = minutes / 60;
0070 minutes = minutes % 60;
0071 seconds = up_secs % 60;
0072 nanosecs = uptime % 1000000000;
0073
0074 printf ("%5" PRIu32 ":%02" PRIu32 ":%02" PRIu32".%09" PRIu32,
0075 hours, minutes, seconds, nanosecs);
0076 }
0077
0078 static int
0079 rtems_trace_buffering_shell_status (int argc, char *argv[])
0080 {
0081 uint32_t buffer_size;
0082 uint32_t buffer_in;
0083 bool finished;
0084 bool triggered;
0085 uint32_t names;
0086
0087 if (argc != 1)
0088 return rtems_trace_buffering_wrong_number_of_args ();
0089
0090 if (!rtems_trace_buffering_present ())
0091 return rtems_trace_buffering_no_trace_buffer_code ();
0092
0093 buffer_size = rtems_trace_buffering_buffer_size ();
0094 buffer_in = rtems_trace_buffering_buffer_in ();
0095 finished = rtems_trace_buffering_finished ();
0096 triggered = rtems_trace_buffering_triggered ();
0097 names = rtems_trace_names_size ();
0098
0099 rtems_trace_buffering_banner ("status");
0100 printf(" Running: %s\n", finished ? "no" : "yes");
0101 printf(" Triggered: %s\n", triggered ? "yes" : "no");
0102 printf(" Level: %3" PRIu32 "%%\n", (buffer_in * 100) / buffer_size);
0103 printf(" Traces: %4" PRIu32 "\n", names);
0104
0105 return 0;
0106 }
0107
0108 static int
0109 rtems_trace_buffering_shell_funcs (int argc, char *argv[])
0110 {
0111 size_t traces = rtems_trace_names_size ();
0112 size_t t;
0113 size_t max = 0;
0114
0115 if (argc != 1)
0116 return rtems_trace_buffering_wrong_number_of_args ();
0117
0118 if (!rtems_trace_buffering_present ())
0119 return rtems_trace_buffering_no_trace_buffer_code ();
0120
0121 rtems_trace_buffering_banner ("trace functions");
0122 printf(" Total: %4zu\n", traces);
0123
0124 for (t = 0; t < traces; ++t)
0125 {
0126 size_t l = strlen (rtems_trace_names (t));
0127 if (l > max)
0128 max = l;
0129 }
0130
0131 for (t = 0; t < traces; ++t)
0132 {
0133 printf(" %4zu: %c%c %-*s\n", t,
0134 rtems_trace_enable_set(t) ? 'E' : '-',
0135 rtems_trace_trigger_set(t) ? 'T' : '-',
0136 (int) max, rtems_trace_names (t));
0137 }
0138
0139 return 0;
0140 }
0141
0142 static int
0143 rtems_trace_buffering_shell_start (int argc, char *argv[])
0144 {
0145 if (argc != 1)
0146 return rtems_trace_buffering_wrong_number_of_args ();
0147
0148 if (!rtems_trace_buffering_present ())
0149 return rtems_trace_buffering_no_trace_buffer_code ();
0150
0151 rtems_trace_buffering_banner ("resume");
0152
0153 if (!rtems_trace_buffering_finished ())
0154 {
0155 printf("already running\n");
0156 return 0;
0157 }
0158
0159 rtems_trace_buffering_start ();
0160
0161 return 0;
0162 }
0163
0164 static int
0165 rtems_trace_buffering_shell_stop (int argc, char *argv[])
0166 {
0167 if (argc != 1)
0168 return rtems_trace_buffering_wrong_number_of_args ();
0169
0170 if (!rtems_trace_buffering_present ())
0171 return rtems_trace_buffering_no_trace_buffer_code ();
0172
0173 rtems_trace_buffering_banner ("stop");
0174
0175 if (rtems_trace_buffering_finished ())
0176 {
0177 printf("already stopped\n");
0178 return 0;
0179 }
0180
0181 rtems_trace_buffering_stop ();
0182
0183 return 0;
0184 }
0185
0186 static int
0187 rtems_trace_buffering_shell_resume (int argc, char *argv[])
0188 {
0189 if (argc != 1)
0190 return rtems_trace_buffering_wrong_number_of_args ();
0191
0192 if (!rtems_trace_buffering_present ())
0193 return rtems_trace_buffering_no_trace_buffer_code ();
0194
0195 rtems_trace_buffering_banner ("resume");
0196
0197 if (!rtems_trace_buffering_finished ())
0198 {
0199 printf("already running\n");
0200 return 0;
0201 }
0202
0203 rtems_trace_buffering_start ();
0204
0205 return 0;
0206 }
0207
0208 static void rtems_trace_buffering_print_arg (const rtems_trace_sig_arg* arg,
0209 const uint8_t* argv)
0210 {
0211 if (arg->size)
0212 {
0213 union
0214 {
0215 uint8_t bytes[sizeof (uint64_t)];
0216 uint16_t u16;
0217 uint32_t u32;
0218 uint64_t u64;
0219 void* pointer;
0220 } variable;
0221
0222 if (arg->size <= sizeof(uint64_t))
0223 memcpy (&variable.bytes[0], argv, arg->size);
0224
0225 printf ("(%s) ", arg->type);
0226
0227 if (strchr (arg->type, '*') != NULL)
0228 {
0229 printf ("%p", variable.pointer);
0230 }
0231 else
0232 {
0233 size_t b;
0234 switch (arg->size)
0235 {
0236 case 2:
0237 printf ("%04" PRIx16, variable.u16);
0238 break;
0239 case 4:
0240 printf ("%08" PRIx32, variable.u32);
0241 break;
0242 case 8:
0243 printf ("%016" PRIx64, variable.u64);
0244 break;
0245 default:
0246 for (b = 0; b < arg->size; ++b)
0247 printf ("%02" PRIx32, (uint32_t) *argv++);
0248 break;
0249 }
0250 }
0251 }
0252 }
0253
0254 static int
0255 rtems_trace_buffering_shell_trace (int argc, char *argv[])
0256 {
0257 uint32_t* trace_buffer;
0258 uint32_t records;
0259 uint32_t traces;
0260 uint32_t r;
0261 size_t start = 0;
0262 size_t end = 40;
0263 size_t count;
0264 uint64_t last_sample = 0;
0265
0266 if (!rtems_trace_buffering_present ())
0267 return rtems_trace_buffering_no_trace_buffer_code ();
0268
0269 trace_buffer = rtems_trace_buffering_buffer ();
0270 records = rtems_trace_buffering_buffer_in ();
0271 traces = rtems_trace_names_size ();
0272
0273 if (argc > 1)
0274 {
0275 if (argc > 3)
0276 return rtems_trace_buffering_wrong_number_of_args ();
0277
0278 if (argv[1][0] == '+')
0279 {
0280 if (argc > 2)
0281 return rtems_trace_buffering_wrong_number_of_args ();
0282 end = strtoul (argv[1] + 1, 0, 0);
0283 if (end == 0)
0284 {
0285 printf("error: invalid number of lines\n");
0286 return 1;
0287 }
0288 ++end;
0289 }
0290 else
0291 {
0292 start = strtoul (argv[1], 0, 0);
0293 if (start >= records)
0294 {
0295 printf ("error: start record out of range (max %" PRIu32 ")\n", records);
0296 return 1;
0297 }
0298 }
0299
0300 end += start;
0301
0302 if (argc == 3)
0303 {
0304 if (argv[2][0] == '+')
0305 {
0306 end = strtoul (argv[2] + 1, 0, 0);
0307 if (end == 0)
0308 {
0309 printf("error: invalid number of lines\n");
0310 return 1;
0311 }
0312 end += start + 1;
0313 }
0314 else
0315 {
0316 end = strtoul (argv[2], 0, 0);
0317 if (end < start)
0318 {
0319 printf ("error: end record before start\n");
0320 return 1;
0321 }
0322 else if (end > records)
0323 {
0324 printf ("error: end record out of range (max %" PRIu32 ")\n", records);
0325 }
0326 }
0327 }
0328 }
0329
0330 rtems_trace_buffering_banner ("trace");
0331
0332 if (!rtems_trace_buffering_finished ())
0333 {
0334 printf("tracing still running\n");
0335 return 0;
0336 }
0337
0338 printf(" Trace buffer: %p\n", trace_buffer);
0339 printf(" Words traced: %" PRIu32 "\n", records);
0340 printf(" Traces: %" PRIu32 "\n", traces);
0341
0342 count = 0;
0343 r = 0;
0344
0345 while ((r < records) && (count < end))
0346 {
0347 const uint32_t header = trace_buffer[r];
0348 const uint32_t func_index = header & 0xffff;
0349 const uint32_t len = (header >> 16) & 0x0fff;
0350 const uint32_t task_id = trace_buffer[r + 1];
0351 const uint32_t task_status = trace_buffer[r + 2];
0352 const uint64_t when = (((uint64_t) trace_buffer[r + 4]) << 32) | trace_buffer[r + 5];
0353 const uint8_t* argv = (uint8_t*) &trace_buffer[r + 6];
0354 const bool ret = (header & (1 << 30)) == 0 ? false : true;
0355 const bool irq = (header & (1 << 31)) == 0 ? false : true;
0356
0357 if (count > start)
0358 {
0359 const rtems_trace_sig* sig = rtems_trace_signatures (func_index);
0360
0361 rtems_trace_buffering_print_timestamp (when);
0362 printf (" %10" PRIu32 " %c%08" PRIx32 " [%3" PRIu32 "/%3" PRIu32 "] %c %s",
0363 (uint32_t) (when - last_sample),
0364 irq ? '*' : ' ', task_id, (task_status >> 8) & 0xff, task_status & 0xff,
0365 ret ? '<' : '>', rtems_trace_names (func_index));
0366
0367 if (sig->argc)
0368 {
0369 if (ret)
0370 {
0371 if (sig->args[0].size)
0372 printf(" => ");
0373 rtems_trace_buffering_print_arg (&sig->args[0], argv);
0374 }
0375 else
0376 {
0377 size_t a;
0378 printf("(");
0379 for (a = 1; a < sig->argc; ++a)
0380 {
0381 if (a > 1)
0382 printf (", ");
0383 rtems_trace_buffering_print_arg (&sig->args[a], argv);
0384 argv += sig->args[a].size;
0385 }
0386 printf(")");
0387 }
0388 }
0389
0390 printf("\n");
0391 }
0392
0393 r += ((len - 1) / sizeof (uint32_t)) + 1;
0394 last_sample = when;
0395 ++count;
0396 }
0397
0398 return 0;
0399 }
0400
0401 static ssize_t
0402 rtems_trace_buffering_file_write (int out, const void* vbuffer, ssize_t length)
0403 {
0404 const uint8_t* buffer = vbuffer;
0405 while (length)
0406 {
0407 ssize_t w = write (out, buffer, length);
0408 if (w < 0)
0409 {
0410 printf ("error: write failed: %s\n", strerror(errno));
0411 return false;
0412 }
0413 if (w == 0)
0414 {
0415 printf ("error: write failed: EOF\n");
0416 return false;
0417 }
0418
0419 length -= w;
0420 buffer += w;
0421 }
0422 return true;
0423 }
0424
0425 static int
0426 rtems_trace_buffering_shell_save (int argc, char *argv[])
0427 {
0428 uint32_t* trace_buffer;
0429 uint32_t records;
0430 uint32_t traces;
0431 uint8_t* buffer;
0432 size_t length;
0433 uint32_t r;
0434 int out;
0435 uint8_t* buf;
0436 uint8_t* in;
0437
0438 if (argc != 2)
0439 return rtems_trace_buffering_wrong_number_of_args ();
0440
0441 if (!rtems_trace_buffering_present ())
0442 return rtems_trace_buffering_no_trace_buffer_code ();
0443
0444 rtems_trace_buffering_banner ("trace");
0445
0446 if (!rtems_trace_buffering_finished ())
0447 {
0448 printf("tracing still running\n");
0449 return 0;
0450 }
0451
0452 trace_buffer = rtems_trace_buffering_buffer ();
0453 records = rtems_trace_buffering_buffer_in ();
0454 traces = rtems_trace_names_size ();
0455
0456 printf(" Trace File: %s\n", argv[1]);
0457 printf(" Trace buffer: %p\n", trace_buffer);
0458 printf(" Words traced: %" PRIu32 "\n", records);
0459 printf(" Traces: %" PRIu32 "\n", traces);
0460
0461 out = open (argv[1], O_WRONLY | O_TRUNC | O_CREAT,
0462 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
0463 if (out < 0)
0464 {
0465 printf ("error: opening file: %s: %s\n", argv[1], strerror(errno));
0466 return 1;
0467 }
0468
0469 #define SAVE_BUF_SIZE (1024)
0470
0471 buf = malloc(SAVE_BUF_SIZE);
0472 if (!buf)
0473 {
0474 close (out);
0475 printf ("error: no memory\n");
0476 return 1;
0477 }
0478
0479 memset (buf, 0, SAVE_BUF_SIZE);
0480
0481 in = buf;
0482
0483
0484
0485
0486 memcpy (in, "RTEMS-TRACE", sizeof("RTEMS-TRACE"));
0487 in += 12;
0488
0489
0490
0491
0492 *((uint32_t*) in) = 0x11223344;
0493 in += sizeof(uint32_t);
0494
0495
0496
0497
0498 *((uint32_t*) in) = traces;
0499 in += sizeof(uint32_t);
0500
0501
0502
0503
0504 if (!rtems_trace_buffering_file_write (out, buf, in - buf))
0505 {
0506 free (buf);
0507 close (out);
0508 return 1;
0509 }
0510
0511
0512
0513
0514 for (r = 0; r < traces; ++r)
0515 {
0516 const char* name = rtems_trace_names (r);
0517 if (!rtems_trace_buffering_file_write (out, name, strlen (name) + 1))
0518 {
0519 free (buf);
0520 close (out);
0521 return 1;
0522 }
0523 }
0524
0525
0526
0527
0528 for (r = 0; r < traces; ++r)
0529 {
0530 const rtems_trace_sig* sig = rtems_trace_signatures (r);
0531 size_t s;
0532
0533 in = buf;
0534
0535 memcpy (in, &sig->argc, sizeof (sig->argc));
0536 in += sizeof(uint32_t);
0537
0538 for (s = 0; s < sig->argc; ++s)
0539 {
0540 const rtems_trace_sig_arg* arg = &sig->args[s];
0541 size_t arg_len = strlen (arg->type) + 1;
0542
0543 if ((in - buf) > SAVE_BUF_SIZE)
0544 {
0545 printf ("error: save temp buffer to small\n");
0546 free (buf);
0547 close (out);
0548 return 1;
0549 }
0550
0551 memcpy (in, &arg->size, sizeof (arg->size));
0552 in += sizeof(uint32_t);
0553 memcpy (in, arg->type, arg_len);
0554 in += arg_len;
0555 }
0556
0557 if (!rtems_trace_buffering_file_write (out, buf, in - buf))
0558 {
0559 free (buf);
0560 close (out);
0561 return 1;
0562 }
0563 }
0564
0565 free (buf);
0566
0567 buffer = (uint8_t*) trace_buffer;
0568 length = records * sizeof (uint32_t);
0569
0570 while (length)
0571 {
0572 ssize_t w = write (out, buffer, length);
0573 if (w < 0)
0574 {
0575 printf ("error: write failed: %s\n", strerror(errno));
0576 close (out);
0577 return 1;
0578 }
0579 if (w == 0)
0580 {
0581 printf ("error: write failed: EOF\n");
0582 close (out);
0583 return 1;
0584 }
0585
0586 length -= w;
0587 buffer += w;
0588 }
0589
0590 close (out);
0591
0592 return 0;
0593 }
0594
0595 static void
0596 rtems_trace_buffering_shell_usage (const char* arg)
0597 {
0598 printf ("%s: Trace Buffer Help\n", arg);
0599 printf (" %s [-hl] <command>\n", arg);
0600 printf (" where:\n");
0601 printf (" command: The TBG subcommand. See -l for a list plus help.\n");
0602 printf (" -h: This help\n");
0603 printf (" -l: The command list.\n");
0604 }
0605
0606 static const rtems_trace_buffering_shell_cmd_t table[] =
0607 {
0608 {
0609 "status",
0610 rtems_trace_buffering_shell_status,
0611 " : Show the current status"
0612 },
0613 {
0614 "funcs",
0615 rtems_trace_buffering_shell_funcs,
0616 " : List the trace functions"
0617 },
0618 {
0619 "start",
0620 rtems_trace_buffering_shell_start,
0621 " : Start or restart tracing"
0622 },
0623 {
0624 "stop",
0625 rtems_trace_buffering_shell_stop,
0626 " : Stop tracing"
0627 },
0628 {
0629 "resume",
0630 rtems_trace_buffering_shell_resume,
0631 " : Resume tracing."
0632 },
0633 {
0634 "trace",
0635 rtems_trace_buffering_shell_trace,
0636 " [start] [end/+length] : List the current trace records"
0637 },
0638 {
0639 "save",
0640 rtems_trace_buffering_shell_save,
0641 " file : Save the trace buffer to a file"
0642 },
0643 };
0644
0645 #define RTEMS_TRACE_BUFFERING_COMMANDS \
0646 (sizeof (table) / sizeof (const rtems_trace_buffering_shell_cmd_t))
0647
0648 static int
0649 rtems_shell_main_rtrace (int argc, char* argv[])
0650 {
0651 int arg;
0652 size_t t;
0653
0654 for (arg = 1; arg < argc; arg++)
0655 {
0656 if (argv[arg][0] != '-')
0657 break;
0658
0659 switch (argv[arg][1])
0660 {
0661 case 'h':
0662 rtems_trace_buffering_shell_usage (argv[0]);
0663 return 0;
0664 case 'l':
0665 printf ("%s: commands are:\n", argv[0]);
0666 for (t = 0; t < RTEMS_TRACE_BUFFERING_COMMANDS; ++t)
0667 printf (" %-7s %s\n", table[t].name, table[t].help);
0668 return 0;
0669 default:
0670 printf ("error: unknown option: %s\n", argv[arg]);
0671 return 1;
0672 }
0673 }
0674
0675 if ((argc - arg) < 1)
0676 printf ("error: you need to provide a command, try %s -h\n", argv[0]);
0677 else
0678 {
0679 for (t = 0; t < RTEMS_TRACE_BUFFERING_COMMANDS; ++t)
0680 {
0681 if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
0682 {
0683 int r = table[t].handler (argc - arg, argv + 1);
0684 return r;
0685 }
0686 }
0687 printf ("error: command not found: %s (try -h)\n", argv[arg]);
0688 }
0689
0690 return 1;
0691 }
0692
0693 rtems_shell_cmd_t rtems_shell_RTRACE_Command = {
0694 "rtrace",
0695 "rtrace [-l]",
0696 "misc",
0697 rtems_shell_main_rtrace,
0698 NULL,
0699 NULL
0700 };