|  | /* | 
|  | * Copyright 2017, Data61 | 
|  | * Commonwealth Scientific and Industrial Research Organisation (CSIRO) | 
|  | * ABN 41 687 119 230. | 
|  | * | 
|  | * This software may be distributed and modified according to the terms of | 
|  | * the BSD 2-Clause license. Note that NO WARRANTY is provided. | 
|  | * See "LICENSE_BSD2.txt" for details. | 
|  | * | 
|  | *  @LICENSE(DATA61_BSD) | 
|  | */ | 
|  | #include <autoconf.h> | 
|  | #include <sel4debug/gen_config.h> | 
|  | #include <sel4/sel4.h> | 
|  | #include <sel4debug/instrumentation.h> | 
|  |  | 
|  | /* Don't instrument seL4_GetIPCBuffer so we don't recurse. */ | 
|  | seL4_IPCBuffer *seL4_GetIPCBuffer(void) __attribute__((no_instrument_function)); | 
|  |  | 
|  | /* We can't just store backtrace information in a single static area because it | 
|  | * needs to be tracked per-thread. To do this we assume each thread has a | 
|  | * different IPC buffer and write backtrace information into the area of memory | 
|  | * directly following the IPC buffer. Note that this assumes that such an area | 
|  | * is mapped and not in use for anything else. This is not true in environments | 
|  | * like CAmkES, where you will have to tweak the following #define for the base | 
|  | * of this region. We also assume that the size of the stack is initialised to | 
|  | * 0 for us because seL4 zeroes frames on creation. The stored information looks | 
|  | * like this: | 
|  | * | 
|  | *   |        ↑        | | 
|  | *   | backtrace stack | | 
|  | *   +-----------------+ | 
|  | *   |   stack size    | | 
|  | *   +-----------------+ BACKTRACE_BASE | 
|  | */ | 
|  | #define BACKTRACE_BASE (((void*)seL4_GetIPCBuffer()) + sizeof(seL4_IPCBuffer)) | 
|  |  | 
|  | int backtrace(void **buffer, int size) | 
|  | { | 
|  | int *bt_stack_sz = (int *)BACKTRACE_BASE; | 
|  | void **bt_stack = (void **)(BACKTRACE_BASE + sizeof(int)); | 
|  |  | 
|  | /* Write as many entries as we can, starting from the top of the stack, | 
|  | * into the caller's buffer. | 
|  | */ | 
|  | int i; | 
|  | for (i = 0; i < size && i < *bt_stack_sz; i++) { | 
|  | buffer[i] = bt_stack[*bt_stack_sz - 1 - i]; | 
|  | } | 
|  |  | 
|  | return i; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_LIBSEL4DEBUG_FUNCTION_INSTRUMENTATION_BACKTRACE | 
|  |  | 
|  | void __cyg_profile_func_enter(void *func, void *caller) | 
|  | { | 
|  | if (seL4_GetIPCBuffer() == NULL) { | 
|  | /* The caller doesn't have a valid IPC buffer. Assume it has not been | 
|  | * setup yet and just skip logging the current function. | 
|  | */ | 
|  | return; | 
|  | } | 
|  | int *bt_stack_sz = (int *)BACKTRACE_BASE; | 
|  | void **bt_stack = (void **)(BACKTRACE_BASE + sizeof(int)); | 
|  |  | 
|  | /* Push the current function */ | 
|  | bt_stack[*bt_stack_sz] = func; | 
|  | *bt_stack_sz += 1; | 
|  | } | 
|  |  | 
|  | void __cyg_profile_func_exit(void *func, void *caller) | 
|  | { | 
|  | if (seL4_GetIPCBuffer() == NULL) { | 
|  | return; | 
|  | } | 
|  | int *bt_stack_sz = (int *)BACKTRACE_BASE; | 
|  |  | 
|  | /* Pop the current function */ | 
|  | *bt_stack_sz -= 1; | 
|  | } | 
|  |  | 
|  | #endif |