1 /*
2 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
3 * economic rights: Technische Universität Dresden (Germany)
4 * This file is part of TUD:OS and distributed under the terms of the
5 * GNU Lesser General Public License 2.1.
6 * Please see the COPYING-LGPL-2.1 file for details.
7 */
8 #include <l4/util/backtrace.h>
9
10 #include <unwind.h>
11 #include <stdlib.h>
12
13 #if defined NOT_FOR_L4 && defined __PIC__
14
15 #include <dlfcn.h>
16
17 static _Unwind_Reason_Code (*uw_bt) (_Unwind_Trace_Fn, void *);
18 static _Unwind_Ptr (*uw_getpc) (struct _Unwind_Context *);
19 static _Unwind_Ptr (*uw_getcfa) (struct _Unwind_Context *);
20 static _Unwind_Ptr (*uw_getgr) (struct _Unwind_Context *, int);
21
22 static void
init(void)23 init (void)
24 {
25 void *handle = dlopen ("libgcc_s.so.1", 0);
26
27 if (handle == NULL)
28 return;
29
30 uw_bt = dlsym (handle, "_Unwind_Backtrace");
31 uw_getpc = dlsym (handle, "_Unwind_GetIP");
32 uw_getcfa = dlsym (handle, "_Unwind_GetCFA");
33 uw_getgr = dlsym (handle, "_Unwind_GetGR");
34 if (uw_getpc == NULL || uw_getgr == NULL || uw_getcfa == NULL)
35 uw_bt = NULL;
36 }
37 #else
38
39 #define uw_getgr _Unwind_GetGR
40 #define uw_getpc _Unwind_GetIP
41 #define uw_bt _Unwind_Backtrace
42 #define uw_getcfa _Unwind_GetCFA
43
44 #endif
45
46 struct Bt_arg
47 {
48 void **pc_array;
49 int cnt, max;
50 void *last_frame;
51 void *last_sp;
52 };
53
54
55 static _Unwind_Reason_Code
__bt_helper(struct _Unwind_Context * ctx,void * a)56 __bt_helper(struct _Unwind_Context *ctx, void *a)
57 {
58 struct Bt_arg *arg = a;
59
60 /* Skip first function, it is l4util_backtrace ... */
61 if (arg->cnt != -1)
62 arg->pc_array[arg->cnt] = (void *)uw_getpc (ctx);
63 if (++arg->cnt == arg->max)
64 return _URC_END_OF_STACK;
65
66 /* IA32: %ebp is DWARF2 register 5 */
67 arg->last_sp = (void *)uw_getcfa (ctx);
68 arg->last_frame = (void *)uw_getgr (ctx, 5);
69 return _URC_NO_REASON;
70 }
71 struct Frame
72 {
73 struct Frame *fp;
74 void *ret;
75 };
76
77
78 int
l4util_backtrace(void ** pc_array,int max)79 l4util_backtrace(void **pc_array, int max)
80 {
81 struct Bt_arg arg = { .pc_array = pc_array, .max = max, .cnt = -1 };
82
83 #if defined NOT_FOR_L4 && defined __PIC__
84 static int initialized = 0;
85 if (!initialized)
86 {
87 initialized = 1;
88 init();
89 }
90
91 if (uw_bt == NULL)
92 return 0;
93 #endif
94
95 if (max >= 1)
96 uw_bt (__bt_helper, &arg);
97
98 if (arg.cnt > 1 && arg.pc_array[arg.cnt - 1] == (void*)0)
99 --arg.cnt;
100 else if (arg.cnt < max)
101 {
102 struct Frame *fp = (struct Frame *)arg.last_frame;
103
104 while (arg.cnt < max)
105 {
106 /* Check for out of range. */
107 if ((void *)fp < arg.last_sp
108 /* || (void *) ebp > __libc_stack_end*/
109 || ((long)fp & 3))
110 break;
111
112 pc_array[arg.cnt++] = fp->ret;
113 fp = fp->fp;
114 }
115 }
116 return arg.cnt != -1 ? arg.cnt : 0;
117 }
118
119