Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*
0002  *  Copyright (c) 2015 Chris Johns <chrisj@rtems.org>
0003  *
0004  *  The license and distribution terms for this file may be
0005  *  found in the file LICENSE in this distribution or at
0006  *  http://www.rtems.org/license/LICENSE.
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  * The type of the shell handlers we have.
0025  */
0026 typedef int (*rtems_trace_buffering_shell_handler_t) (int argc, char *argv[]);
0027 
0028 /**
0029  * Table of handlers we parse to invoke the command.
0030  */
0031 typedef struct
0032 {
0033   const char*                           name;    /**< The sub-command's name. */
0034   rtems_trace_buffering_shell_handler_t handler; /**< The sub-command's handler. */
0035   const char*                           help;    /**< The sub-command's 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    * Header label.
0485    */
0486   memcpy (in, "RTEMS-TRACE", sizeof("RTEMS-TRACE"));
0487   in += 12;
0488 
0489   /*
0490    * Endian detection.
0491    */
0492   *((uint32_t*) in) = 0x11223344;
0493   in += sizeof(uint32_t);
0494 
0495   /*
0496    * Number of traces.
0497    */
0498   *((uint32_t*) in) = traces;
0499   in += sizeof(uint32_t);
0500 
0501   /*
0502    * Write it.
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    * The trace names.
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    * The trace signatures.
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",                      /* name */
0695   "rtrace [-l]",                 /* usage */
0696   "misc",                        /* topic */
0697   rtems_shell_main_rtrace,       /* command */
0698   NULL,                          /* alias */
0699   NULL                           /* next */
0700 };