14b6da826SThomas Huth /*
24b6da826SThomas Huth * stack related functions
34b6da826SThomas Huth *
44b6da826SThomas Huth * This code is free software; you can redistribute it and/or modify it
54b6da826SThomas Huth * under the terms of the GNU Library General Public License version 2.
64b6da826SThomas Huth */
74b6da826SThomas Huth
852266791SPeter Feiner #include <libcflat.h>
935c167a6SNadav Amit #include <stdbool.h>
1052266791SPeter Feiner #include <stack.h>
1152266791SPeter Feiner
1252266791SPeter Feiner #define MAX_DEPTH 20
1352266791SPeter Feiner
14*ab0bbb9fSAndrew Jones #if defined(CONFIG_RELOC) && !defined(HAVE_ARCH_BASE_ADDRESS)
1535c167a6SNadav Amit extern char _text, _etext;
1635c167a6SNadav Amit
base_address(const void * rebased_addr,unsigned long * addr)17*ab0bbb9fSAndrew Jones bool base_address(const void *rebased_addr, unsigned long *addr)
1835c167a6SNadav Amit {
1935c167a6SNadav Amit unsigned long ra = (unsigned long)rebased_addr;
2035c167a6SNadav Amit unsigned long start = (unsigned long)&_text;
2135c167a6SNadav Amit unsigned long end = (unsigned long)&_etext;
2235c167a6SNadav Amit
2335c167a6SNadav Amit if (ra < start || ra >= end)
2435c167a6SNadav Amit return false;
2535c167a6SNadav Amit
2635c167a6SNadav Amit *addr = ra - start;
2735c167a6SNadav Amit return true;
2835c167a6SNadav Amit }
29*ab0bbb9fSAndrew Jones #elif !defined(CONFIG_RELOC) && !defined(HAVE_ARCH_BASE_ADDRESS)
base_address(const void * rebased_addr,unsigned long * addr)30*ab0bbb9fSAndrew Jones bool base_address(const void *rebased_addr, unsigned long *addr)
3135c167a6SNadav Amit {
3235c167a6SNadav Amit *addr = (unsigned long)rebased_addr;
3335c167a6SNadav Amit return true;
3435c167a6SNadav Amit }
3535c167a6SNadav Amit #endif
3635c167a6SNadav Amit
print_stack(const void ** return_addrs,int depth,bool top_is_return_address)3752266791SPeter Feiner static void print_stack(const void **return_addrs, int depth,
3852266791SPeter Feiner bool top_is_return_address)
3952266791SPeter Feiner {
4035c167a6SNadav Amit unsigned long addr;
4152266791SPeter Feiner int i = 0;
4252266791SPeter Feiner
4352266791SPeter Feiner printf("\tSTACK:");
4452266791SPeter Feiner
4552266791SPeter Feiner /* @addr indicates a non-return address, as expected by the stack
4652266791SPeter Feiner * pretty printer script. */
4752266791SPeter Feiner if (depth > 0 && !top_is_return_address) {
48*ab0bbb9fSAndrew Jones if (base_address(return_addrs[0], &addr))
4935c167a6SNadav Amit printf(" @%lx", addr);
5052266791SPeter Feiner i++;
5152266791SPeter Feiner }
5252266791SPeter Feiner
5352266791SPeter Feiner for (; i < depth; i++) {
54*ab0bbb9fSAndrew Jones if (base_address(return_addrs[i], &addr))
5535c167a6SNadav Amit printf(" %lx", addr);
5652266791SPeter Feiner }
5752266791SPeter Feiner printf("\n");
5852266791SPeter Feiner }
5952266791SPeter Feiner
dump_stack(void)6052266791SPeter Feiner void dump_stack(void)
6152266791SPeter Feiner {
6252266791SPeter Feiner const void *return_addrs[MAX_DEPTH];
6352266791SPeter Feiner int depth;
6452266791SPeter Feiner
6552266791SPeter Feiner depth = backtrace(return_addrs, MAX_DEPTH);
6652266791SPeter Feiner print_stack(&return_addrs[1], depth ? depth - 1 : 0, true);
6752266791SPeter Feiner }
6852266791SPeter Feiner
dump_frame_stack(const void * instruction,const void * frame)6952266791SPeter Feiner void dump_frame_stack(const void *instruction, const void *frame)
7052266791SPeter Feiner {
7152266791SPeter Feiner const void *return_addrs[MAX_DEPTH];
7252266791SPeter Feiner int depth;
7352266791SPeter Feiner
7452266791SPeter Feiner return_addrs[0] = instruction;
7552266791SPeter Feiner depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1);
7652266791SPeter Feiner print_stack(return_addrs, depth + 1, false);
7752266791SPeter Feiner }
7852266791SPeter Feiner
7952266791SPeter Feiner #ifndef HAVE_ARCH_BACKTRACE
backtrace(const void ** return_addrs,int max_depth)8052266791SPeter Feiner int backtrace(const void **return_addrs, int max_depth)
8152266791SPeter Feiner {
8252266791SPeter Feiner static int walking;
8352266791SPeter Feiner int depth = 0;
8452266791SPeter Feiner void *addr;
8552266791SPeter Feiner
8652266791SPeter Feiner if (walking) {
8752266791SPeter Feiner printf("RECURSIVE STACK WALK!!!\n");
8852266791SPeter Feiner return 0;
8952266791SPeter Feiner }
9052266791SPeter Feiner walking = 1;
9152266791SPeter Feiner
9252266791SPeter Feiner /* __builtin_return_address requires a compile-time constant argument */
9352266791SPeter Feiner #define GET_RETURN_ADDRESS(i) \
9452266791SPeter Feiner if (max_depth == i) \
9552266791SPeter Feiner goto done; \
9652266791SPeter Feiner addr = __builtin_return_address(i); \
9752266791SPeter Feiner if (!addr) \
9852266791SPeter Feiner goto done; \
9952266791SPeter Feiner return_addrs[i] = __builtin_extract_return_addr(addr); \
10052266791SPeter Feiner depth = i + 1; \
10152266791SPeter Feiner
10252266791SPeter Feiner GET_RETURN_ADDRESS(0)
10352266791SPeter Feiner GET_RETURN_ADDRESS(1)
10452266791SPeter Feiner GET_RETURN_ADDRESS(2)
10552266791SPeter Feiner GET_RETURN_ADDRESS(3)
10652266791SPeter Feiner GET_RETURN_ADDRESS(4)
10752266791SPeter Feiner GET_RETURN_ADDRESS(5)
10852266791SPeter Feiner GET_RETURN_ADDRESS(6)
10952266791SPeter Feiner GET_RETURN_ADDRESS(7)
11052266791SPeter Feiner GET_RETURN_ADDRESS(8)
11152266791SPeter Feiner GET_RETURN_ADDRESS(9)
11252266791SPeter Feiner GET_RETURN_ADDRESS(10)
11352266791SPeter Feiner GET_RETURN_ADDRESS(11)
11452266791SPeter Feiner GET_RETURN_ADDRESS(12)
11552266791SPeter Feiner GET_RETURN_ADDRESS(13)
11652266791SPeter Feiner GET_RETURN_ADDRESS(14)
11752266791SPeter Feiner GET_RETURN_ADDRESS(15)
11852266791SPeter Feiner GET_RETURN_ADDRESS(16)
11952266791SPeter Feiner GET_RETURN_ADDRESS(17)
12052266791SPeter Feiner GET_RETURN_ADDRESS(18)
12152266791SPeter Feiner GET_RETURN_ADDRESS(19)
12252266791SPeter Feiner GET_RETURN_ADDRESS(20)
12352266791SPeter Feiner
12452266791SPeter Feiner #undef GET_RETURN_ADDRESS
12552266791SPeter Feiner
12652266791SPeter Feiner done:
12752266791SPeter Feiner walking = 0;
12852266791SPeter Feiner return depth;
12952266791SPeter Feiner }
13052266791SPeter Feiner #endif /* HAVE_ARCH_BACKTRACE */
131