1353944Sdim//===-- tsan_symbolize.cpp ------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of ThreadSanitizer (TSan), a race detector.
10353944Sdim//
11353944Sdim//===----------------------------------------------------------------------===//
12353944Sdim
13353944Sdim#include "tsan_symbolize.h"
14353944Sdim
15353944Sdim#include "sanitizer_common/sanitizer_common.h"
16353944Sdim#include "sanitizer_common/sanitizer_placement_new.h"
17353944Sdim#include "sanitizer_common/sanitizer_symbolizer.h"
18353944Sdim#include "tsan_flags.h"
19353944Sdim#include "tsan_report.h"
20353944Sdim#include "tsan_rtl.h"
21353944Sdim
22353944Sdimnamespace __tsan {
23353944Sdim
24353944Sdimvoid EnterSymbolizer() {
25353944Sdim  ThreadState *thr = cur_thread();
26353944Sdim  CHECK(!thr->in_symbolizer);
27353944Sdim  thr->in_symbolizer = true;
28353944Sdim  thr->ignore_interceptors++;
29353944Sdim}
30353944Sdim
31353944Sdimvoid ExitSymbolizer() {
32353944Sdim  ThreadState *thr = cur_thread();
33353944Sdim  CHECK(thr->in_symbolizer);
34353944Sdim  thr->in_symbolizer = false;
35353944Sdim  thr->ignore_interceptors--;
36353944Sdim}
37353944Sdim
38353944Sdim// Legacy API.
39353944Sdim// May be overriden by JIT/JAVA/etc,
40353944Sdim// whatever produces PCs marked with kExternalPCBit.
41353944SdimSANITIZER_WEAK_DEFAULT_IMPL
42353944Sdimbool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,
43353944Sdim                               char *file_buf, uptr file_siz, int *line,
44353944Sdim                               int *col) {
45353944Sdim  return false;
46353944Sdim}
47353944Sdim
48353944Sdim// New API: call __tsan_symbolize_external_ex only when it exists.
49353944Sdim// Once old clients are gone, provide dummy implementation.
50353944SdimSANITIZER_WEAK_DEFAULT_IMPL
51353944Sdimvoid __tsan_symbolize_external_ex(uptr pc,
52353944Sdim                                  void (*add_frame)(void *, const char *,
53353944Sdim                                                    const char *, int, int),
54353944Sdim                                  void *ctx) {}
55353944Sdim
56353944Sdimstruct SymbolizedStackBuilder {
57353944Sdim  SymbolizedStack *head;
58353944Sdim  SymbolizedStack *tail;
59353944Sdim  uptr addr;
60353944Sdim};
61353944Sdim
62353944Sdimstatic void AddFrame(void *ctx, const char *function_name, const char *file,
63353944Sdim                     int line, int column) {
64353944Sdim  SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx;
65353944Sdim  if (ssb->tail) {
66353944Sdim    ssb->tail->next = SymbolizedStack::New(ssb->addr);
67353944Sdim    ssb->tail = ssb->tail->next;
68353944Sdim  } else {
69353944Sdim    ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr);
70353944Sdim  }
71353944Sdim  AddressInfo *info = &ssb->tail->info;
72353944Sdim  if (function_name) {
73353944Sdim    info->function = internal_strdup(function_name);
74353944Sdim  }
75353944Sdim  if (file) {
76353944Sdim    info->file = internal_strdup(file);
77353944Sdim  }
78353944Sdim  info->line = line;
79353944Sdim  info->column = column;
80353944Sdim}
81353944Sdim
82353944SdimSymbolizedStack *SymbolizeCode(uptr addr) {
83353944Sdim  // Check if PC comes from non-native land.
84353944Sdim  if (addr & kExternalPCBit) {
85353944Sdim    SymbolizedStackBuilder ssb = {nullptr, nullptr, addr};
86353944Sdim    __tsan_symbolize_external_ex(addr, AddFrame, &ssb);
87353944Sdim    if (ssb.head)
88353944Sdim      return ssb.head;
89353944Sdim    // Legacy code: remove along with the declaration above
90353944Sdim    // once all clients using this API are gone.
91353944Sdim    // Declare static to not consume too much stack space.
92353944Sdim    // We symbolize reports in a single thread, so this is fine.
93353944Sdim    static char func_buf[1024];
94353944Sdim    static char file_buf[1024];
95353944Sdim    int line, col;
96353944Sdim    SymbolizedStack *frame = SymbolizedStack::New(addr);
97353944Sdim    if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
98353944Sdim                                  sizeof(file_buf), &line, &col)) {
99353944Sdim      frame->info.function = internal_strdup(func_buf);
100353944Sdim      frame->info.file = internal_strdup(file_buf);
101353944Sdim      frame->info.line = line;
102353944Sdim      frame->info.column = col;
103353944Sdim    }
104353944Sdim    return frame;
105353944Sdim  }
106353944Sdim  return Symbolizer::GetOrInit()->SymbolizePC(addr);
107353944Sdim}
108353944Sdim
109353944SdimReportLocation *SymbolizeData(uptr addr) {
110353944Sdim  DataInfo info;
111353944Sdim  if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
112353944Sdim    return 0;
113353944Sdim  ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
114353944Sdim  internal_memcpy(&ent->global, &info, sizeof(info));
115353944Sdim  return ent;
116353944Sdim}
117353944Sdim
118353944Sdimvoid SymbolizeFlush() {
119353944Sdim  Symbolizer::GetOrInit()->Flush();
120353944Sdim}
121353944Sdim
122353944Sdim}  // namespace __tsan
123