168d75effSDimitry Andric //===-- sanitizer_symbolizer_libbacktrace.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 shared between AddressSanitizer and ThreadSanitizer
1068d75effSDimitry Andric // run-time libraries.
1168d75effSDimitry Andric // Libbacktrace implementation of symbolizer parts.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1406c3fb27SDimitry Andric #include "sanitizer_symbolizer_libbacktrace.h"
1568d75effSDimitry Andric 
1668d75effSDimitry Andric #include "sanitizer_internal_defs.h"
1706c3fb27SDimitry Andric #include "sanitizer_platform.h"
1868d75effSDimitry Andric #include "sanitizer_symbolizer.h"
1968d75effSDimitry Andric 
2068d75effSDimitry Andric #if SANITIZER_LIBBACKTRACE
2168d75effSDimitry Andric # include "backtrace-supported.h"
2268d75effSDimitry Andric # if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
2368d75effSDimitry Andric #  include "backtrace.h"
2468d75effSDimitry Andric #  if SANITIZER_CP_DEMANGLE
2568d75effSDimitry Andric #   undef ARRAY_SIZE
2668d75effSDimitry Andric #   include "demangle.h"
2768d75effSDimitry Andric #  endif
2868d75effSDimitry Andric # else
2968d75effSDimitry Andric #  define SANITIZER_LIBBACKTRACE 0
3068d75effSDimitry Andric # endif
3168d75effSDimitry Andric #endif
3268d75effSDimitry Andric 
3368d75effSDimitry Andric namespace __sanitizer {
3468d75effSDimitry Andric 
3568d75effSDimitry Andric static char *DemangleAlloc(const char *name, bool always_alloc);
3668d75effSDimitry Andric 
3768d75effSDimitry Andric #if SANITIZER_LIBBACKTRACE
3868d75effSDimitry Andric 
3968d75effSDimitry Andric namespace {
4068d75effSDimitry Andric 
4168d75effSDimitry Andric # if SANITIZER_CP_DEMANGLE
4268d75effSDimitry Andric struct CplusV3DemangleData {
4368d75effSDimitry Andric   char *buf;
4468d75effSDimitry Andric   uptr size, allocated;
4568d75effSDimitry Andric };
4668d75effSDimitry Andric 
4768d75effSDimitry Andric extern "C" {
4868d75effSDimitry Andric static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
4968d75effSDimitry Andric   CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
5068d75effSDimitry Andric   uptr needed = data->size + l + 1;
5168d75effSDimitry Andric   if (needed > data->allocated) {
5268d75effSDimitry Andric     data->allocated *= 2;
5368d75effSDimitry Andric     if (needed > data->allocated)
5468d75effSDimitry Andric       data->allocated = needed;
5568d75effSDimitry Andric     char *buf = (char *)InternalAlloc(data->allocated);
5668d75effSDimitry Andric     if (data->buf) {
5768d75effSDimitry Andric       internal_memcpy(buf, data->buf, data->size);
5868d75effSDimitry Andric       InternalFree(data->buf);
5968d75effSDimitry Andric     }
6068d75effSDimitry Andric     data->buf = buf;
6168d75effSDimitry Andric   }
6268d75effSDimitry Andric   internal_memcpy(data->buf + data->size, s, l);
6368d75effSDimitry Andric   data->buf[data->size + l] = '\0';
6468d75effSDimitry Andric   data->size += l;
6568d75effSDimitry Andric }
6668d75effSDimitry Andric }  // extern "C"
6768d75effSDimitry Andric 
6868d75effSDimitry Andric char *CplusV3Demangle(const char *name) {
6968d75effSDimitry Andric   CplusV3DemangleData data;
7068d75effSDimitry Andric   data.buf = 0;
7168d75effSDimitry Andric   data.size = 0;
7268d75effSDimitry Andric   data.allocated = 0;
7368d75effSDimitry Andric   if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
7468d75effSDimitry Andric                                  CplusV3DemangleCallback, &data)) {
7568d75effSDimitry Andric     if (data.size + 64 > data.allocated)
7668d75effSDimitry Andric       return data.buf;
7768d75effSDimitry Andric     char *buf = internal_strdup(data.buf);
7868d75effSDimitry Andric     InternalFree(data.buf);
7968d75effSDimitry Andric     return buf;
8068d75effSDimitry Andric   }
8168d75effSDimitry Andric   if (data.buf)
8268d75effSDimitry Andric     InternalFree(data.buf);
8368d75effSDimitry Andric   return 0;
8468d75effSDimitry Andric }
8568d75effSDimitry Andric # endif  // SANITIZER_CP_DEMANGLE
8668d75effSDimitry Andric 
8768d75effSDimitry Andric struct SymbolizeCodeCallbackArg {
8868d75effSDimitry Andric   SymbolizedStack *first;
8968d75effSDimitry Andric   SymbolizedStack *last;
9068d75effSDimitry Andric   uptr frames_symbolized;
9168d75effSDimitry Andric 
9268d75effSDimitry Andric   AddressInfo *get_new_frame(uintptr_t addr) {
9368d75effSDimitry Andric     CHECK(last);
9468d75effSDimitry Andric     if (frames_symbolized > 0) {
9568d75effSDimitry Andric       SymbolizedStack *cur = SymbolizedStack::New(addr);
9668d75effSDimitry Andric       AddressInfo *info = &cur->info;
9768d75effSDimitry Andric       info->FillModuleInfo(first->info.module, first->info.module_offset,
9868d75effSDimitry Andric                            first->info.module_arch);
9968d75effSDimitry Andric       last->next = cur;
10068d75effSDimitry Andric       last = cur;
10168d75effSDimitry Andric     }
10268d75effSDimitry Andric     CHECK_EQ(addr, first->info.address);
10368d75effSDimitry Andric     CHECK_EQ(addr, last->info.address);
10468d75effSDimitry Andric     return &last->info;
10568d75effSDimitry Andric   }
10668d75effSDimitry Andric };
10768d75effSDimitry Andric 
10868d75effSDimitry Andric extern "C" {
10968d75effSDimitry Andric static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
11068d75effSDimitry Andric                                        const char *filename, int lineno,
11168d75effSDimitry Andric                                        const char *function) {
11268d75effSDimitry Andric   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
11368d75effSDimitry Andric   if (function) {
11468d75effSDimitry Andric     AddressInfo *info = cdata->get_new_frame(addr);
11568d75effSDimitry Andric     info->function = DemangleAlloc(function, /*always_alloc*/ true);
11668d75effSDimitry Andric     if (filename)
11768d75effSDimitry Andric       info->file = internal_strdup(filename);
11868d75effSDimitry Andric     info->line = lineno;
11968d75effSDimitry Andric     cdata->frames_symbolized++;
12068d75effSDimitry Andric   }
12168d75effSDimitry Andric   return 0;
12268d75effSDimitry Andric }
12368d75effSDimitry Andric 
12468d75effSDimitry Andric static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
12568d75effSDimitry Andric                                   const char *symname, uintptr_t, uintptr_t) {
12668d75effSDimitry Andric   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
12768d75effSDimitry Andric   if (symname) {
12868d75effSDimitry Andric     AddressInfo *info = cdata->get_new_frame(addr);
12968d75effSDimitry Andric     info->function = DemangleAlloc(symname, /*always_alloc*/ true);
13068d75effSDimitry Andric     cdata->frames_symbolized++;
13168d75effSDimitry Andric   }
13268d75effSDimitry Andric }
13368d75effSDimitry Andric 
13468d75effSDimitry Andric static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
13568d75effSDimitry Andric                                   uintptr_t symval, uintptr_t symsize) {
13668d75effSDimitry Andric   DataInfo *info = (DataInfo *)vdata;
13768d75effSDimitry Andric   if (symname && symval) {
13868d75effSDimitry Andric     info->name = DemangleAlloc(symname, /*always_alloc*/ true);
13968d75effSDimitry Andric     info->start = symval;
14068d75effSDimitry Andric     info->size = symsize;
14168d75effSDimitry Andric   }
14268d75effSDimitry Andric }
14368d75effSDimitry Andric 
14468d75effSDimitry Andric static void ErrorCallback(void *, const char *, int) {}
14568d75effSDimitry Andric }  // extern "C"
14668d75effSDimitry Andric 
14768d75effSDimitry Andric }  // namespace
14868d75effSDimitry Andric 
14968d75effSDimitry Andric LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
15068d75effSDimitry Andric   // State created in backtrace_create_state is leaked.
15168d75effSDimitry Andric   void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
15268d75effSDimitry Andric                                                 ErrorCallback, NULL));
15368d75effSDimitry Andric   if (!state)
15468d75effSDimitry Andric     return 0;
15568d75effSDimitry Andric   return new(*alloc) LibbacktraceSymbolizer(state);
15668d75effSDimitry Andric }
15768d75effSDimitry Andric 
15868d75effSDimitry Andric bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
15968d75effSDimitry Andric   SymbolizeCodeCallbackArg data;
16068d75effSDimitry Andric   data.first = stack;
16168d75effSDimitry Andric   data.last = stack;
16268d75effSDimitry Andric   data.frames_symbolized = 0;
16368d75effSDimitry Andric   backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
16468d75effSDimitry Andric                    ErrorCallback, &data);
16568d75effSDimitry Andric   if (data.frames_symbolized > 0)
16668d75effSDimitry Andric     return true;
16768d75effSDimitry Andric   backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
16868d75effSDimitry Andric                     ErrorCallback, &data);
16968d75effSDimitry Andric   return (data.frames_symbolized > 0);
17068d75effSDimitry Andric }
17168d75effSDimitry Andric 
17268d75effSDimitry Andric bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
17368d75effSDimitry Andric   backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback,
17468d75effSDimitry Andric                     ErrorCallback, info);
17568d75effSDimitry Andric   return true;
17668d75effSDimitry Andric }
17768d75effSDimitry Andric 
17868d75effSDimitry Andric #else  // SANITIZER_LIBBACKTRACE
17968d75effSDimitry Andric 
18068d75effSDimitry Andric LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
18168d75effSDimitry Andric   return 0;
18268d75effSDimitry Andric }
18368d75effSDimitry Andric 
18468d75effSDimitry Andric bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
18568d75effSDimitry Andric   (void)state_;
18668d75effSDimitry Andric   return false;
18768d75effSDimitry Andric }
18868d75effSDimitry Andric 
18968d75effSDimitry Andric bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
19068d75effSDimitry Andric   return false;
19168d75effSDimitry Andric }
19268d75effSDimitry Andric 
19368d75effSDimitry Andric #endif  // SANITIZER_LIBBACKTRACE
19468d75effSDimitry Andric 
19568d75effSDimitry Andric static char *DemangleAlloc(const char *name, bool always_alloc) {
19668d75effSDimitry Andric #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
19768d75effSDimitry Andric   if (char *demangled = CplusV3Demangle(name))
19868d75effSDimitry Andric     return demangled;
19968d75effSDimitry Andric #endif
20068d75effSDimitry Andric   if (always_alloc)
20168d75effSDimitry Andric     return internal_strdup(name);
202*5f757f3fSDimitry Andric   return nullptr;
20368d75effSDimitry Andric }
20468d75effSDimitry Andric 
20568d75effSDimitry Andric const char *LibbacktraceSymbolizer::Demangle(const char *name) {
20668d75effSDimitry Andric   return DemangleAlloc(name, /*always_alloc*/ false);
20768d75effSDimitry Andric }
20868d75effSDimitry Andric 
20968d75effSDimitry Andric }  // namespace __sanitizer
210