diff options
author | Chris Johns <chrisj@rtems.org> | 2015-03-26 17:08:18 +1100 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2015-03-26 17:08:18 +1100 |
commit | b988768f83da0b06bc564d2be135af01d5b2dec8 (patch) | |
tree | 5f36ea7fbe84d7106e988e065f5fd8a0179d57e3 /linkers/rtld-trace-buffer.ini | |
parent | rtems-tld: Add lock and buffer allocator support to generators. (diff) | |
download | rtems-tools-b988768f83da0b06bc564d2be135af01d5b2dec8.tar.bz2 |
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.ini | 171 |
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 |