Home | History | Annotate | Download | only in sanitizer_common
      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