145
|
1 //===-- sanitizer_symbolizer_libbacktrace.cpp -----------------------------===//
|
|
2 //
|
|
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
4 // See https://llvm.org/LICENSE.txt for license information.
|
|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
6 //
|
|
7 //===----------------------------------------------------------------------===//
|
|
8 //
|
|
9 // This file is shared between AddressSanitizer and ThreadSanitizer
|
|
10 // run-time libraries.
|
|
11 // Libbacktrace implementation of symbolizer parts.
|
|
12 //===----------------------------------------------------------------------===//
|
|
13
|
|
14 #include "sanitizer_platform.h"
|
|
15
|
|
16 #include "sanitizer_internal_defs.h"
|
|
17 #include "sanitizer_symbolizer.h"
|
|
18 #include "sanitizer_symbolizer_libbacktrace.h"
|
|
19
|
|
20 #if SANITIZER_LIBBACKTRACE
|
|
21 # include "backtrace-supported.h"
|
|
22 # if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
|
|
23 # include "backtrace.h"
|
|
24 # if SANITIZER_CP_DEMANGLE
|
|
25 # undef ARRAY_SIZE
|
|
26 # include "demangle.h"
|
|
27 # endif
|
|
28 # else
|
|
29 # define SANITIZER_LIBBACKTRACE 0
|
|
30 # endif
|
|
31 #endif
|
|
32
|
|
33 namespace __sanitizer {
|
|
34
|
|
35 static char *DemangleAlloc(const char *name, bool always_alloc);
|
|
36
|
|
37 #if SANITIZER_LIBBACKTRACE
|
|
38
|
|
39 namespace {
|
|
40
|
|
41 # if SANITIZER_CP_DEMANGLE
|
|
42 struct CplusV3DemangleData {
|
|
43 char *buf;
|
|
44 uptr size, allocated;
|
|
45 };
|
|
46
|
|
47 extern "C" {
|
|
48 static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
|
|
49 CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
|
|
50 uptr needed = data->size + l + 1;
|
|
51 if (needed > data->allocated) {
|
|
52 data->allocated *= 2;
|
|
53 if (needed > data->allocated)
|
|
54 data->allocated = needed;
|
|
55 char *buf = (char *)InternalAlloc(data->allocated);
|
|
56 if (data->buf) {
|
|
57 internal_memcpy(buf, data->buf, data->size);
|
|
58 InternalFree(data->buf);
|
|
59 }
|
|
60 data->buf = buf;
|
|
61 }
|
|
62 internal_memcpy(data->buf + data->size, s, l);
|
|
63 data->buf[data->size + l] = '\0';
|
|
64 data->size += l;
|
|
65 }
|
|
66 } // extern "C"
|
|
67
|
|
68 char *CplusV3Demangle(const char *name) {
|
|
69 CplusV3DemangleData data;
|
|
70 data.buf = 0;
|
|
71 data.size = 0;
|
|
72 data.allocated = 0;
|
|
73 if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
|
|
74 CplusV3DemangleCallback, &data)) {
|
|
75 if (data.size + 64 > data.allocated)
|
|
76 return data.buf;
|
|
77 char *buf = internal_strdup(data.buf);
|
|
78 InternalFree(data.buf);
|
|
79 return buf;
|
|
80 }
|
|
81 if (data.buf)
|
|
82 InternalFree(data.buf);
|
|
83 return 0;
|
|
84 }
|
|
85 # endif // SANITIZER_CP_DEMANGLE
|
|
86
|
|
87 struct SymbolizeCodeCallbackArg {
|
|
88 SymbolizedStack *first;
|
|
89 SymbolizedStack *last;
|
|
90 uptr frames_symbolized;
|
|
91
|
|
92 AddressInfo *get_new_frame(uintptr_t addr) {
|
|
93 CHECK(last);
|
|
94 if (frames_symbolized > 0) {
|
|
95 SymbolizedStack *cur = SymbolizedStack::New(addr);
|
|
96 AddressInfo *info = &cur->info;
|
|
97 info->FillModuleInfo(first->info.module, first->info.module_offset,
|
|
98 first->info.module_arch);
|
|
99 last->next = cur;
|
|
100 last = cur;
|
|
101 }
|
|
102 CHECK_EQ(addr, first->info.address);
|
|
103 CHECK_EQ(addr, last->info.address);
|
|
104 return &last->info;
|
|
105 }
|
|
106 };
|
|
107
|
|
108 extern "C" {
|
|
109 static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
|
|
110 const char *filename, int lineno,
|
|
111 const char *function) {
|
|
112 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
|
|
113 if (function) {
|
|
114 AddressInfo *info = cdata->get_new_frame(addr);
|
|
115 info->function = DemangleAlloc(function, /*always_alloc*/ true);
|
|
116 if (filename)
|
|
117 info->file = internal_strdup(filename);
|
|
118 info->line = lineno;
|
|
119 cdata->frames_symbolized++;
|
|
120 }
|
|
121 return 0;
|
|
122 }
|
|
123
|
|
124 static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
|
|
125 const char *symname, uintptr_t, uintptr_t) {
|
|
126 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
|
|
127 if (symname) {
|
|
128 AddressInfo *info = cdata->get_new_frame(addr);
|
|
129 info->function = DemangleAlloc(symname, /*always_alloc*/ true);
|
|
130 cdata->frames_symbolized++;
|
|
131 }
|
|
132 }
|
|
133
|
|
134 static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
|
|
135 uintptr_t symval, uintptr_t symsize) {
|
|
136 DataInfo *info = (DataInfo *)vdata;
|
|
137 if (symname && symval) {
|
|
138 info->name = DemangleAlloc(symname, /*always_alloc*/ true);
|
|
139 info->start = symval;
|
|
140 info->size = symsize;
|
|
141 }
|
|
142 }
|
|
143
|
|
144 static void ErrorCallback(void *, const char *, int) {}
|
|
145 } // extern "C"
|
|
146
|
|
147 } // namespace
|
|
148
|
|
149 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
|
|
150 // State created in backtrace_create_state is leaked.
|
|
151 void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
|
|
152 ErrorCallback, NULL));
|
|
153 if (!state)
|
|
154 return 0;
|
|
155 return new(*alloc) LibbacktraceSymbolizer(state);
|
|
156 }
|
|
157
|
|
158 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
|
|
159 SymbolizeCodeCallbackArg data;
|
|
160 data.first = stack;
|
|
161 data.last = stack;
|
|
162 data.frames_symbolized = 0;
|
|
163 backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
|
|
164 ErrorCallback, &data);
|
|
165 if (data.frames_symbolized > 0)
|
|
166 return true;
|
|
167 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
|
|
168 ErrorCallback, &data);
|
|
169 return (data.frames_symbolized > 0);
|
|
170 }
|
|
171
|
|
172 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
|
|
173 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback,
|
|
174 ErrorCallback, info);
|
|
175 return true;
|
|
176 }
|
|
177
|
|
178 #else // SANITIZER_LIBBACKTRACE
|
|
179
|
|
180 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
|
|
181 return 0;
|
|
182 }
|
|
183
|
|
184 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
|
|
185 (void)state_;
|
|
186 return false;
|
|
187 }
|
|
188
|
|
189 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
|
|
190 return false;
|
|
191 }
|
|
192
|
|
193 #endif // SANITIZER_LIBBACKTRACE
|
|
194
|
|
195 static char *DemangleAlloc(const char *name, bool always_alloc) {
|
|
196 #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
|
|
197 if (char *demangled = CplusV3Demangle(name))
|
|
198 return demangled;
|
|
199 #endif
|
|
200 if (always_alloc)
|
|
201 return internal_strdup(name);
|
|
202 return 0;
|
|
203 }
|
|
204
|
|
205 const char *LibbacktraceSymbolizer::Demangle(const char *name) {
|
|
206 return DemangleAlloc(name, /*always_alloc*/ false);
|
|
207 }
|
|
208
|
|
209 } // namespace __sanitizer
|