summaryrefslogtreecommitdiff
path: root/linkers/rtld-trace-buffer.ini
blob: 0d01259ea34c97e60cae57bda138239f7e9be437 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
;
; 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