1 //===-- sanitizer_symbolizer.cc -------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries. See sanitizer_symbolizer.h for details.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_placement_new.h"
14 #include "sanitizer_procmaps.h"
15 #include "sanitizer_symbolizer.h"
17 namespace __sanitizer
{
19 void AddressInfo::Clear() {
21 InternalFree(function
);
23 internal_memset(this, 0, sizeof(AddressInfo
));
26 LoadedModule::LoadedModule(const char *module_name
, uptr base_address
) {
27 full_name_
= internal_strdup(module_name
);
28 base_address_
= base_address
;
32 void LoadedModule::addAddressRange(uptr beg
, uptr end
) {
33 CHECK_LT(n_ranges_
, kMaxNumberOfAddressRanges
);
34 ranges_
[n_ranges_
].beg
= beg
;
35 ranges_
[n_ranges_
].end
= end
;
39 bool LoadedModule::containsAddress(uptr address
) const {
40 for (uptr i
= 0; i
< n_ranges_
; i
++) {
41 if (ranges_
[i
].beg
<= address
&& address
< ranges_
[i
].end
)
47 // Extracts the prefix of "str" that consists of any characters not
48 // present in "delims" string, and copies this prefix to "result", allocating
50 // Returns a pointer to "str" after skipping extracted prefix and first
52 static const char *ExtractToken(const char *str
, const char *delims
,
54 uptr prefix_len
= internal_strcspn(str
, delims
);
55 *result
= (char*)InternalAlloc(prefix_len
+ 1);
56 internal_memcpy(*result
, str
, prefix_len
);
57 (*result
)[prefix_len
] = '\0';
58 const char *prefix_end
= str
+ prefix_len
;
59 if (*prefix_end
!= '\0') prefix_end
++;
63 // Same as ExtractToken, but converts extracted token to integer.
64 static const char *ExtractInt(const char *str
, const char *delims
,
67 const char *ret
= ExtractToken(str
, delims
, &buff
);
69 *result
= (int)internal_atoll(buff
);
75 static const char *ExtractUptr(const char *str
, const char *delims
,
78 const char *ret
= ExtractToken(str
, delims
, &buff
);
80 *result
= (uptr
)internal_atoll(buff
);
86 // ExternalSymbolizer encapsulates communication between the tool and
87 // external symbolizer program, running in a different subprocess,
88 // For now we assume the following protocol:
89 // For each request of the form
90 // <module_name> <module_offset>
91 // passed to STDIN, external symbolizer prints to STDOUT response:
93 // <file_name>:<line_number>:<column_number>
95 // <file_name>:<line_number>:<column_number>
98 class ExternalSymbolizer
{
100 ExternalSymbolizer(const char *path
, int input_fd
, int output_fd
)
103 output_fd_(output_fd
),
104 times_restarted_(0) {
106 CHECK_NE(input_fd_
, kInvalidFd
);
107 CHECK_NE(output_fd_
, kInvalidFd
);
110 char *SendCommand(bool is_data
, const char *module_name
, uptr module_offset
) {
112 internal_snprintf(buffer_
, kBufferSize
, "%s%s 0x%zx\n",
113 is_data
? "DATA " : "", module_name
, module_offset
);
114 if (!writeToSymbolizer(buffer_
, internal_strlen(buffer_
)))
116 if (!readFromSymbolizer(buffer_
, kBufferSize
))
122 if (times_restarted_
>= kMaxTimesRestarted
) return false;
124 internal_close(input_fd_
);
125 internal_close(output_fd_
);
126 return StartSymbolizerSubprocess(path_
, &input_fd_
, &output_fd_
);
130 bool readFromSymbolizer(char *buffer
, uptr max_length
) {
135 uptr just_read
= internal_read(input_fd_
, buffer
+ read_len
,
136 max_length
- read_len
);
137 // We can't read 0 bytes, as we don't expect external symbolizer to close
139 if (just_read
== 0 || just_read
== (uptr
)-1) {
140 Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_
);
143 read_len
+= just_read
;
144 // Empty line marks the end of symbolizer output.
145 if (read_len
>= 2 && buffer
[read_len
- 1] == '\n' &&
146 buffer
[read_len
- 2] == '\n') {
153 bool writeToSymbolizer(const char *buffer
, uptr length
) {
156 uptr write_len
= internal_write(output_fd_
, buffer
, length
);
157 if (write_len
== 0 || write_len
== (uptr
)-1) {
158 Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_
);
168 static const uptr kBufferSize
= 16 * 1024;
169 char buffer_
[kBufferSize
];
171 static const uptr kMaxTimesRestarted
= 5;
172 uptr times_restarted_
;
175 static LowLevelAllocator symbolizer_allocator
; // Linker initialized.
177 #if SANITIZER_SUPPORTS_WEAK_HOOKS
179 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
180 bool __sanitizer_symbolize_code(const char *ModuleName
, u64 ModuleOffset
,
181 char *Buffer
, int MaxLength
);
182 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
183 bool __sanitizer_symbolize_data(const char *ModuleName
, u64 ModuleOffset
,
184 char *Buffer
, int MaxLength
);
187 class InternalSymbolizer
{
189 typedef bool (*SanitizerSymbolizeFn
)(const char*, u64
, char*, int);
190 static InternalSymbolizer
*get() {
191 if (__sanitizer_symbolize_code
!= 0 &&
192 __sanitizer_symbolize_data
!= 0) {
193 void *mem
= symbolizer_allocator
.Allocate(sizeof(InternalSymbolizer
));
194 return new(mem
) InternalSymbolizer();
198 char *SendCommand(bool is_data
, const char *module_name
, uptr module_offset
) {
199 SanitizerSymbolizeFn symbolize_fn
= is_data
? __sanitizer_symbolize_data
200 : __sanitizer_symbolize_code
;
201 if (symbolize_fn(module_name
, module_offset
, buffer_
, kBufferSize
))
207 InternalSymbolizer() { }
209 static const int kBufferSize
= 16 * 1024;
210 char buffer_
[kBufferSize
];
212 #else // SANITIZER_SUPPORTS_WEAK_HOOKS
214 class InternalSymbolizer
{
216 static InternalSymbolizer
*get() { return 0; }
217 char *SendCommand(bool is_data
, const char *module_name
, uptr module_offset
) {
222 #endif // SANITIZER_SUPPORTS_WEAK_HOOKS
226 uptr
SymbolizeCode(uptr addr
, AddressInfo
*frames
, uptr max_frames
) {
229 LoadedModule
*module
= FindModuleForAddress(addr
);
232 const char *module_name
= module
->full_name();
233 uptr module_offset
= addr
- module
->base_address();
234 const char *str
= SendCommand(false, module_name
, module_offset
);
236 // External symbolizer was not initialized or failed. Fill only data
237 // about module name and offset.
238 AddressInfo
*info
= &frames
[0];
240 info
->FillAddressAndModuleInfo(addr
, module_name
, module_offset
);
244 for (frame_id
= 0; frame_id
< max_frames
; frame_id
++) {
245 AddressInfo
*info
= &frames
[frame_id
];
246 char *function_name
= 0;
247 str
= ExtractToken(str
, "\n", &function_name
);
248 CHECK(function_name
);
249 if (function_name
[0] == '\0') {
250 // There are no more frames.
254 info
->FillAddressAndModuleInfo(addr
, module_name
, module_offset
);
255 info
->function
= function_name
;
256 // Parse <file>:<line>:<column> buffer.
257 char *file_line_info
= 0;
258 str
= ExtractToken(str
, "\n", &file_line_info
);
259 CHECK(file_line_info
);
260 const char *line_info
= ExtractToken(file_line_info
, ":", &info
->file
);
261 line_info
= ExtractInt(line_info
, ":", &info
->line
);
262 line_info
= ExtractInt(line_info
, "", &info
->column
);
263 InternalFree(file_line_info
);
265 // Functions and filenames can be "??", in which case we write 0
266 // to address info to mark that names are unknown.
267 if (0 == internal_strcmp(info
->function
, "??")) {
268 InternalFree(info
->function
);
271 if (0 == internal_strcmp(info
->file
, "??")) {
272 InternalFree(info
->file
);
277 // Make sure we return at least one frame.
278 AddressInfo
*info
= &frames
[0];
280 info
->FillAddressAndModuleInfo(addr
, module_name
, module_offset
);
286 bool SymbolizeData(uptr addr
, DataInfo
*info
) {
287 LoadedModule
*module
= FindModuleForAddress(addr
);
290 const char *module_name
= module
->full_name();
291 uptr module_offset
= addr
- module
->base_address();
292 internal_memset(info
, 0, sizeof(*info
));
293 info
->address
= addr
;
294 info
->module
= internal_strdup(module_name
);
295 info
->module_offset
= module_offset
;
296 const char *str
= SendCommand(true, module_name
, module_offset
);
299 str
= ExtractToken(str
, "\n", &info
->name
);
300 str
= ExtractUptr(str
, " ", &info
->start
);
301 str
= ExtractUptr(str
, "\n", &info
->size
);
302 info
->start
+= module
->base_address();
306 bool InitializeExternalSymbolizer(const char *path_to_symbolizer
) {
307 int input_fd
, output_fd
;
308 if (!StartSymbolizerSubprocess(path_to_symbolizer
, &input_fd
, &output_fd
))
310 void *mem
= symbolizer_allocator
.Allocate(sizeof(ExternalSymbolizer
));
311 external_symbolizer_
= new(mem
) ExternalSymbolizer(path_to_symbolizer
,
312 input_fd
, output_fd
);
316 bool IsSymbolizerAvailable() {
317 if (internal_symbolizer_
== 0)
318 internal_symbolizer_
= InternalSymbolizer::get();
319 return internal_symbolizer_
|| external_symbolizer_
;
323 char *SendCommand(bool is_data
, const char *module_name
, uptr module_offset
) {
324 // First, try to use internal symbolizer.
325 if (internal_symbolizer_
== 0) {
326 internal_symbolizer_
= InternalSymbolizer::get();
328 if (internal_symbolizer_
) {
329 return internal_symbolizer_
->SendCommand(is_data
, module_name
,
332 // Otherwise, fall back to external symbolizer.
333 if (external_symbolizer_
== 0) {
334 ReportExternalSymbolizerError(
335 "WARNING: Trying to symbolize code, but external "
336 "symbolizer is not initialized!\n");
340 char *reply
= external_symbolizer_
->SendCommand(is_data
, module_name
,
344 // Try to restart symbolizer subprocess. If we don't succeed, forget
345 // about it and don't try to use it later.
346 if (!external_symbolizer_
->Restart()) {
347 ReportExternalSymbolizerError(
348 "WARNING: Failed to use and restart external symbolizer!\n");
349 external_symbolizer_
= 0;
355 LoadedModule
*FindModuleForAddress(uptr address
) {
357 modules_
= (LoadedModule
*)(symbolizer_allocator
.Allocate(
358 kMaxNumberOfModuleContexts
* sizeof(LoadedModule
)));
360 n_modules_
= GetListOfModules(modules_
, kMaxNumberOfModuleContexts
);
361 CHECK_GT(n_modules_
, 0);
362 CHECK_LT(n_modules_
, kMaxNumberOfModuleContexts
);
364 for (uptr i
= 0; i
< n_modules_
; i
++) {
365 if (modules_
[i
].containsAddress(address
)) {
371 void ReportExternalSymbolizerError(const char *msg
) {
372 // Don't use atomics here for now, as SymbolizeCode can't be called
373 // from multiple threads anyway.
374 static bool reported
;
381 // 16K loaded modules should be enough for everyone.
382 static const uptr kMaxNumberOfModuleContexts
= 1 << 14;
383 LoadedModule
*modules_
; // Array of module descriptions is leaked.
386 ExternalSymbolizer
*external_symbolizer_
; // Leaked.
387 InternalSymbolizer
*internal_symbolizer_
; // Leaked.
390 static Symbolizer symbolizer
; // Linker initialized.
392 uptr
SymbolizeCode(uptr address
, AddressInfo
*frames
, uptr max_frames
) {
393 return symbolizer
.SymbolizeCode(address
, frames
, max_frames
);
396 bool SymbolizeData(uptr address
, DataInfo
*info
) {
397 return symbolizer
.SymbolizeData(address
, info
);
400 bool InitializeExternalSymbolizer(const char *path_to_symbolizer
) {
401 return symbolizer
.InitializeExternalSymbolizer(path_to_symbolizer
);
404 bool IsSymbolizerAvailable() {
405 return symbolizer
.IsSymbolizerAvailable();
408 } // namespace __sanitizer