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