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 27 namespace __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. 40 const 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. 51 bool 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. 58 bool 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. 68 SymbolizedStack *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. 77 bool 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. 84 void RenderData(InternalScopedString *buffer, const char *format, 85 const DataInfo *DI, const char *strip_path_prefix) { 86 buffer->append(kFormatData, DI->start); 87 } 88 89 bool RenderNeedsSymbolization(const char *format) { return false; } 90 91 // We don't support the stack_trace_format flag at all. 92 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 93 uptr address, const AddressInfo *info, bool vs_style, 94 const char *strip_path_prefix) { 95 CHECK(!RenderNeedsSymbolization(format)); 96 buffer->append(kFormatFrame, frame_no, address); 97 } 98 99 Symbolizer *Symbolizer::PlatformInit() { 100 return new (symbolizer_allocator_) Symbolizer({}); 101 } 102 103 void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } 104 105 void StartReportDeadlySignal() {} 106 void ReportDeadlySignal(const SignalContext &sig, u32 tid, 107 UnwindSignalStackCallbackType unwind, 108 const void *unwind_context) {} 109 110 #if SANITIZER_CAN_SLOW_UNWIND 111 struct UnwindTraceArg { 112 BufferedStackTrace *stack; 113 u32 max_depth; 114 }; 115 116 _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { 117 UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); 118 CHECK_LT(arg->stack->size, arg->max_depth); 119 uptr pc = _Unwind_GetIP(ctx); 120 if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; 121 arg->stack->trace_buffer[arg->stack->size++] = pc; 122 return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP 123 : _URC_NO_REASON); 124 } 125 126 void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { 127 CHECK_GE(max_depth, 2); 128 size = 0; 129 UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; 130 _Unwind_Backtrace(Unwind_Trace, &arg); 131 CHECK_GT(size, 0); 132 // We need to pop a few frames so that pc is on top. 133 uptr to_pop = LocatePcInTrace(pc); 134 // trace_buffer[0] belongs to the current function so we always pop it, 135 // unless there is only 1 frame in the stack trace (1 frame is always better 136 // than 0!). 137 PopStackFrames(Min(to_pop, static_cast<uptr>(1))); 138 trace_buffer[0] = pc; 139 } 140 141 void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { 142 CHECK(context); 143 CHECK_GE(max_depth, 2); 144 UNREACHABLE("signal context doesn't exist"); 145 } 146 #endif // SANITIZER_CAN_SLOW_UNWIND 147 148 } // namespace __sanitizer 149 150 #endif // SANITIZER_SYMBOLIZER_MARKUP 151