tsan_symbolize.cc revision 66d91e3356a0c4d7aff3beaaaff3e87bbaec805c
1//===-- tsan_symbolize.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
14#include "tsan_symbolize.h"
15
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_placement_new.h"
18#include "sanitizer_common/sanitizer_symbolizer.h"
19#include "tsan_flags.h"
20#include "tsan_report.h"
21#include "tsan_rtl.h"
22
23namespace __tsan {
24
25void EnterSymbolizer() {
26  ThreadState *thr = cur_thread();
27  CHECK(!thr->in_symbolizer);
28  thr->in_symbolizer = true;
29}
30
31void ExitSymbolizer() {
32  ThreadState *thr = cur_thread();
33  CHECK(thr->in_symbolizer);
34  thr->in_symbolizer = false;
35}
36
37ReportStack *NewReportStackEntry(uptr addr) {
38  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
39                                                  sizeof(ReportStack));
40  internal_memset(ent, 0, sizeof(*ent));
41  ent->pc = addr;
42  return ent;
43}
44
45// Strip module path to make output shorter.
46static char *StripModuleName(const char *module) {
47  if (module == 0)
48    return 0;
49  const char *short_module_name = internal_strrchr(module, '/');
50  if (short_module_name)
51    short_module_name += 1;
52  else
53    short_module_name = module;
54  return internal_strdup(short_module_name);
55}
56
57static ReportStack *NewReportStackEntry(const AddressInfo &info) {
58  ReportStack *ent = NewReportStackEntry(info.address);
59  ent->module = StripModuleName(info.module);
60  ent->offset = info.module_offset;
61  if (info.function)
62    ent->func = internal_strdup(info.function);
63  if (info.file)
64    ent->file = internal_strdup(info.file);
65  ent->line = info.line;
66  ent->col = info.column;
67  return ent;
68}
69
70
71  ReportStack *next;
72  char *module;
73  uptr offset;
74  uptr pc;
75  char *func;
76  char *file;
77  int line;
78  int col;
79
80
81// Denotes fake PC values that come from JIT/JAVA/etc.
82// For such PC values __tsan_symbolize_external() will be called.
83const uptr kExternalPCBit = 1ULL << 60;
84
85// May be overriden by JIT/JAVA/etc,
86// whatever produces PCs marked with kExternalPCBit.
87extern "C" bool __tsan_symbolize_external(uptr pc,
88                               char *func_buf, uptr func_siz,
89                               char *file_buf, uptr file_siz,
90                               int *line, int *col)
91                               SANITIZER_WEAK_ATTRIBUTE;
92
93bool __tsan_symbolize_external(uptr pc,
94                               char *func_buf, uptr func_siz,
95                               char *file_buf, uptr file_siz,
96                               int *line, int *col) {
97  return false;
98}
99
100ReportStack *SymbolizeCode(uptr addr) {
101  // Check if PC comes from non-native land.
102  if (addr & kExternalPCBit) {
103    // Declare static to not consume too much stack space.
104    // We symbolize reports in a single thread, so this is fine.
105    static char func_buf[1024];
106    static char file_buf[1024];
107    int line, col;
108    if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
109                                  file_buf, sizeof(file_buf), &line, &col))
110      return NewReportStackEntry(addr);
111    ReportStack *ent = NewReportStackEntry(addr);
112    ent->module = 0;
113    ent->offset = 0;
114    ent->func = internal_strdup(func_buf);
115    ent->file = internal_strdup(file_buf);
116    ent->line = line;
117    ent->col = col;
118    return ent;
119  }
120  if (!Symbolizer::Get()->IsAvailable())
121    return SymbolizeCodeAddr2Line(addr);
122  static const uptr kMaxAddrFrames = 16;
123  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
124  for (uptr i = 0; i < kMaxAddrFrames; i++)
125    new(&addr_frames[i]) AddressInfo();
126  uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
127      addr, addr_frames.data(), kMaxAddrFrames);
128  if (addr_frames_num == 0)
129    return NewReportStackEntry(addr);
130  ReportStack *top = 0;
131  ReportStack *bottom = 0;
132  for (uptr i = 0; i < addr_frames_num; i++) {
133    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
134    CHECK(cur_entry);
135    addr_frames[i].Clear();
136    if (i == 0)
137      top = cur_entry;
138    else
139      bottom->next = cur_entry;
140    bottom = cur_entry;
141  }
142  return top;
143}
144
145ReportLocation *SymbolizeData(uptr addr) {
146  if (!Symbolizer::Get()->IsAvailable())
147    return 0;
148  DataInfo info;
149  if (!Symbolizer::Get()->SymbolizeData(addr, &info))
150    return 0;
151  ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
152                                                        sizeof(ReportLocation));
153  internal_memset(ent, 0, sizeof(*ent));
154  ent->type = ReportLocationGlobal;
155  ent->module = StripModuleName(info.module);
156  ent->offset = info.module_offset;
157  if (info.name)
158    ent->name = internal_strdup(info.name);
159  ent->addr = info.start;
160  ent->size = info.size;
161  return ent;
162}
163
164void SymbolizeFlush() {
165  if (!Symbolizer::Get()->IsAvailable())
166    return;
167  Symbolizer::Get()->Flush();
168}
169
170}  // namespace __tsan
171