• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InitModule(ModuleDesc * m)50 static 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 
dl_iterate_phdr_cb(dl_phdr_info * info,size_t size,void * arg)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", 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 
InitSections()129 static SectionDesc *InitSections() {
130   DlIteratePhdrCtx ctx = {0, true};
131   dl_iterate_phdr(dl_iterate_phdr_cb, &ctx);
132   return ctx.sections;
133 }
134 
GetSectionDesc(uptr addr)135 static 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 
SymbolizeCodeAddr2Line(uptr addr)149 ReportStack *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 
SymbolizeDataAddr2Line(uptr addr)189 ReportStack *SymbolizeDataAddr2Line(uptr addr) {
190   return 0;
191 }
192 
193 }  // namespace __tsan
194