181 | | Generators sections specify how to generate trace wrapping code. |
| 187 | Generators sections specify how to generate trace wrapping code. The section's name specifies the generator and can be listed in a `generator` key in a `tracer` or `trace` section. |
| 188 | |
| 189 | A generator specifies the code generated when: |
| 190 | |
| 191 | * Entering a trace function (`entry-trace`) |
| 192 | * Entry argument of a trace function (`arg-trace`), called once per argument |
| 193 | * Return value of a trace function (`ret-trace`), called if not `void`. |
| 194 | * Exit value of a trace function (`exit-trace`) |
| 195 | |
| 196 | The the generator is not interested in a specific phase it does not need to define and nothing will be generated. For example code to profile specific function may only provide the `entry-trace` and `exit-trace` code where a nano-second time stamp is taken. |
| 197 | |
| 198 | The section supports: |
| 199 | |
| 200 | headers:: List of header sections. |
| 201 | header:: A header key. Typically the include code. |
| 202 | entry-trace: The code or call made on entry to a function. |
| 203 | arg-trace:: The code or call made for each argument to a function. |
| 204 | ret-trace:: The code or call made with the return value if not `void`. |
| 205 | exit-trace:: The code or call made after the trace function has exited. |
| 206 | code:: Code to be added into the trace file. The code is tagged between `<<<CODE` and `CODE` markers. |
| 207 | |
| 208 | An example generator section is: |
| 209 | |
| 210 | {{{ |
| 211 | #!c |
| 212 | [printk-generator] |
| 213 | headers = printk-generator-headers |
| 214 | entry-trace = "rtld_pg_printk_entry(@FUNC_NAME@, (void*) &@FUNC_LABEL@);" |
| 215 | arg-trace = "rtld_pg_printk_arg(@ARG_NUM@, @ARG_TYPE@, @ARG_SIZE@, (void*) &@ARG_LABEL@);" |
| 216 | exit-trace = "rtld_pg_printk_exit(@FUNC_NAME@, (void*) &@FUNC_LABEL@);" |
| 217 | ret-trace = "rtld_pg_printk_ret(@RET_TYPE@, @RET_SIZE@, (void*) &@RET_LABEL@);" |
| 218 | code = <<<CODE |
| 219 | static inline void rtld_pg_printk_entry(const char* func_name, |
| 220 | void* func_addr) |
| 221 | { |
| 222 | printk (">>> %s (0x%08x)\n", func_name, func_addr); |
| 223 | } |
| 224 | static inline void rtld_pg_printk_arg(int arg_num, |
| 225 | const char* arg_type, |
| 226 | int arg_size, |
| 227 | void* arg) |
| 228 | { |
| 229 | const unsigned char* p = arg; |
| 230 | int i; |
| 231 | printk (" %2d] %s(%d) = ", arg_num, arg_type, arg_size); |
| 232 | for (i = 0; i < arg_size; ++i, ++p) printk ("%02x", (unsigned int) *p); |
| 233 | printk ("\n"); |
| 234 | } |
| 235 | static inline void rtld_pg_printk_exit(const char* func_name, |
| 236 | void* func_addr) |
| 237 | { |
| 238 | printk ("<<< %s (0x%08x)\n", func_name, func_addr); |
| 239 | } |
| 240 | static inline void rtld_pg_printk_ret(const char* ret_type, |
| 241 | int ret_size, |
| 242 | void* ret) |
| 243 | { |
| 244 | const unsigned char* p = ret; |
| 245 | int i; |
| 246 | printk (" rt] %s(%d) = ", ret_type, ret_size); |
| 247 | for (i = 0; i < ret_size; ++i, ++p) printk ("%02x", (unsigned int) *p); |
| 248 | printk ("\n"); |
| 249 | } |
| 250 | CODE |
| 251 | |
| 252 | [printk-generator-headers] |
| 253 | header = "#include <stdio.h>" |
| 254 | }}} |
| 255 | |
| 256 | The generator code can use a number of token's that are expanded when generating trace functions. They are: |
| 257 | |
| 258 | @FUNC_NAME@:: The name of the function being wrapped. |
| 259 | @FUNC_LABEL@:: The C label of the function being wrapped. You can take the address of this label. |
| 260 | @ARG_NUM@:: The argument number bring processed. |
| 261 | @ARG_TYPE@:: The type of the argument. |
| 262 | @ARG_SIZE@:: The size of the argument in bytes. |
| 263 | @ARG_LABEL@:: The C label of the argument. You can take the address of this label. |
| 264 | @RET_TYPE@:: The type of the return value. |
| 265 | @RET_SIZE@:: The size of the return value in bytes. |
| 266 | @RET_LABEL@:: The C label of the return value as held in the wrapping code. |
| 267 | |
| 268 | == Limitation == |
| 269 | |
| 270 | The trace linker and software tracing in this way currently has some limitations. The are: |
| 271 | |
| 272 | * Function signatures are held in configuration file and so a change in a signature will not be automatically handled. |
| 273 | * Variable argument lists cannot be wrapped. |
| 274 | * 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. |