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