1//===-- sanitizer_symbolizer_markup.cc ------------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is shared between various sanitizers' runtime libraries. 9// 10// Implementation of offline markup symbolizer. 11//===----------------------------------------------------------------------===// 12 13#include "sanitizer_platform.h" 14#if SANITIZER_SYMBOLIZER_MARKUP 15 16#if SANITIZER_FUCHSIA 17#include "sanitizer_symbolizer_fuchsia.h" 18#elif SANITIZER_RTEMS 19#include "sanitizer_symbolizer_rtems.h" 20#endif 21#include "sanitizer_stacktrace.h" 22#include "sanitizer_symbolizer.h" 23 24#include <limits.h> 25#include <unwind.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 used in some places for suppression checking, which we 57// don't really support for Fuchsia. It's also used in UBSan to 58// identify a PC location to a function name, so we always fill in 59// the function member with a string containing markup around the PC 60// value. 61// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan 62// to render stack frames, but that should be changed to use 63// RenderStackFrame. 64SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { 65 SymbolizedStack *s = SymbolizedStack::New(addr); 66 char buffer[kFormatFunctionMax]; 67 internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); 68 s->info.function = internal_strdup(buffer); 69 return s; 70} 71 72// Always claim we succeeded, so that RenderDataInfo will be called. 73bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { 74 info->Clear(); 75 info->start = addr; 76 return true; 77} 78 79// We ignore the format argument to __sanitizer_symbolize_global. 80void RenderData(InternalScopedString *buffer, const char *format, 81 const DataInfo *DI, const char *strip_path_prefix) { 82 buffer->append(kFormatData, DI->start); 83} 84 85// We don't support the stack_trace_format flag at all. 86void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 87 const AddressInfo &info, bool vs_style, 88 const char *strip_path_prefix, const char *strip_func_prefix) { 89 buffer->append(kFormatFrame, frame_no, info.address); 90} 91 92Symbolizer *Symbolizer::PlatformInit() { 93 return new (symbolizer_allocator_) Symbolizer({}); 94} 95 96void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } 97 98void StartReportDeadlySignal() {} 99void ReportDeadlySignal(const SignalContext &sig, u32 tid, 100 UnwindSignalStackCallbackType unwind, 101 const void *unwind_context) {} 102 103#if SANITIZER_CAN_SLOW_UNWIND 104struct UnwindTraceArg { 105 BufferedStackTrace *stack; 106 u32 max_depth; 107}; 108 109_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { 110 UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); 111 CHECK_LT(arg->stack->size, arg->max_depth); 112 uptr pc = _Unwind_GetIP(ctx); 113 if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; 114 arg->stack->trace_buffer[arg->stack->size++] = pc; 115 return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP 116 : _URC_NO_REASON); 117} 118 119void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { 120 CHECK_GE(max_depth, 2); 121 size = 0; 122 UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; 123 _Unwind_Backtrace(Unwind_Trace, &arg); 124 CHECK_GT(size, 0); 125 // We need to pop a few frames so that pc is on top. 126 uptr to_pop = LocatePcInTrace(pc); 127 // trace_buffer[0] belongs to the current function so we always pop it, 128 // unless there is only 1 frame in the stack trace (1 frame is always better 129 // than 0!). 130 PopStackFrames(Min(to_pop, static_cast<uptr>(1))); 131 trace_buffer[0] = pc; 132} 133 134void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, 135 u32 max_depth) { 136 CHECK_NE(context, nullptr); 137 UNREACHABLE("signal context doesn't exist"); 138} 139#endif // SANITIZER_CAN_SLOW_UNWIND 140 141} // namespace __sanitizer 142 143#endif // SANITIZER_SYMBOLIZER_MARKUP 144