Index: linkers/rtems-tld.cpp
===================================================================
--- linkers/rtems-tld.cpp	(revision 1703041074e5e70bb4a61d8a99355509759a673d)
+++ linkers/rtems-tld.cpp	(revision b988768f83da0b06bc564d2be135af01d5b2dec8)
@@ -176,10 +176,11 @@
       std::string  lock_release;    /**< The lock release if provided. */
       std::string  buffer_local;    /**< Code template to declare a local buffer variable. */
-      std::string  buffer_alloc;    /**< Code template to perform a buffer allocation. */
       rld::strings headers;         /**< Include statements. */
       rld::strings defines;         /**< Define statements. */
       std::string  entry_trace;     /**< Code template to trace the function entry. */
+      std::string  entry_alloc;     /**< Code template to perform a buffer allocation. */
       std::string  arg_trace;       /**< Code template to trace an argument. */
       std::string  exit_trace;      /**< Code template to trace the function exit. */
+      std::string  exit_alloc;      /**< Code template to perform a buffer allocation. */
       std::string  ret_trace;       /**< Code template to trace the return value. */
       rld::strings code;            /**< Code block inserted before the trace code. */
@@ -646,12 +647,14 @@
       if (section.has_record ("buffer-local"))
         buffer_local = rld::dequote (section.get_record_item ("buffer-local"));
-      if (section.has_record ("buffer-local"))
-        buffer_alloc = rld::dequote (section.get_record_item ("buffer-alloc"));
       if (section.has_record ("entry-trace"))
         entry_trace = rld::dequote (section.get_record_item ("entry-trace"));
+      if (section.has_record ("entry-alloc"))
+        entry_alloc = rld::dequote (section.get_record_item ("entry-alloc"));
       if (section.has_record ("arg-trace"))
         arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
       if (section.has_record ("exit-trace"))
         exit_trace = rld::dequote (section.get_record_item ("exit-trace"));
+      if (section.has_record ("exit-alloc"))
+        exit_alloc = rld::dequote (section.get_record_item ("exit-alloc"));
       if (section.has_record ("ret-trace"))
         ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
@@ -955,5 +958,6 @@
 
       std::stringstream sss;
-      sss << "const char const* __rld_trace_names[" << traces.size() << "] = " << std::endl
+      sss << "uint32_t __rtld_trace_names_size = " << traces.size() << ";" << std::endl
+          << "const char const* __rtld_trace_names[" << traces.size() << "] = " << std::endl
           << "{";
       c.write_line (sss.str ());
@@ -1076,35 +1080,58 @@
             lss << count;
 
-            std::string l;
-
             c.write_line("");
 
             if (sig.has_args () || (sig.has_ret () && !generator_.ret_trace.empty ()))
             {
-              bool added = false;
-              l = "#define FUNC_DATA_SIZE_" + sig.name + " (";
+              std::string ds;
+              std::string des;
+              std::string drs;
+              bool        ds_added = false;
+              bool        des_added = false;
+              bool        drs_added = false;
+              ds  = "#define FUNC_DATA_SIZE_" + sig.name + " (";
+              des = "#define FUNC_DATA_ENTRY_SIZE_" + sig.name + " (";
+              drs = "#define FUNC_DATA_RET_SIZE_" + sig.name + " (";
               if (sig.has_args ())
               {
                 for (size_t a = 0; a < sig.args.size (); ++a)
                 {
-                  if (added)
-                    l += " + ";
+                  if (ds_added)
+                    ds += " + ";
                   else
-                    added = true;
-                  l += "sizeof(" + sig.args[a] + ')';
+                    ds_added = true;
+                  if (des_added)
+                    des += " + ";
+                  else
+                    des_added = true;
+                  ds += "sizeof(" + sig.args[a] + ')';
+                  des += "sizeof(" + sig.args[a] + ')';
                 }
               }
               if (sig.has_ret () && !generator_.ret_trace.empty ())
               {
-                if (added)
-                  l += " + ";
+                if (ds_added)
+                  ds += " + ";
                 else
-                  added = true;
-                l += "sizeof(" + sig.ret + ')';
+                  ds_added = true;
+                if (drs_added)
+                  drs += " + ";
+                else
+                  drs_added = true;
+                ds += "sizeof(" + sig.ret + ')';
+                drs += "sizeof(" + sig.ret + ')';
               }
-              if (!added)
-                l += '0';
-              l += ')';
-              c.write_line(l);
+              if (!ds_added)
+                ds += '0';
+              ds += ')';
+              if (!des_added)
+                des += '0';
+              des += ')';
+              if (!drs_added)
+                drs += '0';
+              drs += ')';
+              c.write_line(ds);
+              c.write_line(des);
+              c.write_line(drs);
             }
 
@@ -1123,14 +1150,18 @@
               c.write_line(" " + sig.ret + " ret;");
 
+            std::string l;
+
             if (!generator_.lock_acquire.empty ())
               c.write_line(generator_.lock_acquire);
 
-            if (!generator_.buffer_alloc.empty ())
+            if (!generator_.entry_alloc.empty ())
             {
-              l = " " + generator_.buffer_alloc;
+              l = " " + generator_.entry_alloc;
               l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
               l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
               l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
               l = rld::find_replace (l, "@FUNC_DATA_SIZE@", "FUNC_DATA_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
               c.write_line(l);
             }
@@ -1146,4 +1177,6 @@
               l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
               l = rld::find_replace (l, "@FUNC_DATA_SIZE@", "FUNC_DATA_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
               c.write_line(l);
             }
@@ -1181,4 +1214,22 @@
             c.write_line(l);
 
+            if (!generator_.lock_acquire.empty ())
+              c.write_line(generator_.lock_acquire);
+
+            if (!generator_.exit_alloc.empty ())
+            {
+              l = " " + generator_.exit_alloc;
+              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
+              l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
+              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_SIZE@", "FUNC_DATA_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
+              c.write_line(l);
+            }
+
+            if (!generator_.lock_release.empty ())
+              c.write_line(generator_.lock_release);
+
             if (!generator_.exit_trace.empty ())
             {
@@ -1187,4 +1238,6 @@
               l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
               l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
+              l = rld::find_replace (l, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
               c.write_line(l);
             }
@@ -1221,5 +1274,6 @@
       std::stringstream ss;
 
-      ss << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
+      ss << "uint32_t __rtld_trace_" << label << "_size = " << traces.size() << ";" << std::endl
+         << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
          << "{" << std::endl;
 
Index: linkers/rtld-trace-buffer.ini
===================================================================
--- linkers/rtld-trace-buffer.ini	(revision b988768f83da0b06bc564d2be135af01d5b2dec8)
+++ linkers/rtld-trace-buffer.ini	(revision b988768f83da0b06bc564d2be135af01d5b2dec8)
@@ -0,0 +1,171 @@
+;
+; RTEMS Trace Linker Trace Buffer
+;
+; Copyright 2015 Chris Johns <chrisj@rtems.org>
+;
+
+;
+; A trace buffer generator buffers records to a buffer that can be extracted
+; latter.
+;
+[trace-buffer-generator]
+headers = trace-buffer-generator-headers
+code-blocks = trace-buffer-tracers
+lock-local = " rtems_interrupt_lock_context lcontext;"
+lock-acquire = " rtems_interrupt_lock_acquire(&__rtld_tbg_lock, &lcontext);"
+lock-release = " rtems_interrupt_lock_release(&__rtld_tbg_lock, &lcontext);"
+entry-trace = "__rtld_tbg_buffer_entry(&in, @FUNC_INDEX@, RTLD_TBG_REC_OVERHEAD + @FUNC_DATA_ENTRY_SIZE@);"
+entry-alloc = "in = __rtld_tbg_buffer_alloc(@FUNC_INDEX@, RTLD_TBG_REC_OVERHEAD + @FUNC_DATA_ENTRY_SIZE@);"
+arg-trace = "__rtld_tbg_buffer_arg(&in, @ARG_SIZE@, (void*) &@ARG_LABEL@);"
+exit-trace = "__rtld_tbg_buffer_exit(&in, @FUNC_INDEX@, RTLD_TBG_REC_OVERHEAD + @FUNC_DATA_RET_SIZE@);"
+exit-alloc = "in = __rtld_tbg_buffer_alloc(@FUNC_INDEX@, RTLD_TBG_REC_OVERHEAD + @FUNC_DATA_RET_SIZE@);"
+ret-trace = "__rtld_tbg_buffer_ret(in, @RET_SIZE@, (void*) &@RET_LABEL@);"
+buffer-local = " uint8_t* in;"
+
+[trace-buffer-generator-headers]
+header = "#include <stdint.h>"
+header = "#include <rtems.h>"
+
+[trace-buffer-tracers]
+code = <<<CODE
+/*
+ * Mode bits.
+ */
+#define RTLD_TRACE_BUFFER_VERSION 0  /* data format version, lower 8bits */
+#if RTLD_TRACE_BUFFER_TIMESTAMP
+ #undef RTLD_TRACE_BUFFER_TIMESTAMP
+ #define RTLD_TRACE_BUFFER_TIMESTAMP (1 << 8)
+#else
+ #define RTLD_TRACE_BUFFER_TIMESTAMP 0
+#endif
+#if defined(RTLD_TRACE_BUFFER_THREAD)
+ #undef RTLD_TRACE_BUFFER_THREAD
+ #define RTLD_TRACE_BUFFER_THREAD    (1 << 9)
+#else
+ #define RTLD_TRACE_BUFFER_THREAD 0
+#endif
+#define RTLD_TRACE_BUFFER_MODE RTLD_TRACE_BUFFER_VERSION | \
+                               RTLD_TRACE_BUFFER_TIMESTAMP | \
+			       RTLD_TRACE_BUFFER_THREAD
+/*
+ * The number of word in the buffer.
+ */
+#define RTLD_TRACE_BUFFER_WORDS (RTLD_TRACE_BUFFER_SIZE / sizeof(uint32_t))
+/*
+ * We log the header record and then a 64bit timestamp.
+ */
+#define RTLD_TBG_REC_OVERHEAD (6 * sizeof(uint32_t))
+/*
+ * Symbols are public to allow external access to the buffers.
+ */
+const bool __rtld_tbg_present = true;
+const uint32_t __rtld_tbg_mode = RTLD_TRACE_BUFFER_MODE;
+const uint32_t __rtld_tbg_buffer_size = RTLD_TRACE_BUFFER_WORDS;
+uint32_t __rtld_tbg_buffer[RTLD_TRACE_BUFFER_WORDS];
+volatile uint32_t __rtld_tbg_buffer_in;
+volatile bool __rtld_tbg_finished;
+volatile bool __rtld_tbg_triggered;
+rtems_interrupt_lock __rtld_tbg_lock = RTEMS_INTERRUPT_LOCK_INITIALIZER("rtld-trace-buffer");
+
+static inline uint32_t __rtld_tbg_in_irq(void)
+{
+  return _ISR_Nest_level ? (1 << 31) : 0;
+}
+
+static inline uint32_t __rtld_tbg_executing_id(void)
+{
+  return _Thread_Executing->Object.id;
+}
+
+static inline uint32_t __rtld_tbg_executing_status(void)
+{
+  /* @fixme Add the current CPU for SMP. */
+  return (_Thread_Executing->current_priority << 8) | _Thread_Executing->real_priority;
+}
+
+static inline uint32_t __rtld_tbg_executing_state(void)
+{
+  return _Thread_Executing->current_state;
+}
+
+static inline bool __rtld_tbg_is_enabled(const uint32_t index)
+{
+  return (__rtld_trace_enables[index / 32] & (1 << (index & (32 - 1)))) != 0 ? true : false;
+}
+
+static inline bool __rtld_tbg_has_triggered(const uint32_t index)
+{
+  if (!__rtld_tbg_triggered)
+    __rtld_tbg_triggered =
+        (__rtld_trace_triggers[index / 32] & (1 << (index & (32 - 1)))) != 0 ? true : false;
+  return __rtld_tbg_triggered;
+}
+
+static inline uint8_t* __rtld_tbg_buffer_alloc(const uint32_t index, const uint32_t size)
+{
+  uint8_t* in = NULL;
+  if (!__rtld_tbg_finished && __rtld_tbg_has_triggered(index) && __rtld_tbg_is_enabled(index))
+  {
+    const uint32_t slots = ((size - 1) / sizeof(uint32_t)) + 1;
+    if (__rtld_tbg_buffer_in >= ((RTLD_TRACE_BUFFER_WORDS - slots)))
+    {
+      __rtld_tbg_finished = true;
+    }
+    else
+    {
+      in = (uint8_t*) &__rtld_tbg_buffer[__rtld_tbg_buffer_in];
+      __rtld_tbg_buffer_in += slots;
+    }
+  }
+  return in;
+}
+
+static inline void __rtld_tbg_buffer_entry(uint8_t** in, uint32_t func_index, uint32_t size)
+{
+  if (*in)
+  {
+    uint32_t* in32 = (uint32_t*) *in;
+    uint64_t  now = rtems_clock_get_uptime_nanoseconds();
+    *in32++ = func_index | (size << 16) | __rtld_tbg_in_irq();
+    *in32++ = __rtld_tbg_executing_id();
+    *in32++ = __rtld_tbg_executing_status();
+    *in32++ = __rtld_tbg_executing_state();
+    *in32++ = now >> 32;
+    *in32 = now;
+    *in += sizeof(func_index) + (3 * sizeof(uint32_t)) + sizeof(uint64_t);
+  }
+}
+
+static inline void __rtld_tbg_buffer_arg(uint8_t** in, int arg_size, void* arg)
+{
+  if (*in)
+  {
+    memcpy(*in, arg, arg_size);
+    *in += arg_size;
+  }
+}
+
+static inline void __rtld_tbg_buffer_exit(uint8_t** in, uint32_t func_index, uint32_t size)
+{
+  if (*in)
+  {
+    uint32_t* in32 = (uint32_t*) *in;
+    uint64_t  now = rtems_clock_get_uptime_nanoseconds();
+    *in32++ = (1 << 30) | func_index | (size << 16) | __rtld_tbg_in_irq();
+    *in32++ = __rtld_tbg_executing_id();
+    *in32++ = __rtld_tbg_executing_status();
+    *in32++ = __rtld_tbg_executing_state();
+    *in32++ = now >> 32;
+    *in32 = now;
+    *in += sizeof(func_index) + (3 * sizeof(uint32_t)) + sizeof(uint64_t);
+  }
+}
+
+static inline void __rtld_tbg_buffer_ret(uint8_t* in, int ret_size, void* ret)
+{
+  if (in)
+  {
+    memcpy(in, ret, ret_size);
+  }
+}
+CODE
Index: linkers/wscript
===================================================================
--- linkers/wscript	(revision 1703041074e5e70bb4a61d8a99355509759a673d)
+++ linkers/wscript	(revision b988768f83da0b06bc564d2be135af01d5b2dec8)
@@ -101,4 +101,5 @@
                        'rtems-score-coremutex.ini',
                        'rtld-base.ini',
+                       'rtld-trace-buffer.ini',
                        'rtld-print.ini'])
 
