Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_symbolize_addr2line.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 a part of ThreadSanitizer (TSan), a race detector.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 #include "sanitizer_common/sanitizer_common.h"
     14 #include "sanitizer_common/sanitizer_libc.h"
     15 #include "tsan_symbolize.h"
     16 #include "tsan_mman.h"
     17 #include "tsan_rtl.h"
     18 #include "tsan_platform.h"
     19 
     20 #include <unistd.h>
     21 #include <stdlib.h>
     22 #include <stdio.h>
     23 #include <errno.h>
     24 #include <link.h>
     25 #include <linux/limits.h>
     26 #include <sys/types.h>
     27 
     28 namespace __tsan {
     29 
     30 struct ModuleDesc {
     31   const char *fullname;
     32   const char *name;
     33   uptr base;
     34   int inp_fd;
     35   int out_fd;
     36 };
     37 
     38 struct SectionDesc {
     39   SectionDesc *next;
     40   ModuleDesc *module;
     41   uptr base;
     42   uptr end;
     43 };
     44 
     45 struct DlIteratePhdrCtx {
     46   SectionDesc *sections;
     47   bool is_first;
     48 };
     49 
     50 static void NOINLINE InitModule(ModuleDesc *m) {
     51   int outfd[2] = {};
     52   if (pipe(&outfd[0])) {
     53     Printf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno);
     54     Die();
     55   }
     56   int infd[2] = {};
     57   if (pipe(&infd[0])) {
     58     Printf("ThreadSanitizer: infd pipe() failed (%d)\n", errno);
     59     Die();
     60   }
     61   int pid = fork();
     62   if (pid == 0) {
     63     __sanitizer_set_report_fd(STDERR_FILENO);
     64     internal_close(STDOUT_FILENO);
     65     internal_close(STDIN_FILENO);
     66     internal_dup2(outfd[0], STDIN_FILENO);
     67     internal_dup2(infd[1], STDOUT_FILENO);
     68     internal_close(outfd[0]);
     69     internal_close(outfd[1]);
     70     internal_close(infd[0]);
     71     internal_close(infd[1]);
     72     for (int fd = getdtablesize(); fd > 2; fd--)
     73       internal_close(fd);
     74     execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0);
     75     _exit(0);
     76   } else if (pid < 0) {
     77     Printf("ThreadSanitizer: failed to fork symbolizer\n");
     78     Die();
     79   }
     80   internal_close(outfd[0]);
     81   internal_close(infd[1]);
     82   m->inp_fd = infd[0];
     83   m->out_fd = outfd[1];
     84 }
     85 
     86 static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
     87   DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg;
     88   InternalScopedBuffer<char> tmp(128);
     89   if (ctx->is_first) {
     90     internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe",
     91                       (int)internal_getpid());
     92     info->dlpi_name = tmp.data();
     93   }
     94   ctx->is_first = false;
     95   if (info->dlpi_name == 0 || info->dlpi_name[0] == 0)
     96     return 0;
     97   ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack,
     98                                               sizeof(ModuleDesc));
     99   m->fullname = internal_strdup(info->dlpi_name);
    100   m->name = internal_strrchr(m->fullname, '/');
    101   if (m->name)
    102     m->name += 1;
    103   else
    104     m->name = m->fullname;
    105   m->base = (uptr)info->dlpi_addr;
    106   m->inp_fd = -1;
    107   m->out_fd = -1;
    108   DPrintf2("Module %s %zx\n", m->name, m->base);
    109   for (int i = 0; i < info->dlpi_phnum; i++) {
    110     const Elf64_Phdr *s = &info->dlpi_phdr[i];
    111     DPrintf2("  Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx"
    112         " p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n",
    113             (uptr)s->p_type, (uptr)s->p_offset, (uptr)s->p_vaddr,
    114             (uptr)s->p_paddr, (uptr)s->p_filesz, (uptr)s->p_memsz,
    115             (uptr)s->p_flags, (uptr)s->p_align);
    116     if (s->p_type != PT_LOAD)
    117       continue;
    118     SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack,
    119                                                     sizeof(SectionDesc));
    120     sec->module = m;
    121     sec->base = info->dlpi_addr + s->p_vaddr;
    122     sec->end = sec->base + s->p_memsz;
    123     sec->next = ctx->sections;
    124     ctx->sections = sec;
    125     DPrintf2("  Section %zx-%zx\n", sec->base, sec->end);
    126   }
    127   return 0;
    128 }
    129 
    130 static SectionDesc *InitSections() {
    131   DlIteratePhdrCtx ctx = {0, true};
    132   dl_iterate_phdr(dl_iterate_phdr_cb, &ctx);
    133   return ctx.sections;
    134 }
    135 
    136 static SectionDesc *GetSectionDesc(uptr addr) {
    137   static SectionDesc *sections = 0;
    138   if (sections == 0)
    139     sections = InitSections();
    140   for (SectionDesc *s = sections; s; s = s->next) {
    141     if (addr >= s->base && addr < s->end) {
    142       if (s->module->inp_fd == -1)
    143         InitModule(s->module);
    144       return s;
    145     }
    146   }
    147   return 0;
    148 }
    149 
    150 ReportStack *SymbolizeCodeAddr2Line(uptr addr) {
    151   SectionDesc *s = GetSectionDesc(addr);
    152   if (s == 0)
    153     return NewReportStackEntry(addr);
    154   ModuleDesc *m = s->module;
    155   uptr offset = addr - m->base;
    156   char addrstr[32];
    157   internal_snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset);
    158   if (0 >= internal_write(m->out_fd, addrstr, internal_strlen(addrstr))) {
    159     Printf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
    160         m->out_fd, errno);
    161     Die();
    162   }
    163   InternalScopedBuffer<char> func(1024);
    164   ssize_t len = internal_read(m->inp_fd, func.data(), func.size() - 1);
    165   if (len <= 0) {
    166     Printf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
    167         m->inp_fd, errno);
    168     Die();
    169   }
    170   func.data()[len] = 0;
    171   ReportStack *res = NewReportStackEntry(addr);
    172   res->module = internal_strdup(m->name);
    173   res->offset = offset;
    174   char *pos = (char*)internal_strchr(func.data(), '\n');
    175   if (pos && func[0] != '?') {
    176     res->func = (char*)internal_alloc(MBlockReportStack, pos - func.data() + 1);
    177     internal_memcpy(res->func, func.data(), pos - func.data());
    178     res->func[pos - func.data()] = 0;
    179     char *pos2 = (char*)internal_strchr(pos, ':');
    180     if (pos2) {
    181       res->file = (char*)internal_alloc(MBlockReportStack, pos2 - pos - 1 + 1);
    182       internal_memcpy(res->file, pos + 1, pos2 - pos - 1);
    183       res->file[pos2 - pos - 1] = 0;
    184       res->line = atoi(pos2 + 1);
    185      }
    186   }
    187   return res;
    188 }
    189 
    190 ReportStack *SymbolizeDataAddr2Line(uptr addr) {
    191   return 0;
    192 }
    193 
    194 }  // namespace __tsan
    195