1 //===-- sanitizer_symbolizer_libcdep.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
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_allocator_internal.h"
13 #include "sanitizer_internal_defs.h"
14 #include "sanitizer_symbolizer_internal.h"
16 namespace __sanitizer
{
18 Symbolizer
*Symbolizer::GetOrInit() {
19 SpinMutexLock
l(&init_mu_
);
22 symbolizer_
= PlatformInit();
27 // See sanitizer_symbolizer_markup.cc.
28 #if !SANITIZER_SYMBOLIZER_MARKUP
30 const char *ExtractToken(const char *str
, const char *delims
, char **result
) {
31 uptr prefix_len
= internal_strcspn(str
, delims
);
32 *result
= (char*)InternalAlloc(prefix_len
+ 1);
33 internal_memcpy(*result
, str
, prefix_len
);
34 (*result
)[prefix_len
] = '\0';
35 const char *prefix_end
= str
+ prefix_len
;
36 if (*prefix_end
!= '\0') prefix_end
++;
40 const char *ExtractInt(const char *str
, const char *delims
, int *result
) {
42 const char *ret
= ExtractToken(str
, delims
, &buff
);
44 *result
= (int)internal_atoll(buff
);
50 const char *ExtractUptr(const char *str
, const char *delims
, uptr
*result
) {
52 const char *ret
= ExtractToken(str
, delims
, &buff
);
54 *result
= (uptr
)internal_atoll(buff
);
60 const char *ExtractTokenUpToDelimiter(const char *str
, const char *delimiter
,
62 const char *found_delimiter
= internal_strstr(str
, delimiter
);
64 found_delimiter
? found_delimiter
- str
: internal_strlen(str
);
65 *result
= (char *)InternalAlloc(prefix_len
+ 1);
66 internal_memcpy(*result
, str
, prefix_len
);
67 (*result
)[prefix_len
] = '\0';
68 const char *prefix_end
= str
+ prefix_len
;
69 if (*prefix_end
!= '\0') prefix_end
+= internal_strlen(delimiter
);
73 SymbolizedStack
*Symbolizer::SymbolizePC(uptr addr
) {
74 BlockingMutexLock
l(&mu_
);
75 const char *module_name
;
78 SymbolizedStack
*res
= SymbolizedStack::New(addr
);
79 if (!FindModuleNameAndOffsetForAddress(addr
, &module_name
, &module_offset
,
82 // Always fill data about module name and offset.
83 res
->info
.FillModuleInfo(module_name
, module_offset
, arch
);
84 for (auto &tool
: tools_
) {
85 SymbolizerScope
sym_scope(this);
86 if (tool
.SymbolizePC(addr
, res
)) {
93 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
94 BlockingMutexLock
l(&mu_
);
95 const char *module_name
;
98 if (!FindModuleNameAndOffsetForAddress(addr
, &module_name
, &module_offset
,
102 info
->module
= internal_strdup(module_name
);
103 info
->module_offset
= module_offset
;
104 info
->module_arch
= arch
;
105 for (auto &tool
: tools_
) {
106 SymbolizerScope
sym_scope(this);
107 if (tool
.SymbolizeData(addr
, info
)) {
114 bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc
, const char **module_name
,
115 uptr
*module_address
) {
116 BlockingMutexLock
l(&mu_
);
117 const char *internal_module_name
= nullptr;
119 if (!FindModuleNameAndOffsetForAddress(pc
, &internal_module_name
,
120 module_address
, &arch
))
124 *module_name
= module_names_
.GetOwnedCopy(internal_module_name
);
128 void Symbolizer::Flush() {
129 BlockingMutexLock
l(&mu_
);
130 for (auto &tool
: tools_
) {
131 SymbolizerScope
sym_scope(this);
136 const char *Symbolizer::Demangle(const char *name
) {
137 BlockingMutexLock
l(&mu_
);
138 for (auto &tool
: tools_
) {
139 SymbolizerScope
sym_scope(this);
140 if (const char *demangled
= tool
.Demangle(name
))
143 return PlatformDemangle(name
);
146 bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address
,
147 const char **module_name
,
149 ModuleArch
*module_arch
) {
150 const LoadedModule
*module
= FindModuleForAddress(address
);
151 if (module
== nullptr)
153 *module_name
= module
->full_name();
154 *module_offset
= address
- module
->base_address();
155 *module_arch
= module
->arch();
159 void Symbolizer::RefreshModules() {
161 fallback_modules_
.fallbackInit();
162 RAW_CHECK(modules_
.size() > 0);
163 modules_fresh_
= true;
166 static const LoadedModule
*SearchForModule(const ListOfModules
&modules
,
168 for (uptr i
= 0; i
< modules
.size(); i
++) {
169 if (modules
[i
].containsAddress(address
)) {
176 const LoadedModule
*Symbolizer::FindModuleForAddress(uptr address
) {
177 bool modules_were_reloaded
= false;
178 if (!modules_fresh_
) {
180 modules_were_reloaded
= true;
182 const LoadedModule
*module
= SearchForModule(modules_
, address
);
183 if (module
) return module
;
185 // dlopen/dlclose interceptors invalidate the module list, but when
186 // interception is disabled, we need to retry if the lookup fails in
187 // case the module list changed.
188 #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
189 if (!modules_were_reloaded
) {
191 module
= SearchForModule(modules_
, address
);
192 if (module
) return module
;
196 if (fallback_modules_
.size()) {
197 module
= SearchForModule(fallback_modules_
, address
);
202 // For now we assume the following protocol:
203 // For each request of the form
204 // <module_name> <module_offset>
205 // passed to STDIN, external symbolizer prints to STDOUT response:
207 // <file_name>:<line_number>:<column_number>
209 // <file_name>:<line_number>:<column_number>
212 class LLVMSymbolizerProcess
: public SymbolizerProcess
{
214 explicit LLVMSymbolizerProcess(const char *path
) : SymbolizerProcess(path
) {}
217 bool ReachedEndOfOutput(const char *buffer
, uptr length
) const override
{
218 // Empty line marks the end of llvm-symbolizer output.
219 return length
>= 2 && buffer
[length
- 1] == '\n' &&
220 buffer
[length
- 2] == '\n';
223 // When adding a new architecture, don't forget to also update
224 // script/asan_symbolize.py and sanitizer_common.h.
225 void GetArgV(const char *path_to_binary
,
226 const char *(&argv
)[kArgVMax
]) const override
{
227 #if defined(__x86_64h__)
228 const char* const kSymbolizerArch
= "--default-arch=x86_64h";
229 #elif defined(__x86_64__)
230 const char* const kSymbolizerArch
= "--default-arch=x86_64";
231 #elif defined(__i386__)
232 const char* const kSymbolizerArch
= "--default-arch=i386";
233 #elif defined(__aarch64__)
234 const char* const kSymbolizerArch
= "--default-arch=arm64";
235 #elif defined(__arm__)
236 const char* const kSymbolizerArch
= "--default-arch=arm";
237 #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
238 const char* const kSymbolizerArch
= "--default-arch=powerpc64";
239 #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
240 const char* const kSymbolizerArch
= "--default-arch=powerpc64le";
241 #elif defined(__s390x__)
242 const char* const kSymbolizerArch
= "--default-arch=s390x";
243 #elif defined(__s390__)
244 const char* const kSymbolizerArch
= "--default-arch=s390";
246 const char* const kSymbolizerArch
= "--default-arch=unknown";
249 const char *const inline_flag
= common_flags()->symbolize_inline_frames
251 : "--inlining=false";
253 argv
[i
++] = path_to_binary
;
254 argv
[i
++] = inline_flag
;
255 argv
[i
++] = kSymbolizerArch
;
260 LLVMSymbolizer::LLVMSymbolizer(const char *path
, LowLevelAllocator
*allocator
)
261 : symbolizer_process_(new(*allocator
) LLVMSymbolizerProcess(path
)) {}
263 // Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on
264 // Windows, so extract tokens from the right hand side first. The column info is
266 static const char *ParseFileLineInfo(AddressInfo
*info
, const char *str
) {
267 char *file_line_info
= 0;
268 str
= ExtractToken(str
, "\n", &file_line_info
);
269 CHECK(file_line_info
);
271 if (uptr size
= internal_strlen(file_line_info
)) {
272 char *back
= file_line_info
+ size
- 1;
273 for (int i
= 0; i
< 2; ++i
) {
274 while (back
> file_line_info
&& IsDigit(*back
)) --back
;
275 if (*back
!= ':' || !IsDigit(back
[1])) break;
276 info
->column
= info
->line
;
277 info
->line
= internal_atoll(back
+ 1);
278 // Truncate the string at the colon to keep only filename.
282 ExtractToken(file_line_info
, "", &info
->file
);
285 InternalFree(file_line_info
);
289 // Parses one or more two-line strings in the following format:
291 // <file_name>:<line_number>[:<column_number>]
292 // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
293 // them use the same output format.
294 void ParseSymbolizePCOutput(const char *str
, SymbolizedStack
*res
) {
295 bool top_frame
= true;
296 SymbolizedStack
*last
= res
;
298 char *function_name
= 0;
299 str
= ExtractToken(str
, "\n", &function_name
);
300 CHECK(function_name
);
301 if (function_name
[0] == '\0') {
302 // There are no more frames.
303 InternalFree(function_name
);
306 SymbolizedStack
*cur
;
311 cur
= SymbolizedStack::New(res
->info
.address
);
312 cur
->info
.FillModuleInfo(res
->info
.module
, res
->info
.module_offset
,
313 res
->info
.module_arch
);
318 AddressInfo
*info
= &cur
->info
;
319 info
->function
= function_name
;
320 str
= ParseFileLineInfo(info
, str
);
322 // Functions and filenames can be "??", in which case we write 0
323 // to address info to mark that names are unknown.
324 if (0 == internal_strcmp(info
->function
, "??")) {
325 InternalFree(info
->function
);
328 if (0 == internal_strcmp(info
->file
, "??")) {
329 InternalFree(info
->file
);
335 // Parses a two-line string in the following format:
337 // <start_address> <size>
338 // Used by LLVMSymbolizer and InternalSymbolizer.
339 void ParseSymbolizeDataOutput(const char *str
, DataInfo
*info
) {
340 str
= ExtractToken(str
, "\n", &info
->name
);
341 str
= ExtractUptr(str
, " ", &info
->start
);
342 str
= ExtractUptr(str
, "\n", &info
->size
);
345 bool LLVMSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
346 AddressInfo
*info
= &stack
->info
;
347 const char *buf
= FormatAndSendCommand(
348 /*is_data*/ false, info
->module
, info
->module_offset
, info
->module_arch
);
350 ParseSymbolizePCOutput(buf
, stack
);
356 bool LLVMSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
357 const char *buf
= FormatAndSendCommand(
358 /*is_data*/ true, info
->module
, info
->module_offset
, info
->module_arch
);
360 ParseSymbolizeDataOutput(buf
, info
);
361 info
->start
+= (addr
- info
->module_offset
); // Add the base address.
367 const char *LLVMSymbolizer::FormatAndSendCommand(bool is_data
,
368 const char *module_name
,
372 const char *is_data_str
= is_data
? "DATA " : "";
373 if (arch
== kModuleArchUnknown
) {
374 if (internal_snprintf(buffer_
, kBufferSize
, "%s\"%s\" 0x%zx\n", is_data_str
,
376 module_offset
) >= static_cast<int>(kBufferSize
)) {
377 Report("WARNING: Command buffer too small");
381 if (internal_snprintf(buffer_
, kBufferSize
, "%s\"%s:%s\" 0x%zx\n",
382 is_data_str
, module_name
, ModuleArchToString(arch
),
383 module_offset
) >= static_cast<int>(kBufferSize
)) {
384 Report("WARNING: Command buffer too small");
388 return symbolizer_process_
->SendCommand(buffer_
);
391 SymbolizerProcess::SymbolizerProcess(const char *path
, bool use_forkpty
)
393 input_fd_(kInvalidFd
),
394 output_fd_(kInvalidFd
),
396 failed_to_start_(false),
397 reported_invalid_path_(false),
398 use_forkpty_(use_forkpty
) {
400 CHECK_NE(path_
[0], '\0');
403 static bool IsSameModule(const char* path
) {
404 if (const char* ProcessName
= GetProcessName()) {
405 if (const char* SymbolizerName
= StripModuleName(path
)) {
406 return !internal_strcmp(ProcessName
, SymbolizerName
);
412 const char *SymbolizerProcess::SendCommand(const char *command
) {
413 if (failed_to_start_
)
415 if (IsSameModule(path_
)) {
416 Report("WARNING: Symbolizer was blocked from starting itself!\n");
417 failed_to_start_
= true;
420 for (; times_restarted_
< kMaxTimesRestarted
; times_restarted_
++) {
421 // Start or restart symbolizer if we failed to send command to it.
422 if (const char *res
= SendCommandImpl(command
))
426 if (!failed_to_start_
) {
427 Report("WARNING: Failed to use and restart external symbolizer!\n");
428 failed_to_start_
= true;
433 const char *SymbolizerProcess::SendCommandImpl(const char *command
) {
434 if (input_fd_
== kInvalidFd
|| output_fd_
== kInvalidFd
)
436 if (!WriteToSymbolizer(command
, internal_strlen(command
)))
438 if (!ReadFromSymbolizer(buffer_
, kBufferSize
))
443 bool SymbolizerProcess::Restart() {
444 if (input_fd_
!= kInvalidFd
)
445 CloseFile(input_fd_
);
446 if (output_fd_
!= kInvalidFd
)
447 CloseFile(output_fd_
);
448 return StartSymbolizerSubprocess();
451 bool SymbolizerProcess::ReadFromSymbolizer(char *buffer
, uptr max_length
) {
457 bool success
= ReadFromFile(input_fd_
, buffer
+ read_len
,
458 max_length
- read_len
- 1, &just_read
);
459 // We can't read 0 bytes, as we don't expect external symbolizer to close
461 if (!success
|| just_read
== 0) {
462 Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_
);
465 read_len
+= just_read
;
466 if (ReachedEndOfOutput(buffer
, read_len
))
468 if (read_len
+ 1 == max_length
) {
469 Report("WARNING: Symbolizer buffer too small\n");
474 buffer
[read_len
] = '\0';
478 bool SymbolizerProcess::WriteToSymbolizer(const char *buffer
, uptr length
) {
482 bool success
= WriteToFile(output_fd_
, buffer
, length
, &write_len
);
483 if (!success
|| write_len
!= length
) {
484 Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_
);
490 #endif // !SANITIZER_SYMBOLIZER_MARKUP
492 } // namespace __sanitizer