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 29 namespace __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. 42 const 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. 53 bool 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. 66 SymbolizedStack *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. 75 bool 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. 82 void 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. 88 void 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 94 Symbolizer *Symbolizer::PlatformInit() { 95 return new (symbolizer_allocator_) Symbolizer({}); 96 } 97 98 void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } 99 100 void StartReportDeadlySignal() {} 101 void ReportDeadlySignal(const SignalContext &sig, u32 tid, 102 UnwindSignalStackCallbackType unwind, 103 const void *unwind_context) {} 104 105 #if SANITIZER_CAN_SLOW_UNWIND 106 struct 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 121 void 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 136 void 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