diff options
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc | 182 |
1 files changed, 111 insertions, 71 deletions
diff --git a/compiler-rt/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/compiler-rt/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc index 55b7c5d7c84..90770fae1ae 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc @@ -15,7 +15,6 @@ #include "tsan_rtl.h" #include <unistd.h> -#include <dlfcn.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -23,101 +22,142 @@ #include <link.h> #include <linux/limits.h> #include <sys/types.h> -#include <sys/wait.h> namespace __tsan { -static bool GetSymbolizerFd(int *infdp, int *outfdp) { - static int outfd[2]; - static int infd[2]; - static int pid = -1; - static int inited = 0; - if (inited == 0) { - inited = -1; - if (pipe(outfd)) { - Printf("ThreadSanitizer: pipe() failed (%d)\n", errno); - Die(); - } - if (pipe(infd)) { - Printf("ThreadSanitizer: pipe() failed (%d)\n", errno); - Die(); - } - pid = fork(); - if (pid == 0) { - close(STDOUT_FILENO); - close(STDIN_FILENO); - dup2(outfd[0], STDIN_FILENO); - dup2(infd[1], STDOUT_FILENO); - close(outfd[0]); - close(outfd[1]); - close(infd[0]); - close(infd[1]); - InternalScopedBuf<char> exe(PATH_MAX); - ssize_t len = readlink("/proc/self/exe", exe, exe.Size() - 1); - exe.Ptr()[len] = 0; - execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", exe.Ptr(), - NULL); - _exit(0); - } else if (pid < 0) { - Printf("ThreadSanitizer: failed to fork symbolizer\n"); - Die(); - } +struct ModuleDesc { + ModuleDesc *next; + const char *fullname; + const char *name; + uptr base; + uptr end; + int inp_fd; + int out_fd; +}; + +struct DlIteratePhdrCtx { + ModuleDesc *modules; + bool is_first; +}; + +static void InitModule(ModuleDesc *m) { + int outfd[2]; + if (pipe(outfd)) { + Printf("ThreadSanitizer: pipe() failed (%d)\n", errno); + Die(); + } + int infd[2]; + if (pipe(infd)) { + Printf("ThreadSanitizer: pipe() failed (%d)\n", errno); + Die(); + } + int pid = fork(); + if (pid == 0) { + close(STDOUT_FILENO); + close(STDIN_FILENO); + dup2(outfd[0], STDIN_FILENO); + dup2(infd[1], STDOUT_FILENO); close(outfd[0]); + close(outfd[1]); + close(infd[0]); close(infd[1]); - inited = 1; - } else if (inited > 0) { - int status = 0; - if (pid == waitpid(pid, &status, WNOHANG)) { - Printf("ThreadSanitizer: symbolizer died with status %d\n", - WEXITSTATUS(status)); - Die(); - } + execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0); + _exit(0); + } else if (pid < 0) { + Printf("ThreadSanitizer: failed to fork symbolizer\n"); + Die(); } - *infdp = infd[0]; - *outfdp = outfd[1]; - return inited > 0; + close(outfd[0]); + close(infd[1]); + m->inp_fd = infd[0]; + m->out_fd = outfd[1]; } -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *ctx) { - *(uptr*)ctx = (uptr)info->dlpi_addr; - return 1; +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { + DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg; + InternalScopedBuf<char> tmp(128); + if (ctx->is_first) { + Snprintf(tmp.Ptr(), tmp.Size(), "/proc/%d/exe", (int)getpid()); + info->dlpi_name = tmp.Ptr(); + } + ctx->is_first = false; + if (info->dlpi_name == 0 || info->dlpi_name[0] == 0) + return 0; + ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack, + sizeof(ModuleDesc)); + m->next = ctx->modules; + ctx->modules = m; + m->fullname = internal_strdup(info->dlpi_name); + m->name = strrchr(m->fullname, '/'); // FIXME: internal_strrchr + if (m->name) + m->name += 1; + else + m->name = m->fullname; + m->base = (uptr)-1; + m->end = 0; + m->inp_fd = -1; + m->out_fd = -1; + for (int i = 0; i < info->dlpi_phnum; i++) { + uptr base1 = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; + uptr end1 = base1 + info->dlpi_phdr[i].p_memsz; + if (m->base > base1) + m->base = base1; + if (m->end < end1) + m->end = end1; + } + DPrintf("Module %s %lx-%lx\n", m->name, m->base, m->end); + return 0; } -static uptr GetImageBase() { - static uptr base = 0; - if (base == 0) - dl_iterate_phdr(dl_iterate_phdr_cb, &base); - return base; +static ModuleDesc *InitModules() { + DlIteratePhdrCtx ctx = {0, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &ctx); + return ctx.modules; +} + +static ModuleDesc *GetModuleDesc(uptr addr) { + static ModuleDesc *modules = 0; + if (modules == 0) + modules = InitModules(); + for (ModuleDesc *m = modules; m; m = m->next) { + if (addr >= m->base && addr < m->end) { + if (m->inp_fd == -1) + InitModule(m); + return m; + } + } + return 0; +} + +static ReportStack *NewFrame(uptr addr) { + ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack, + sizeof(ReportStack)); + internal_memset(ent, 0, sizeof(*ent)); + ent->pc = addr; + return ent; } ReportStack *SymbolizeCode(uptr addr) { - uptr base = GetImageBase(); - uptr offset = addr - base; - int infd = -1; - int outfd = -1; - if (!GetSymbolizerFd(&infd, &outfd)) - return 0; + ModuleDesc *m = GetModuleDesc(addr); + if (m == 0) + NewFrame(addr); + uptr offset = addr - m->base; char addrstr[32]; Snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset); - if (0 >= write(outfd, addrstr, internal_strlen(addrstr))) { + if (0 >= write(m->out_fd, addrstr, internal_strlen(addrstr))) { Printf("ThreadSanitizer: can't write from symbolizer\n"); Die(); } InternalScopedBuf<char> func(1024); - ssize_t len = read(infd, func, func.Size() - 1); + ssize_t len = read(m->inp_fd, func, func.Size() - 1); if (len <= 0) { Printf("ThreadSanitizer: can't read from symbolizer\n"); Die(); } func.Ptr()[len] = 0; - ReportStack *res = (ReportStack*)internal_alloc(MBlockReportStack, - sizeof(ReportStack)); - internal_memset(res, 0, sizeof(*res)); - res->module = (char*)internal_alloc(MBlockReportStack, 4); - internal_memcpy(res->module, "exe", 4); + ReportStack *res = NewFrame(addr); + res->module = internal_strdup(m->name); res->offset = offset; - res->pc = addr; - char *pos = strchr(func, '\n'); if (pos && func[0] != '?') { res->func = (char*)internal_alloc(MBlockReportStack, pos - func + 1); |

