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