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_file.h" 20 #include "sanitizer_flags.h" 21 #include "sanitizer_internal_defs.h" 22 #include "sanitizer_linux.h" 23 #include "sanitizer_placement_new.h" 24 #include "sanitizer_posix.h" 25 #include "sanitizer_procmaps.h" 26 #include "sanitizer_symbolizer_internal.h" 27 #include "sanitizer_symbolizer_libbacktrace.h" 28 #include "sanitizer_symbolizer_mac.h" 29 30 #include <dlfcn.h> // for dlsym() 31 #include <errno.h> 32 #include <stdint.h> 33 #include <stdlib.h> 34 #include <sys/wait.h> 35 #include <unistd.h> 36 37 #if SANITIZER_MAC 38 #include <util.h> // for forkpty() 39 #endif // SANITIZER_MAC 40 41 // C++ demangling function, as required by Itanium C++ ABI. This is weak, 42 // because we do not require a C++ ABI library to be linked to a program 43 // using sanitizers; if it's not present, we'll just use the mangled name. 44 namespace __cxxabiv1 { 45 extern "C" SANITIZER_WEAK_ATTRIBUTE 46 char *__cxa_demangle(const char *mangled, char *buffer, 47 size_t *length, int *status); 48 } 49 50 namespace __sanitizer { 51 52 // Attempts to demangle the name via __cxa_demangle from __cxxabiv1. 53 const char *DemangleCXXABI(const char *name) { 54 // FIXME: __cxa_demangle aggressively insists on allocating memory. 55 // There's not much we can do about that, short of providing our 56 // own demangler (libc++abi's implementation could be adapted so that 57 // it does not allocate). For now, we just call it anyway, and we leak 58 // the returned value. 59 if (&__cxxabiv1::__cxa_demangle) 60 if (const char *demangled_name = 61 __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) 62 return demangled_name; 63 64 return name; 65 } 66 67 // As of now, there are no headers for the Swift runtime. Once they are 68 // present, we will weakly link since we do not require Swift runtime to be 69 // linked. 70 typedef char *(*swift_demangle_ft)(const char *mangledName, 71 size_t mangledNameLength, char *outputBuffer, 72 size_t *outputBufferSize, uint32_t flags); 73 static swift_demangle_ft swift_demangle_f; 74 75 // This must not happen lazily at symbolication time, because dlsym uses 76 // malloc and thread-local storage, which is not a good thing to do during 77 // symbolication. 78 static void InitializeSwiftDemangler() { 79 swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle"); 80 (void)dlerror(); // Cleanup error message in case of failure 81 } 82 83 // Attempts to demangle a Swift name. The demangler will return nullptr if a 84 // non-Swift name is passed in. 85 const char *DemangleSwift(const char *name) { 86 if (!name) return nullptr; 87 88 // Check if we are dealing with a Swift mangled name first. 89 if (name[0] != '_' || name[1] != 'T') { 90 return nullptr; 91 } 92 93 if (swift_demangle_f) 94 return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); 95 96 return nullptr; 97 } 98 99 const char *DemangleSwiftAndCXX(const char *name) { 100 if (!name) return nullptr; 101 if (const char *swift_demangled_name = DemangleSwift(name)) 102 return swift_demangled_name; 103 return DemangleCXXABI(name); 104 } 105 106 static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) { 107 int *infd = NULL; 108 int *outfd = NULL; 109 // The client program may close its stdin and/or stdout and/or stderr 110 // thus allowing socketpair to reuse file descriptors 0, 1 or 2. 111 // In this case the communication between the forked processes may be 112 // broken if either the parent or the child tries to close or duplicate 113 // these descriptors. The loop below produces two pairs of file 114 // descriptors, each greater than 2 (stderr). 115 int sock_pair[5][2]; 116 for (int i = 0; i < 5; i++) { 117 if (pipe(sock_pair[i]) == -1) { 118 for (int j = 0; j < i; j++) { 119 internal_close(sock_pair[j][0]); 120 internal_close(sock_pair[j][1]); 121 } 122 return false; 123 } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { 124 if (infd == NULL) { 125 infd = sock_pair[i]; 126 } else { 127 outfd = sock_pair[i]; 128 for (int j = 0; j < i; j++) { 129 if (sock_pair[j] == infd) continue; 130 internal_close(sock_pair[j][0]); 131 internal_close(sock_pair[j][1]); 132 } 133 break; 134 } 135 } 136 } 137 CHECK(infd); 138 CHECK(outfd); 139 infd_[0] = infd[0]; 140 infd_[1] = infd[1]; 141 outfd_[0] = outfd[0]; 142 outfd_[1] = outfd[1]; 143 return true; 144 } 145 146 bool SymbolizerProcess::StartSymbolizerSubprocess() { 147 if (!FileExists(path_)) { 148 if (!reported_invalid_path_) { 149 Report("WARNING: invalid path to external symbolizer!\n"); 150 reported_invalid_path_ = true; 151 } 152 return false; 153 } 154 155 int pid = -1; 156 157 int infd[2]; 158 internal_memset(&infd, 0, sizeof(infd)); 159 int outfd[2]; 160 internal_memset(&outfd, 0, sizeof(outfd)); 161 if (!CreateTwoHighNumberedPipes(infd, outfd)) { 162 Report("WARNING: Can't create a socket pair to start " 163 "external symbolizer (errno: %d)\n", errno); 164 return false; 165 } 166 167 if (use_forkpty_) { 168 #if SANITIZER_MAC 169 fd_t fd = kInvalidFd; 170 171 // forkpty redirects stdout and stderr into a single stream, so we would 172 // receive error messages as standard replies. To avoid that, let's dup 173 // stderr and restore it in the child. 174 int saved_stderr = dup(STDERR_FILENO); 175 CHECK_GE(saved_stderr, 0); 176 177 // We only need one pipe, for stdin of the child. 178 close(outfd[0]); 179 close(outfd[1]); 180 181 // Use forkpty to disable buffering in the new terminal. 182 pid = internal_forkpty(&fd); 183 if (pid == -1) { 184 // forkpty() failed. 185 Report("WARNING: failed to fork external symbolizer (errno: %d)\n", 186 errno); 187 return false; 188 } else if (pid == 0) { 189 // Child subprocess. 190 191 // infd[0] is the child's reading end. 192 close(infd[1]); 193 194 // Set up stdin to read from the pipe. 195 CHECK_GE(dup2(infd[0], STDIN_FILENO), 0); 196 close(infd[0]); 197 198 // Restore stderr. 199 CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0); 200 close(saved_stderr); 201 202 const char *argv[kArgVMax]; 203 GetArgV(path_, argv); 204 execv(path_, const_cast<char **>(&argv[0])); 205 internal__exit(1); 206 } 207 208 // Input for the child, infd[1] is our writing end. 209 output_fd_ = infd[1]; 210 close(infd[0]); 211 212 // Continue execution in parent process. 213 input_fd_ = fd; 214 215 close(saved_stderr); 216 217 // Disable echo in the new terminal, disable CR. 218 struct termios termflags; 219 tcgetattr(fd, &termflags); 220 termflags.c_oflag &= ~ONLCR; 221 termflags.c_lflag &= ~ECHO; 222 tcsetattr(fd, TCSANOW, &termflags); 223 #else // SANITIZER_MAC 224 UNIMPLEMENTED(); 225 #endif // SANITIZER_MAC 226 } else { 227 const char *argv[kArgVMax]; 228 GetArgV(path_, argv); 229 pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], 230 /* stdout */ infd[1]); 231 if (pid < 0) { 232 internal_close(infd[0]); 233 internal_close(outfd[1]); 234 return false; 235 } 236 237 input_fd_ = infd[0]; 238 output_fd_ = outfd[1]; 239 } 240 241 CHECK_GT(pid, 0); 242 243 // Check that symbolizer subprocess started successfully. 244 SleepForMillis(kSymbolizerStartupTimeMillis); 245 if (!IsProcessRunning(pid)) { 246 // Either waitpid failed, or child has already exited. 247 Report("WARNING: external symbolizer didn't start up correctly!\n"); 248 return false; 249 } 250 251 return true; 252 } 253 254 class Addr2LineProcess : public SymbolizerProcess { 255 public: 256 Addr2LineProcess(const char *path, const char *module_name) 257 : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} 258 259 const char *module_name() const { return module_name_; } 260 261 private: 262 void GetArgV(const char *path_to_binary, 263 const char *(&argv)[kArgVMax]) const override { 264 int i = 0; 265 argv[i++] = path_to_binary; 266 argv[i++] = "-iCfe"; 267 argv[i++] = module_name_; 268 argv[i++] = nullptr; 269 } 270 271 bool ReachedEndOfOutput(const char *buffer, uptr length) const override; 272 273 bool ReadFromSymbolizer(char *buffer, uptr max_length) override { 274 if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) 275 return false; 276 // The returned buffer is empty when output is valid, but exceeds 277 // max_length. 278 if (*buffer == '\0') 279 return true; 280 // We should cut out output_terminator_ at the end of given buffer, 281 // appended by addr2line to mark the end of its meaningful output. 282 // We cannot scan buffer from it's beginning, because it is legal for it 283 // to start with output_terminator_ in case given offset is invalid. So, 284 // scanning from second character. 285 char *garbage = internal_strstr(buffer + 1, output_terminator_); 286 // This should never be NULL since buffer must end up with 287 // output_terminator_. 288 CHECK(garbage); 289 // Trim the buffer. 290 garbage[0] = '\0'; 291 return true; 292 } 293 294 const char *module_name_; // Owned, leaked. 295 static const char output_terminator_[]; 296 }; 297 298 const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n"; 299 300 bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, 301 uptr length) const { 302 const size_t kTerminatorLen = sizeof(output_terminator_) - 1; 303 // Skip, if we read just kTerminatorLen bytes, because Addr2Line output 304 // should consist at least of two pairs of lines: 305 // 1. First one, corresponding to given offset to be symbolized 306 // (may be equal to output_terminator_, if offset is not valid). 307 // 2. Second one for output_terminator_, itself to mark the end of output. 308 if (length <= kTerminatorLen) return false; 309 // Addr2Line output should end up with output_terminator_. 310 return !internal_memcmp(buffer + length - kTerminatorLen, 311 output_terminator_, kTerminatorLen); 312 } 313 314 class Addr2LinePool : public SymbolizerTool { 315 public: 316 explicit Addr2LinePool(const char *addr2line_path, 317 LowLevelAllocator *allocator) 318 : addr2line_path_(addr2line_path), allocator_(allocator) { 319 addr2line_pool_.reserve(16); 320 } 321 322 bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { 323 if (const char *buf = 324 SendCommand(stack->info.module, stack->info.module_offset)) { 325 ParseSymbolizePCOutput(buf, stack); 326 return true; 327 } 328 return false; 329 } 330 331 bool SymbolizeData(uptr addr, DataInfo *info) override { 332 return false; 333 } 334 335 private: 336 const char *SendCommand(const char *module_name, uptr module_offset) { 337 Addr2LineProcess *addr2line = 0; 338 for (uptr i = 0; i < addr2line_pool_.size(); ++i) { 339 if (0 == 340 internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { 341 addr2line = addr2line_pool_[i]; 342 break; 343 } 344 } 345 if (!addr2line) { 346 addr2line = 347 new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); 348 addr2line_pool_.push_back(addr2line); 349 } 350 CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); 351 char buffer[kBufferSize]; 352 internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", 353 module_offset, dummy_address_); 354 return addr2line->SendCommand(buffer); 355 } 356 357 static const uptr kBufferSize = 64; 358 const char *addr2line_path_; 359 LowLevelAllocator *allocator_; 360 InternalMmapVector<Addr2LineProcess*> addr2line_pool_; 361 static const uptr dummy_address_ = 362 FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); 363 }; 364 365 #if SANITIZER_SUPPORTS_WEAK_HOOKS 366 extern "C" { 367 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 368 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, 369 char *Buffer, int MaxLength); 370 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 371 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, 372 char *Buffer, int MaxLength); 373 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 374 void __sanitizer_symbolize_flush(); 375 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 376 int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, 377 int MaxLength); 378 } // extern "C" 379 380 class InternalSymbolizer : public SymbolizerTool { 381 public: 382 static InternalSymbolizer *get(LowLevelAllocator *alloc) { 383 if (__sanitizer_symbolize_code != 0 && 384 __sanitizer_symbolize_data != 0) { 385 return new(*alloc) InternalSymbolizer(); 386 } 387 return 0; 388 } 389 390 bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { 391 bool result = __sanitizer_symbolize_code( 392 stack->info.module, stack->info.module_offset, buffer_, kBufferSize); 393 if (result) ParseSymbolizePCOutput(buffer_, stack); 394 return result; 395 } 396 397 bool SymbolizeData(uptr addr, DataInfo *info) override { 398 bool result = __sanitizer_symbolize_data(info->module, info->module_offset, 399 buffer_, kBufferSize); 400 if (result) { 401 ParseSymbolizeDataOutput(buffer_, info); 402 info->start += (addr - info->module_offset); // Add the base address. 403 } 404 return result; 405 } 406 407 void Flush() override { 408 if (__sanitizer_symbolize_flush) 409 __sanitizer_symbolize_flush(); 410 } 411 412 const char *Demangle(const char *name) override { 413 if (__sanitizer_symbolize_demangle) { 414 for (uptr res_length = 1024; 415 res_length <= InternalSizeClassMap::kMaxSize;) { 416 char *res_buff = static_cast<char*>(InternalAlloc(res_length)); 417 uptr req_length = 418 __sanitizer_symbolize_demangle(name, res_buff, res_length); 419 if (req_length > res_length) { 420 res_length = req_length + 1; 421 InternalFree(res_buff); 422 continue; 423 } 424 return res_buff; 425 } 426 } 427 return name; 428 } 429 430 private: 431 InternalSymbolizer() { } 432 433 static const int kBufferSize = 16 * 1024; 434 char buffer_[kBufferSize]; 435 }; 436 #else // SANITIZER_SUPPORTS_WEAK_HOOKS 437 438 class InternalSymbolizer : public SymbolizerTool { 439 public: 440 static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } 441 }; 442 443 #endif // SANITIZER_SUPPORTS_WEAK_HOOKS 444 445 const char *Symbolizer::PlatformDemangle(const char *name) { 446 return DemangleSwiftAndCXX(name); 447 } 448 449 static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { 450 const char *path = common_flags()->external_symbolizer_path; 451 const char *binary_name = path ? StripModuleName(path) : ""; 452 if (path && path[0] == '\0') { 453 VReport(2, "External symbolizer is explicitly disabled.\n"); 454 return nullptr; 455 } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) { 456 VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); 457 return new(*allocator) LLVMSymbolizer(path, allocator); 458 } else if (!internal_strcmp(binary_name, "atos")) { 459 #if SANITIZER_MAC 460 VReport(2, "Using atos at user-specified path: %s\n", path); 461 return new(*allocator) AtosSymbolizer(path, allocator); 462 #else // SANITIZER_MAC 463 Report("ERROR: Using `atos` is only supported on Darwin.\n"); 464 Die(); 465 #endif // SANITIZER_MAC 466 } else if (!internal_strcmp(binary_name, "addr2line")) { 467 VReport(2, "Using addr2line at user-specified path: %s\n", path); 468 return new(*allocator) Addr2LinePool(path, allocator); 469 } else if (path) { 470 Report("ERROR: External symbolizer path is set to '%s' which isn't " 471 "a known symbolizer. Please set the path to the llvm-symbolizer " 472 "binary or other known tool.\n", path); 473 Die(); 474 } 475 476 // Otherwise symbolizer program is unknown, let's search $PATH 477 CHECK(path == nullptr); 478 #if SANITIZER_MAC 479 if (const char *found_path = FindPathToBinary("atos")) { 480 VReport(2, "Using atos found at: %s\n", found_path); 481 return new(*allocator) AtosSymbolizer(found_path, allocator); 482 } 483 #endif // SANITIZER_MAC 484 if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { 485 VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); 486 return new(*allocator) LLVMSymbolizer(found_path, allocator); 487 } 488 if (common_flags()->allow_addr2line) { 489 if (const char *found_path = FindPathToBinary("addr2line")) { 490 VReport(2, "Using addr2line found at: %s\n", found_path); 491 return new(*allocator) Addr2LinePool(found_path, allocator); 492 } 493 } 494 return nullptr; 495 } 496 497 static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, 498 LowLevelAllocator *allocator) { 499 if (!common_flags()->symbolize) { 500 VReport(2, "Symbolizer is disabled.\n"); 501 return; 502 } 503 if (IsAllocatorOutOfMemory()) { 504 VReport(2, "Cannot use internal symbolizer: out of memory\n"); 505 } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { 506 VReport(2, "Using internal symbolizer.\n"); 507 list->push_back(tool); 508 return; 509 } 510 if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { 511 VReport(2, "Using libbacktrace symbolizer.\n"); 512 list->push_back(tool); 513 return; 514 } 515 516 if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { 517 list->push_back(tool); 518 } 519 520 #if SANITIZER_MAC 521 VReport(2, "Using dladdr symbolizer.\n"); 522 list->push_back(new(*allocator) DlAddrSymbolizer()); 523 #endif // SANITIZER_MAC 524 } 525 526 Symbolizer *Symbolizer::PlatformInit() { 527 IntrusiveList<SymbolizerTool> list; 528 list.clear(); 529 ChooseSymbolizerTools(&list, &symbolizer_allocator_); 530 return new(symbolizer_allocator_) Symbolizer(list); 531 } 532 533 void Symbolizer::LateInitialize() { 534 Symbolizer::GetOrInit(); 535 InitializeSwiftDemangler(); 536 } 537 538 } // namespace __sanitizer 539 540 #endif // SANITIZER_POSIX 541