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 28namespace __tsan { 29 30struct ModuleDesc { 31 const char *fullname; 32 const char *name; 33 uptr base; 34 int inp_fd; 35 int out_fd; 36}; 37 38struct SectionDesc { 39 SectionDesc *next; 40 ModuleDesc *module; 41 uptr base; 42 uptr end; 43}; 44 45struct DlIteratePhdrCtx { 46 SectionDesc *sections; 47 bool is_first; 48}; 49 50static void NOINLINE InitModule(ModuleDesc *m) { 51 int outfd[2] = {}; 52 if (pipe(&outfd[0])) { 53 TsanPrintf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno); 54 Die(); 55 } 56 int infd[2] = {}; 57 if (pipe(&infd[0])) { 58 TsanPrintf("ThreadSanitizer: infd pipe() failed (%d)\n", errno); 59 Die(); 60 } 61 int pid = fork(); 62 if (pid == 0) { 63 flags()->log_fileno = 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 TsanPrintf("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 86static 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", GetPid()); 91 info->dlpi_name = tmp.data(); 92 } 93 ctx->is_first = false; 94 if (info->dlpi_name == 0 || info->dlpi_name[0] == 0) 95 return 0; 96 ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack, 97 sizeof(ModuleDesc)); 98 m->fullname = internal_strdup(info->dlpi_name); 99 m->name = internal_strrchr(m->fullname, '/'); 100 if (m->name) 101 m->name += 1; 102 else 103 m->name = m->fullname; 104 m->base = (uptr)info->dlpi_addr; 105 m->inp_fd = -1; 106 m->out_fd = -1; 107 DPrintf("Module %s %zx\n", m->name, m->base); 108 for (int i = 0; i < info->dlpi_phnum; i++) { 109 const Elf64_Phdr *s = &info->dlpi_phdr[i]; 110 DPrintf(" Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx" 111 " p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n", 112 (uptr)s->p_type, (uptr)s->p_offset, (uptr)s->p_vaddr, 113 (uptr)s->p_paddr, (uptr)s->p_filesz, (uptr)s->p_memsz, 114 (uptr)s->p_flags, (uptr)s->p_align); 115 if (s->p_type != PT_LOAD) 116 continue; 117 SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack, 118 sizeof(SectionDesc)); 119 sec->module = m; 120 sec->base = info->dlpi_addr + s->p_vaddr; 121 sec->end = sec->base + s->p_memsz; 122 sec->next = ctx->sections; 123 ctx->sections = sec; 124 DPrintf(" Section %zx-%zx\n", sec->base, sec->end); 125 } 126 return 0; 127} 128 129static SectionDesc *InitSections() { 130 DlIteratePhdrCtx ctx = {0, true}; 131 dl_iterate_phdr(dl_iterate_phdr_cb, &ctx); 132 return ctx.sections; 133} 134 135static SectionDesc *GetSectionDesc(uptr addr) { 136 static SectionDesc *sections = 0; 137 if (sections == 0) 138 sections = InitSections(); 139 for (SectionDesc *s = sections; s; s = s->next) { 140 if (addr >= s->base && addr < s->end) { 141 if (s->module->inp_fd == -1) 142 InitModule(s->module); 143 return s; 144 } 145 } 146 return 0; 147} 148 149ReportStack *SymbolizeCodeAddr2Line(uptr addr) { 150 SectionDesc *s = GetSectionDesc(addr); 151 if (s == 0) 152 return NewReportStackEntry(addr); 153 ModuleDesc *m = s->module; 154 uptr offset = addr - m->base; 155 char addrstr[32]; 156 internal_snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset); 157 if (0 >= internal_write(m->out_fd, addrstr, internal_strlen(addrstr))) { 158 TsanPrintf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n", 159 m->out_fd, errno); 160 Die(); 161 } 162 InternalScopedBuffer<char> func(1024); 163 ssize_t len = internal_read(m->inp_fd, func.data(), func.size() - 1); 164 if (len <= 0) { 165 TsanPrintf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n", 166 m->inp_fd, errno); 167 Die(); 168 } 169 func.data()[len] = 0; 170 ReportStack *res = NewReportStackEntry(addr); 171 res->module = internal_strdup(m->name); 172 res->offset = offset; 173 char *pos = (char*)internal_strchr(func.data(), '\n'); 174 if (pos && func[0] != '?') { 175 res->func = (char*)internal_alloc(MBlockReportStack, pos - func.data() + 1); 176 internal_memcpy(res->func, func.data(), pos - func.data()); 177 res->func[pos - func.data()] = 0; 178 char *pos2 = (char*)internal_strchr(pos, ':'); 179 if (pos2) { 180 res->file = (char*)internal_alloc(MBlockReportStack, pos2 - pos - 1 + 1); 181 internal_memcpy(res->file, pos + 1, pos2 - pos - 1); 182 res->file[pos2 - pos - 1] = 0; 183 res->line = atoi(pos2 + 1); 184 } 185 } 186 return res; 187} 188 189ReportStack *SymbolizeDataAddr2Line(uptr addr) { 190 return 0; 191} 192 193} // namespace __tsan 194