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