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"
20 #include "sanitizer_symbolizer_rtems.h"
22 #include "sanitizer_stacktrace.h"
23 #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 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
62 // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
63 // to render stack frames, but that should be changed to use
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
);
73 // Always claim we succeeded, so that RenderDataInfo will be called.
74 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
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
);
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
);
93 Symbolizer
*Symbolizer::PlatformInit() {
94 return new (symbolizer_allocator_
) Symbolizer({});
97 void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
99 void StartReportDeadlySignal() {}
100 void ReportDeadlySignal(const SignalContext
&sig
, u32 tid
,
101 UnwindSignalStackCallbackType unwind
,
102 const void *unwind_context
) {}
104 #if SANITIZER_CAN_SLOW_UNWIND
105 struct UnwindTraceArg
{
106 BufferedStackTrace
*stack
;
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
120 void BufferedStackTrace::UnwindSlow(uptr pc
, u32 max_depth
) {
121 CHECK_GE(max_depth
, 2);
123 UnwindTraceArg arg
= {this, Min(max_depth
+ 1, kStackTraceMax
)};
124 _Unwind_Backtrace(Unwind_Trace
, &arg
);
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
131 PopStackFrames(Min(to_pop
, static_cast<uptr
>(1)));
132 trace_buffer
[0] = pc
;
135 void BufferedStackTrace::UnwindSlow(uptr pc
, void *context
, u32 max_depth
) {
137 CHECK_GE(max_depth
, 2);
138 UNREACHABLE("signal context doesn't exist");
140 #endif // SANITIZER_CAN_SLOW_UNWIND
142 } // namespace __sanitizer
144 #endif // SANITIZER_SYMBOLIZER_MARKUP