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_symbolizer.h"
27 namespace __sanitizer
{
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
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
);
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
) {
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; }
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
65 // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
66 // to render stack frames, but that should be changed to use
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
);
76 // Always claim we succeeded, so that RenderDataInfo will be called.
77 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
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
);
89 bool RenderNeedsSymbolization(const char *format
) { return false; }
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
, const char *strip_func_prefix
) {
95 CHECK(!RenderNeedsSymbolization(format
));
96 buffer
->append(kFormatFrame
, frame_no
, address
);
99 Symbolizer
*Symbolizer::PlatformInit() {
100 return new (symbolizer_allocator_
) Symbolizer({});
103 void Symbolizer::LateInitialize() {
104 Symbolizer::GetOrInit()->LateInitializeTools();
107 void StartReportDeadlySignal() {}
108 void ReportDeadlySignal(const SignalContext
&sig
, u32 tid
,
109 UnwindSignalStackCallbackType unwind
,
110 const void *unwind_context
) {}
112 #if SANITIZER_CAN_SLOW_UNWIND
113 struct UnwindTraceArg
{
114 BufferedStackTrace
*stack
;
118 _Unwind_Reason_Code
Unwind_Trace(struct _Unwind_Context
*ctx
, void *param
) {
119 UnwindTraceArg
*arg
= static_cast<UnwindTraceArg
*>(param
);
120 CHECK_LT(arg
->stack
->size
, arg
->max_depth
);
121 uptr pc
= _Unwind_GetIP(ctx
);
122 if (pc
< PAGE_SIZE
) return _URC_NORMAL_STOP
;
123 arg
->stack
->trace_buffer
[arg
->stack
->size
++] = pc
;
124 return (arg
->stack
->size
== arg
->max_depth
? _URC_NORMAL_STOP
128 void BufferedStackTrace::UnwindSlow(uptr pc
, u32 max_depth
) {
129 CHECK_GE(max_depth
, 2);
131 UnwindTraceArg arg
= {this, Min(max_depth
+ 1, kStackTraceMax
)};
132 _Unwind_Backtrace(Unwind_Trace
, &arg
);
134 // We need to pop a few frames so that pc is on top.
135 uptr to_pop
= LocatePcInTrace(pc
);
136 // trace_buffer[0] belongs to the current function so we always pop it,
137 // unless there is only 1 frame in the stack trace (1 frame is always better
139 PopStackFrames(Min(to_pop
, static_cast<uptr
>(1)));
140 trace_buffer
[0] = pc
;
143 void BufferedStackTrace::UnwindSlow(uptr pc
, void *context
, u32 max_depth
) {
145 CHECK_GE(max_depth
, 2);
146 UNREACHABLE("signal context doesn't exist");
148 #endif // SANITIZER_CAN_SLOW_UNWIND
150 } // namespace __sanitizer
152 #endif // SANITIZER_SYMBOLIZER_MARKUP