summaryrefslogtreecommitdiffstats
path: root/user/tracing/tracelinker.rst
blob: 0fd1757e345e45b1cf880c20168e50132c417ea0 (plain) (blame)
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
.. SPDX-License-Identifier: CC-BY-SA-4.0

.. Copyright (C) 2016 Chris Johns <chrisj@rtems.org>

.. _tracelinker:

Trace Linker
************

RTEMS trace linker is a post link tool central to the RTEMS trace framework. It
is installed as a part of the RTEMS Tool Project. The RTEMS Trace Linker is a
post link tool that performs a re-link of your application to produce a trace
executable. A trace executable has been instrumented by the RTEMS Trace Linker
with additional code that implements software tracing. A key requirement of the
trace process in RTEMS is to take existing code in a compiled format (ELF) and
instrument it without rebuilding that code from source and without annotating
that source with trace code.

Command Line
============

A typical command to invoke the trace linker consists of two parts separated by
``--``.  The first part controls the trace linker and provides the various
options it needs and the second part is a standard linker command line you would
use to link an RTEMS application. The current command line for trace linker
consists of:

.. code-block:: shell

  $ rtems-tld -h
  rtems-trace-ld [options] objects
  Options and arguments:
   -h          : help (also --help)
   -V          : print linker version number and exit (also --version)
   -v          : verbose (trace import parts), can supply multiple times
                 to increase verbosity (also --verbose)
   -w          : generate warnings (also --warn)
   -k          : keep temporary files (also --keep)
   -c compiler : target compiler is not standard (also --compiler)
   -l linker   : target linker is not standard (also --linker)
   -E prefix   : the RTEMS tool prefix (also --exec-prefix)
   -f cflags   : C compiler flags (also --cflags)
   -r path     : RTEMS path (also --rtems)
   -B bsp      : RTEMS arch/bsp (also --rtems-bsp)
   -W wrapper  : wrapper file name without ext (also --wrapper)
   -C ini      : user configuration INI file (also --config)
   -P path     : user configuration INI file search path (also --path)

The trace linker generates code that needs to be compiled and linked to the
application executable so it needs to know the target compiler and `CFLAGS`.
There are a couple of ways to do this. The simplest is to provide the path to
RTEMS using the `-r` option and the architecture and BSP name in the standard
RTEMS format of arch/bsp. The trace linker will extract the compiler and flags
used to build RTEMS and will use them. If you require specific options you can
use the `-f`, `-c`, `-l`, and `-E` options to provide them. If the functions you
are tracing use types from your code then add the include path to the `CFLAGS`.

The trace linker requires you to provide a user configuration file using the
`-C` or ``--config`` option. This is an INI format file detailed in the
Configuration section. You can also provide an INI file search path using the
`-P` option.

If you are working with new configuration files and you want to view the files
the trace linker generates, add the `-k` option to keep the temporary files, and
`-W` to specify an explicit wrapper C file name. If you set the
``dump-on-error`` option in the configuration options section you will get a
dump of the configuration on an error.

Configuration (INI) files
=========================

The Trace Linker is controlled using configuration files. Configuration files
are categorized into 3 types:

- User Configuration: These are specific to the user application to be traced.
  This file initializes the values of the trace generator, triggers, enables,
  and traces.

- Tracer Configuration: These are like a library of common or base trace
  functions that can be referenced by an application. These files tend to hold
  the details needed to wrap a specific set of functions. Examples provided with
  the RTEMS Linker are the RTEMS API and Libc.

- Generator Configuration: This is used to encapsulate a specific method of
  tracing. RTEMS currently provides generators for trace buffering, printk, and
  printf.

The configuration files are in the *INI file format* which is composed of
`sections`. Each section has a section name and set of *keys* which consist of
*names* and *values*. A typical key is of the form ``name=value``. Keys can be
used to include other INI files using the include key name. This is shown in the
following example where the values indicate rtems and rtld-base configuration
files:

.. code-block:: shell

  include = rtems.ini, rtld-base.ini

The trace linker also uses values in keys to specify other sections. In this
example the functions name lists `test-trace-funcs` and that section contains a
headers key that further references a section called `test-headers`:

.. code-block:: shell

  functions = test-trace-funcs, rtems-api

  [test-trace-funcs]
  ; Parsed via the 'function-set', not parse as a 'trace'.
  headers = test-headers

  [test-headers]
  header = '#include "test-trace-1.h"'

The format of a configuration file is explained next. Snippets of the file:
`test-trace.ini` have been used for explicit understanding. This file can
be found in the rtems-tools directory of the rtems installation.

Tracer Section
--------------

The topmost level section is the ``tracer`` section. It can contains the
following keys:

- ``name``: The name of trace being linked.

- ``options``: A list of option sections.

- ``defines``: A list of sections containing defines or define record.

- ``define``: A list of define string that are single or double quoted.

- ``enables``: The list of sections containing enabled functions to trace.

- ``triggers``: The list of sections containing enabled functions to trigger
  trace on.

- ``traces``: The list of sections containing function lists to trace.

- ``functions``: The list of sections containing function details.

- ``include``: The list of files to include.

The tracer section of the file:`test-trace.ini` is shown below with explanatory
comments.

.. code-block:: shell

  ;
  ; RTEMS Trace Linker Test Configuration.
  ;
  ; We must provide a top level trace section.
  ;
  [tracer]
  ;
  ; Name of the trace.
  ;
  name = RTEMS Trace Linker Test
  ;
  ; The BSP.
  ;
  bsp = sparc/sis
  ;
  ; Functions to trace.
  ;
  traces = test-trace, test-trace-funcs, rtems-api-task
  ;
  ; Specify the options.
  ;
  options = test-options
  ;
  ; Define the function sets. These are the function's that can be
  ; added to the trace lists.
  ;
  functions = test-trace-funcs, rtems-api
  ;
  ; Include RTEMS Trace support.
  ;
  include = rtems.ini, rtld-base.ini

Options section
---------------

The options section in the fileio-trace.ini is called the `fileio-options`. A
general options section can contain following sets of keys:

- ``dump-on-error``: Dump the parsed configuration data on error. The value can
  be true or false.

- ``verbose``: Set the verbose level. The value can be true or a number value.

- ``prefix``: The prefix for the tools and an install RTEMS if rtems-path is not
  set.

- ``cc``: The compiler used to compile the generated wrapper code. Overrides the
  BSP configuration value if a BSP is specified.

- ``ld``: The linker used to link the application. The default is the cc value
  as read from the BSP configuration if specified. If your application contains
  C++ code use this setting to the change the linker to g++.

- ``cflags``: Set the CFLAGS used to compiler the wrapper. These flags are
  pre-pended to the BSP read flags if a BSP is specified. This option is used
  to provide extra include paths to header files in your application that
  contain types referenced by functions being traced.

- ``rtems-path``: The path to an install RTEMS if not installed under the
  prefix.

- ``rtems-bsp``: The BSP we are building the trace executable for. The is an
  arch and bsp pair. For example sparc/erc32.

The options section of the file: `test-trace.ini` uses two of the aforementioned
keys as shown below:

.. code-block:: shell

  ;
  ; Options can be defined here or on the command line.
  ;
  [test-options]
  prefix = /development/rtems/5
  verbose = true

Trace Section
-------------

A trace section defines how trace wrapper functions are built. To build a trace
function that wraps an existing function in an ELF object file or library
archive we need to have the function's signature. A signature is the function's
declaration with any types used. The signature has specific types and we need
access to those types which means the wrapper code needs to include header files
that define those types. There may also be specific defines needed to access
those types. A trace section can contain the following keys:

- ``generator``: The generator defines the type of tracing being used.

- ``headers``: List of sections that contain header file's keys.

- ``header``: A header key. Typically the include code.

- ``defines``: List of sections that contain defines.

- ``define``: A define key. Typically the define code.

- ``signatures``: List of function signature sections.

- ``trace``: Functions that are instrumented with trace code.

The trace section of the file: `test-trace.ini` is shown below. A trace section
can reference other trace sections of a specific type. This allows a trace
sections to build on other trace sections.

.. code:: shell

  ; User application trace example.
  ;
  [test-trace]
  generator = printf-generator
  ; Just here for testing.
  trace = test_trace_3

  [test-trace-funcs]
  ; Parsed via the 'function-set', not parse as a 'trace'.
  headers = test-headers
  header = '#include "test-trace-2.h"'
  defines = test-defines
  define = "#define TEST_TRACE_2 2"
  signatures = test-signatures
  ; Parsed via the 'trace', not parsed as a function-set
  trace = test_trace_1, test_trace_2

  [test-headers]
  header = '#include "test-trace-1.h"'

  [test-defines]
  define = "#define TEST_TRACE_1 1"

  [test-signatures]
  test_trace_1 = void, int
  test_trace_2 = test_type_2, test_type_1
  test_trace_3 = float, float*

Function Section
----------------

Function sections define functions that can be traced. Defining a function so it
can be traced does not mean it is traced. The function must be added to a trace
list to be traced. Function sections provide any required defines, header files,
and the function signatures.

A function signature is the function's declaration. It is the name of the
function, the return value, and the arguments. Tracing using function wrappers
requires that we have accurate function signatures and ideally we would like to
determine the function signature from the data held in ELF files. ELF files can
contain DWARF data, the ELF debugging data format. In time the trace project
would like to support libdwarf so the DWARF data can be accessed and used to
determine a function's signature. This work is planned but not scheduled to be
done and so in the meantime we explicitly define the function signatures in the
configuration files.

A function section can consist of the following keys:

- ``headers``: A list of sections containing headers or header records.
- ``header``: A list of include string that are single or double quoted.
- ``defines``: A list of sections containing defines or define record.
- ``defines``: A list of define string that are single or double quoted.
- ``signatures``: A list of section names of function signatures.
- ``includes``: A list of files to include.

Function signatures are specified with the function name being the key's name
and the key's value being the return value and a list of function arguments. You
need to provide void if the function uses void. Variable argument list are
currently not supported. There is no way to determine statically a variable
argument list. The function section in the file: `test-trace.ini` has been
labeled as `test-trace-funcs`. This can be seen in the file snippet of the
previous section.

Generators
----------

The trace linker's major role is to wrap functions in the existing executable
with trace code. The directions on how to wrap application functions is provided
by the generator configuration. The wrapping function uses a GNU linker option
called --wrap=symbol. The GNU Ld manual states:

"Use a wrapper function for symbol. Any undefined reference to symbol will be
resolved to __wrap_symbol. Any undefined reference to __real_symbol will be
resolved to symbol."

Generator sections specify how to generate trace wrapping code. The trace
linker and generator section must match to work. The trace linker expects a some
things to be present when wrapping functions. The section's name specifies the
generator and can be listed in a generator key in a tracer or trace section. If
the generator is not interested in a specific phase it does not need to define
it. Nothing will be generated in regard to this phase. For example code to
profile specific functions may only provide the entry-trace and exit-trace code
where a nano-second time stamp is taken.

The generate code will create an entry and exit call and the generator code
block can be used to allocate buffer space for each with the lock held. The
entry call and argument copy is performed with the lock released. The buffer
space having been allocated will cause the trace events to be in order. The same
goes for the exit call. Space is allocated in separate buffer allocate calls so
the blocking calls will have the exit event appear in the correct location in
the buffer.

The following keys can be a part of the generator configuration:

- ``headers``: A list of sections containing headers or header records.
- ``header``: A list of include string that are single or double quoted.
- ``defines``: A list of sections containing defines or define record.
- ``define``: A list of define string that are single or double quoted.
- ``entry-trace``: The wrapper call made on a function's entry. Returns bool
  where true is the function is being traced. This call is made without the lock
  being held if a lock is defined.
- ``arg-trace``: The wrapper call made for each argument to the trace function
  if the function is being traced. This call is made without the lock being held
  if a lock is defined.
- ``exit-trace``: The wrapper call made after a function's exit. Returns bool
  where true is the function is being traced. This call is made without the lock
  being held if a lock is defined.
- ``ret-trace``: The wrapper call made to log the return value if the function
  is being traced. This call is made without the lock being held if a lock is
  defined.
- ``lock-local``: The wrapper code to declare a local lock variable.
- ``lock-acquire``: The wrapper code to acquire the lock.
- ``lock-release``: The wrapper code to release the lock.
- ``buffer-local``: The wrapper code to declare a buffer index local variable.
- ``buffer-alloc``: The wrapper call made with a lock held if defined to
  allocate buffer space to hold the trace data. A suitable 32bit buffer index is
  returned. If there is no space an invalid index is returned. The generator
  must handle any overhead space needed. The generator needs to make sure the
  space is available before making the alloc all.
- ``code-blocks``: A list of code block section names.
- ``code``: A code block in <<CODE --- CODE (without the single quote).
- ``includes``: A list of files to include.

The following macros can be used in wrapper calls:

- ``@FUNC_NAME@``: The trace function name as a quote C string.
- ``@FUNC_INDEX@``: The trace function index as a held in the sorted list of
  trace functions by the trace linker. It can be used to index the names,
  enables, and triggers data.
- ``@FUNC_LABEL@``: The trace function name as a C label that can be referenced.
  You can take the address of the label.
- ``@FUNC_DATA_SIZE@``: The size of the data in bytes.
- ``@FUNC_DATA_ENTRY_SIZE@``: The size of the entry data in bytes.
- ``@FUNC_DATA_RET_SIZE@``: The size of the return data in bytes.
- ``@ARG_NUM@``: The argument number to the trace function.
- ``@ARG_TYPE@``: The type of the argument as a C string.
- ``@ARG_SIZE@``: The size of the type of the argument in bytes.
- ``@ARG_LABEL@``: The argument as a C label that can be referenced.
- ``@RET_TYPE@``: The type of the return value as a C string.
- ``@RET_SIZE@``: The size of the type of the return value in bytes.
- ``@RET_LABEL@``: The return value as a C label that can be referenced.

The `buffer-alloc`, `entry-trace`, and `exit-trace` can be transformed using the
following macros:

- ``@FUNC_NAME@``
- ``@FUNC_INDEX@``
- ``@FUNC_LABEL@``
- ``@FUNC_DATA_SZIE@``
- ``@FUNC_DATA_ENTRY_SZIE@``
- ``@FUNC_DATA_EXIT_SZIE@``

The `arg-trace` can be transformed using the following macros:

- ``@ARG_NUM@``
- ``@ARG_TYPE@``
- ``@ARG_SIZE@``
- ``@ARG_LABEL@``

The `ret-trace` can be transformed using the following macros:

- ``@RET_TYPE@``
- ``@RET_SIZE@``
- ``@RET_LABEL@``

The file: `test-trace.ini` specifies ``printf-generator`` as its generator. This
section can be found in the file: `rtld-print.ini` in the rtems-tools directory
and is shown below:

.. code:: shell

  ;
  ; A printf generator prints to stdout the trace functions.
  ;
  [printf-generator]
  headers = printf-generator-headers
  entry-trace = "rtld_pg_printf_entry(@FUNC_NAME@, (void*) &@FUNC_LABEL@);"
  arg-trace = "rtld_pg_printf_arg(@ARG_NUM@, @ARG_TYPE@, @ARG_SIZE@, (void*) &@ARG_LABEL@);"
  exit-trace = "rtld_pg_printf_exit(@FUNC_NAME@, (void*) &@FUNC_LABEL@);"
  ret-trace = "rtld_pg_printf_ret(@RET_TYPE@, @RET_SIZE@, (void*) &@RET_LABEL@);"
  code = <<<CODE
  static inline void rtld_pg_printf_entry(const char* func_name,
                                          void*       func_addr)
  {
    printf (">>> %s (0x%08x)\n", func_name, func_addr);
  }
  static inline void rtld_pg_printf_arg(int         arg_num,
                                        const char* arg_type,
                                        int         arg_size,
                                        void*       arg)
  {
    const unsigned char* p = arg;
    int   i;
    printf (" %2d] %s(%d) = ", arg_num, arg_type, arg_size);
    for (i = 0; i < arg_size; ++i, ++p) printf ("%02x", (unsigned int) *p);
    printf ("\n");
  }
  static inline void rtld_pg_printf_exit(const char* func_name,
                                         void*       func_addr)
  {
    printf ("<<< %s (0x%08x)\n", func_name, func_addr);
  }
  static inline void rtld_pg_printf_ret(const char* ret_type,
                                        int         ret_size,
                                        void*       ret)
  {
    const unsigned char* p = ret;
    int   i;
    printf (" rt] %s(%d) = ", ret_type, ret_size);
    for (i = 0; i < ret_size; ++i, ++p) printf ("%02x", (unsigned int) *p);
    printf ("\n");
  }
  CODE

  [printf-generator-headers]
  header = "#include <stdio.h>"

The trace linker generates C code with a wrapper for each function to be
instrumented. The trace code generated is driven by the configuration INI files.

Development
===========

The Trace Linker is part of the RTEMS tools git repository available at :
https://git.rtems.org/rtems-tools
The RTEMS tools project utilizes the waf build system. Use the following
commands in the topmost build directory to build the tools project:

First we configure using:

.. code-block:: shell

  $./waf configure --prefix=$HOME/development/rtems/5

Then we build and install using:

.. code-block:: shell

  $./waf build install