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