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