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