summaryrefslogblamecommitdiffstats
path: root/linkers/rtld-trace-buffer.ini
blob: 0d01259ea34c97e60cae57bda138239f7e9be437 (plain) (tree)


























                                                                                                           
                                             
                                              







































                                                                           



                                                                          


                                              
                                                          



                                                    
                                            




                                                        

                                                                      



                                                       
                                                


















































































                                                                                              
;
; 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