1 //===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is shared between AddressSanitizer and ThreadSanitizer 11 // run-time libraries. 12 // POSIX-specific implementation of symbolizer parts. 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_platform.h" 16 #if SANITIZER_POSIX 17 #include "sanitizer_allocator_internal.h" 18 #include "sanitizer_common.h" 19 #include "sanitizer_flags.h" 20 #include "sanitizer_internal_defs.h" 21 #include "sanitizer_linux.h" 22 #include "sanitizer_placement_new.h" 23 #include "sanitizer_procmaps.h" 24 #include "sanitizer_symbolizer.h" 25 #include "sanitizer_symbolizer_libbacktrace.h" 26 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <sys/wait.h> 30 #include <unistd.h> 31 32 // C++ demangling function, as required by Itanium C++ ABI. This is weak, 33 // because we do not require a C++ ABI library to be linked to a program 34 // using sanitizers; if it's not present, we'll just use the mangled name. 35 namespace __cxxabiv1 { 36 extern "C" SANITIZER_WEAK_ATTRIBUTE 37 char *__cxa_demangle(const char *mangled, char *buffer, 38 size_t *length, int *status); 39 } 40 41 namespace __sanitizer { 42 43 // Attempts to demangle the name via __cxa_demangle from __cxxabiv1. 44 static const char *DemangleCXXABI(const char *name) { 45 // FIXME: __cxa_demangle aggressively insists on allocating memory. 46 // There's not much we can do about that, short of providing our 47 // own demangler (libc++abi's implementation could be adapted so that 48 // it does not allocate). For now, we just call it anyway, and we leak 49 // the returned value. 50 if (__cxxabiv1::__cxa_demangle) 51 if (const char *demangled_name = 52 __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) 53 return demangled_name; 54 55 return name; 56 } 57 58 // Extracts the prefix of "str" that consists of any characters not 59 // present in "delims" string, and copies this prefix to "result", allocating 60 // space for it. 61 // Returns a pointer to "str" after skipping extracted prefix and first 62 // delimiter char. 63 static const char *ExtractToken(const char *str, const char *delims, 64 char **result) { 65 uptr prefix_len = internal_strcspn(str, delims); 66 *result = (char*)InternalAlloc(prefix_len + 1); 67 internal_memcpy(*result, str, prefix_len); 68 (*result)[prefix_len] = '\0'; 69 const char *prefix_end = str + prefix_len; 70 if (*prefix_end != '\0') prefix_end++; 71 return prefix_end; 72 } 73 74 // Same as ExtractToken, but converts extracted token to integer. 75 static const char *ExtractInt(const char *str, const char *delims, 76 int *result) { 77 char *buff; 78 const char *ret = ExtractToken(str, delims, &buff); 79 if (buff != 0) { 80 *result = (int)internal_atoll(buff); 81 } 82 InternalFree(buff); 83 return ret; 84 } 85 86 static const char *ExtractUptr(const char *str, const char *delims, 87 uptr *result) { 88 char *buff; 89 const char *ret = ExtractToken(str, delims, &buff); 90 if (buff != 0) { 91 *result = (uptr)internal_atoll(buff); 92 } 93 InternalFree(buff); 94 return ret; 95 } 96 97 class ExternalSymbolizerInterface { 98 public: 99 // Can't declare pure virtual functions in sanitizer runtimes: 100 // __cxa_pure_virtual might be unavailable. 101 virtual char *SendCommand(bool is_data, const char *module_name, 102 uptr module_offset) { 103 UNIMPLEMENTED(); 104 } 105 }; 106 107 // SymbolizerProcess encapsulates communication between the tool and 108 // external symbolizer program, running in a different subprocess. 109 // SymbolizerProcess may not be used from two threads simultaneously. 110 class SymbolizerProcess : public ExternalSymbolizerInterface { 111 public: 112 explicit SymbolizerProcess(const char *path) 113 : path_(path), 114 input_fd_(kInvalidFd), 115 output_fd_(kInvalidFd), 116 times_restarted_(0), 117 failed_to_start_(false), 118 reported_invalid_path_(false) { 119 CHECK(path_); 120 CHECK_NE(path_[0], '\0'); 121 } 122 123 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { 124 for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { 125 // Start or restart symbolizer if we failed to send command to it. 126 if (char *res = SendCommandImpl(is_data, module_name, module_offset)) 127 return res; 128 Restart(); 129 } 130 if (!failed_to_start_) { 131 Report("WARNING: Failed to use and restart external symbolizer!\n"); 132 failed_to_start_ = true; 133 } 134 return 0; 135 } 136 137 private: 138 bool Restart() { 139 if (input_fd_ != kInvalidFd) 140 internal_close(input_fd_); 141 if (output_fd_ != kInvalidFd) 142 internal_close(output_fd_); 143 return StartSymbolizerSubprocess(); 144 } 145 146 char *SendCommandImpl(bool is_data, const char *module_name, 147 uptr module_offset) { 148 if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) 149 return 0; 150 CHECK(module_name); 151 if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name, 152 module_offset)) 153 return 0; 154 if (!writeToSymbolizer(buffer_, internal_strlen(buffer_))) 155 return 0; 156 if (!readFromSymbolizer(buffer_, kBufferSize)) 157 return 0; 158 return buffer_; 159 } 160 161 bool readFromSymbolizer(char *buffer, uptr max_length) { 162 if (max_length == 0) 163 return true; 164 uptr read_len = 0; 165 while (true) { 166 uptr just_read = internal_read(input_fd_, buffer + read_len, 167 max_length - read_len - 1); 168 // We can't read 0 bytes, as we don't expect external symbolizer to close 169 // its stdout. 170 if (just_read == 0 || just_read == (uptr)-1) { 171 Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); 172 return false; 173 } 174 read_len += just_read; 175 if (ReachedEndOfOutput(buffer, read_len)) 176 break; 177 } 178 buffer[read_len] = '\0'; 179 return true; 180 } 181 182 bool writeToSymbolizer(const char *buffer, uptr length) { 183 if (length == 0) 184 return true; 185 uptr write_len = internal_write(output_fd_, buffer, length); 186 if (write_len == 0 || write_len == (uptr)-1) { 187 Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); 188 return false; 189 } 190 return true; 191 } 192 193 bool StartSymbolizerSubprocess() { 194 if (!FileExists(path_)) { 195 if (!reported_invalid_path_) { 196 Report("WARNING: invalid path to external symbolizer!\n"); 197 reported_invalid_path_ = true; 198 } 199 return false; 200 } 201 202 int *infd = NULL; 203 int *outfd = NULL; 204 // The client program may close its stdin and/or stdout and/or stderr 205 // thus allowing socketpair to reuse file descriptors 0, 1 or 2. 206 // In this case the communication between the forked processes may be 207 // broken if either the parent or the child tries to close or duplicate 208 // these descriptors. The loop below produces two pairs of file 209 // descriptors, each greater than 2 (stderr). 210 int sock_pair[5][2]; 211 for (int i = 0; i < 5; i++) { 212 if (pipe(sock_pair[i]) == -1) { 213 for (int j = 0; j < i; j++) { 214 internal_close(sock_pair[j][0]); 215 internal_close(sock_pair[j][1]); 216 } 217 Report("WARNING: Can't create a socket pair to start " 218 "external symbolizer (errno: %d)\n", errno); 219 return false; 220 } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { 221 if (infd == NULL) { 222 infd = sock_pair[i]; 223 } else { 224 outfd = sock_pair[i]; 225 for (int j = 0; j < i; j++) { 226 if (sock_pair[j] == infd) continue; 227 internal_close(sock_pair[j][0]); 228 internal_close(sock_pair[j][1]); 229 } 230 break; 231 } 232 } 233 } 234 CHECK(infd); 235 CHECK(outfd); 236 237 // Real fork() may call user callbacks registered with pthread_atfork(). 238 int pid = internal_fork(); 239 if (pid == -1) { 240 // Fork() failed. 241 internal_close(infd[0]); 242 internal_close(infd[1]); 243 internal_close(outfd[0]); 244 internal_close(outfd[1]); 245 Report("WARNING: failed to fork external symbolizer " 246 " (errno: %d)\n", errno); 247 return false; 248 } else if (pid == 0) { 249 // Child subprocess. 250 internal_close(STDOUT_FILENO); 251 internal_close(STDIN_FILENO); 252 internal_dup2(outfd[0], STDIN_FILENO); 253 internal_dup2(infd[1], STDOUT_FILENO); 254 internal_close(outfd[0]); 255 internal_close(outfd[1]); 256 internal_close(infd[0]); 257 internal_close(infd[1]); 258 for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) 259 internal_close(fd); 260 ExecuteWithDefaultArgs(path_); 261 internal__exit(1); 262 } 263 264 // Continue execution in parent process. 265 internal_close(outfd[0]); 266 internal_close(infd[1]); 267 input_fd_ = infd[0]; 268 output_fd_ = outfd[1]; 269 270 // Check that symbolizer subprocess started successfully. 271 int pid_status; 272 SleepForMillis(kSymbolizerStartupTimeMillis); 273 int exited_pid = waitpid(pid, &pid_status, WNOHANG); 274 if (exited_pid != 0) { 275 // Either waitpid failed, or child has already exited. 276 Report("WARNING: external symbolizer didn't start up correctly!\n"); 277 return false; 278 } 279 280 return true; 281 } 282 283 virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, 284 const char *module_name, 285 uptr module_offset) const { 286 UNIMPLEMENTED(); 287 } 288 289 virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { 290 UNIMPLEMENTED(); 291 } 292 293 virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const { 294 UNIMPLEMENTED(); 295 } 296 297 const char *path_; 298 int input_fd_; 299 int output_fd_; 300 301 static const uptr kBufferSize = 16 * 1024; 302 char buffer_[kBufferSize]; 303 304 static const uptr kMaxTimesRestarted = 5; 305 static const int kSymbolizerStartupTimeMillis = 10; 306 uptr times_restarted_; 307 bool failed_to_start_; 308 bool reported_invalid_path_; 309 }; 310 311 // For now we assume the following protocol: 312 // For each request of the form 313 // <module_name> <module_offset> 314 // passed to STDIN, external symbolizer prints to STDOUT response: 315 // <function_name> 316 // <file_name>:<line_number>:<column_number> 317 // <function_name> 318 // <file_name>:<line_number>:<column_number> 319 // ... 320 // <empty line> 321 class LLVMSymbolizerProcess : public SymbolizerProcess { 322 public: 323 explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} 324 325 private: 326 bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, 327 const char *module_name, uptr module_offset) const { 328 internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n", 329 is_data ? "DATA " : "", module_name, module_offset); 330 return true; 331 } 332 333 bool ReachedEndOfOutput(const char *buffer, uptr length) const { 334 // Empty line marks the end of llvm-symbolizer output. 335 return length >= 2 && buffer[length - 1] == '\n' && 336 buffer[length - 2] == '\n'; 337 } 338 339 void ExecuteWithDefaultArgs(const char *path_to_binary) const { 340 #if defined(__x86_64__) 341 const char* const kSymbolizerArch = "--default-arch=x86_64"; 342 #elif defined(__i386__) 343 const char* const kSymbolizerArch = "--default-arch=i386"; 344 #elif defined(__powerpc64__) 345 const char* const kSymbolizerArch = "--default-arch=powerpc64"; 346 #else 347 const char* const kSymbolizerArch = "--default-arch=unknown"; 348 #endif 349 execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0); 350 } 351 }; 352 353 class Addr2LineProcess : public SymbolizerProcess { 354 public: 355 Addr2LineProcess(const char *path, const char *module_name) 356 : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} 357 358 const char *module_name() const { return module_name_; } 359 360 private: 361 bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, 362 const char *module_name, uptr module_offset) const { 363 if (is_data) 364 return false; 365 CHECK_EQ(0, internal_strcmp(module_name, module_name_)); 366 internal_snprintf(buffer, max_length, "0x%zx\n", module_offset); 367 return true; 368 } 369 370 bool ReachedEndOfOutput(const char *buffer, uptr length) const { 371 // Output should consist of two lines. 372 int num_lines = 0; 373 for (uptr i = 0; i < length; ++i) { 374 if (buffer[i] == '\n') 375 num_lines++; 376 if (num_lines >= 2) 377 return true; 378 } 379 return false; 380 } 381 382 void ExecuteWithDefaultArgs(const char *path_to_binary) const { 383 execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0); 384 } 385 386 const char *module_name_; // Owned, leaked. 387 }; 388 389 class Addr2LinePool : public ExternalSymbolizerInterface { 390 public: 391 explicit Addr2LinePool(const char *addr2line_path, 392 LowLevelAllocator *allocator) 393 : addr2line_path_(addr2line_path), allocator_(allocator), 394 addr2line_pool_(16) {} 395 396 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { 397 if (is_data) 398 return 0; 399 Addr2LineProcess *addr2line = 0; 400 for (uptr i = 0; i < addr2line_pool_.size(); ++i) { 401 if (0 == 402 internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { 403 addr2line = addr2line_pool_[i]; 404 break; 405 } 406 } 407 if (!addr2line) { 408 addr2line = 409 new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); 410 addr2line_pool_.push_back(addr2line); 411 } 412 return addr2line->SendCommand(is_data, module_name, module_offset); 413 } 414 415 private: 416 const char *addr2line_path_; 417 LowLevelAllocator *allocator_; 418 InternalMmapVector<Addr2LineProcess*> addr2line_pool_; 419 }; 420 421 #if SANITIZER_SUPPORTS_WEAK_HOOKS 422 extern "C" { 423 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 424 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, 425 char *Buffer, int MaxLength); 426 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 427 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, 428 char *Buffer, int MaxLength); 429 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 430 void __sanitizer_symbolize_flush(); 431 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 432 int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, 433 int MaxLength); 434 } // extern "C" 435 436 class InternalSymbolizer { 437 public: 438 typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int); 439 440 static InternalSymbolizer *get(LowLevelAllocator *alloc) { 441 if (__sanitizer_symbolize_code != 0 && 442 __sanitizer_symbolize_data != 0) { 443 return new(*alloc) InternalSymbolizer(); 444 } 445 return 0; 446 } 447 448 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { 449 SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data 450 : __sanitizer_symbolize_code; 451 if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize)) 452 return buffer_; 453 return 0; 454 } 455 456 void Flush() { 457 if (__sanitizer_symbolize_flush) 458 __sanitizer_symbolize_flush(); 459 } 460 461 const char *Demangle(const char *name) { 462 if (__sanitizer_symbolize_demangle) { 463 for (uptr res_length = 1024; 464 res_length <= InternalSizeClassMap::kMaxSize;) { 465 char *res_buff = static_cast<char*>(InternalAlloc(res_length)); 466 uptr req_length = 467 __sanitizer_symbolize_demangle(name, res_buff, res_length); 468 if (req_length > res_length) { 469 res_length = req_length + 1; 470 InternalFree(res_buff); 471 continue; 472 } 473 return res_buff; 474 } 475 } 476 return name; 477 } 478 479 private: 480 InternalSymbolizer() { } 481 482 static const int kBufferSize = 16 * 1024; 483 static const int kMaxDemangledNameSize = 1024; 484 char buffer_[kBufferSize]; 485 }; 486 #else // SANITIZER_SUPPORTS_WEAK_HOOKS 487 488 class InternalSymbolizer { 489 public: 490 static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } 491 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { 492 return 0; 493 } 494 void Flush() { } 495 const char *Demangle(const char *name) { return name; } 496 }; 497 498 #endif // SANITIZER_SUPPORTS_WEAK_HOOKS 499 500 class POSIXSymbolizer : public Symbolizer { 501 public: 502 POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer, 503 InternalSymbolizer *internal_symbolizer, 504 LibbacktraceSymbolizer *libbacktrace_symbolizer) 505 : Symbolizer(), 506 external_symbolizer_(external_symbolizer), 507 internal_symbolizer_(internal_symbolizer), 508 libbacktrace_symbolizer_(libbacktrace_symbolizer) {} 509 510 uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) { 511 BlockingMutexLock l(&mu_); 512 if (max_frames == 0) 513 return 0; 514 const char *module_name; 515 uptr module_offset; 516 if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) 517 return 0; 518 // First, try to use libbacktrace symbolizer (if it's available). 519 if (libbacktrace_symbolizer_ != 0) { 520 mu_.CheckLocked(); 521 uptr res = libbacktrace_symbolizer_->SymbolizeCode( 522 addr, frames, max_frames, module_name, module_offset); 523 if (res > 0) 524 return res; 525 } 526 const char *str = SendCommand(false, module_name, module_offset); 527 if (str == 0) { 528 // Symbolizer was not initialized or failed. Fill only data 529 // about module name and offset. 530 AddressInfo *info = &frames[0]; 531 info->Clear(); 532 info->FillAddressAndModuleInfo(addr, module_name, module_offset); 533 return 1; 534 } 535 uptr frame_id = 0; 536 for (frame_id = 0; frame_id < max_frames; frame_id++) { 537 AddressInfo *info = &frames[frame_id]; 538 char *function_name = 0; 539 str = ExtractToken(str, "\n", &function_name); 540 CHECK(function_name); 541 if (function_name[0] == '\0') { 542 // There are no more frames. 543 break; 544 } 545 info->Clear(); 546 info->FillAddressAndModuleInfo(addr, module_name, module_offset); 547 info->function = function_name; 548 // Parse <file>:<line>:<column> buffer. 549 char *file_line_info = 0; 550 str = ExtractToken(str, "\n", &file_line_info); 551 CHECK(file_line_info); 552 const char *line_info = ExtractToken(file_line_info, ":", &info->file); 553 line_info = ExtractInt(line_info, ":", &info->line); 554 line_info = ExtractInt(line_info, "", &info->column); 555 InternalFree(file_line_info); 556 557 // Functions and filenames can be "??", in which case we write 0 558 // to address info to mark that names are unknown. 559 if (0 == internal_strcmp(info->function, "??")) { 560 InternalFree(info->function); 561 info->function = 0; 562 } 563 if (0 == internal_strcmp(info->file, "??")) { 564 InternalFree(info->file); 565 info->file = 0; 566 } 567 } 568 if (frame_id == 0) { 569 // Make sure we return at least one frame. 570 AddressInfo *info = &frames[0]; 571 info->Clear(); 572 info->FillAddressAndModuleInfo(addr, module_name, module_offset); 573 frame_id = 1; 574 } 575 return frame_id; 576 } 577 578 bool SymbolizeData(uptr addr, DataInfo *info) { 579 BlockingMutexLock l(&mu_); 580 LoadedModule *module = FindModuleForAddress(addr); 581 if (module == 0) 582 return false; 583 const char *module_name = module->full_name(); 584 uptr module_offset = addr - module->base_address(); 585 internal_memset(info, 0, sizeof(*info)); 586 info->address = addr; 587 info->module = internal_strdup(module_name); 588 info->module_offset = module_offset; 589 // First, try to use libbacktrace symbolizer (if it's available). 590 if (libbacktrace_symbolizer_ != 0) { 591 mu_.CheckLocked(); 592 if (libbacktrace_symbolizer_->SymbolizeData(info)) 593 return true; 594 } 595 const char *str = SendCommand(true, module_name, module_offset); 596 if (str == 0) 597 return true; 598 str = ExtractToken(str, "\n", &info->name); 599 str = ExtractUptr(str, " ", &info->start); 600 str = ExtractUptr(str, "\n", &info->size); 601 info->start += module->base_address(); 602 return true; 603 } 604 605 bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, 606 uptr *module_address) { 607 BlockingMutexLock l(&mu_); 608 return FindModuleNameAndOffsetForAddress(pc, module_name, module_address); 609 } 610 611 bool CanReturnFileLineInfo() { 612 return internal_symbolizer_ != 0 || external_symbolizer_ != 0 || 613 libbacktrace_symbolizer_ != 0; 614 } 615 616 void Flush() { 617 BlockingMutexLock l(&mu_); 618 if (internal_symbolizer_ != 0) { 619 SymbolizerScope sym_scope(this); 620 internal_symbolizer_->Flush(); 621 } 622 } 623 624 const char *Demangle(const char *name) { 625 BlockingMutexLock l(&mu_); 626 // Run hooks even if we don't use internal symbolizer, as cxxabi 627 // demangle may call system functions. 628 SymbolizerScope sym_scope(this); 629 // Try to use libbacktrace demangler (if available). 630 if (libbacktrace_symbolizer_ != 0) { 631 if (const char *demangled = libbacktrace_symbolizer_->Demangle(name)) 632 return demangled; 633 } 634 if (internal_symbolizer_ != 0) 635 return internal_symbolizer_->Demangle(name); 636 return DemangleCXXABI(name); 637 } 638 639 void PrepareForSandboxing() { 640 #if SANITIZER_LINUX && !SANITIZER_ANDROID 641 BlockingMutexLock l(&mu_); 642 // Cache /proc/self/exe on Linux. 643 CacheBinaryName(); 644 #endif 645 } 646 647 private: 648 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { 649 mu_.CheckLocked(); 650 // First, try to use internal symbolizer. 651 if (internal_symbolizer_) { 652 SymbolizerScope sym_scope(this); 653 return internal_symbolizer_->SendCommand(is_data, module_name, 654 module_offset); 655 } 656 // Otherwise, fall back to external symbolizer. 657 if (external_symbolizer_) { 658 SymbolizerScope sym_scope(this); 659 return external_symbolizer_->SendCommand(is_data, module_name, 660 module_offset); 661 } 662 return 0; 663 } 664 665 LoadedModule *FindModuleForAddress(uptr address) { 666 mu_.CheckLocked(); 667 bool modules_were_reloaded = false; 668 if (modules_ == 0 || !modules_fresh_) { 669 modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate( 670 kMaxNumberOfModuleContexts * sizeof(LoadedModule))); 671 CHECK(modules_); 672 n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts, 673 /* filter */ 0); 674 CHECK_GT(n_modules_, 0); 675 CHECK_LT(n_modules_, kMaxNumberOfModuleContexts); 676 modules_fresh_ = true; 677 modules_were_reloaded = true; 678 } 679 for (uptr i = 0; i < n_modules_; i++) { 680 if (modules_[i].containsAddress(address)) { 681 return &modules_[i]; 682 } 683 } 684 // Reload the modules and look up again, if we haven't tried it yet. 685 if (!modules_were_reloaded) { 686 // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors. 687 // It's too aggressive to reload the list of modules each time we fail 688 // to find a module for a given address. 689 modules_fresh_ = false; 690 return FindModuleForAddress(address); 691 } 692 return 0; 693 } 694 695 bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, 696 uptr *module_offset) { 697 mu_.CheckLocked(); 698 LoadedModule *module = FindModuleForAddress(address); 699 if (module == 0) 700 return false; 701 *module_name = module->full_name(); 702 *module_offset = address - module->base_address(); 703 return true; 704 } 705 706 // 16K loaded modules should be enough for everyone. 707 static const uptr kMaxNumberOfModuleContexts = 1 << 14; 708 LoadedModule *modules_; // Array of module descriptions is leaked. 709 uptr n_modules_; 710 // If stale, need to reload the modules before looking up addresses. 711 bool modules_fresh_; 712 BlockingMutex mu_; 713 714 ExternalSymbolizerInterface *external_symbolizer_; // Leaked. 715 InternalSymbolizer *const internal_symbolizer_; // Leaked. 716 LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. 717 }; 718 719 Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { 720 if (!common_flags()->symbolize) { 721 return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0); 722 } 723 InternalSymbolizer* internal_symbolizer = 724 InternalSymbolizer::get(&symbolizer_allocator_); 725 ExternalSymbolizerInterface *external_symbolizer = 0; 726 LibbacktraceSymbolizer *libbacktrace_symbolizer = 0; 727 728 if (!internal_symbolizer) { 729 libbacktrace_symbolizer = 730 LibbacktraceSymbolizer::get(&symbolizer_allocator_); 731 if (!libbacktrace_symbolizer) { 732 if (path_to_external && path_to_external[0] == '\0') { 733 // External symbolizer is explicitly disabled. Do nothing. 734 } else { 735 // Find path to llvm-symbolizer if it's not provided. 736 if (!path_to_external) 737 path_to_external = FindPathToBinary("llvm-symbolizer"); 738 if (path_to_external) { 739 external_symbolizer = new(symbolizer_allocator_) 740 LLVMSymbolizerProcess(path_to_external); 741 } else if (common_flags()->allow_addr2line) { 742 // If llvm-symbolizer is not found, try to use addr2line. 743 if (const char *addr2line_path = FindPathToBinary("addr2line")) { 744 external_symbolizer = new(symbolizer_allocator_) 745 Addr2LinePool(addr2line_path, &symbolizer_allocator_); 746 } 747 } 748 } 749 } 750 } 751 752 return new(symbolizer_allocator_) POSIXSymbolizer( 753 external_symbolizer, internal_symbolizer, libbacktrace_symbolizer); 754 } 755 756 } // namespace __sanitizer 757 758 #endif // SANITIZER_POSIX 759