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