1 //===-- sanitizer_symbolizer_libbacktrace.cpp -----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 // Libbacktrace implementation of symbolizer parts.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_platform.h"
16 #include "sanitizer_internal_defs.h"
17 #include "sanitizer_symbolizer.h"
18 #include "sanitizer_symbolizer_libbacktrace.h"
20 #if SANITIZER_LIBBACKTRACE
21 # include "backtrace-supported.h"
22 # if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
23 # include "backtrace.h"
24 # if SANITIZER_CP_DEMANGLE
26 # include "demangle.h"
29 # define SANITIZER_LIBBACKTRACE 0
33 namespace __sanitizer
{
35 static char *DemangleAlloc(const char *name
, bool always_alloc
);
37 #if SANITIZER_LIBBACKTRACE
41 # if SANITIZER_CP_DEMANGLE
42 struct CplusV3DemangleData
{
48 static void CplusV3DemangleCallback(const char *s
, size_t l
, void *vdata
) {
49 CplusV3DemangleData
*data
= (CplusV3DemangleData
*)vdata
;
50 uptr needed
= data
->size
+ l
+ 1;
51 if (needed
> data
->allocated
) {
53 if (needed
> data
->allocated
)
54 data
->allocated
= needed
;
55 char *buf
= (char *)InternalAlloc(data
->allocated
);
57 internal_memcpy(buf
, data
->buf
, data
->size
);
58 InternalFree(data
->buf
);
62 internal_memcpy(data
->buf
+ data
->size
, s
, l
);
63 data
->buf
[data
->size
+ l
] = '\0';
68 char *CplusV3Demangle(const char *name
) {
69 CplusV3DemangleData data
;
73 if (cplus_demangle_v3_callback(name
, DMGL_PARAMS
| DMGL_ANSI
,
74 CplusV3DemangleCallback
, &data
)) {
75 if (data
.size
+ 64 > data
.allocated
)
77 char *buf
= internal_strdup(data
.buf
);
78 InternalFree(data
.buf
);
82 InternalFree(data
.buf
);
85 # endif // SANITIZER_CP_DEMANGLE
87 struct SymbolizeCodeCallbackArg
{
88 SymbolizedStack
*first
;
89 SymbolizedStack
*last
;
90 uptr frames_symbolized
;
92 AddressInfo
*get_new_frame(uintptr_t addr
) {
94 if (frames_symbolized
> 0) {
95 SymbolizedStack
*cur
= SymbolizedStack::New(addr
);
96 AddressInfo
*info
= &cur
->info
;
97 info
->FillModuleInfo(first
->info
.module
, first
->info
.module_offset
,
98 first
->info
.module_arch
);
102 CHECK_EQ(addr
, first
->info
.address
);
103 CHECK_EQ(addr
, last
->info
.address
);
109 static int SymbolizeCodePCInfoCallback(void *vdata
, uintptr_t addr
,
110 const char *filename
, int lineno
,
111 const char *function
) {
112 SymbolizeCodeCallbackArg
*cdata
= (SymbolizeCodeCallbackArg
*)vdata
;
114 AddressInfo
*info
= cdata
->get_new_frame(addr
);
115 info
->function
= DemangleAlloc(function
, /*always_alloc*/ true);
117 info
->file
= internal_strdup(filename
);
119 cdata
->frames_symbolized
++;
124 static void SymbolizeCodeCallback(void *vdata
, uintptr_t addr
,
125 const char *symname
, uintptr_t, uintptr_t) {
126 SymbolizeCodeCallbackArg
*cdata
= (SymbolizeCodeCallbackArg
*)vdata
;
128 AddressInfo
*info
= cdata
->get_new_frame(addr
);
129 info
->function
= DemangleAlloc(symname
, /*always_alloc*/ true);
130 cdata
->frames_symbolized
++;
134 static void SymbolizeDataCallback(void *vdata
, uintptr_t, const char *symname
,
135 uintptr_t symval
, uintptr_t symsize
) {
136 DataInfo
*info
= (DataInfo
*)vdata
;
137 if (symname
&& symval
) {
138 info
->name
= DemangleAlloc(symname
, /*always_alloc*/ true);
139 info
->start
= symval
;
140 info
->size
= symsize
;
144 static void ErrorCallback(void *, const char *, int) {}
149 LibbacktraceSymbolizer
*LibbacktraceSymbolizer::get(LowLevelAllocator
*alloc
) {
150 // State created in backtrace_create_state is leaked.
151 void *state
= (void *)(backtrace_create_state("/proc/self/exe", 0,
152 ErrorCallback
, NULL
));
155 return new(*alloc
) LibbacktraceSymbolizer(state
);
158 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
159 SymbolizeCodeCallbackArg data
;
162 data
.frames_symbolized
= 0;
163 backtrace_pcinfo((backtrace_state
*)state_
, addr
, SymbolizeCodePCInfoCallback
,
164 ErrorCallback
, &data
);
165 if (data
.frames_symbolized
> 0)
167 backtrace_syminfo((backtrace_state
*)state_
, addr
, SymbolizeCodeCallback
,
168 ErrorCallback
, &data
);
169 return (data
.frames_symbolized
> 0);
172 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
173 backtrace_syminfo((backtrace_state
*)state_
, addr
, SymbolizeDataCallback
,
174 ErrorCallback
, info
);
178 #else // SANITIZER_LIBBACKTRACE
180 LibbacktraceSymbolizer
*LibbacktraceSymbolizer::get(LowLevelAllocator
*alloc
) {
184 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
189 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
193 #endif // SANITIZER_LIBBACKTRACE
195 static char *DemangleAlloc(const char *name
, bool always_alloc
) {
196 #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
197 if (char *demangled
= CplusV3Demangle(name
))
201 return internal_strdup(name
);
205 const char *LibbacktraceSymbolizer::Demangle(const char *name
) {
206 return DemangleAlloc(name
, /*always_alloc*/ false);
209 } // namespace __sanitizer