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