1*3cab2bb3Spatrick //===-- sanitizer_symbolizer_libbacktrace.cpp -----------------------------===//
2*3cab2bb3Spatrick //
3*3cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick //
7*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick //
9*3cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
10*3cab2bb3Spatrick // run-time libraries.
11*3cab2bb3Spatrick // Libbacktrace implementation of symbolizer parts.
12*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
13*3cab2bb3Spatrick 
14*3cab2bb3Spatrick #include "sanitizer_platform.h"
15*3cab2bb3Spatrick 
16*3cab2bb3Spatrick #include "sanitizer_internal_defs.h"
17*3cab2bb3Spatrick #include "sanitizer_symbolizer.h"
18*3cab2bb3Spatrick #include "sanitizer_symbolizer_libbacktrace.h"
19*3cab2bb3Spatrick 
20*3cab2bb3Spatrick #if SANITIZER_LIBBACKTRACE
21*3cab2bb3Spatrick # include "backtrace-supported.h"
22*3cab2bb3Spatrick # if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
23*3cab2bb3Spatrick #  include "backtrace.h"
24*3cab2bb3Spatrick #  if SANITIZER_CP_DEMANGLE
25*3cab2bb3Spatrick #   undef ARRAY_SIZE
26*3cab2bb3Spatrick #   include "demangle.h"
27*3cab2bb3Spatrick #  endif
28*3cab2bb3Spatrick # else
29*3cab2bb3Spatrick #  define SANITIZER_LIBBACKTRACE 0
30*3cab2bb3Spatrick # endif
31*3cab2bb3Spatrick #endif
32*3cab2bb3Spatrick 
33*3cab2bb3Spatrick namespace __sanitizer {
34*3cab2bb3Spatrick 
35*3cab2bb3Spatrick static char *DemangleAlloc(const char *name, bool always_alloc);
36*3cab2bb3Spatrick 
37*3cab2bb3Spatrick #if SANITIZER_LIBBACKTRACE
38*3cab2bb3Spatrick 
39*3cab2bb3Spatrick namespace {
40*3cab2bb3Spatrick 
41*3cab2bb3Spatrick # if SANITIZER_CP_DEMANGLE
42*3cab2bb3Spatrick struct CplusV3DemangleData {
43*3cab2bb3Spatrick   char *buf;
44*3cab2bb3Spatrick   uptr size, allocated;
45*3cab2bb3Spatrick };
46*3cab2bb3Spatrick 
47*3cab2bb3Spatrick extern "C" {
CplusV3DemangleCallback(const char * s,size_t l,void * vdata)48*3cab2bb3Spatrick static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
49*3cab2bb3Spatrick   CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
50*3cab2bb3Spatrick   uptr needed = data->size + l + 1;
51*3cab2bb3Spatrick   if (needed > data->allocated) {
52*3cab2bb3Spatrick     data->allocated *= 2;
53*3cab2bb3Spatrick     if (needed > data->allocated)
54*3cab2bb3Spatrick       data->allocated = needed;
55*3cab2bb3Spatrick     char *buf = (char *)InternalAlloc(data->allocated);
56*3cab2bb3Spatrick     if (data->buf) {
57*3cab2bb3Spatrick       internal_memcpy(buf, data->buf, data->size);
58*3cab2bb3Spatrick       InternalFree(data->buf);
59*3cab2bb3Spatrick     }
60*3cab2bb3Spatrick     data->buf = buf;
61*3cab2bb3Spatrick   }
62*3cab2bb3Spatrick   internal_memcpy(data->buf + data->size, s, l);
63*3cab2bb3Spatrick   data->buf[data->size + l] = '\0';
64*3cab2bb3Spatrick   data->size += l;
65*3cab2bb3Spatrick }
66*3cab2bb3Spatrick }  // extern "C"
67*3cab2bb3Spatrick 
CplusV3Demangle(const char * name)68*3cab2bb3Spatrick char *CplusV3Demangle(const char *name) {
69*3cab2bb3Spatrick   CplusV3DemangleData data;
70*3cab2bb3Spatrick   data.buf = 0;
71*3cab2bb3Spatrick   data.size = 0;
72*3cab2bb3Spatrick   data.allocated = 0;
73*3cab2bb3Spatrick   if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
74*3cab2bb3Spatrick                                  CplusV3DemangleCallback, &data)) {
75*3cab2bb3Spatrick     if (data.size + 64 > data.allocated)
76*3cab2bb3Spatrick       return data.buf;
77*3cab2bb3Spatrick     char *buf = internal_strdup(data.buf);
78*3cab2bb3Spatrick     InternalFree(data.buf);
79*3cab2bb3Spatrick     return buf;
80*3cab2bb3Spatrick   }
81*3cab2bb3Spatrick   if (data.buf)
82*3cab2bb3Spatrick     InternalFree(data.buf);
83*3cab2bb3Spatrick   return 0;
84*3cab2bb3Spatrick }
85*3cab2bb3Spatrick # endif  // SANITIZER_CP_DEMANGLE
86*3cab2bb3Spatrick 
87*3cab2bb3Spatrick struct SymbolizeCodeCallbackArg {
88*3cab2bb3Spatrick   SymbolizedStack *first;
89*3cab2bb3Spatrick   SymbolizedStack *last;
90*3cab2bb3Spatrick   uptr frames_symbolized;
91*3cab2bb3Spatrick 
get_new_frame__sanitizer::__anon9316d81e0111::SymbolizeCodeCallbackArg92*3cab2bb3Spatrick   AddressInfo *get_new_frame(uintptr_t addr) {
93*3cab2bb3Spatrick     CHECK(last);
94*3cab2bb3Spatrick     if (frames_symbolized > 0) {
95*3cab2bb3Spatrick       SymbolizedStack *cur = SymbolizedStack::New(addr);
96*3cab2bb3Spatrick       AddressInfo *info = &cur->info;
97*3cab2bb3Spatrick       info->FillModuleInfo(first->info.module, first->info.module_offset,
98*3cab2bb3Spatrick                            first->info.module_arch);
99*3cab2bb3Spatrick       last->next = cur;
100*3cab2bb3Spatrick       last = cur;
101*3cab2bb3Spatrick     }
102*3cab2bb3Spatrick     CHECK_EQ(addr, first->info.address);
103*3cab2bb3Spatrick     CHECK_EQ(addr, last->info.address);
104*3cab2bb3Spatrick     return &last->info;
105*3cab2bb3Spatrick   }
106*3cab2bb3Spatrick };
107*3cab2bb3Spatrick 
108*3cab2bb3Spatrick extern "C" {
SymbolizeCodePCInfoCallback(void * vdata,uintptr_t addr,const char * filename,int lineno,const char * function)109*3cab2bb3Spatrick static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
110*3cab2bb3Spatrick                                        const char *filename, int lineno,
111*3cab2bb3Spatrick                                        const char *function) {
112*3cab2bb3Spatrick   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
113*3cab2bb3Spatrick   if (function) {
114*3cab2bb3Spatrick     AddressInfo *info = cdata->get_new_frame(addr);
115*3cab2bb3Spatrick     info->function = DemangleAlloc(function, /*always_alloc*/ true);
116*3cab2bb3Spatrick     if (filename)
117*3cab2bb3Spatrick       info->file = internal_strdup(filename);
118*3cab2bb3Spatrick     info->line = lineno;
119*3cab2bb3Spatrick     cdata->frames_symbolized++;
120*3cab2bb3Spatrick   }
121*3cab2bb3Spatrick   return 0;
122*3cab2bb3Spatrick }
123*3cab2bb3Spatrick 
SymbolizeCodeCallback(void * vdata,uintptr_t addr,const char * symname,uintptr_t,uintptr_t)124*3cab2bb3Spatrick static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
125*3cab2bb3Spatrick                                   const char *symname, uintptr_t, uintptr_t) {
126*3cab2bb3Spatrick   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
127*3cab2bb3Spatrick   if (symname) {
128*3cab2bb3Spatrick     AddressInfo *info = cdata->get_new_frame(addr);
129*3cab2bb3Spatrick     info->function = DemangleAlloc(symname, /*always_alloc*/ true);
130*3cab2bb3Spatrick     cdata->frames_symbolized++;
131*3cab2bb3Spatrick   }
132*3cab2bb3Spatrick }
133*3cab2bb3Spatrick 
SymbolizeDataCallback(void * vdata,uintptr_t,const char * symname,uintptr_t symval,uintptr_t symsize)134*3cab2bb3Spatrick static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
135*3cab2bb3Spatrick                                   uintptr_t symval, uintptr_t symsize) {
136*3cab2bb3Spatrick   DataInfo *info = (DataInfo *)vdata;
137*3cab2bb3Spatrick   if (symname && symval) {
138*3cab2bb3Spatrick     info->name = DemangleAlloc(symname, /*always_alloc*/ true);
139*3cab2bb3Spatrick     info->start = symval;
140*3cab2bb3Spatrick     info->size = symsize;
141*3cab2bb3Spatrick   }
142*3cab2bb3Spatrick }
143*3cab2bb3Spatrick 
ErrorCallback(void *,const char *,int)144*3cab2bb3Spatrick static void ErrorCallback(void *, const char *, int) {}
145*3cab2bb3Spatrick }  // extern "C"
146*3cab2bb3Spatrick 
147*3cab2bb3Spatrick }  // namespace
148*3cab2bb3Spatrick 
get(LowLevelAllocator * alloc)149*3cab2bb3Spatrick LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
150*3cab2bb3Spatrick   // State created in backtrace_create_state is leaked.
151*3cab2bb3Spatrick   void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
152*3cab2bb3Spatrick                                                 ErrorCallback, NULL));
153*3cab2bb3Spatrick   if (!state)
154*3cab2bb3Spatrick     return 0;
155*3cab2bb3Spatrick   return new(*alloc) LibbacktraceSymbolizer(state);
156*3cab2bb3Spatrick }
157*3cab2bb3Spatrick 
SymbolizePC(uptr addr,SymbolizedStack * stack)158*3cab2bb3Spatrick bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
159*3cab2bb3Spatrick   SymbolizeCodeCallbackArg data;
160*3cab2bb3Spatrick   data.first = stack;
161*3cab2bb3Spatrick   data.last = stack;
162*3cab2bb3Spatrick   data.frames_symbolized = 0;
163*3cab2bb3Spatrick   backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
164*3cab2bb3Spatrick                    ErrorCallback, &data);
165*3cab2bb3Spatrick   if (data.frames_symbolized > 0)
166*3cab2bb3Spatrick     return true;
167*3cab2bb3Spatrick   backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
168*3cab2bb3Spatrick                     ErrorCallback, &data);
169*3cab2bb3Spatrick   return (data.frames_symbolized > 0);
170*3cab2bb3Spatrick }
171*3cab2bb3Spatrick 
SymbolizeData(uptr addr,DataInfo * info)172*3cab2bb3Spatrick bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
173*3cab2bb3Spatrick   backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback,
174*3cab2bb3Spatrick                     ErrorCallback, info);
175*3cab2bb3Spatrick   return true;
176*3cab2bb3Spatrick }
177*3cab2bb3Spatrick 
178*3cab2bb3Spatrick #else  // SANITIZER_LIBBACKTRACE
179*3cab2bb3Spatrick 
get(LowLevelAllocator * alloc)180*3cab2bb3Spatrick LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
181*3cab2bb3Spatrick   return 0;
182*3cab2bb3Spatrick }
183*3cab2bb3Spatrick 
SymbolizePC(uptr addr,SymbolizedStack * stack)184*3cab2bb3Spatrick bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
185*3cab2bb3Spatrick   (void)state_;
186*3cab2bb3Spatrick   return false;
187*3cab2bb3Spatrick }
188*3cab2bb3Spatrick 
SymbolizeData(uptr addr,DataInfo * info)189*3cab2bb3Spatrick bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
190*3cab2bb3Spatrick   return false;
191*3cab2bb3Spatrick }
192*3cab2bb3Spatrick 
193*3cab2bb3Spatrick #endif  // SANITIZER_LIBBACKTRACE
194*3cab2bb3Spatrick 
DemangleAlloc(const char * name,bool always_alloc)195*3cab2bb3Spatrick static char *DemangleAlloc(const char *name, bool always_alloc) {
196*3cab2bb3Spatrick #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
197*3cab2bb3Spatrick   if (char *demangled = CplusV3Demangle(name))
198*3cab2bb3Spatrick     return demangled;
199*3cab2bb3Spatrick #endif
200*3cab2bb3Spatrick   if (always_alloc)
201*3cab2bb3Spatrick     return internal_strdup(name);
202*3cab2bb3Spatrick   return 0;
203*3cab2bb3Spatrick }
204*3cab2bb3Spatrick 
Demangle(const char * name)205*3cab2bb3Spatrick const char *LibbacktraceSymbolizer::Demangle(const char *name) {
206*3cab2bb3Spatrick   return DemangleAlloc(name, /*always_alloc*/ false);
207*3cab2bb3Spatrick }
208*3cab2bb3Spatrick 
209*3cab2bb3Spatrick }  // namespace __sanitizer
210