;
; 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>"
header = "#include <rtems/rtems/tasksimpl.h>"
header = "#include <rtems/score/threadimpl.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;
/*
* Lock the access.
*/
RTEMS_INTERRUPT_LOCK_DEFINE(static, __rtld_tbg_lock, "rtld-trace-buffer");
static inline uint32_t __rtld_tbg_in_irq(void)
{
return rtems_interrupt_is_in_progress() ? (1 << 31) : 0;
}
static inline uint32_t __rtld_tbg_executing_id(void)
{
return _Thread_Get_executing()->Object.id;
}
static inline uint32_t __rtld_tbg_executing_status(void)
{
/* @fixme Add the current CPU for SMP. */
Thread_Control* tc = _Thread_Get_executing();
return (_Thread_Get_priority(tc) << 8) | tc->Real_priority.priority;
}
static inline uint32_t __rtld_tbg_executing_state(void)
{
return _Thread_Get_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