]>
Commit | Line | Data |
---|---|---|
d2ef4bee | 1 | //===-- sanitizer_symbolizer_markup.cc ------------------------------------===// |
36093749 | 2 | // |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
8 | // This file is shared between various sanitizers' runtime libraries. | |
9 | // | |
d2ef4bee | 10 | // Implementation of offline markup symbolizer. |
36093749 | 11 | //===----------------------------------------------------------------------===// |
12 | ||
13 | #include "sanitizer_platform.h" | |
d2ef4bee | 14 | #if SANITIZER_SYMBOLIZER_MARKUP |
36093749 | 15 | |
d2ef4bee | 16 | #if SANITIZER_FUCHSIA |
17 | #include "sanitizer_symbolizer_fuchsia.h" | |
18 | #elif SANITIZER_RTEMS | |
19 | #include "sanitizer_symbolizer_rtems.h" | |
20 | #endif | |
21 | #include "sanitizer_stacktrace.h" | |
36093749 | 22 | #include "sanitizer_symbolizer.h" |
23 | ||
d2ef4bee | 24 | #include <limits.h> |
25 | #include <unwind.h> | |
26 | ||
36093749 | 27 | namespace __sanitizer { |
28 | ||
d2ef4bee | 29 | // This generic support for offline symbolizing is based on the |
30 | // Fuchsia port. We don't do any actual symbolization per se. | |
36093749 | 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 | |
37 | ||
36093749 | 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); | |
43 | return buffer; | |
44 | } | |
45 | ||
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) { | |
53 | return false; | |
54 | } | |
55 | ||
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 | |
60 | // value. | |
61 | // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan | |
62 | // to render stack frames, but that should be changed to use | |
63 | // RenderStackFrame. | |
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); | |
69 | return s; | |
70 | } | |
71 | ||
72 | // Always claim we succeeded, so that RenderDataInfo will be called. | |
73 | bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { | |
74 | info->Clear(); | |
75 | info->start = addr; | |
76 | return true; | |
77 | } | |
78 | ||
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); | |
83 | } | |
84 | ||
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); | |
90 | } | |
91 | ||
92 | Symbolizer *Symbolizer::PlatformInit() { | |
93 | return new (symbolizer_allocator_) Symbolizer({}); | |
94 | } | |
95 | ||
96 | void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } | |
97 | ||
d2ef4bee | 98 | void StartReportDeadlySignal() {} |
99 | void ReportDeadlySignal(const SignalContext &sig, u32 tid, | |
100 | UnwindSignalStackCallbackType unwind, | |
101 | const void *unwind_context) {} | |
102 | ||
103 | #if SANITIZER_CAN_SLOW_UNWIND | |
104 | struct UnwindTraceArg { | |
105 | BufferedStackTrace *stack; | |
106 | u32 max_depth; | |
107 | }; | |
108 | ||
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 | |
116 | : _URC_NO_REASON); | |
117 | } | |
118 | ||
119 | void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { | |
120 | CHECK_GE(max_depth, 2); | |
121 | size = 0; | |
122 | UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; | |
123 | _Unwind_Backtrace(Unwind_Trace, &arg); | |
124 | CHECK_GT(size, 0); | |
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 | |
129 | // than 0!). | |
130 | PopStackFrames(Min(to_pop, static_cast<uptr>(1))); | |
131 | trace_buffer[0] = pc; | |
132 | } | |
133 | ||
134 | void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, | |
135 | u32 max_depth) { | |
136 | CHECK_NE(context, nullptr); | |
137 | UNREACHABLE("signal context doesn't exist"); | |
138 | } | |
139 | #endif // SANITIZER_CAN_SLOW_UNWIND | |
140 | ||
36093749 | 141 | } // namespace __sanitizer |
142 | ||
d2ef4bee | 143 | #endif // SANITIZER_SYMBOLIZER_MARKUP |