1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU Lesser General Public License 2.1.
7  * Please see the COPYING-LGPL-2.1 file for details.
8  */
9 #include <l4/util/backtrace.h>
10 
11 #include <unwind.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 
15 #if defined NOT_FOR_L4 && defined __PIC__
16 
17 #include <dlfcn.h>
18 
19 static _Unwind_Reason_Code (*uw_bt) (_Unwind_Trace_Fn, void *);
20 static _Unwind_Ptr (*uw_getpc) (struct _Unwind_Context *);
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   if (uw_getpc == NULL)
33     uw_bt = NULL;
34 }
35 #else
36 
37 #define uw_getgr _Unwind_GetGR
38 #define uw_getpc _Unwind_GetIP
39 #define uw_bt _Unwind_Backtrace
40 #define uw_getcfa _Unwind_GetCFA
41 
42 #endif
43 
44 struct Bt_arg
45 {
46   void **pc_array;
47   int  cnt, max;
48 };
49 
50 static _Unwind_Reason_Code
__bt_helper(struct _Unwind_Context * ctx,void * a)51 __bt_helper(struct _Unwind_Context *ctx, void *a)
52 {
53   struct Bt_arg *arg = a;
54 
55   /* Skip first function, it is l4util_backtrace ... */
56   if (arg->cnt != -1)
57     arg->pc_array[arg->cnt] = (void *)(uintptr_t)uw_getpc (ctx);
58   if (++arg->cnt == arg->max)
59     return _URC_END_OF_STACK;
60 
61   return _URC_NO_REASON;
62 }
63 
64 
65 int
l4util_backtrace(void ** pc_array,int max)66 l4util_backtrace(void **pc_array, int max)
67 {
68   struct Bt_arg arg = { .pc_array = pc_array, .max = max, .cnt = -1 };
69 
70 #if defined NOT_FOR_L4 && defined __PIC__
71   static int initialized = 0;
72   if (!initialized)
73     {
74       initialized = 1;
75       init();
76     }
77 
78   if (uw_bt == NULL)
79     return 0;
80 #endif
81 
82   if (max >= 1)
83     uw_bt (__bt_helper, &arg);
84 
85   if (arg.cnt > 1 && arg.pc_array[arg.cnt - 1] == (void*)0)
86     --arg.cnt;
87   return arg.cnt != -1 ? arg.cnt : 0;
88 }
89 
90