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