1353944Sdim//===-- sanitizer_symbolizer_markup.cpp -----------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is shared between various sanitizers' runtime libraries. 10353944Sdim// 11353944Sdim// Implementation of offline markup symbolizer. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "sanitizer_platform.h" 15353944Sdim#if SANITIZER_SYMBOLIZER_MARKUP 16353944Sdim 17353944Sdim#if SANITIZER_FUCHSIA 18353944Sdim#include "sanitizer_symbolizer_fuchsia.h" 19353944Sdim#elif SANITIZER_RTEMS 20353944Sdim#include "sanitizer_symbolizer_rtems.h" 21353944Sdim#endif 22353944Sdim#include "sanitizer_stacktrace.h" 23353944Sdim#include "sanitizer_symbolizer.h" 24353944Sdim 25353944Sdim#include <limits.h> 26353944Sdim#include <unwind.h> 27353944Sdim 28353944Sdimnamespace __sanitizer { 29353944Sdim 30353944Sdim// This generic support for offline symbolizing is based on the 31353944Sdim// Fuchsia port. We don't do any actual symbolization per se. 32353944Sdim// Instead, we emit text containing raw addresses and raw linkage 33353944Sdim// symbol names, embedded in Fuchsia's symbolization markup format. 34353944Sdim// Fuchsia's logging infrastructure emits enough information about 35353944Sdim// process memory layout that a post-processing filter can do the 36353944Sdim// symbolization and pretty-print the markup. See the spec at: 37353944Sdim// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md 38353944Sdim 39353944Sdim// This is used by UBSan for type names, and by ASan for global variable names. 40353944Sdim// It's expected to return a static buffer that will be reused on each call. 41353944Sdimconst char *Symbolizer::Demangle(const char *name) { 42353944Sdim static char buffer[kFormatDemangleMax]; 43353944Sdim internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); 44353944Sdim return buffer; 45353944Sdim} 46353944Sdim 47353944Sdim// This is used mostly for suppression matching. Making it work 48353944Sdim// would enable "interceptor_via_lib" suppressions. It's also used 49353944Sdim// once in UBSan to say "in module ..." in a message that also 50353944Sdim// includes an address in the module, so post-processing can already 51353944Sdim// pretty-print that so as to indicate the module. 52353944Sdimbool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, 53353944Sdim uptr *module_address) { 54353944Sdim return false; 55353944Sdim} 56353944Sdim 57353944Sdim// This is used in some places for suppression checking, which we 58353944Sdim// don't really support for Fuchsia. It's also used in UBSan to 59353944Sdim// identify a PC location to a function name, so we always fill in 60353944Sdim// the function member with a string containing markup around the PC 61353944Sdim// value. 62353944Sdim// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan 63353944Sdim// to render stack frames, but that should be changed to use 64353944Sdim// RenderStackFrame. 65353944SdimSymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { 66353944Sdim SymbolizedStack *s = SymbolizedStack::New(addr); 67353944Sdim char buffer[kFormatFunctionMax]; 68353944Sdim internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); 69353944Sdim s->info.function = internal_strdup(buffer); 70353944Sdim return s; 71353944Sdim} 72353944Sdim 73353944Sdim// Always claim we succeeded, so that RenderDataInfo will be called. 74353944Sdimbool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { 75353944Sdim info->Clear(); 76353944Sdim info->start = addr; 77353944Sdim return true; 78353944Sdim} 79353944Sdim 80353944Sdim// We ignore the format argument to __sanitizer_symbolize_global. 81353944Sdimvoid RenderData(InternalScopedString *buffer, const char *format, 82353944Sdim const DataInfo *DI, const char *strip_path_prefix) { 83353944Sdim buffer->append(kFormatData, DI->start); 84353944Sdim} 85353944Sdim 86353944Sdim// We don't support the stack_trace_format flag at all. 87353944Sdimvoid RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 88353944Sdim const AddressInfo &info, bool vs_style, 89353944Sdim const char *strip_path_prefix, const char *strip_func_prefix) { 90353944Sdim buffer->append(kFormatFrame, frame_no, info.address); 91353944Sdim} 92353944Sdim 93353944SdimSymbolizer *Symbolizer::PlatformInit() { 94353944Sdim return new (symbolizer_allocator_) Symbolizer({}); 95353944Sdim} 96353944Sdim 97353944Sdimvoid Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } 98353944Sdim 99353944Sdimvoid StartReportDeadlySignal() {} 100353944Sdimvoid ReportDeadlySignal(const SignalContext &sig, u32 tid, 101353944Sdim UnwindSignalStackCallbackType unwind, 102353944Sdim const void *unwind_context) {} 103353944Sdim 104353944Sdim#if SANITIZER_CAN_SLOW_UNWIND 105353944Sdimstruct UnwindTraceArg { 106353944Sdim BufferedStackTrace *stack; 107353944Sdim u32 max_depth; 108353944Sdim}; 109353944Sdim 110353944Sdim_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { 111353944Sdim UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); 112353944Sdim CHECK_LT(arg->stack->size, arg->max_depth); 113353944Sdim uptr pc = _Unwind_GetIP(ctx); 114353944Sdim if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; 115353944Sdim arg->stack->trace_buffer[arg->stack->size++] = pc; 116353944Sdim return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP 117353944Sdim : _URC_NO_REASON); 118353944Sdim} 119353944Sdim 120353944Sdimvoid BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { 121353944Sdim CHECK_GE(max_depth, 2); 122353944Sdim size = 0; 123353944Sdim UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; 124353944Sdim _Unwind_Backtrace(Unwind_Trace, &arg); 125353944Sdim CHECK_GT(size, 0); 126353944Sdim // We need to pop a few frames so that pc is on top. 127353944Sdim uptr to_pop = LocatePcInTrace(pc); 128353944Sdim // trace_buffer[0] belongs to the current function so we always pop it, 129353944Sdim // unless there is only 1 frame in the stack trace (1 frame is always better 130353944Sdim // than 0!). 131353944Sdim PopStackFrames(Min(to_pop, static_cast<uptr>(1))); 132353944Sdim trace_buffer[0] = pc; 133353944Sdim} 134353944Sdim 135353944Sdimvoid BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { 136353944Sdim CHECK(context); 137353944Sdim CHECK_GE(max_depth, 2); 138353944Sdim UNREACHABLE("signal context doesn't exist"); 139353944Sdim} 140353944Sdim#endif // SANITIZER_CAN_SLOW_UNWIND 141353944Sdim 142353944Sdim} // namespace __sanitizer 143353944Sdim 144353944Sdim#endif // SANITIZER_SYMBOLIZER_MARKUP 145