summaryrefslogtreecommitdiff
path: root/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2012-05-14 14:38:29 +0000
committerDmitry Vyukov <dvyukov@google.com>2012-05-14 14:38:29 +0000
commita762200b9765014453b2761375ca7512672a7a6c (patch)
tree5b6aa1c0599688ea6260b044ee3ed1a91b9c4d3f /lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
parent38a2f2ac4ec70d4a10c549a9d4ba55711a9ff3f8 (diff)
downloadcompiler-rt-a762200b9765014453b2761375ca7512672a7a6c.tar.gz
compiler-rt-a762200b9765014453b2761375ca7512672a7a6c.tar.bz2
compiler-rt-a762200b9765014453b2761375ca7512672a7a6c.tar.xz
tsan: make addr2line symbolizer understand dynamic libraries
Collect info about all dynamic libraries in the process (name, base, size). Determine to what dyn lib the address relates, route request to addr2line instance for the lib. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@156759 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc')
-rw-r--r--lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc182
1 files changed, 111 insertions, 71 deletions
diff --git a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
index 55b7c5d7..90770fae 100644
--- a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
+++ b/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);