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
25struct ScopedInSymbolizer {
26  ScopedInSymbolizer() {
27    ThreadState *thr = cur_thread();
28    CHECK(!thr->in_symbolizer);
29    thr->in_symbolizer = true;
30  }
31
32  ~ScopedInSymbolizer() {
33    ThreadState *thr = cur_thread();
34    CHECK(thr->in_symbolizer);
35    thr->in_symbolizer = false;
36  }
37};
38
39ReportStack *NewReportStackEntry(uptr addr) {
40  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
41                                                  sizeof(ReportStack));
42  internal_memset(ent, 0, sizeof(*ent));
43  ent->pc = addr;
44  return ent;
45}
46
47// Strip module path to make output shorter.
48static char *StripModuleName(const char *module) {
49  if (module == 0)
50    return 0;
51  const char *short_module_name = internal_strrchr(module, '/');
52  if (short_module_name)
53    short_module_name += 1;
54  else
55    short_module_name = module;
56  return internal_strdup(short_module_name);
57}
58
59static ReportStack *NewReportStackEntry(const AddressInfo &info) {
60  ReportStack *ent = NewReportStackEntry(info.address);
61  ent->module = StripModuleName(info.module);
62  ent->offset = info.module_offset;
63  if (info.function)
64    ent->func = internal_strdup(info.function);
65  if (info.file)
66    ent->file = internal_strdup(info.file);
67  ent->line = info.line;
68  ent->col = info.column;
69  return ent;
70}
71
72ReportStack *SymbolizeCode(uptr addr) {
73  if (!IsSymbolizerAvailable())
74    return SymbolizeCodeAddr2Line(addr);
75  ScopedInSymbolizer in_symbolizer;
76  static const uptr kMaxAddrFrames = 16;
77  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
78  for (uptr i = 0; i < kMaxAddrFrames; i++)
79    new(&addr_frames[i]) AddressInfo();
80  uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
81                                                    kMaxAddrFrames);
82  if (addr_frames_num == 0)
83    return NewReportStackEntry(addr);
84  ReportStack *top = 0;
85  ReportStack *bottom = 0;
86  for (uptr i = 0; i < addr_frames_num; i++) {
87    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
88    CHECK(cur_entry);
89    addr_frames[i].Clear();
90    if (i == 0)
91      top = cur_entry;
92    else
93      bottom->next = cur_entry;
94    bottom = cur_entry;
95  }
96  return top;
97}
98
99ReportLocation *SymbolizeData(uptr addr) {
100  if (!IsSymbolizerAvailable())
101    return 0;
102  ScopedInSymbolizer in_symbolizer;
103  DataInfo info;
104  if (!__sanitizer::SymbolizeData(addr, &info))
105    return 0;
106  ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
107                                                        sizeof(ReportLocation));
108  internal_memset(ent, 0, sizeof(*ent));
109  ent->type = ReportLocationGlobal;
110  ent->module = StripModuleName(info.module);
111  ent->offset = info.module_offset;
112  if (info.name)
113    ent->name = internal_strdup(info.name);
114  ent->addr = info.start;
115  ent->size = info.size;
116  return ent;
117}
118
119}  // namespace __tsan
120