• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define _GNU_SOURCE
17 #include <stdint.h>
18 #include <malloc.h>
19 #include <dlfcn.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <debug.h>
23 #include <unwind.h>
24 
25 #define TRACE_MAX_DEPTH 16
26 #define STRING_MAX_LEN  256
27 #define TRACE_IGNORE    1
28 
29 struct unwind_state_t {
30 	_Unwind_Word **cur;
31 	_Unwind_Word **end;
32 };
33 
unwind_callback(struct _Unwind_Context * context,void * arg)34 static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg)
35 {
36 	struct unwind_state_t *state = (struct unwind_state_t *)arg;
37 	_Unwind_Word pc = _Unwind_GetIP(context);
38 	if (pc != 0) {
39 		if (state->cur != state->end) {
40 			*state->cur = (_Unwind_Word *)pc;
41 		} else {
42 			return _URC_END_OF_STACK;
43 		}
44 	}
45 	++state->cur;
46 
47 	return _URC_NO_REASON;
48 }
49 
backtrace(void ** buffer,int size)50 int backtrace(void **buffer, int size)
51 {
52 	struct unwind_state_t state;
53 
54 	if ((buffer == NULL) || (size <= 0)) {
55 		return 0;
56 	}
57 
58 	state.cur = (_Unwind_Word **)buffer;
59 	state.end = (_Unwind_Word **)(buffer + size);
60 	_Unwind_Backtrace(&unwind_callback, &state);
61 
62 	return (void **)state.cur - buffer;
63 }
64 
backtrace_symbols(void * const * buffer,int size)65 char **backtrace_symbols(void *const *buffer, int size)
66 {
67 	int i;
68 	char **str_location = NULL;
69 	char *str_buffer = NULL;
70 	char *str_base = NULL;
71 	char **string = NULL;
72 	Dl_info info = { 0 };
73 	size_t total_size = 0;
74 
75 	if ((buffer == NULL) || (size <= 0)) {
76 		return NULL;
77 	}
78 	str_location = (char **)malloc(size * sizeof(char *));
79 	if (str_location == NULL) {
80 		return NULL;
81 	}
82 	memset(str_location, 0, size * sizeof(char *));
83 	for (i = 0; i < size; ++i) {
84 		dladdr((void *)buffer[i], &info);
85 		if ((info.dli_fname == NULL) || (info.dli_fname[0] == '\0')) {
86 			break;
87 		}
88 		str_buffer = (char *)malloc(STRING_MAX_LEN * sizeof(char));
89 		if (str_buffer == NULL) {
90 			goto err;
91 		}
92 
93 		snprintf(str_buffer, STRING_MAX_LEN, "    #%02d: <%s+%#x>[%#x] -> %s\n", i, info.dli_sname,
94 			(uintptr_t)buffer[i] - (uintptr_t)info.dli_saddr,
95 			(uintptr_t)buffer[i] - (uintptr_t)info.dli_fbase, info.dli_fname);
96 		str_location[i] = str_buffer;
97 		total_size += strlen(str_buffer) + 1;
98 	}
99 	string = (char **)malloc(total_size + (size * sizeof(char *)));
100 	if (string == NULL) {
101 		goto err;
102 	}
103 	memset(string, 0, total_size + (size * sizeof(char *)));
104 	str_base = (char *)(string + size);
105 	for (i = 0; i < size; ++i) {
106 		if (str_location[i] == NULL) {
107 			break;
108 		}
109 		strcpy(str_base, str_location[i]);
110 		string[i] = str_base;
111 		str_base += strlen(string[i]) + 1;
112 		free(str_location[i]);
113 	}
114 	free(str_location);
115 	return string;
116 
117 err:
118 	for (i = 0; i < size; ++i) {
119 		if (str_location[i]) {
120 			free(str_location[i]);
121 		}
122 	}
123 	free(str_location);
124 	return NULL;
125 }
126 
get_backtrace_addr(void * const * buffer,int nptrs)127 static void get_backtrace_addr(void *const *buffer, int nptrs)
128 {
129 	for (int i = 1; i < nptrs; ++i) {
130 		printf("    #%02d: %#x\n", i, buffer[i]);
131 	}
132 }
133 
print_trace()134 void print_trace()
135 {
136 	int nptrs, i;
137 	void *buffer[TRACE_MAX_DEPTH];
138 	char **strings = NULL;
139 
140 	nptrs = backtrace(buffer, TRACE_MAX_DEPTH);
141 	printf("\nBacktrace() returned %d addresses\n", nptrs - TRACE_IGNORE);
142 	strings = backtrace_symbols(buffer, nptrs);
143 	if (strings == NULL) {
144 		printf("backtrace_symbols() err!\n");
145 		return;
146 	}
147 	for (i = 1; i < nptrs; ++i) {
148 		if ((i == 1) && (strings[i] == NULL)) {
149 			get_backtrace_addr(buffer, nptrs);
150 			break;
151 		}
152 		printf("%s", strings[i]);
153 	}
154 	free(strings);
155 }
156 
157