1 #define _GNU_SOURCE
2 #include <stdint.h>
3 #include <malloc.h>
4 #include <dlfcn.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <debug.h>
8 #include <unwind.h>
9
10 #define TRACE_MAX_DEPTH 16
11 #define STRING_MAX_LEN 256
12 #define TRACE_IGNORE 1
13
14 struct unwind_state_t {
15 _Unwind_Word **cur;
16 _Unwind_Word **end;
17 };
18
unwind_callback(struct _Unwind_Context * context,void * arg)19 static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg)
20 {
21 struct unwind_state_t *state = (struct unwind_state_t *)arg;
22 _Unwind_Word pc = _Unwind_GetIP(context);
23 if (pc != 0) {
24 if (state->cur != state->end) {
25 *state->cur = (_Unwind_Word *)pc;
26 } else {
27 return _URC_END_OF_STACK;
28 }
29 }
30 ++state->cur;
31
32 return _URC_NO_REASON;
33 }
34
backtrace(void ** buffer,int size)35 int backtrace(void **buffer, int size)
36 {
37 struct unwind_state_t state;
38
39 if ((buffer == NULL) || (size <= 0)) {
40 return 0;
41 }
42
43 state.cur = (_Unwind_Word **)buffer;
44 state.end = (_Unwind_Word **)(buffer + size);
45 _Unwind_Backtrace(&unwind_callback, &state);
46
47 return (void **)state.cur - buffer;
48 }
49
backtrace_symbols(void * const * buffer,int size)50 char **backtrace_symbols(void *const *buffer, int size)
51 {
52 int i;
53 char **str_location = NULL;
54 char *str_buffer = NULL;
55 char *str_base = NULL;
56 char **string = NULL;
57 Dl_info info = { 0 };
58 size_t total_size = 0;
59
60 if ((buffer == NULL) || (size <= 0)) {
61 return NULL;
62 }
63 str_location = (char **)malloc(size * sizeof(char *));
64 if (str_location == NULL) {
65 return NULL;
66 }
67 memset(str_location, 0, size * sizeof(char *));
68 for (i = 0; i < size; ++i) {
69 dladdr((void *)buffer[i], &info);
70 if ((info.dli_fname == NULL) || (info.dli_fname[0] == '\0')) {
71 break;
72 }
73 str_buffer = (char *)malloc(STRING_MAX_LEN * sizeof(char));
74 if (str_buffer == NULL) {
75 goto err;
76 }
77
78 snprintf(str_buffer, STRING_MAX_LEN, " #%02d: <%s+%#x>[%#x] -> %s\n", i, info.dli_sname,
79 (uintptr_t)buffer[i] - (uintptr_t)info.dli_saddr,
80 (uintptr_t)buffer[i] - (uintptr_t)info.dli_fbase, info.dli_fname);
81 str_location[i] = str_buffer;
82 total_size += strlen(str_buffer) + 1;
83 }
84 string = (char **)malloc(total_size + (size * sizeof(char *)));
85 if (string == NULL) {
86 goto err;
87 }
88 memset(string, 0, total_size + (size * sizeof(char *)));
89 str_base = (char *)(string + size);
90 for (i = 0; i < size; ++i) {
91 if (str_location[i] == NULL) {
92 break;
93 }
94 strcpy(str_base, str_location[i]);
95 string[i] = str_base;
96 str_base += strlen(string[i]) + 1;
97 free(str_location[i]);
98 }
99 free(str_location);
100 return string;
101
102 err:
103 for (i = 0; i < size; ++i) {
104 if (str_location[i]) {
105 free(str_location[i]);
106 }
107 }
108 free(str_location);
109 return NULL;
110 }
111
get_backtrace_addr(void * const * buffer,int nptrs)112 static void get_backtrace_addr(void *const *buffer, int nptrs)
113 {
114 for (int i = 1; i < nptrs; ++i) {
115 printf(" #%02d: %#x\n", i, buffer[i]);
116 }
117 }
118
print_trace()119 void print_trace()
120 {
121 int nptrs, i;
122 void *buffer[TRACE_MAX_DEPTH];
123 char **strings = NULL;
124
125 nptrs = backtrace(buffer, TRACE_MAX_DEPTH);
126 printf("\nBacktrace() returned %d addresses\n", nptrs - TRACE_IGNORE);
127 strings = backtrace_symbols(buffer, nptrs);
128 if (strings == NULL) {
129 printf("backtrace_symbols() err!\n");
130 return;
131 }
132 for (i = 1; i < nptrs; ++i) {
133 if ((i == 1) && (strings[i] == NULL)) {
134 get_backtrace_addr(buffer, nptrs);
135 break;
136 }
137 printf("%s", strings[i]);
138 }
139 free(strings);
140 }
141
142