Quick comments:<br><br>Avoid abbreviations but feel free to use acronyms in "rtems" APIs . Make sure acronyms are documented, what is TBG?<br><br>If divide by 32 is on hot path might want to reconsider it if possible<br><br>A macro for the bit masks would improve readability<br><br>I've seen this print timestamp functionality before in shell I think, might be worth sharing code<br><br>-- <br>Sent from a mobile device.<br><br>-----Original Message-----<br>[PATCH] libmisc/shell: Add the rtrace command for buffered tracing support.<br>From: Chris Johns <chrisj@rtems.org><br>To:  <deve@rtems.org>, <devel@rtems.org><br>Sunday, March 29, 2015 at 3:55 AM<br><br>The rtrace command interfaces to the RTEMS Trace Linker's trace<br>buffering data allowing users to capture and report trace data.<br>---<br> cpukit/Makefile.am                               |   5 +<br> cpukit/libmisc/Makefile.am                       |   5 +-<br> cpukit/libmisc/capture/rtems-trace-buffer-vars.c | 178 ++++++<br> cpukit/libmisc/capture/rtems-trace-buffer-vars.h | 147 +++++<br> cpukit/libmisc/shell/main_rtrace.c               | 676 +++++++++++++++++++++++<br> cpukit/libmisc/shell/shellconfig.h               |  10 +<br> cpukit/preinstall.am                             |   9 +<br> 7 files changed, 1028 insertions(+), 2 deletions(-)<br> create mode 100644 cpukit/libmisc/capture/rtems-trace-buffer-vars.c<br> create mode 100644 cpukit/libmisc/capture/rtems-trace-buffer-vars.h<br> create mode 100644 cpukit/libmisc/shell/main_rtrace.c<br><br>diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am<br>index 10b59db..7df116c 100644<br>--- a/cpukit/Makefile.am<br>+++ b/cpukit/Makefile.am<br>@@ -172,6 +172,11 @@ include_rtems_HEADERS += libmisc/capture/capture.h<br> include_rtems_HEADERS += libmisc/capture/capture-cli.h<br> include_rtems_HEADERS += libmisc/capture/captureimpl.h<br> <br>+# tracing headers<br>+include_rtems_tracedir = $(include_rtemsdir)/trace<br>+include_rtems_trace_HEADERS =<br>+include_rtems_trace_HEADERS += libmisc/capture/rtems-trace-buffer-vars.h<br>+<br> ## cpuuse<br> include_rtems_HEADERS += libmisc/cpuuse/cpuuse.h<br> <br>diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am<br>index f09b69d..ac703ad 100644<br>--- a/cpukit/libmisc/Makefile.am<br>+++ b/cpukit/libmisc/Makefile.am<br>@@ -21,7 +21,8 @@ libcapture_a_SOURCES = capture/capture.c capture/capture-cli.c \<br>     capture/capture_user_extension.c capture/capture_buffer.c \<br>     capture/capture_support.c \<br>     capture/capture.h capture/captureimpl.h capture/capture-cli.h \<br>-    capture/capture_buffer.h<br>+    capture/capture_buffer.h \<br>+    capture/rtems-trace-buffer-vars.c capture/rtems-trace-buffer-vars.h<br> <br> ## cpuuse<br> EXTRA_DIST += cpuuse/README<br>@@ -108,7 +109,7 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \<br>     shell/main_setenv.c shell/main_getenv.c shell/main_unsetenv.c \<br>     shell/main_mkrfs.c shell/main_debugrfs.c shell/main_df.c \<br>     shell/main_lsof.c shell/main_edit.c \<br>-    shell/main_blkstats.c \<br>+    shell/main_blkstats.c shell/main_rtrace.c \<br>     shell/shell-wait-for-input.c<br> libshell_a_SOURCES += shell/main_cmdls.c<br> libshell_a_SOURCES += shell/main_cmdchown.c<br>diff --git a/cpukit/libmisc/capture/rtems-trace-buffer-vars.c b/cpukit/libmisc/capture/rtems-trace-buffer-vars.c<br>new file mode 100644<br>index 0000000..92054bf<br>--- /dev/null<br>+++ b/cpukit/libmisc/capture/rtems-trace-buffer-vars.c<br>@@ -0,0 +1,178 @@<br>+/*<br>+ *  Copyright (c) 2015 Chris Johns <chrisj@rtems.org><br>+ *<br>+ *  The license and distribution terms for this file may be<br>+ *  found in the file LICENSE in this distribution or at<br>+ *  <a href="http://www.rtems.org/license/LICENSE.">http://www.rtems.org/license/LICENSE.</a><br><br>+ */<br>+<br>+#include <rtems.h><br>+<br>+#include <rtems/trace/rtems-trace-buffer-vars.h><br>+<br>+/**<br>+ * External Trace Linker and TBG data. We provide weak versions to allow us to<br>+ * link and be present in an application that has not been trace linked.<br>+ */<br>+<br>+/*<br>+ * Trace linker data.<br>+ */<br>+uint32_t __rtld_trace_names_size __attribute__ ((weak));<br>+const char const* __rtld_trace_names[1] __attribute__ ((weak));<br>+uint32_t __rtld_trace_enables_size __attribute__ ((weak));<br>+const uint32_t __rtld_trace_enables[1] __attribute__ ((weak));<br>+uint32_t __rtld_trace_triggers_size __attribute__ ((weak));<br>+const uint32_t __rtld_trace_triggers[1] __attribute__ ((weak));<br>+const __rtld_trace_sig __rtld_trace_signatures[1] __attribute__ ((weak));<br>+<br>+/*<br>+ * Trace buffer generator data.<br>+ */<br>+const bool __rtld_tbg_present __attribute__ ((weak));<br>+const uint32_t __rtld_tbg_mode __attribute__ ((weak));<br>+const uint32_t __rtld_tbg_buffer_size __attribute__ ((weak));<br>+uint32_t __rtld_tbg_buffer[1] __attribute__ ((weak));<br>+volatile uint32_t __rtld_tbg_buffer_in __attribute__ ((weak));<br>+volatile bool __rtld_tbg_finished __attribute__ ((weak));<br>+volatile bool __rtld_tbg_triggered __attribute__ ((weak));<br>+<br>+uint32_t<br>+rtems_trace_names_size (void)<br>+{<br>+  return __rtld_trace_names_size;<br>+}<br>+<br>+const char*<br>+rtems_trace_names (const uint32_t index)<br>+{<br>+  return __rtld_trace_names[index];<br>+}<br>+<br>+uint32_t<br>+rtems_trace_enables_size (void)<br>+{<br>+  return __rtld_trace_enables_size;<br>+}<br>+<br>+uint32_t<br>+rtems_trace_enables (const uint32_t index)<br>+{<br>+  return __rtld_trace_enables[index];<br>+}<br>+<br>+uint32_t<br>+rtems_trace_triggers_size (void)<br>+{<br>+  return __rtld_trace_triggers_size;<br>+}<br>+<br>+uint32_t<br>+rtems_trace_triggers (const uint32_t index)<br>+{<br>+  return __rtld_trace_triggers[index];<br>+}<br>+<br>+const rtems_trace_sig*<br>+rtems_trace_signatures (const uint32_t index)<br>+{<br>+  return &__rtld_trace_signatures[index];<br>+}<br>+<br>+bool<br>+rtems_trace_enable_set(const uint32_t index)<br>+{<br>+  return (__rtld_trace_enables[index / 32] & (1 << (index & (32 - 1)))) != 0 ? true : false;<br>+}<br>+<br>+bool<br>+rtems_trace_trigger_set(const uint32_t index)<br>+{<br>+  return (__rtld_trace_triggers[index / 32] & (1 << (index & (32 - 1)))) != 0 ? true : false;<br>+}<br>+<br>+bool<br>+rtems_trace_tbg_present (void)<br>+{<br>+  return __rtld_tbg_present;<br>+}<br>+<br>+uint32_t<br>+rtems_trace_tbg_mode (void)<br>+{<br>+  return __rtld_tbg_mode;<br>+}<br>+<br>+uint32_t<br>+rtems_trace_tbg_buffer_size (void)<br>+{<br>+  return __rtld_tbg_buffer_size;<br>+}<br>+<br>+uint32_t*<br>+rtems_trace_tbg_buffer (void)<br>+{<br>+  return &__rtld_tbg_buffer[0];<br>+}<br>+<br>+uint32_t<br>+rtems_trace_tbg_buffer_in (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  uint32_t                     in;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  in = __rtld_tbg_buffer_in;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+  return in;<br>+}<br>+<br>+bool<br>+rtems_trace_tbg_finished (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  bool                         finished;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  finished = __rtld_tbg_finished;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+  return finished;<br>+}<br>+<br>+bool<br>+rtems_trace_tbg_triggered (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  bool                         triggered;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  triggered = __rtld_tbg_triggered;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+  return triggered;<br>+}<br>+<br>+void<br>+rtems_trace_tbg_start (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  __rtld_tbg_triggered = false;<br>+  __rtld_tbg_buffer_in = 0;<br>+  __rtld_tbg_finished = false;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+}<br>+<br>+void<br>+rtems_trace_tbg_stop (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  __rtld_tbg_finished = true;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+}<br>+<br>+void<br>+rtems_trace_tbg_resume (void)<br>+{<br>+  rtems_interrupt_lock_context lcontext;<br>+  rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);<br>+  __rtld_tbg_finished = false;<br>+  rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);<br>+}<br>diff --git a/cpukit/libmisc/capture/rtems-trace-buffer-vars.h b/cpukit/libmisc/capture/rtems-trace-buffer-vars.h<br>new file mode 100644<br>index 0000000..eab19ee<br>--- /dev/null<br>+++ b/cpukit/libmisc/capture/rtems-trace-buffer-vars.h<br>@@ -0,0 +1,147 @@<br>+/**<br>+ * @file<br>+ *<br>+ * @ingroup Shell<br>+ *<br>+ * @brief Access to the RTEMS Trace Buffer Generator.<br>+ */<br>+/*<br>+ *  Copyright (c) 2015 Chris Johns <chrisj@rtems.org><br>+ *<br>+ *  The license and distribution terms for this file may be<br>+ *  found in the file LICENSE in this distribution or at<br>+ *  <a href="http://www.rtems.org/license/LICENSE.">http://www.rtems.org/license/LICENSE.</a><br><br>+ */<br>+<br>+#if !defined (_RTEMS_TRACE_BUFFER_VARS_H_)<br>+#define _RTEMS_TRACE_BUFFER_VARS_H_<br>+<br>+#ifdef __cplusplus<br>+extern "C" {<br>+#endif /* __cplusplus */<br>+<br>+/**<br>+ * These functions are provided as a separated interface to the TBG data are<br>+ * not really designed for any real-time performance type interface.<br>+ *<br>+ * Separating the data from the codes stops the compiler incorrectly loop<br>+ * optimising.<br>+ */<br>+<br>+typedef struct<br>+{<br>+  uint32_t          size;<br>+  const char* const type;<br>+} __rtld_trace_sig_arg;<br>+<br>+  typedef struct {<br>+    uint32_t                    argc;<br>+    const __rtld_trace_sig_arg* args;<br>+} __rtld_trace_sig;<br>+<br>+typedef __rtld_trace_sig_arg rtems_trace_sig_arg;<br>+typedef __rtld_trace_sig rtems_trace_sig;<br>+<br>+/**<br>+ * Returns the number of trace functions.<br>+ */<br>+uint32_t  rtems_trace_names_size (void);<br>+<br>+/**<br>+ * Return the name given an index. No range checking.<br>+ */<br>+const char* rtems_trace_names (const uint32_t index);<br>+<br>+/**<br>+ * Returns the number of words in the enables array.<br>+ */<br>+uint32_t rtems_trace_enables_size (void);<br>+<br>+/**<br>+ * Return the enable 32bit bitmap indexed into the enables array. No range<br>+ * checking.<br>+ */<br>+uint32_t rtems_trace_enables (const uint32_t index);<br>+<br>+/**<br>+ * Returns the number of words in the triggers array.<br>+ */<br>+uint32_t rtems_trace_triggers_size (void);<br>+<br>+/**<br>+ * Return the trigger 32bit bitmap indexed into the triggers array. No range<br>+ * checking.<br>+ */<br>+uint32_t rtems_trace_triggers (const uint32_t index);<br>+<br>+/**<br>+ * Return the trace function signature.<br>+ */<br>+const rtems_trace_sig* rtems_trace_signatures (const uint32_t index);<br>+<br>+/**<br>+ * Return true is the enable bit is set for the trace function index.<br>+ */<br>+bool rtems_trace_enable_set(const uint32_t index);<br>+<br>+/**<br>+ * Return true is the trigger bit is set for the trace function index.<br>+ */<br>+bool rtems_trace_trigger_set(const uint32_t index);<br>+<br>+/**<br>+ * The application has been linked with Trace Buffering generated code.<br>+ */<br>+bool rtems_trace_tbg_present (void);<br>+<br>+/**<br>+ * Return the TBG mode flags.<br>+ */<br>+uint32_t rtems_trace_tbg_mode (void);<br>+<br>+/**<br>+ * Return the size of the TBG buffer in words.<br>+ */<br>+uint32_t rtems_trace_tbg_buffer_size (void);<br>+<br>+/**<br>+ * Return the base of the TBG buffer.<br>+ */<br>+uint32_t* rtems_trace_tbg_buffer (void);<br>+<br>+/**<br>+ * Return the buffer level. This is only stable if tracing has finished.<br>+ */<br>+uint32_t rtems_trace_tbg_buffer_in (void);<br>+<br>+/**<br>+ * The tracing has finished.<br>+ */<br>+bool rtems_trace_tbg_finished (void);<br>+<br>+/**<br>+ * Trace has been triggered and enable trace functions are being recorded.<br>+ */<br>+bool rtems_trace_tbg_triggered (void);<br>+<br>+/**<br>+ * Start tracing by clearing the triggered flag, setting to 0 and clearing the<br>+ * finished flag.<br>+ */<br>+void rtems_trace_tbg_start (void);<br>+<br>+/**<br>+ * Stop tracing by setting the finished flag.<br>+ */<br>+void rtems_trace_tbg_stop (void);<br>+<br>+/**<br>+ * Resume tracing by setting the finished flag.<br>+ */<br>+void rtems_trace_tbg_resume (void);<br>+<br>+#ifdef __cplusplus<br>+}<br>+#endif /* __cplusplus */<br>+<br>+#endif<br>diff --git a/cpukit/libmisc/shell/main_rtrace.c b/cpukit/libmisc/shell/main_rtrace.c<br>new file mode 100644<br>index 0000000..2410398<br>--- /dev/null<br>+++ b/cpukit/libmisc/shell/main_rtrace.c<br>@@ -0,0 +1,676 @@<br>+/*<br>+ *  Copyright (c) 2015 Chris Johns <chrisj@rtems.org><br>+ *<br>+ *  The license and distribution terms for this file may be<br>+ *  found in the file LICENSE in this distribution or at<br>+ *  <a href="http://www.rtems.org/license/LICENSE.">http://www.rtems.org/license/LICENSE.</a><br><br>+ */<br>+<br>+#include <ctype.h><br>+#include <errno.h><br>+#include <fcntl.h><br>+#include <inttypes.h><br>+#include <stdio.h><br>+#include <stdlib.h><br>+#include <sys/types.h><br>+#include <time.h><br>+#include <unistd.h><br>+<br>+#include <rtems/shell.h><br>+#include <rtems/trace/rtems-trace-buffer-vars.h><br>+<br>+/**<br>+ * The type of the shell handlers we have.<br>+ */<br>+typedef int (*rtems_tbg_shell_handler_t) (int argc, char *argv[]);<br>+<br>+/**<br>+ * Table of handlers we parse to invoke the command.<br>+ */<br>+typedef struct<br>+{<br>+  const char*               name;    /**< The sub-command's name. */<br>+  rtems_tbg_shell_handler_t handler; /**< The sub-command's handler. */<br>+  const char*               help;    /**< The sub-command's help. */<br>+} rtems_tbg_shell_cmd_t;<br>+<br>+static int<br>+rtems_tbg_wrong_number_of_args (void)<br>+{<br>+  printf ("error: wrong number of arguments\n");<br>+  return 1;<br>+}<br>+<br>+static int<br>+rtems_tbg_invalid_args (const char* arg)<br>+{<br>+  printf ("error: invalid argument: %s\n", arg);<br>+  return 1;<br>+}<br>+<br>+static int<br>+rtems_tbg_no_trace_buffer_code (void)<br>+{<br>+  printf("No trace buffer generated code in the application; see rtems-tld\n");<br>+  return 1;<br>+}<br>+<br>+static void<br>+rtems_tbg_banner (const char* label)<br>+{<br>+  printf("RTEMS Trace Bufferring: %s\n", label);<br>+}<br>+<br>+static void<br>+rtems_tbg_print_timestamp (uint64_t uptime)<br>+{<br>+  uint32_t hours;<br>+  uint32_t minutes;<br>+  uint32_t seconds;<br>+  uint32_t nanosecs;<br>+  uint64_t up_secs;<br>+<br>+  up_secs  = uptime / 1000000000LLU;<br>+  minutes  = up_secs / 60;<br>+  hours    = minutes / 60;<br>+  minutes  = minutes % 60;<br>+  seconds  = up_secs % 60;<br>+  nanosecs = uptime % 1000000000;<br>+<br>+  printf ("%5" PRIu32 ":%02" PRIu32 ":%02" PRIu32".%09" PRIu32,<br>+          hours, minutes, seconds, nanosecs);<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_status (int argc, char *argv[])<br>+{<br>+  uint32_t buffer_size;<br>+  uint32_t buffer_in;<br>+  bool     finished;<br>+  bool     triggered;<br>+  uint32_t names;<br>+<br>+  if (argc != 1)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  buffer_size = rtems_trace_tbg_buffer_size ();<br>+  buffer_in = rtems_trace_tbg_buffer_in ();<br>+  finished = rtems_trace_tbg_finished ();<br>+  triggered = rtems_trace_tbg_triggered ();<br>+  names = rtems_trace_names_size ();<br>+<br>+  rtems_tbg_banner ("status");<br>+  printf("    Running:   %s\n", finished ? "no" : "yes");<br>+  printf("  Triggered:   %s\n", triggered ? "yes" : "no");<br>+  printf("      Level:  %3lu%%\n", (buffer_in * 100) / buffer_size);<br>+  printf("     Traces: %4lu\n", names);<br>+<br>+  return 0;<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_funcs (int argc, char *argv[])<br>+{<br>+  size_t traces = rtems_trace_names_size ();<br>+  size_t          t;<br>+  size_t          max = 0;<br>+<br>+  if (argc != 1)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  rtems_tbg_banner ("trace functions");<br>+  printf(" Total: %4zu\n", traces);<br>+<br>+  for (t = 0; t < traces; ++t)<br>+  {<br>+    size_t l = strlen (rtems_trace_names (t));<br>+    if (l > max)<br>+      max = l;<br>+  }<br>+<br>+  for (t = 0; t < traces; ++t)<br>+  {<br>+    printf(" %4zu: %c%c %-*s\n", t,<br>+           rtems_trace_enable_set(t) ? 'E' : '-',<br>+           rtems_trace_trigger_set(t) ? 'T' : '-',<br>+           max, rtems_trace_names (t));<br>+  }<br>+<br>+  return 0;<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_start (int argc, char *argv[])<br>+{<br>+  if (argc != 1)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  rtems_tbg_banner ("resume");<br>+<br>+  if (!rtems_trace_tbg_finished ())<br>+  {<br>+    printf("already running\n");<br>+    return 0;<br>+  }<br>+<br>+  rtems_trace_tbg_start ();<br>+<br>+  return 0;<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_stop (int argc, char *argv[])<br>+{<br>+  if (argc != 1)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  rtems_tbg_banner ("stop");<br>+<br>+  if (rtems_trace_tbg_finished ())<br>+  {<br>+    printf("already stopped\n");<br>+    return 0;<br>+  }<br>+<br>+  rtems_trace_tbg_stop ();<br>+<br>+  return 0;<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_resume (int argc, char *argv[])<br>+{<br>+  if (argc != 1)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  rtems_tbg_banner ("resume");<br>+<br>+  if (!rtems_trace_tbg_finished ())<br>+  {<br>+    printf("already running\n");<br>+    return 0;<br>+  }<br>+<br>+  rtems_trace_tbg_start ();<br>+<br>+  return 0;<br>+}<br>+<br>+static void rtems_tbg_print_arg (const rtems_trace_sig_arg* arg,<br>+                                 const uint8_t*             argv)<br>+{<br>+  if (arg->size)<br>+  {<br>+    union<br>+    {<br>+      uint8_t  bytes[sizeof (uint64_t)];<br>+      uint16_t u16;<br>+      uint32_t u32;<br>+      uint64_t u64;<br>+      void*    pointer;<br>+    } variable;<br>+<br>+    if (arg->size <= sizeof(uint64_t))<br>+      memcpy (&variable.bytes[0], argv, arg->size);<br>+<br>+    printf ("(%s) ", arg->type);<br>+<br>+    if (strchr (arg->type, '*') != NULL)<br>+    {<br>+      printf ("%p", variable.pointer);<br>+    }<br>+    else<br>+    {<br>+      size_t b;<br>+      switch (arg->size)<br>+      {<br>+        case 2:<br>+          printf ("%04x", variable.u16);<br>+          break;<br>+        case 4:<br>+          printf ("%08lx", variable.u32);<br>+          break;<br>+        case 8:<br>+          printf ("%016llx", variable.u64);<br>+          break;<br>+        default:<br>+          for (b = 0; b < arg->size; ++b)<br>+            printf ("%02x", (unsigned int) *argv++);<br>+          break;<br>+      }<br>+    }<br>+  }<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_trace (int argc, char *argv[])<br>+{<br>+  uint32_t* trace_buffer;<br>+  uint32_t  records;<br>+  uint32_t  traces;<br>+  uint32_t  r = 0;<br>+  size_t    lines = 40;<br>+  size_t    count = 0;<br>+  uint64_t  last_sample = 0;<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  trace_buffer = rtems_trace_tbg_buffer ();<br>+  records = rtems_trace_tbg_buffer_in ();<br>+  traces = rtems_trace_names_size ();<br>+<br>+  if (argc > 1)<br>+  {<br>+    if (argc > 3)<br>+      return rtems_tbg_wrong_number_of_args ();<br>+<br>+    if (argv[1][0] == '+')<br>+    {<br>+      if (argc > 2)<br>+        return rtems_tbg_wrong_number_of_args ();<br>+<br>+      lines = strtoul (argv[1] + 1, 0, 0);<br>+      if (lines == 0)<br>+      {<br>+        printf("error: invalid number of lines\n");<br>+        return 1;<br>+      }<br>+    }<br>+    else<br>+    {<br>+      r = strtoul (argv[1], 0, 0);<br>+      if (r >= records)<br>+      {<br>+        printf ("error: start record out of range (max %lu)\n", records);<br>+        return 1;<br>+      }<br>+    }<br>+<br>+    if (argc == 3)<br>+    {<br>+      if (argv[2][0] == '+')<br>+      {<br>+        lines = strtoul (argv[2] + 1, 0, 0);<br>+        if (lines == 0)<br>+        {<br>+          printf("error: invalid number of lines\n");<br>+          return 1;<br>+        }<br>+      }<br>+      else<br>+      {<br>+        lines = strtoul (argv[2], 0, 0);<br>+        if (lines < r)<br>+        {<br>+          printf ("error: end record before start\n");<br>+          return 1;<br>+        }<br>+        else if (lines > records)<br>+        {<br>+          printf ("error: end record out of range (max %lu)\n", records);<br>+        }<br>+        lines = lines - r;<br>+      }<br>+    }<br>+  }<br>+<br>+  rtems_tbg_banner ("trace");<br>+<br>+  if (!rtems_trace_tbg_finished ())<br>+  {<br>+    printf("tracing still running\n");<br>+    return 0;<br>+  }<br>+<br>+  if (argc > 1)<br>+  {<br>+    lines = strtoul (argv[1], 0, 0);<br>+    if (lines == 0)<br>+      return rtems_tbg_invalid_args (argv[1]);<br>+  }<br>+<br>+  printf(" Trace buffer: %p\n", trace_buffer);<br>+  printf(" Words traced: %lu\n", records);<br>+  printf("       Traces: %lu\n", traces);<br>+<br>+  r = 0;<br>+<br>+  while ((r < records) && ((lines == 0) || (count < lines)))<br>+  {<br>+    const uint32_t header = trace_buffer[r];<br>+    const uint32_t func_index = header & 0xffff;<br>+    const uint32_t len = (header >> 16) & 0x0fff;<br>+    const uint32_t task_id = trace_buffer[r + 1];<br>+    const uint32_t task_status = trace_buffer[r + 2];<br>+    const uint64_t when = (((uint64_t) trace_buffer[r + 4]) << 32) | trace_buffer[r + 5];<br>+    const uint8_t* argv = (uint8_t*) &trace_buffer[r + 6];<br>+    const bool     ret = (header & (1 << 30)) == 0 ? false : true;<br>+    const bool     irq = (header & (1 << 31)) == 0 ? false : true;<br>+<br>+    const rtems_trace_sig* sig = rtems_trace_signatures (func_index);<br>+<br>+    rtems_tbg_print_timestamp (when);<br>+    printf (" %10lu %c%08lx [%3lu/%3lu] %c %s",<br>+            (uint32_t) (when - last_sample),<br>+            irq ? '*' : ' ', task_id, (task_status >> 8) & 0xff, task_status & 0xff,<br>+            ret ? '<' : '>', rtems_trace_names (func_index));<br>+<br>+    if (sig->argc)<br>+    {<br>+      if (ret)<br>+      {<br>+        if (sig->args[0].size)<br>+          printf(" => ");<br>+        rtems_tbg_print_arg (&sig->args[0], argv);<br>+      }<br>+      else<br>+      {<br>+        size_t a;<br>+        printf("(");<br>+        for (a = 1; a < sig->argc; ++a)<br>+        {<br>+          if (a > 1)<br>+            printf (", ");<br>+          rtems_tbg_print_arg (&sig->args[a], argv);<br>+          argv += sig->args[a].size;<br>+        }<br>+        printf(")");<br>+      }<br>+    }<br>+<br>+    printf("\n");<br>+<br>+    r += ((len - 1) / sizeof (uint32_t)) + 1;<br>+    last_sample = when;<br>+    ++count;<br>+  }<br>+<br>+  return 0;<br>+}<br>+<br>+static ssize_t<br>+rtems_tbg_file_write (int out, const void* vbuffer, ssize_t length)<br>+{<br>+  const uint8_t* buffer = vbuffer;<br>+  while (length)<br>+  {<br>+    ssize_t w = write (out, buffer, length);<br>+    if (w < 0)<br>+    {<br>+      printf ("error: write failed: %s\n", strerror(errno));<br>+      return false;<br>+    }<br>+    if (w == 0)<br>+    {<br>+      printf ("error: write failed: EOF\n");<br>+      return false;<br>+    }<br>+<br>+    length -= w;<br>+    buffer += w;<br>+  }<br>+  return true;<br>+}<br>+<br>+static int<br>+rtems_tbg_shell_save (int argc, char *argv[])<br>+{<br>+  uint32_t* trace_buffer;<br>+  uint32_t  records;<br>+  uint32_t  traces;<br>+  uint8_t*  buffer;<br>+  size_t    length;<br>+  uint32_t  r;<br>+  int       out;<br>+  uint8_t*  buf;<br>+  uint8_t*  in;<br>+<br>+  if (argc != 2)<br>+    return rtems_tbg_wrong_number_of_args ();<br>+<br>+  if (!rtems_trace_tbg_present ())<br>+    return rtems_tbg_no_trace_buffer_code ();<br>+<br>+  rtems_tbg_banner ("trace");<br>+<br>+  if (!rtems_trace_tbg_finished ())<br>+  {<br>+    printf("tracing still running\n");<br>+    return 0;<br>+  }<br>+<br>+  trace_buffer = rtems_trace_tbg_buffer ();<br>+  records = rtems_trace_tbg_buffer_in ();<br>+  traces = rtems_trace_names_size ();<br>+<br>+  printf("   Trace File: %s\n", argv[1]);<br>+  printf(" Trace buffer: %p\n", trace_buffer);<br>+  printf(" Words traced: %lu\n", records);<br>+  printf("       Traces: %lu\n", traces);<br>+<br>+  out = open (argv[1], O_WRONLY | O_TRUNC | O_CREAT,<br>+              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);<br>+  if (out < 0)<br>+  {<br>+    printf ("error: opening file: %s: %s\n", argv[1], strerror(errno));<br>+    return 1;<br>+  }<br>+<br>+  #define SAVE_BUF_SIZE (1024)<br>+<br>+  buf = malloc(SAVE_BUF_SIZE);<br>+  if (!buf)<br>+  {<br>+    close (out);<br>+    printf ("error: no memory\n");<br>+  }<br>+<br>+  memset (buf, 0, SAVE_BUF_SIZE);<br>+<br>+  in = buf;<br>+<br>+  /*<br>+   * Header label.<br>+   */<br>+  memcpy (in, "RTEMS-TRACE", sizeof("RTEMS-TRACE"));<br>+  in += 12;<br>+<br>+  /*<br>+   * Endian detection.<br>+   */<br>+  *((uint32_t*) in) = 0x11223344;<br>+  in += sizeof(uint32_t);<br>+<br>+  /*<br>+   * Number of traces.<br>+   */<br>+  *((uint32_t*) in) = traces;<br>+  in += sizeof(uint32_t);<br>+<br>+  /*<br>+   * Write it.<br>+   */<br>+  if (!rtems_tbg_file_write (out, buf, in - buf))<br>+  {<br>+    free (buf);<br>+    close (out);<br>+    return 1;<br>+  }<br>+<br>+  /*<br>+   * The trace names.<br>+   */<br>+  for (r = 0; r < traces; ++r)<br>+  {<br>+    const char* name = rtems_trace_names (r);<br>+    if (!rtems_tbg_file_write (out, name, strlen (name) + 1))<br>+    {<br>+      free (buf);<br>+      close (out);<br>+      return 1;<br>+    }<br>+  }<br>+<br>+  /*<br>+   * The trace signatures.<br>+   */<br>+  for (r = 0; r < traces; ++r)<br>+  {<br>+    const rtems_trace_sig* sig = rtems_trace_signatures (r);<br>+    size_t                 s;<br>+<br>+    in = buf;<br>+<br>+    *((uint32_t*) in) = sig->argc;<br>+    in += sizeof(uint32_t);<br>+<br>+    for (s = 0; s < sig->argc; ++s)<br>+    {<br>+      const rtems_trace_sig_arg* arg = &sig->args[s];<br>+      size_t                     arg_len = strlen (arg->type) + 1;<br>+<br>+      if ((in - buf) > SAVE_BUF_SIZE)<br>+      {<br>+        printf ("error: save temp buffer to small\n");<br>+        free (buf);<br>+        close (out);<br>+        return 1;<br>+      }<br>+<br>+      *((uint32_t*) in) = arg->size;<br>+      in += sizeof(uint32_t);<br>+      memcpy (in, arg->type, arg_len);<br>+      in += arg_len;<br>+    }<br>+<br>+    if (!rtems_tbg_file_write (out, buf, in - buf))<br>+    {<br>+      free (buf);<br>+      close (out);<br>+      return 1;<br>+    }<br>+  }<br>+<br>+  free (buf);<br>+<br>+  buffer = (uint8_t*) trace_buffer;<br>+  length = records * sizeof (uint32_t);<br>+<br>+  while (length)<br>+  {<br>+    ssize_t w = write (out, buffer, length);<br>+    if (w < 0)<br>+    {<br>+      printf ("error: write failed: %s\n", strerror(errno));<br>+      close (out);<br>+      return 1;<br>+    }<br>+    if (w == 0)<br>+    {<br>+      printf ("error: write failed: EOF\n");<br>+      close (out);<br>+      return 1;<br>+    }<br>+<br>+    length -= w;<br>+    buffer += w;<br>+  }<br>+<br>+  close (out);<br>+<br>+  return 0;<br>+}<br>+<br>+void<br>+rtems_tbg_shell_usage (const char* arg)<br>+{<br>+  printf ("%s: Trace Buffer Help\n", arg);<br>+  printf ("  %s [-hl] <command>\n", arg);<br>+  printf ("   where:\n");<br>+  printf ("     command: The TBG subcommand. See -l for a list plus help.\n");<br>+  printf ("     -h:      This help\n");<br>+  printf ("     -l:      The command list.\n");<br>+}<br>+<br>+static const rtems_tbg_shell_cmd_t table[] =<br>+{<br>+  { "status",  rtems_tbg_shell_status,  "                       : Show the current status" },<br>+  { "funcs",   rtems_tbg_shell_funcs,   "                       : List the trace functions" },<br>+  { "start",   rtems_tbg_shell_start,   "                       : Start or restart tracing" },<br>+  { "stop",    rtems_tbg_shell_stop,    "                       : Stop tracing" },<br>+  { "resume",  rtems_tbg_shell_resume,  "                       : Resume tracing." },<br>+  { "trace",   rtems_tbg_shell_trace,   " [start] [end/+length] : List the current trace records" },<br>+  { "save",    rtems_tbg_shell_save,    " file                  : Save the trace buffer to a file" },<br>+};<br>+<br>+#define RTEMS_TBG_COMMANDS (sizeof (table) / sizeof (const rtems_tbg_shell_cmd_t))<br>+<br>+static int<br>+rtems_shell_main_rtrace (int argc, char* argv[])<br>+{<br>+  int    arg;<br>+  size_t t;<br>+<br>+  for (arg = 1; arg < argc; arg++)<br>+  {<br>+    if (argv[arg][0] != '-')<br>+      break;<br>+<br>+    switch (argv[arg][1])<br>+    {<br>+      case 'h':<br>+        rtems_tbg_shell_usage (argv[0]);<br>+        return 0;<br>+      case 'l':<br>+        printf ("%s: commands are:\n", argv[0]);<br>+        for (t = 0; t < RTEMS_TBG_COMMANDS; ++t)<br>+          printf ("  %-7s %s\n", table[t].name, table[t].help);<br>+        return 0;<br>+      default:<br>+        printf ("error: unknown option: %s\n", argv[arg]);<br>+        return 1;<br>+    }<br>+  }<br>+<br>+  if ((argc - arg) < 1)<br>+    printf ("error: you need to provide a command, try %s -h\n", argv[0]);<br>+  else<br>+  {<br>+    for (t = 0; t < RTEMS_TBG_COMMANDS; ++t)<br>+    {<br>+      if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)<br>+      {<br>+        int r = table[t].handler (argc - arg, argv + 1);<br>+        return r;<br>+      }<br>+    }<br>+    printf ("error: command not found: %s (try -h)\n", argv[arg]);<br>+  }<br>+<br>+  return 1;<br>+}<br>+<br>+rtems_shell_cmd_t rtems_shell_RTRACE_Command = {<br>+  "rtrace",                      /* name */<br>+  "rtrace [-l]",                 /* usage */<br>+  "misc",                        /* topic */<br>+  rtems_shell_main_rtrace,       /* command */<br>+  NULL,                          /* alias */<br>+  NULL                           /* next */<br>+};<br>diff --git a/cpukit/libmisc/shell/shellconfig.h b/cpukit/libmisc/shell/shellconfig.h<br>index 2e52a92..9023a60 100644<br>--- a/cpukit/libmisc/shell/shellconfig.h<br>+++ b/cpukit/libmisc/shell/shellconfig.h<br>@@ -87,6 +87,7 @@ extern rtems_shell_cmd_t rtems_shell_PERIODUSE_Command;<br> extern rtems_shell_cmd_t rtems_shell_PROFREPORT_Command;<br> extern rtems_shell_cmd_t rtems_shell_WKSPACE_INFO_Command;<br> extern rtems_shell_cmd_t rtems_shell_MALLOC_INFO_Command;<br>+extern rtems_shell_cmd_t rtems_shell_RTRACE_Command;<br> #if RTEMS_NETWORKING<br>   extern rtems_shell_cmd_t rtems_shell_IFCONFIG_Command;<br>   extern rtems_shell_cmd_t rtems_shell_ROUTE_Command;<br>@@ -464,6 +465,15 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[];<br>     #endif<br> <br>     /*<br>+     *  Tracing family commands<br>+     */<br>+    #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \<br>+         !defined(CONFIGURE_SHELL_NO_COMMAND_RTRACE)) || \<br>+        defined(CONFIGURE_SHELL_COMMAND_RTRACE)<br>+      &rtems_shell_RTRACE_Command,<br>+    #endif<br>+<br>+    /*<br>      *  Network related commands<br>      */<br>     #if RTEMS_NETWORKING<br>diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am<br>index 63e3903..40273bb 100644<br>--- a/cpukit/preinstall.am<br>+++ b/cpukit/preinstall.am<br>@@ -423,6 +423,15 @@ $(PROJECT_INCLUDE)/rtems/captureimpl.h: libmisc/capture/captureimpl.h $(PROJECT_<br>     $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/captureimpl.h<br> PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/captureimpl.h<br> <br>+$(PROJECT_INCLUDE)/rtems/trace/$(dirstamp):<br>+    @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/trace<br>+   @: > $(PROJECT_INCLUDE)/rtems/trace/$(dirstamp)<br>+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/trace/$(dirstamp)<br>+<br>+$(PROJECT_INCLUDE)/rtems/trace/rtems-trace-buffer-vars.h: libmisc/capture/rtems-trace-buffer-vars.h $(PROJECT_INCLUDE)/rtems/trace/$(dirstamp)<br>+       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/trace/rtems-trace-buffer-vars.h<br>+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/trace/rtems-trace-buffer-vars.h<br>+<br> $(PROJECT_INCLUDE)/rtems/cpuuse.h: libmisc/cpuuse/cpuuse.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)<br>     $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/cpuuse.h<br> PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/cpuuse.h<br>-- <br>2.3.0<br><br>_______________________________________________<br>devel mailing list<br>devel@rtems.org<br><a href="http://lists.rtems.org/mailman/listinfo/devel">http://lists.rtems.org/mailman/listinfo/devel</a>