]>
Commit | Line | Data |
---|---|---|
4fc7b5ac | 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" | |
9071f223 | 23 | # if SANITIZER_CP_DEMANGLE |
24 | # undef ARRAY_SIZE | |
25 | # include "demangle.h" | |
26 | # endif | |
4fc7b5ac | 27 | # else |
28 | # define SANITIZER_LIBBACKTRACE 0 | |
29 | # endif | |
30 | #endif | |
31 | ||
32 | namespace __sanitizer { | |
33 | ||
5645a48f | 34 | static char *DemangleAlloc(const char *name, bool always_alloc); |
35 | ||
4fc7b5ac | 36 | #if SANITIZER_LIBBACKTRACE |
37 | ||
38 | namespace { | |
39 | ||
7d752f28 | 40 | # if SANITIZER_CP_DEMANGLE |
9071f223 | 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 | ||
7d752f28 | 67 | char *CplusV3Demangle(const char *name) { |
9071f223 | 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, | |
7d752f28 | 73 | CplusV3DemangleCallback, &data)) { |
9071f223 | 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); | |
9071f223 | 82 | return 0; |
83 | } | |
7d752f28 | 84 | # endif // SANITIZER_CP_DEMANGLE |
9071f223 | 85 | |
5645a48f | 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; | |
36093749 | 96 | info->FillModuleInfo(first->info.module, first->info.module_offset, |
97 | first->info.module_arch); | |
5645a48f | 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 | } | |
4fc7b5ac | 105 | }; |
106 | ||
107 | extern "C" { | |
108 | static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, | |
109 | const char *filename, int lineno, | |
110 | const char *function) { | |
5645a48f | 111 | SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; |
4fc7b5ac | 112 | if (function) { |
5645a48f | 113 | AddressInfo *info = cdata->get_new_frame(addr); |
114 | info->function = DemangleAlloc(function, /*always_alloc*/ true); | |
4fc7b5ac | 115 | if (filename) |
116 | info->file = internal_strdup(filename); | |
117 | info->line = lineno; | |
5645a48f | 118 | cdata->frames_symbolized++; |
4fc7b5ac | 119 | } |
120 | return 0; | |
121 | } | |
122 | ||
123 | static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, | |
124 | const char *symname, uintptr_t, uintptr_t) { | |
5645a48f | 125 | SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; |
4fc7b5ac | 126 | if (symname) { |
5645a48f | 127 | AddressInfo *info = cdata->get_new_frame(addr); |
128 | info->function = DemangleAlloc(symname, /*always_alloc*/ true); | |
129 | cdata->frames_symbolized++; | |
4fc7b5ac | 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) { | |
5645a48f | 137 | info->name = DemangleAlloc(symname, /*always_alloc*/ true); |
4fc7b5ac | 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 | ||
5645a48f | 157 | bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { |
158 | SymbolizeCodeCallbackArg data; | |
159 | data.first = stack; | |
160 | data.last = stack; | |
161 | data.frames_symbolized = 0; | |
4fc7b5ac | 162 | backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, |
163 | ErrorCallback, &data); | |
5645a48f | 164 | if (data.frames_symbolized > 0) |
165 | return true; | |
4fc7b5ac | 166 | backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, |
167 | ErrorCallback, &data); | |
5645a48f | 168 | return (data.frames_symbolized > 0); |
4fc7b5ac | 169 | } |
170 | ||
b5e0c6c9 | 171 | bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { |
172 | backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, | |
173 | ErrorCallback, info); | |
4fc7b5ac | 174 | return true; |
175 | } | |
176 | ||
177 | #else // SANITIZER_LIBBACKTRACE | |
178 | ||
179 | LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { | |
180 | return 0; | |
181 | } | |
182 | ||
5645a48f | 183 | bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { |
4fc7b5ac | 184 | (void)state_; |
5645a48f | 185 | return false; |
4fc7b5ac | 186 | } |
187 | ||
b5e0c6c9 | 188 | bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { |
4fc7b5ac | 189 | return false; |
190 | } | |
191 | ||
7d752f28 | 192 | #endif // SANITIZER_LIBBACKTRACE |
193 | ||
5645a48f | 194 | static char *DemangleAlloc(const char *name, bool always_alloc) { |
7d752f28 | 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); | |
9071f223 | 201 | return 0; |
202 | } | |
203 | ||
5645a48f | 204 | const char *LibbacktraceSymbolizer::Demangle(const char *name) { |
205 | return DemangleAlloc(name, /*always_alloc*/ false); | |
206 | } | |
207 | ||
4fc7b5ac | 208 | } // namespace __sanitizer |