blob: d4eca32248b100409648dbf82a3e176e26022ad8 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * Perform stack unwinding by using the _Unwind_Backtrace.
3 *
4 * User application that wants to use backtrace needs to be
5 * compiled with -fasynchronous-unwid-tables option and -rdynamic i
6 * to get full symbols printed.
7 *
8 * Author(s): Khem Raj <raj.khem@gmail.com>
9 * - ARM specific implementation of backtrace
10 *
11 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
12 *
13 */
14
15#include <execinfo.h>
16#include <dlfcn.h>
17#include <stdlib.h>
18#include <unwind.h>
19#include <assert.h>
20#include <stdio.h>
21
22struct trace_arg
23{
24 void **array;
25 int cnt, size;
26};
27
28static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
29static _Unwind_VRS_Result (*unwind_vrs_get) (_Unwind_Context *,
30 _Unwind_VRS_RegClass,
31 _uw,
32 _Unwind_VRS_DataRepresentation,
33 void *);
34
35static void backtrace_init (void)
36{
37 void *handle = dlopen ("libgcc_s.so.1", RTLD_LAZY);
38 if (handle == NULL
39 || ((unwind_backtrace = dlsym (handle, "_Unwind_Backtrace")) == NULL)
40 || ((unwind_vrs_get = dlsym (handle, "_Unwind_VRS_Get")) == NULL)) {
41 printf("libgcc_s.so.1 must be installed for backtrace to work\n");
42 abort();
43 }
44}
45/* This function is identical to "_Unwind_GetGR", except that it uses
46 "unwind_vrs_get" instead of "_Unwind_VRS_Get". */
47static inline _Unwind_Word
48unwind_getgr (_Unwind_Context *context, int regno)
49{
50 _uw val;
51 unwind_vrs_get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
52 return val;
53}
54
55/* This macro is identical to the _Unwind_GetIP macro, except that it
56 uses "unwind_getgr" instead of "_Unwind_GetGR". */
57#define unwind_getip(context) \
58 (unwind_getgr (context, 15) & ~(_Unwind_Word)1)
59
60static _Unwind_Reason_Code
61backtrace_helper (struct _Unwind_Context *ctx, void *a)
62{
63 struct trace_arg *arg = a;
64
65 assert (unwind_getip != NULL);
66
67 /* We are first called with address in the __backtrace function. Skip it. */
68 if (arg->cnt != -1)
69 arg->array[arg->cnt] = (void *) unwind_getip (ctx);
70 if (++arg->cnt == arg->size)
71 return _URC_END_OF_STACK;
72 return _URC_NO_REASON;
73}
74
75/*
76 * Perform stack unwinding by using the _Unwind_Backtrace.
77 *
78 */
79int backtrace (void **array, int size)
80{
81 struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
82
83 if (unwind_backtrace == NULL)
84 backtrace_init();
85
86 if (size >= 1)
87 unwind_backtrace (backtrace_helper, &arg);
88
89 return arg.cnt != -1 ? arg.cnt : 0;
90}