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