1//===-- sanitizer_symbolizer_markup.cpp -----------------------------------===// 2// 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 6// 7//===----------------------------------------------------------------------===// 8// 9// This file is shared between various sanitizers' runtime libraries. 10// 11// Implementation of offline markup symbolizer. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_platform.h" 15#if SANITIZER_SYMBOLIZER_MARKUP 16 17#if SANITIZER_FUCHSIA 18#include "sanitizer_symbolizer_fuchsia.h" 19# endif 20 21# include <limits.h> 22# include <unwind.h> 23 24# include "sanitizer_stacktrace.h" 25# include "sanitizer_symbolizer.h" 26 27namespace __sanitizer { 28 29// This generic support for offline symbolizing is based on the 30// Fuchsia port. We don't do any actual symbolization per se. 31// Instead, we emit text containing raw addresses and raw linkage 32// symbol names, embedded in Fuchsia's symbolization markup format. 33// Fuchsia's logging infrastructure emits enough information about 34// process memory layout that a post-processing filter can do the 35// symbolization and pretty-print the markup. See the spec at: 36// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md 37 38// This is used by UBSan for type names, and by ASan for global variable names. 39// It's expected to return a static buffer that will be reused on each call. 40const char *Symbolizer::Demangle(const char *name) { 41 static char buffer[kFormatDemangleMax]; 42 internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); 43 return buffer; 44} 45 46// This is used mostly for suppression matching. Making it work 47// would enable "interceptor_via_lib" suppressions. It's also used 48// once in UBSan to say "in module ..." in a message that also 49// includes an address in the module, so post-processing can already 50// pretty-print that so as to indicate the module. 51bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, 52 uptr *module_address) { 53 return false; 54} 55 56// This is mainly used by hwasan for online symbolization. This isn't needed 57// since hwasan can always just dump stack frames for offline symbolization. 58bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; } 59 60// This is used in some places for suppression checking, which we 61// don't really support for Fuchsia. It's also used in UBSan to 62// identify a PC location to a function name, so we always fill in 63// the function member with a string containing markup around the PC 64// value. 65// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan 66// to render stack frames, but that should be changed to use 67// RenderStackFrame. 68SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { 69 SymbolizedStack *s = SymbolizedStack::New(addr); 70 char buffer[kFormatFunctionMax]; 71 internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); 72 s->info.function = internal_strdup(buffer); 73 return s; 74} 75 76// Always claim we succeeded, so that RenderDataInfo will be called. 77bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { 78 info->Clear(); 79 info->start = addr; 80 return true; 81} 82 83// We ignore the format argument to __sanitizer_symbolize_global. 84void RenderData(InternalScopedString *buffer, const char *format, 85 const DataInfo *DI, const char *strip_path_prefix) { 86 buffer->append(kFormatData, DI->start); 87} 88 89bool RenderNeedsSymbolization(const char *format) { return false; } 90 91// We don't support the stack_trace_format flag at all. 92void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 93 uptr address, const AddressInfo *info, bool vs_style, 94 const char *strip_path_prefix, const char *strip_func_prefix) { 95 CHECK(!RenderNeedsSymbolization(format)); 96 buffer->append(kFormatFrame, frame_no, address); 97} 98 99Symbolizer *Symbolizer::PlatformInit() { 100 return new (symbolizer_allocator_) Symbolizer({}); 101} 102 103void Symbolizer::LateInitialize() { 104 Symbolizer::GetOrInit()->LateInitializeTools(); 105} 106 107void StartReportDeadlySignal() {} 108void ReportDeadlySignal(const SignalContext &sig, u32 tid, 109 UnwindSignalStackCallbackType unwind, 110 const void *unwind_context) {} 111 112#if SANITIZER_CAN_SLOW_UNWIND 113struct UnwindTraceArg { 114 BufferedStackTrace *stack; 115 u32 max_depth; 116}; 117 118_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { 119 UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); 120 CHECK_LT(arg->stack->size, arg->max_depth); 121 uptr pc = _Unwind_GetIP(ctx); 122 if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; 123 arg->stack->trace_buffer[arg->stack->size++] = pc; 124 return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP 125 : _URC_NO_REASON); 126} 127 128void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { 129 CHECK_GE(max_depth, 2); 130 size = 0; 131 UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; 132 _Unwind_Backtrace(Unwind_Trace, &arg); 133 CHECK_GT(size, 0); 134 // We need to pop a few frames so that pc is on top. 135 uptr to_pop = LocatePcInTrace(pc); 136 // trace_buffer[0] belongs to the current function so we always pop it, 137 // unless there is only 1 frame in the stack trace (1 frame is always better 138 // than 0!). 139 PopStackFrames(Min(to_pop, static_cast<uptr>(1))); 140 trace_buffer[0] = pc; 141} 142 143void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { 144 CHECK(context); 145 CHECK_GE(max_depth, 2); 146 UNREACHABLE("signal context doesn't exist"); 147} 148#endif // SANITIZER_CAN_SLOW_UNWIND 149 150} // namespace __sanitizer 151 152#endif // SANITIZER_SYMBOLIZER_MARKUP 153