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