summaryrefslogtreecommitdiff
path: root/linkers/rtld-trace-buffer.ini
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2015-03-26 17:08:18 +1100
committerChris Johns <chrisj@rtems.org>2015-03-26 17:08:18 +1100
commitb988768f83da0b06bc564d2be135af01d5b2dec8 (patch)
tree5f36ea7fbe84d7106e988e065f5fd8a0179d57e3 /linkers/rtld-trace-buffer.ini
parent1703041074e5e70bb4a61d8a99355509759a673d (diff)
trace-linker: Add Trace Buffering support.
Trace buffering traces into a static buffer complete with timestamp and the executing context. A shell command provides access to the data.
Diffstat (limited to 'linkers/rtld-trace-buffer.ini')
-rw-r--r--linkers/rtld-trace-buffer.ini171
1 files changed, 171 insertions, 0 deletions
diff --git a/linkers/rtld-trace-buffer.ini b/linkers/rtld-trace-buffer.ini
new file mode 100644
index 0000000..f018410
--- /dev/null
+++ b/linkers/rtld-trace-buffer.ini
@@ -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