]>
Commit | Line | Data |
---|---|---|
4fc7b5ac | 1 | //===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===// |
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 AddressSanitizer and ThreadSanitizer | |
9 | // run-time libraries. | |
10 | //===----------------------------------------------------------------------===// | |
11 | ||
7d752f28 | 12 | #include "sanitizer_common.h" |
0328398d | 13 | #include "sanitizer_placement_new.h" |
4fc7b5ac | 14 | #include "sanitizer_stacktrace.h" |
0328398d | 15 | #include "sanitizer_stacktrace_printer.h" |
7d752f28 | 16 | #include "sanitizer_symbolizer.h" |
4fc7b5ac | 17 | |
18 | namespace __sanitizer { | |
19 | ||
0328398d | 20 | void StackTrace::Print() const { |
21 | if (trace == nullptr || size == 0) { | |
7d752f28 | 22 | Printf(" <empty stack>\n\n"); |
23 | return; | |
24 | } | |
7d752f28 | 25 | InternalScopedString frame_desc(GetPageSizeCached() * 2); |
23e39437 | 26 | InternalScopedString dedup_token(GetPageSizeCached()); |
27 | int dedup_frames = common_flags()->dedup_token_length; | |
7d752f28 | 28 | uptr frame_num = 0; |
0328398d | 29 | for (uptr i = 0; i < size && trace[i]; i++) { |
7d752f28 | 30 | // PCs in stack traces are actually the return addresses, that is, |
31 | // addresses of the next instructions after the call. | |
0328398d | 32 | uptr pc = GetPreviousInstructionPc(trace[i]); |
5645a48f | 33 | SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); |
34 | CHECK(frames); | |
35 | for (SymbolizedStack *cur = frames; cur; cur = cur->next) { | |
7d752f28 | 36 | frame_desc.clear(); |
0328398d | 37 | RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, |
5645a48f | 38 | cur->info, common_flags()->symbolize_vs_style, |
39 | common_flags()->strip_path_prefix); | |
7d752f28 | 40 | Printf("%s\n", frame_desc.data()); |
23e39437 | 41 | if (dedup_frames-- > 0) { |
42 | if (dedup_token.length()) | |
43 | dedup_token.append("--"); | |
36093749 | 44 | if (cur->info.function != nullptr) |
45 | dedup_token.append(cur->info.function); | |
23e39437 | 46 | } |
7d752f28 | 47 | } |
5645a48f | 48 | frames->ClearAll(); |
7d752f28 | 49 | } |
50 | // Always print a trailing empty line after stack trace. | |
51 | Printf("\n"); | |
23e39437 | 52 | if (dedup_token.length()) |
53 | Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); | |
7d752f28 | 54 | } |
55 | ||
5645a48f | 56 | void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, |
0328398d | 57 | uptr stack_top, uptr stack_bottom, |
58 | bool request_fast_unwind) { | |
7d752f28 | 59 | top_frame_bp = (max_depth > 0) ? bp : 0; |
60 | // Avoid doing any work for small max_depth. | |
61 | if (max_depth == 0) { | |
62 | size = 0; | |
63 | return; | |
64 | } | |
65 | if (max_depth == 1) { | |
66 | size = 1; | |
0328398d | 67 | trace_buffer[0] = pc; |
7d752f28 | 68 | return; |
69 | } | |
70 | if (!WillUseFastUnwind(request_fast_unwind)) { | |
5645a48f | 71 | #if SANITIZER_CAN_SLOW_UNWIND |
7d752f28 | 72 | if (context) |
73 | SlowUnwindStackWithContext(pc, context, max_depth); | |
74 | else | |
75 | SlowUnwindStack(pc, max_depth); | |
5645a48f | 76 | #else |
77 | UNREACHABLE("slow unwind requested but not available"); | |
78 | #endif | |
7d752f28 | 79 | } else { |
80 | FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); | |
81 | } | |
4fc7b5ac | 82 | } |
83 | ||
36093749 | 84 | static int GetModuleAndOffsetForPc(uptr pc, char *module_name, |
85 | uptr module_name_len, uptr *pc_offset) { | |
86 | const char *found_module_name = nullptr; | |
87 | bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( | |
88 | pc, &found_module_name, pc_offset); | |
89 | ||
90 | if (!ok) return false; | |
91 | ||
92 | if (module_name && module_name_len) { | |
93 | internal_strncpy(module_name, found_module_name, module_name_len); | |
94 | module_name[module_name_len - 1] = '\x00'; | |
95 | } | |
96 | return true; | |
97 | } | |
98 | ||
4fc7b5ac | 99 | } // namespace __sanitizer |
23e39437 | 100 | using namespace __sanitizer; |
101 | ||
102 | extern "C" { | |
103 | SANITIZER_INTERFACE_ATTRIBUTE | |
104 | void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, | |
105 | uptr out_buf_size) { | |
106 | if (!out_buf_size) return; | |
107 | pc = StackTrace::GetPreviousInstructionPc(pc); | |
108 | SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); | |
109 | if (!frame) { | |
110 | internal_strncpy(out_buf, "<can't symbolize>", out_buf_size); | |
111 | out_buf[out_buf_size - 1] = 0; | |
112 | return; | |
113 | } | |
114 | InternalScopedString frame_desc(GetPageSizeCached()); | |
d2ef4bee | 115 | uptr frame_num = 0; |
116 | // Reserve one byte for the final 0. | |
117 | char *out_end = out_buf + out_buf_size - 1; | |
118 | for (SymbolizedStack *cur = frame; cur && out_buf < out_end; | |
119 | cur = cur->next) { | |
120 | frame_desc.clear(); | |
121 | RenderFrame(&frame_desc, fmt, frame_num++, cur->info, | |
122 | common_flags()->symbolize_vs_style, | |
123 | common_flags()->strip_path_prefix); | |
124 | if (!frame_desc.length()) | |
125 | continue; | |
126 | // Reserve one byte for the terminating 0. | |
127 | uptr n = out_end - out_buf - 1; | |
128 | internal_strncpy(out_buf, frame_desc.data(), n); | |
129 | out_buf += __sanitizer::Min<uptr>(n, frame_desc.length()); | |
130 | *out_buf++ = 0; | |
131 | } | |
132 | CHECK(out_buf <= out_end); | |
133 | *out_buf = 0; | |
23e39437 | 134 | } |
135 | ||
136 | SANITIZER_INTERFACE_ATTRIBUTE | |
137 | void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, | |
138 | char *out_buf, uptr out_buf_size) { | |
139 | if (!out_buf_size) return; | |
140 | out_buf[0] = 0; | |
141 | DataInfo DI; | |
142 | if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; | |
143 | InternalScopedString data_desc(GetPageSizeCached()); | |
144 | RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); | |
145 | internal_strncpy(out_buf, data_desc.data(), out_buf_size); | |
146 | out_buf[out_buf_size - 1] = 0; | |
147 | } | |
36093749 | 148 | |
149 | SANITIZER_INTERFACE_ATTRIBUTE | |
150 | int __sanitizer_get_module_and_offset_for_pc( // NOLINT | |
151 | uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) { | |
152 | return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, | |
153 | pc_offset); | |
154 | } | |
23e39437 | 155 | } // extern "C" |