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