1 //===-- tsan_symbolize_addr2line.cc ---------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
11 #include "sanitizer_common/sanitizer_common.h"
12 #include "sanitizer_common/sanitizer_libc.h"
13 #include "tsan_symbolize.h"
14 #include "tsan_mman.h"
16 #include "tsan_platform.h"
23 #include <linux/limits.h>
24 #include <sys/types.h>
43 struct DlIteratePhdrCtx {
44 SectionDesc *sections;
48 static void NOINLINE InitModule(ModuleDesc *m) {
50 if (pipe(&outfd[0])) {
51 Printf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno);
56 Printf("ThreadSanitizer: infd pipe() failed (%d)\n", errno);
61 __sanitizer_set_report_fd(STDERR_FILENO);
62 internal_close(STDOUT_FILENO);
63 internal_close(STDIN_FILENO);
64 internal_dup2(outfd[0], STDIN_FILENO);
65 internal_dup2(infd[1], STDOUT_FILENO);
66 internal_close(outfd[0]);
67 internal_close(outfd[1]);
68 internal_close(infd[0]);
69 internal_close(infd[1]);
70 for (int fd = getdtablesize(); fd > 2; fd--)
72 execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0);
75 Printf("ThreadSanitizer: failed to fork symbolizer\n");
78 internal_close(outfd[0]);
79 internal_close(infd[1]);
84 static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
85 DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg;
86 InternalScopedBuffer<char> tmp(128);
88 internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe", GetPid());
89 info->dlpi_name = tmp.data();
91 ctx->is_first = false;
92 if (info->dlpi_name == 0 || info->dlpi_name[0] == 0)
94 ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack,
96 m->fullname = internal_strdup(info->dlpi_name);
97 m->name = internal_strrchr(m->fullname, '/');
101 m->name = m->fullname;
102 m->base = (uptr)info->dlpi_addr;
105 DPrintf2("Module %s %zx\n", m->name, m->base);
106 for (int i = 0; i < info->dlpi_phnum; i++) {
107 const Elf64_Phdr *s = &info->dlpi_phdr[i];
108 DPrintf2(" Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx"
109 " p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n",
110 (uptr)s->p_type, (uptr)s->p_offset, (uptr)s->p_vaddr,
111 (uptr)s->p_paddr, (uptr)s->p_filesz, (uptr)s->p_memsz,
112 (uptr)s->p_flags, (uptr)s->p_align);
113 if (s->p_type != PT_LOAD)
115 SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack,
116 sizeof(SectionDesc));
118 sec->base = info->dlpi_addr + s->p_vaddr;
119 sec->end = sec->base + s->p_memsz;
120 sec->next = ctx->sections;
122 DPrintf2(" Section %zx-%zx\n", sec->base, sec->end);
127 static SectionDesc *InitSections() {
128 DlIteratePhdrCtx ctx = {0, true};
129 dl_iterate_phdr(dl_iterate_phdr_cb, &ctx);
133 static SectionDesc *GetSectionDesc(uptr addr) {
134 static SectionDesc *sections = 0;
136 sections = InitSections();
137 for (SectionDesc *s = sections; s; s = s->next) {
138 if (addr >= s->base && addr < s->end) {
139 if (s->module->inp_fd == -1)
140 InitModule(s->module);
147 ReportStack *SymbolizeCodeAddr2Line(uptr addr) {
148 SectionDesc *s = GetSectionDesc(addr);
150 return NewReportStackEntry(addr);
151 ModuleDesc *m = s->module;
152 uptr offset = addr - m->base;
154 internal_snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset);
155 if (0 >= internal_write(m->out_fd, addrstr, internal_strlen(addrstr))) {
156 Printf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
160 InternalScopedBuffer<char> func(1024);
161 ssize_t len = internal_read(m->inp_fd, func.data(), func.size() - 1);
163 Printf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
167 func.data()[len] = 0;
168 ReportStack *res = NewReportStackEntry(addr);
169 res->module = internal_strdup(m->name);
170 res->offset = offset;
171 char *pos = (char*)internal_strchr(func.data(), '\n');
172 if (pos && func[0] != '?') {
173 res->func = (char*)internal_alloc(MBlockReportStack, pos - func.data() + 1);
174 internal_memcpy(res->func, func.data(), pos - func.data());
175 res->func[pos - func.data()] = 0;
176 char *pos2 = (char*)internal_strchr(pos, ':');
178 res->file = (char*)internal_alloc(MBlockReportStack, pos2 - pos - 1 + 1);
179 internal_memcpy(res->file, pos + 1, pos2 - pos - 1);
180 res->file[pos2 - pos - 1] = 0;
181 res->line = atoi(pos2 + 1);
187 ReportStack *SymbolizeDataAddr2Line(uptr addr) {
191 } // namespace __tsan