1 //===-- sanitizer_stacktrace_libcdep.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 AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common.h"
14 #include "sanitizer_placement_new.h"
15 #include "sanitizer_stacktrace.h"
16 #include "sanitizer_stacktrace_printer.h"
17 #include "sanitizer_symbolizer.h"
19 namespace __sanitizer
{
21 void StackTrace::Print() const {
22 if (trace
== nullptr || size
== 0) {
23 Printf(" <empty stack>\n\n");
26 InternalScopedString
frame_desc(GetPageSizeCached() * 2);
27 InternalScopedString
dedup_token(GetPageSizeCached());
28 int dedup_frames
= common_flags()->dedup_token_length
;
29 bool symbolize
= RenderNeedsSymbolization(common_flags()->stack_trace_format
);
31 for (uptr i
= 0; i
< size
&& trace
[i
]; i
++) {
32 // PCs in stack traces are actually the return addresses, that is,
33 // addresses of the next instructions after the call.
34 uptr pc
= GetPreviousInstructionPc(trace
[i
]);
35 SymbolizedStack
*frames
;
37 frames
= Symbolizer::GetOrInit()->SymbolizePC(pc
);
39 frames
= SymbolizedStack::New(pc
);
41 for (SymbolizedStack
*cur
= frames
; cur
; cur
= cur
->next
) {
43 RenderFrame(&frame_desc
, common_flags()->stack_trace_format
, frame_num
++,
44 cur
->info
.address
, symbolize
? &cur
->info
: nullptr,
45 common_flags()->symbolize_vs_style
,
46 common_flags()->strip_path_prefix
);
47 Printf("%s\n", frame_desc
.data());
48 if (dedup_frames
-- > 0) {
49 if (dedup_token
.length())
50 dedup_token
.append("--");
51 if (cur
->info
.function
!= nullptr)
52 dedup_token
.append(cur
->info
.function
);
57 // Always print a trailing empty line after stack trace.
59 if (dedup_token
.length())
60 Printf("DEDUP_TOKEN: %s\n", dedup_token
.data());
63 void BufferedStackTrace::Unwind(u32 max_depth
, uptr pc
, uptr bp
, void *context
,
64 uptr stack_top
, uptr stack_bottom
,
65 bool request_fast_unwind
) {
66 // Ensures all call sites get what they requested.
67 CHECK_EQ(request_fast_unwind
, WillUseFastUnwind(request_fast_unwind
));
68 top_frame_bp
= (max_depth
> 0) ? bp
: 0;
69 // Avoid doing any work for small max_depth.
79 if (!WillUseFastUnwind(request_fast_unwind
)) {
80 #if SANITIZER_CAN_SLOW_UNWIND
82 UnwindSlow(pc
, context
, max_depth
);
84 UnwindSlow(pc
, max_depth
);
86 UNREACHABLE("slow unwind requested but not available");
89 UnwindFast(pc
, bp
, stack_top
, stack_bottom
, max_depth
);
93 static int GetModuleAndOffsetForPc(uptr pc
, char *module_name
,
94 uptr module_name_len
, uptr
*pc_offset
) {
95 const char *found_module_name
= nullptr;
96 bool ok
= Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
97 pc
, &found_module_name
, pc_offset
);
99 if (!ok
) return false;
101 if (module_name
&& module_name_len
) {
102 internal_strncpy(module_name
, found_module_name
, module_name_len
);
103 module_name
[module_name_len
- 1] = '\x00';
108 } // namespace __sanitizer
109 using namespace __sanitizer
;
112 SANITIZER_INTERFACE_ATTRIBUTE
113 void __sanitizer_symbolize_pc(uptr pc
, const char *fmt
, char *out_buf
,
115 if (!out_buf_size
) return;
116 pc
= StackTrace::GetPreviousInstructionPc(pc
);
117 SymbolizedStack
*frame
;
118 bool symbolize
= RenderNeedsSymbolization(fmt
);
120 frame
= Symbolizer::GetOrInit()->SymbolizePC(pc
);
122 frame
= SymbolizedStack::New(pc
);
124 internal_strncpy(out_buf
, "<can't symbolize>", out_buf_size
);
125 out_buf
[out_buf_size
- 1] = 0;
128 InternalScopedString
frame_desc(GetPageSizeCached());
130 // Reserve one byte for the final 0.
131 char *out_end
= out_buf
+ out_buf_size
- 1;
132 for (SymbolizedStack
*cur
= frame
; cur
&& out_buf
< out_end
;
135 RenderFrame(&frame_desc
, fmt
, frame_num
++, cur
->info
.address
,
136 symbolize
? &cur
->info
: nullptr,
137 common_flags()->symbolize_vs_style
,
138 common_flags()->strip_path_prefix
);
139 if (!frame_desc
.length())
141 // Reserve one byte for the terminating 0.
142 uptr n
= out_end
- out_buf
- 1;
143 internal_strncpy(out_buf
, frame_desc
.data(), n
);
144 out_buf
+= __sanitizer::Min
<uptr
>(n
, frame_desc
.length());
147 CHECK(out_buf
<= out_end
);
152 SANITIZER_INTERFACE_ATTRIBUTE
153 void __sanitizer_symbolize_global(uptr data_addr
, const char *fmt
,
154 char *out_buf
, uptr out_buf_size
) {
155 if (!out_buf_size
) return;
158 if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr
, &DI
)) return;
159 InternalScopedString
data_desc(GetPageSizeCached());
160 RenderData(&data_desc
, fmt
, &DI
, common_flags()->strip_path_prefix
);
161 internal_strncpy(out_buf
, data_desc
.data(), out_buf_size
);
162 out_buf
[out_buf_size
- 1] = 0;
165 SANITIZER_INTERFACE_ATTRIBUTE
166 int __sanitizer_get_module_and_offset_for_pc(uptr pc
, char *module_name
,
167 uptr module_name_len
,
169 return __sanitizer::GetModuleAndOffsetForPc(pc
, module_name
, module_name_len
,