= RTEMS Trace Linker = [[TOC(Developer/Tracing/Trace_Linker , depth=2)]] The RTEMS Trace Linker is a tool that is part of the [wiki:Developer/Tools RTEMS Tool Project] and is central in the [wiki:Developer/Tracing RTEMS Tracing] framework. 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. The code being trace may be from a 3rd party or already certified or in the process of being certified and the trace testing is part of that process. The RTEMS Trace Linker is controlled using configuration files in a flexible way and can be configured to implement a number of tracing schemes. The [wiki:Developer/Tools/RSB RTEMS Source Builder] builds and installs the [wiki:Developer/Tools RTEMS Tools] package so the RTEMS Trace Linker is available for you to use. == Command Line == The current command line for the trace linker is: {{{ $ 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) }}} There are two parts to the command line passed to the trace linker. 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 first and second parts are separated by `--` the command line option escape sequence. The trace linker generates code that needs to be compiled and linked your standard 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 you code add the include path to the `CFLAGS`. The trace linker requires you provide a 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. == Wrapping == The trace linker's main role is to wrap functions in the existing executable with trace code. The trace linker executable does not know about the trace code added. The trace 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.'' 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. == 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 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 use 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. == Configuration == The trace linker uses the INI file format for configuration files. Users provide a top level configuration that defines the trace executable created. The trace linker comes with a number of standard configurations that provide a range of functionality. A user can use those configurations or they can define a completely new set and produce a localised specific trace executable that meets their needs. There are 3 types of configurations: 1. User configurations. These are specific to an application and are typically kept with the application. 1. Tracer configurations. 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. 1. Generator configurations. These encapsulate a specific method of tracing. The RTEMS Linker provides ''buffer tracer'', ''printk'' and ''printf'' generators. The break down into these types of files promotes reuse. You could combine all the files into a single configuration file. === INI Files === [http://en.wikipedia.org/wiki/INI_file INI file format] consists of ''sections'' with a ''section name'' that groups ''keys''. A key has a ''name'' and ''value'' used as `name=value`. An example format is: {{{ #!ini [section] name1=value1 name2 = value2 }}} The use of keys depends on the user of the INI file and in our case this is the trace linker. The trace linker can include other INI files using the `include` key name and a comma separated list of files to include: {{{ #!ini 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 references a further section `test-headers`: {{{ #!ini 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 ability to include INI files and have key lists reference sections lets the trace linker provide base functionality a user can specialise. == Tracer Section == The top level section is `[tracer]`. The tracer section can contain 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. === Options === The following options are available: 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 specificed. 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'' any functions being traced reference. 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 `arm/xilinx_zynq_zc706`. An example tracer section is: {{{ #!ini ; ; 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 ; ; Options can be defined here or on the command line. ; options = test-options ; ; Functions to trace. ; traces = test-trace, test-trace-funcs, rtems-api-task ; ; 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 [test-options] verbose = true prefix = /opt/rtems/4.11 }}} === 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 the signature has specific types 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. generator:: The generator defines the type of tracing being used. headers:: List of sections that contain header files 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. An example trace section is: {{{ #!ini ; ; 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* }}} A trace section can reference other trace sections of a specific type. This allows a trace sections to build on other trace sections. === Function Sections === Function sections define functions that can be traced. The provide any required defines, header files, and the function signatures. Defining a function so it can be traced does not mean it is traced. The function has to be added to a `trace` list to be traced. 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 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. === Generators === Generators 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. A generator specifies the code generated when: 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:: The name of an RTEMS `rtems_interrupt_lock` 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 `<>> %s (0x%08x)\n", func_name, func_addr); } static inline void rtld_pg_printk_arg(int arg_num, const char* arg_type, int arg_size, void* arg) { const unsigned char* p = arg; int i; printk (" %2d] %s(%d) = ", arg_num, arg_type, arg_size); for (i = 0; i < arg_size; ++i, ++p) printk ("%02x", (unsigned int) *p); printk ("\n"); } static inline void rtld_pg_printk_exit(const char* func_name, void* func_addr) { printk ("<<< %s (0x%08x)\n", func_name, func_addr); } static inline void rtld_pg_printk_ret(const char* ret_type, int ret_size, void* ret) { const unsigned char* p = ret; int i; printk (" rt] %s(%d) = ", ret_type, ret_size); for (i = 0; i < ret_size; ++i, ++p) printk ("%02x", (unsigned int) *p); printk ("\n"); } CODE [printk-generator-headers] header = "#include " }}} == Limitation == The trace linker and software tracing in this way currently has some limitations. The are: * Function signatures are held in configuration file and so a change in a signature will not be automatically handled. * Variable argument lists cannot be wrapped. * C++ is not supported. In time we would like to add C++ support via the demangler support in the RTEMS Toolkit, however there are C++ constructs that make wrapping difficult such as templates. C++ that results in explicit calls should be able to be wrapped.