• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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