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