1 //===-- sanitizer_symbolizer_markup.cc ------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between various sanitizers' runtime libraries.
10 // Implementation of offline markup symbolizer.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
14 #if SANITIZER_SYMBOLIZER_MARKUP
17 #include "sanitizer_symbolizer_fuchsia.h"
19 #include "sanitizer_symbolizer_rtems.h"
21 #include "sanitizer_stacktrace.h"
22 #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 used in some places for suppression checking, which we
57 // don't really support for Fuchsia. It's also used in UBSan to
58 // identify a PC location to a function name, so we always fill in
59 // the function member with a string containing markup around the PC
61 // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
62 // to render stack frames, but that should be changed to use
64 SymbolizedStack
*Symbolizer::SymbolizePC(uptr addr
) {
65 SymbolizedStack
*s
= SymbolizedStack::New(addr
);
66 char buffer
[kFormatFunctionMax
];
67 internal_snprintf(buffer
, sizeof(buffer
), kFormatFunction
, addr
);
68 s
->info
.function
= internal_strdup(buffer
);
72 // Always claim we succeeded, so that RenderDataInfo will be called.
73 bool Symbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
79 // We ignore the format argument to __sanitizer_symbolize_global.
80 void RenderData(InternalScopedString
*buffer
, const char *format
,
81 const DataInfo
*DI
, const char *strip_path_prefix
) {
82 buffer
->append(kFormatData
, DI
->start
);
85 // We don't support the stack_trace_format flag at all.
86 void RenderFrame(InternalScopedString
*buffer
, const char *format
, int frame_no
,
87 const AddressInfo
&info
, bool vs_style
,
88 const char *strip_path_prefix
, const char *strip_func_prefix
) {
89 buffer
->append(kFormatFrame
, frame_no
, info
.address
);
92 Symbolizer
*Symbolizer::PlatformInit() {
93 return new (symbolizer_allocator_
) Symbolizer({});
96 void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
98 void StartReportDeadlySignal() {}
99 void ReportDeadlySignal(const SignalContext
&sig
, u32 tid
,
100 UnwindSignalStackCallbackType unwind
,
101 const void *unwind_context
) {}
103 #if SANITIZER_CAN_SLOW_UNWIND
104 struct UnwindTraceArg
{
105 BufferedStackTrace
*stack
;
109 _Unwind_Reason_Code
Unwind_Trace(struct _Unwind_Context
*ctx
, void *param
) {
110 UnwindTraceArg
*arg
= static_cast<UnwindTraceArg
*>(param
);
111 CHECK_LT(arg
->stack
->size
, arg
->max_depth
);
112 uptr pc
= _Unwind_GetIP(ctx
);
113 if (pc
< PAGE_SIZE
) return _URC_NORMAL_STOP
;
114 arg
->stack
->trace_buffer
[arg
->stack
->size
++] = pc
;
115 return (arg
->stack
->size
== arg
->max_depth
? _URC_NORMAL_STOP
119 void BufferedStackTrace::SlowUnwindStack(uptr pc
, u32 max_depth
) {
120 CHECK_GE(max_depth
, 2);
122 UnwindTraceArg arg
= {this, Min(max_depth
+ 1, kStackTraceMax
)};
123 _Unwind_Backtrace(Unwind_Trace
, &arg
);
125 // We need to pop a few frames so that pc is on top.
126 uptr to_pop
= LocatePcInTrace(pc
);
127 // trace_buffer[0] belongs to the current function so we always pop it,
128 // unless there is only 1 frame in the stack trace (1 frame is always better
130 PopStackFrames(Min(to_pop
, static_cast<uptr
>(1)));
131 trace_buffer
[0] = pc
;
134 void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc
, void *context
,
136 CHECK_NE(context
, nullptr);
137 UNREACHABLE("signal context doesn't exist");
139 #endif // SANITIZER_CAN_SLOW_UNWIND
141 } // namespace __sanitizer
143 #endif // SANITIZER_SYMBOLIZER_MARKUP