xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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