168d75effSDimitry Andric //===-- tsan_symbolize.cpp ------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric
1368d75effSDimitry Andric #include "tsan_symbolize.h"
1468d75effSDimitry Andric
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
1868d75effSDimitry Andric #include "tsan_flags.h"
1968d75effSDimitry Andric #include "tsan_report.h"
2068d75effSDimitry Andric #include "tsan_rtl.h"
2168d75effSDimitry Andric
2268d75effSDimitry Andric namespace __tsan {
2368d75effSDimitry Andric
EnterSymbolizer()2468d75effSDimitry Andric void EnterSymbolizer() {
2568d75effSDimitry Andric ThreadState *thr = cur_thread();
2668d75effSDimitry Andric CHECK(!thr->in_symbolizer);
2768d75effSDimitry Andric thr->in_symbolizer = true;
2868d75effSDimitry Andric thr->ignore_interceptors++;
2968d75effSDimitry Andric }
3068d75effSDimitry Andric
ExitSymbolizer()3168d75effSDimitry Andric void ExitSymbolizer() {
3268d75effSDimitry Andric ThreadState *thr = cur_thread();
3368d75effSDimitry Andric CHECK(thr->in_symbolizer);
3468d75effSDimitry Andric thr->in_symbolizer = false;
3568d75effSDimitry Andric thr->ignore_interceptors--;
3668d75effSDimitry Andric }
3768d75effSDimitry Andric
3868d75effSDimitry Andric // Legacy API.
3968d75effSDimitry Andric // May be overriden by JIT/JAVA/etc,
4068d75effSDimitry Andric // whatever produces PCs marked with kExternalPCBit.
4168d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL
__tsan_symbolize_external(uptr pc,char * func_buf,uptr func_siz,char * file_buf,uptr file_siz,int * line,int * col)4268d75effSDimitry Andric bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,
4368d75effSDimitry Andric char *file_buf, uptr file_siz, int *line,
4468d75effSDimitry Andric int *col) {
4568d75effSDimitry Andric return false;
4668d75effSDimitry Andric }
4768d75effSDimitry Andric
4868d75effSDimitry Andric // New API: call __tsan_symbolize_external_ex only when it exists.
4968d75effSDimitry Andric // Once old clients are gone, provide dummy implementation.
5068d75effSDimitry Andric SANITIZER_WEAK_DEFAULT_IMPL
__tsan_symbolize_external_ex(uptr pc,void (* add_frame)(void *,const char *,const char *,int,int),void * ctx)5168d75effSDimitry Andric void __tsan_symbolize_external_ex(uptr pc,
5268d75effSDimitry Andric void (*add_frame)(void *, const char *,
5368d75effSDimitry Andric const char *, int, int),
5468d75effSDimitry Andric void *ctx) {}
5568d75effSDimitry Andric
5668d75effSDimitry Andric struct SymbolizedStackBuilder {
5768d75effSDimitry Andric SymbolizedStack *head;
5868d75effSDimitry Andric SymbolizedStack *tail;
5968d75effSDimitry Andric uptr addr;
6068d75effSDimitry Andric };
6168d75effSDimitry Andric
AddFrame(void * ctx,const char * function_name,const char * file,int line,int column)6268d75effSDimitry Andric static void AddFrame(void *ctx, const char *function_name, const char *file,
6368d75effSDimitry Andric int line, int column) {
6468d75effSDimitry Andric SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx;
6568d75effSDimitry Andric if (ssb->tail) {
6668d75effSDimitry Andric ssb->tail->next = SymbolizedStack::New(ssb->addr);
6768d75effSDimitry Andric ssb->tail = ssb->tail->next;
6868d75effSDimitry Andric } else {
6968d75effSDimitry Andric ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr);
7068d75effSDimitry Andric }
7168d75effSDimitry Andric AddressInfo *info = &ssb->tail->info;
7268d75effSDimitry Andric if (function_name) {
7368d75effSDimitry Andric info->function = internal_strdup(function_name);
7468d75effSDimitry Andric }
7568d75effSDimitry Andric if (file) {
7668d75effSDimitry Andric info->file = internal_strdup(file);
7768d75effSDimitry Andric }
7868d75effSDimitry Andric info->line = line;
7968d75effSDimitry Andric info->column = column;
8068d75effSDimitry Andric }
8168d75effSDimitry Andric
SymbolizeCode(uptr addr)8268d75effSDimitry Andric SymbolizedStack *SymbolizeCode(uptr addr) {
8368d75effSDimitry Andric // Check if PC comes from non-native land.
8468d75effSDimitry Andric if (addr & kExternalPCBit) {
8568d75effSDimitry Andric SymbolizedStackBuilder ssb = {nullptr, nullptr, addr};
8668d75effSDimitry Andric __tsan_symbolize_external_ex(addr, AddFrame, &ssb);
8768d75effSDimitry Andric if (ssb.head)
8868d75effSDimitry Andric return ssb.head;
8968d75effSDimitry Andric // Legacy code: remove along with the declaration above
9068d75effSDimitry Andric // once all clients using this API are gone.
9168d75effSDimitry Andric // Declare static to not consume too much stack space.
9268d75effSDimitry Andric // We symbolize reports in a single thread, so this is fine.
9368d75effSDimitry Andric static char func_buf[1024];
9468d75effSDimitry Andric static char file_buf[1024];
9568d75effSDimitry Andric int line, col;
9668d75effSDimitry Andric SymbolizedStack *frame = SymbolizedStack::New(addr);
9768d75effSDimitry Andric if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
9868d75effSDimitry Andric sizeof(file_buf), &line, &col)) {
9968d75effSDimitry Andric frame->info.function = internal_strdup(func_buf);
10068d75effSDimitry Andric frame->info.file = internal_strdup(file_buf);
10168d75effSDimitry Andric frame->info.line = line;
10268d75effSDimitry Andric frame->info.column = col;
10368d75effSDimitry Andric }
10468d75effSDimitry Andric return frame;
10568d75effSDimitry Andric }
10668d75effSDimitry Andric return Symbolizer::GetOrInit()->SymbolizePC(addr);
10768d75effSDimitry Andric }
10868d75effSDimitry Andric
SymbolizeData(uptr addr)10968d75effSDimitry Andric ReportLocation *SymbolizeData(uptr addr) {
11068d75effSDimitry Andric DataInfo info;
11168d75effSDimitry Andric if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
11268d75effSDimitry Andric return 0;
113*349cc55cSDimitry Andric auto *ent = New<ReportLocation>();
114*349cc55cSDimitry Andric ent->type = ReportLocationGlobal;
11568d75effSDimitry Andric internal_memcpy(&ent->global, &info, sizeof(info));
11668d75effSDimitry Andric return ent;
11768d75effSDimitry Andric }
11868d75effSDimitry Andric
SymbolizeFlush()11968d75effSDimitry Andric void SymbolizeFlush() {
12068d75effSDimitry Andric Symbolizer::GetOrInit()->Flush();
12168d75effSDimitry Andric }
12268d75effSDimitry Andric
12368d75effSDimitry Andric } // namespace __tsan
124