1 //===-- sanitizer_symbolizer_markup.cpp -----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between various sanitizers' runtime libraries.
11 // Implementation of offline markup symbolizer.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_platform.h"
15 #if SANITIZER_SYMBOLIZER_MARKUP
18 #include "sanitizer_symbolizer_fuchsia.h"
24 # include "sanitizer_stacktrace.h"
25 # include "sanitizer_stacktrace_printer.h"
26 # include "sanitizer_symbolizer.h"
28 namespace __sanitizer
{
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
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
);
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
) {
57 // This is mainly used by hwasan for online symbolization. This isn't needed
58 // since hwasan can always just dump stack frames for offline symbolization.
59 bool Symbolizer::SymbolizeFrame(uptr addr
, FrameInfo
*info
) { return false; }
61 // This is used in some places for suppression checking, which we
62 // don't really support for Fuchsia. It's also used in UBSan to
63 // identify a PC location to a function name, so we always fill in
64 // the function member with a string containing markup around the PC
66 // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
67 // to render stack frames, but that should be changed to use
69 SymbolizedStack
*Symbolizer::SymbolizePC(uptr addr
) {
70 SymbolizedStack
*s
= SymbolizedStack::New(addr
);
71 char buffer
[kFormatFunctionMax
];
72 internal_snprintf(buffer
, sizeof(buffer
), kFormatFunction
, addr
);
73 s
->info
.function
= internal_strdup(buffer
);
77 // Always claim we succeeded, so that RenderDataInfo will be called.
78 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
84 // We ignore the format argument to __sanitizer_symbolize_global.
85 void FormattedStackTracePrinter::RenderData(InternalScopedString
*buffer
,
88 const char *strip_path_prefix
) {
89 buffer
->AppendF(kFormatData
, DI
->start
);
92 bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format
) {
96 // We don't support the stack_trace_format flag at all.
97 void FormattedStackTracePrinter::RenderFrame(InternalScopedString
*buffer
,
98 const char *format
, int frame_no
,
100 const AddressInfo
*info
,
102 const char *strip_path_prefix
) {
103 CHECK(!RenderNeedsSymbolization(format
));
104 buffer
->AppendF(kFormatFrame
, frame_no
, address
);
107 Symbolizer
*Symbolizer::PlatformInit() {
108 return new (symbolizer_allocator_
) Symbolizer({});
111 void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
113 void StartReportDeadlySignal() {}
114 void ReportDeadlySignal(const SignalContext
&sig
, u32 tid
,
115 UnwindSignalStackCallbackType unwind
,
116 const void *unwind_context
) {}
118 #if SANITIZER_CAN_SLOW_UNWIND
119 struct UnwindTraceArg
{
120 BufferedStackTrace
*stack
;
124 _Unwind_Reason_Code
Unwind_Trace(struct _Unwind_Context
*ctx
, void *param
) {
125 UnwindTraceArg
*arg
= static_cast<UnwindTraceArg
*>(param
);
126 CHECK_LT(arg
->stack
->size
, arg
->max_depth
);
127 uptr pc
= _Unwind_GetIP(ctx
);
128 if (pc
< PAGE_SIZE
) return _URC_NORMAL_STOP
;
129 arg
->stack
->trace_buffer
[arg
->stack
->size
++] = pc
;
130 return (arg
->stack
->size
== arg
->max_depth
? _URC_NORMAL_STOP
134 void BufferedStackTrace::UnwindSlow(uptr pc
, u32 max_depth
) {
135 CHECK_GE(max_depth
, 2);
137 UnwindTraceArg arg
= {this, Min(max_depth
+ 1, kStackTraceMax
)};
138 _Unwind_Backtrace(Unwind_Trace
, &arg
);
140 // We need to pop a few frames so that pc is on top.
141 uptr to_pop
= LocatePcInTrace(pc
);
142 // trace_buffer[0] belongs to the current function so we always pop it,
143 // unless there is only 1 frame in the stack trace (1 frame is always better
145 PopStackFrames(Min(to_pop
, static_cast<uptr
>(1)));
146 trace_buffer
[0] = pc
;
149 void BufferedStackTrace::UnwindSlow(uptr pc
, void *context
, u32 max_depth
) {
151 CHECK_GE(max_depth
, 2);
152 UNREACHABLE("signal context doesn't exist");
154 #endif // SANITIZER_CAN_SLOW_UNWIND
156 } // namespace __sanitizer
158 #endif // SANITIZER_SYMBOLIZER_MARKUP