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