1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @LICENSE(DATA61_BSD) 11 */ 12#include <autoconf.h> 13#include <sel4debug/gen_config.h> 14#include <sel4/sel4.h> 15#include <sel4debug/instrumentation.h> 16 17/* Don't instrument seL4_GetIPCBuffer so we don't recurse. */ 18seL4_IPCBuffer *seL4_GetIPCBuffer(void) __attribute__((no_instrument_function)); 19 20/* We can't just store backtrace information in a single static area because it 21 * needs to be tracked per-thread. To do this we assume each thread has a 22 * different IPC buffer and write backtrace information into the area of memory 23 * directly following the IPC buffer. Note that this assumes that such an area 24 * is mapped and not in use for anything else. This is not true in environments 25 * like CAmkES, where you will have to tweak the following #define for the base 26 * of this region. We also assume that the size of the stack is initialised to 27 * 0 for us because seL4 zeroes frames on creation. The stored information looks 28 * like this: 29 * 30 * | ��� | 31 * | backtrace stack | 32 * +-----------------+ 33 * | stack size | 34 * +-----------------+ BACKTRACE_BASE 35 */ 36#define BACKTRACE_BASE (((void*)seL4_GetIPCBuffer()) + sizeof(seL4_IPCBuffer)) 37 38int backtrace(void **buffer, int size) 39{ 40 int *bt_stack_sz = (int *)BACKTRACE_BASE; 41 void **bt_stack = (void **)(BACKTRACE_BASE + sizeof(int)); 42 43 /* Write as many entries as we can, starting from the top of the stack, 44 * into the caller's buffer. 45 */ 46 int i; 47 for (i = 0; i < size && i < *bt_stack_sz; i++) { 48 buffer[i] = bt_stack[*bt_stack_sz - 1 - i]; 49 } 50 51 return i; 52} 53 54#ifdef CONFIG_LIBSEL4DEBUG_FUNCTION_INSTRUMENTATION_BACKTRACE 55 56void __cyg_profile_func_enter(void *func, void *caller) 57{ 58 if (seL4_GetIPCBuffer() == NULL) { 59 /* The caller doesn't have a valid IPC buffer. Assume it has not been 60 * setup yet and just skip logging the current function. 61 */ 62 return; 63 } 64 int *bt_stack_sz = (int *)BACKTRACE_BASE; 65 void **bt_stack = (void **)(BACKTRACE_BASE + sizeof(int)); 66 67 /* Push the current function */ 68 bt_stack[*bt_stack_sz] = func; 69 *bt_stack_sz += 1; 70} 71 72void __cyg_profile_func_exit(void *func, void *caller) 73{ 74 if (seL4_GetIPCBuffer() == NULL) { 75 return; 76 } 77 int *bt_stack_sz = (int *)BACKTRACE_BASE; 78 79 /* Pop the current function */ 80 *bt_stack_sz -= 1; 81} 82 83#endif 84