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