1 //===-- sanitizer_symbolizer_libcdep.cpp ----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_allocator_internal.h"
14 #include "sanitizer_internal_defs.h"
15 #include "sanitizer_platform.h"
16 #include "sanitizer_symbolizer_internal.h"
18 namespace __sanitizer
{
20 Symbolizer
*Symbolizer::GetOrInit() {
21 SpinMutexLock
l(&init_mu_
);
24 symbolizer_
= PlatformInit();
29 // See sanitizer_symbolizer_markup.cpp.
30 #if !SANITIZER_SYMBOLIZER_MARKUP
32 const char *ExtractToken(const char *str
, const char *delims
, char **result
) {
33 uptr prefix_len
= internal_strcspn(str
, delims
);
34 *result
= (char*)InternalAlloc(prefix_len
+ 1);
35 internal_memcpy(*result
, str
, prefix_len
);
36 (*result
)[prefix_len
] = '\0';
37 const char *prefix_end
= str
+ prefix_len
;
38 if (*prefix_end
!= '\0') prefix_end
++;
42 const char *ExtractInt(const char *str
, const char *delims
, int *result
) {
44 const char *ret
= ExtractToken(str
, delims
, &buff
);
46 *result
= (int)internal_atoll(buff
);
52 const char *ExtractUptr(const char *str
, const char *delims
, uptr
*result
) {
54 const char *ret
= ExtractToken(str
, delims
, &buff
);
56 *result
= (uptr
)internal_atoll(buff
);
62 const char *ExtractSptr(const char *str
, const char *delims
, sptr
*result
) {
64 const char *ret
= ExtractToken(str
, delims
, &buff
);
66 *result
= (sptr
)internal_atoll(buff
);
72 const char *ExtractTokenUpToDelimiter(const char *str
, const char *delimiter
,
74 const char *found_delimiter
= internal_strstr(str
, delimiter
);
76 found_delimiter
? found_delimiter
- str
: internal_strlen(str
);
77 *result
= (char *)InternalAlloc(prefix_len
+ 1);
78 internal_memcpy(*result
, str
, prefix_len
);
79 (*result
)[prefix_len
] = '\0';
80 const char *prefix_end
= str
+ prefix_len
;
81 if (*prefix_end
!= '\0') prefix_end
+= internal_strlen(delimiter
);
85 SymbolizedStack
*Symbolizer::SymbolizePC(uptr addr
) {
86 BlockingMutexLock
l(&mu_
);
87 const char *module_name
= nullptr;
90 SymbolizedStack
*res
= SymbolizedStack::New(addr
);
91 if (!FindModuleNameAndOffsetForAddress(addr
, &module_name
, &module_offset
,
94 // Always fill data about module name and offset.
95 res
->info
.FillModuleInfo(module_name
, module_offset
, arch
);
96 for (auto &tool
: tools_
) {
97 SymbolizerScope
sym_scope(this);
98 if (tool
.SymbolizePC(addr
, res
)) {
105 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
106 BlockingMutexLock
l(&mu_
);
107 const char *module_name
= nullptr;
110 if (!FindModuleNameAndOffsetForAddress(addr
, &module_name
, &module_offset
,
114 info
->module
= internal_strdup(module_name
);
115 info
->module_offset
= module_offset
;
116 info
->module_arch
= arch
;
117 for (auto &tool
: tools_
) {
118 SymbolizerScope
sym_scope(this);
119 if (tool
.SymbolizeData(addr
, info
)) {
126 bool Symbolizer::SymbolizeFrame(uptr addr
, FrameInfo
*info
) {
127 BlockingMutexLock
l(&mu_
);
128 const char *module_name
= nullptr;
129 if (!FindModuleNameAndOffsetForAddress(
130 addr
, &module_name
, &info
->module_offset
, &info
->module_arch
))
132 info
->module
= internal_strdup(module_name
);
133 for (auto &tool
: tools_
) {
134 SymbolizerScope
sym_scope(this);
135 if (tool
.SymbolizeFrame(addr
, info
)) {
142 bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc
, const char **module_name
,
143 uptr
*module_address
) {
144 BlockingMutexLock
l(&mu_
);
145 const char *internal_module_name
= nullptr;
147 if (!FindModuleNameAndOffsetForAddress(pc
, &internal_module_name
,
148 module_address
, &arch
))
152 *module_name
= module_names_
.GetOwnedCopy(internal_module_name
);
156 void Symbolizer::Flush() {
157 BlockingMutexLock
l(&mu_
);
158 for (auto &tool
: tools_
) {
159 SymbolizerScope
sym_scope(this);
164 const char *Symbolizer::Demangle(const char *name
) {
165 BlockingMutexLock
l(&mu_
);
166 for (auto &tool
: tools_
) {
167 SymbolizerScope
sym_scope(this);
168 if (const char *demangled
= tool
.Demangle(name
))
171 return PlatformDemangle(name
);
174 bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address
,
175 const char **module_name
,
177 ModuleArch
*module_arch
) {
178 const LoadedModule
*module
= FindModuleForAddress(address
);
181 *module_name
= module
->full_name();
182 *module_offset
= address
- module
->base_address();
183 *module_arch
= module
->arch();
187 void Symbolizer::RefreshModules() {
189 fallback_modules_
.fallbackInit();
190 RAW_CHECK(modules_
.size() > 0);
191 modules_fresh_
= true;
194 static const LoadedModule
*SearchForModule(const ListOfModules
&modules
,
196 for (uptr i
= 0; i
< modules
.size(); i
++) {
197 if (modules
[i
].containsAddress(address
)) {
204 const LoadedModule
*Symbolizer::FindModuleForAddress(uptr address
) {
205 bool modules_were_reloaded
= false;
206 if (!modules_fresh_
) {
208 modules_were_reloaded
= true;
210 const LoadedModule
*module
= SearchForModule(modules_
, address
);
211 if (module
) return module
;
213 // dlopen/dlclose interceptors invalidate the module list, but when
214 // interception is disabled, we need to retry if the lookup fails in
215 // case the module list changed.
216 #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
217 if (!modules_were_reloaded
) {
219 module
= SearchForModule(modules_
, address
);
220 if (module
) return module
;
224 if (fallback_modules_
.size()) {
225 module
= SearchForModule(fallback_modules_
, address
);
230 // For now we assume the following protocol:
231 // For each request of the form
232 // <module_name> <module_offset>
233 // passed to STDIN, external symbolizer prints to STDOUT response:
235 // <file_name>:<line_number>:<column_number>
237 // <file_name>:<line_number>:<column_number>
240 class LLVMSymbolizerProcess final
: public SymbolizerProcess
{
242 explicit LLVMSymbolizerProcess(const char *path
)
243 : SymbolizerProcess(path
, /*use_posix_spawn=*/SANITIZER_MAC
) {}
246 bool ReachedEndOfOutput(const char *buffer
, uptr length
) const override
{
247 // Empty line marks the end of llvm-symbolizer output.
248 return length
>= 2 && buffer
[length
- 1] == '\n' &&
249 buffer
[length
- 2] == '\n';
252 // When adding a new architecture, don't forget to also update
253 // script/asan_symbolize.py and sanitizer_common.h.
254 void GetArgV(const char *path_to_binary
,
255 const char *(&argv
)[kArgVMax
]) const override
{
256 #if defined(__x86_64h__)
257 const char* const kSymbolizerArch
= "--default-arch=x86_64h";
258 #elif defined(__x86_64__)
259 const char* const kSymbolizerArch
= "--default-arch=x86_64";
260 #elif defined(__i386__)
261 const char* const kSymbolizerArch
= "--default-arch=i386";
262 #elif SANITIZER_RISCV64
263 const char *const kSymbolizerArch
= "--default-arch=riscv64";
264 #elif defined(__aarch64__)
265 const char* const kSymbolizerArch
= "--default-arch=arm64";
266 #elif defined(__arm__)
267 const char* const kSymbolizerArch
= "--default-arch=arm";
268 #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
269 const char* const kSymbolizerArch
= "--default-arch=powerpc64";
270 #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
271 const char* const kSymbolizerArch
= "--default-arch=powerpc64le";
272 #elif defined(__s390x__)
273 const char* const kSymbolizerArch
= "--default-arch=s390x";
274 #elif defined(__s390__)
275 const char* const kSymbolizerArch
= "--default-arch=s390";
277 const char* const kSymbolizerArch
= "--default-arch=unknown";
280 const char *const inline_flag
= common_flags()->symbolize_inline_frames
284 argv
[i
++] = path_to_binary
;
285 argv
[i
++] = inline_flag
;
286 argv
[i
++] = kSymbolizerArch
;
291 LLVMSymbolizer::LLVMSymbolizer(const char *path
, LowLevelAllocator
*allocator
)
292 : symbolizer_process_(new(*allocator
) LLVMSymbolizerProcess(path
)) {}
294 // Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on
295 // Windows, so extract tokens from the right hand side first. The column info is
297 static const char *ParseFileLineInfo(AddressInfo
*info
, const char *str
) {
298 char *file_line_info
= nullptr;
299 str
= ExtractToken(str
, "\n", &file_line_info
);
300 CHECK(file_line_info
);
302 if (uptr size
= internal_strlen(file_line_info
)) {
303 char *back
= file_line_info
+ size
- 1;
304 for (int i
= 0; i
< 2; ++i
) {
305 while (back
> file_line_info
&& IsDigit(*back
)) --back
;
306 if (*back
!= ':' || !IsDigit(back
[1])) break;
307 info
->column
= info
->line
;
308 info
->line
= internal_atoll(back
+ 1);
309 // Truncate the string at the colon to keep only filename.
313 ExtractToken(file_line_info
, "", &info
->file
);
316 InternalFree(file_line_info
);
320 // Parses one or more two-line strings in the following format:
322 // <file_name>:<line_number>[:<column_number>]
323 // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
324 // them use the same output format.
325 void ParseSymbolizePCOutput(const char *str
, SymbolizedStack
*res
) {
326 bool top_frame
= true;
327 SymbolizedStack
*last
= res
;
329 char *function_name
= nullptr;
330 str
= ExtractToken(str
, "\n", &function_name
);
331 CHECK(function_name
);
332 if (function_name
[0] == '\0') {
333 // There are no more frames.
334 InternalFree(function_name
);
337 SymbolizedStack
*cur
;
342 cur
= SymbolizedStack::New(res
->info
.address
);
343 cur
->info
.FillModuleInfo(res
->info
.module
, res
->info
.module_offset
,
344 res
->info
.module_arch
);
349 AddressInfo
*info
= &cur
->info
;
350 info
->function
= function_name
;
351 str
= ParseFileLineInfo(info
, str
);
353 // Functions and filenames can be "??", in which case we write 0
354 // to address info to mark that names are unknown.
355 if (0 == internal_strcmp(info
->function
, "??")) {
356 InternalFree(info
->function
);
359 if (0 == internal_strcmp(info
->file
, "??")) {
360 InternalFree(info
->file
);
366 // Parses a two-line string in the following format:
368 // <start_address> <size>
369 // Used by LLVMSymbolizer and InternalSymbolizer.
370 void ParseSymbolizeDataOutput(const char *str
, DataInfo
*info
) {
371 str
= ExtractToken(str
, "\n", &info
->name
);
372 str
= ExtractUptr(str
, " ", &info
->start
);
373 str
= ExtractUptr(str
, "\n", &info
->size
);
376 static void ParseSymbolizeFrameOutput(const char *str
,
377 InternalMmapVector
<LocalInfo
> *locals
) {
378 if (internal_strncmp(str
, "??", 2) == 0)
383 str
= ExtractToken(str
, "\n", &local
.function_name
);
384 str
= ExtractToken(str
, "\n", &local
.name
);
387 str
= ParseFileLineInfo(&addr
, str
);
388 local
.decl_file
= addr
.file
;
389 local
.decl_line
= addr
.line
;
391 local
.has_frame_offset
= internal_strncmp(str
, "??", 2) != 0;
392 str
= ExtractSptr(str
, " ", &local
.frame_offset
);
394 local
.has_size
= internal_strncmp(str
, "??", 2) != 0;
395 str
= ExtractUptr(str
, " ", &local
.size
);
397 local
.has_tag_offset
= internal_strncmp(str
, "??", 2) != 0;
398 str
= ExtractUptr(str
, "\n", &local
.tag_offset
);
400 locals
->push_back(local
);
404 bool LLVMSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
405 AddressInfo
*info
= &stack
->info
;
406 const char *buf
= FormatAndSendCommand(
407 "CODE", info
->module
, info
->module_offset
, info
->module_arch
);
410 ParseSymbolizePCOutput(buf
, stack
);
414 bool LLVMSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
415 const char *buf
= FormatAndSendCommand(
416 "DATA", info
->module
, info
->module_offset
, info
->module_arch
);
419 ParseSymbolizeDataOutput(buf
, info
);
420 info
->start
+= (addr
- info
->module_offset
); // Add the base address.
424 bool LLVMSymbolizer::SymbolizeFrame(uptr addr
, FrameInfo
*info
) {
425 const char *buf
= FormatAndSendCommand(
426 "FRAME", info
->module
, info
->module_offset
, info
->module_arch
);
429 ParseSymbolizeFrameOutput(buf
, &info
->locals
);
433 const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix
,
434 const char *module_name
,
439 if (arch
== kModuleArchUnknown
)
440 size_needed
= internal_snprintf(buffer_
, kBufferSize
, "%s \"%s\" 0x%zx\n",
441 command_prefix
, module_name
, module_offset
);
443 size_needed
= internal_snprintf(buffer_
, kBufferSize
,
444 "%s \"%s:%s\" 0x%zx\n", command_prefix
,
445 module_name
, ModuleArchToString(arch
),
448 if (size_needed
>= static_cast<int>(kBufferSize
)) {
449 Report("WARNING: Command buffer too small");
453 return symbolizer_process_
->SendCommand(buffer_
);
456 SymbolizerProcess::SymbolizerProcess(const char *path
, bool use_posix_spawn
)
458 input_fd_(kInvalidFd
),
459 output_fd_(kInvalidFd
),
461 failed_to_start_(false),
462 reported_invalid_path_(false),
463 use_posix_spawn_(use_posix_spawn
) {
465 CHECK_NE(path_
[0], '\0');
468 static bool IsSameModule(const char* path
) {
469 if (const char* ProcessName
= GetProcessName()) {
470 if (const char* SymbolizerName
= StripModuleName(path
)) {
471 return !internal_strcmp(ProcessName
, SymbolizerName
);
477 const char *SymbolizerProcess::SendCommand(const char *command
) {
478 if (failed_to_start_
)
480 if (IsSameModule(path_
)) {
481 Report("WARNING: Symbolizer was blocked from starting itself!\n");
482 failed_to_start_
= true;
485 for (; times_restarted_
< kMaxTimesRestarted
; times_restarted_
++) {
486 // Start or restart symbolizer if we failed to send command to it.
487 if (const char *res
= SendCommandImpl(command
))
491 if (!failed_to_start_
) {
492 Report("WARNING: Failed to use and restart external symbolizer!\n");
493 failed_to_start_
= true;
498 const char *SymbolizerProcess::SendCommandImpl(const char *command
) {
499 if (input_fd_
== kInvalidFd
|| output_fd_
== kInvalidFd
)
501 if (!WriteToSymbolizer(command
, internal_strlen(command
)))
503 if (!ReadFromSymbolizer(buffer_
, kBufferSize
))
508 bool SymbolizerProcess::Restart() {
509 if (input_fd_
!= kInvalidFd
)
510 CloseFile(input_fd_
);
511 if (output_fd_
!= kInvalidFd
)
512 CloseFile(output_fd_
);
513 return StartSymbolizerSubprocess();
516 bool SymbolizerProcess::ReadFromSymbolizer(char *buffer
, uptr max_length
) {
522 bool success
= ReadFromFile(input_fd_
, buffer
+ read_len
,
523 max_length
- read_len
- 1, &just_read
);
524 // We can't read 0 bytes, as we don't expect external symbolizer to close
526 if (!success
|| just_read
== 0) {
527 Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_
);
530 read_len
+= just_read
;
531 if (ReachedEndOfOutput(buffer
, read_len
))
533 if (read_len
+ 1 == max_length
) {
534 Report("WARNING: Symbolizer buffer too small\n");
539 buffer
[read_len
] = '\0';
543 bool SymbolizerProcess::WriteToSymbolizer(const char *buffer
, uptr length
) {
547 bool success
= WriteToFile(output_fd_
, buffer
, length
, &write_len
);
548 if (!success
|| write_len
!= length
) {
549 Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_
);
555 #endif // !SANITIZER_SYMBOLIZER_MARKUP
557 } // namespace __sanitizer