1 //===-- sanitizer_stacktrace.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 AddressSanitizer and ThreadSanitizer
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_flags.h"
14 #include "sanitizer_procmaps.h"
15 #include "sanitizer_stacktrace.h"
16 #include "sanitizer_symbolizer.h"
18 namespace __sanitizer
{
20 uptr
StackTrace::GetPreviousInstructionPc(uptr pc
) {
25 #if defined(__powerpc__) || defined(__powerpc64__)
26 // PCs are always 4 byte aligned.
28 #elif defined(__sparc__)
35 static void PrintStackFramePrefix(InternalScopedString
*buffer
, uptr frame_num
,
37 buffer
->append(" #%zu 0x%zx", frame_num
, pc
);
40 void StackTrace::PrintStack(const uptr
*addr
, uptr size
,
41 SymbolizeCallback symbolize_callback
) {
42 if (addr
== 0 || size
== 0) {
43 Printf(" <empty stack>\n\n");
46 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
47 InternalScopedBuffer
<char> buff(GetPageSizeCached() * 2);
48 InternalScopedBuffer
<AddressInfo
> addr_frames(64);
49 InternalScopedString
frame_desc(GetPageSizeCached() * 2);
51 for (uptr i
= 0; i
< size
&& addr
[i
]; i
++) {
52 // PCs in stack traces are actually the return addresses, that is,
53 // addresses of the next instructions after the call.
54 uptr pc
= GetPreviousInstructionPc(addr
[i
]);
55 uptr addr_frames_num
= 0; // The number of stack frames for current
56 // instruction address.
57 if (symbolize_callback
) {
58 if (symbolize_callback((void*)pc
, buff
.data(), buff
.size())) {
61 PrintStackFramePrefix(&frame_desc
, frame_num
, pc
);
62 // We can't know anything about the string returned by external
63 // symbolizer, but if it starts with filename, try to strip path prefix
67 StripPathPrefix(buff
.data(), common_flags()->strip_path_prefix
));
68 Printf("%s\n", frame_desc
.data());
72 if (common_flags()->symbolize
&& addr_frames_num
== 0) {
73 // Use our own (online) symbolizer, if necessary.
74 if (Symbolizer
*sym
= Symbolizer::GetOrNull())
76 sym
->SymbolizeCode(pc
, addr_frames
.data(), addr_frames
.size());
77 for (uptr j
= 0; j
< addr_frames_num
; j
++) {
78 AddressInfo
&info
= addr_frames
[j
];
80 PrintStackFramePrefix(&frame_desc
, frame_num
, pc
);
82 frame_desc
.append(" in %s", info
.function
);
85 frame_desc
.append(" ");
86 PrintSourceLocation(&frame_desc
, info
.file
, info
.line
, info
.column
);
87 } else if (info
.module
) {
88 frame_desc
.append(" ");
89 PrintModuleAndOffset(&frame_desc
, info
.module
, info
.module_offset
);
91 Printf("%s\n", frame_desc
.data());
96 if (addr_frames_num
== 0) {
97 // If online symbolization failed, try to output at least module and
98 // offset for instruction.
100 PrintStackFramePrefix(&frame_desc
, frame_num
, pc
);
102 if (proc_maps
.GetObjectNameAndOffset(pc
, &offset
,
103 buff
.data(), buff
.size(),
104 /* protection */0)) {
105 frame_desc
.append(" ");
106 PrintModuleAndOffset(&frame_desc
, buff
.data(), offset
);
108 Printf("%s\n", frame_desc
.data());
112 // Always print a trailing empty line after stack trace.
116 uptr
StackTrace::GetCurrentPc() {
117 return GET_CALLER_PC();
120 void StackTrace::FastUnwindStack(uptr pc
, uptr bp
,
121 uptr stack_top
, uptr stack_bottom
,
123 if (max_depth
== 0) {
129 uhwptr
*frame
= (uhwptr
*)bp
;
130 uhwptr
*prev_frame
= frame
- 1;
131 if (stack_top
< 4096) return; // Sanity check for stack top.
132 // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
133 while (frame
> prev_frame
&&
134 frame
< (uhwptr
*)stack_top
- 2 &&
135 frame
> (uhwptr
*)stack_bottom
&&
136 IsAligned((uptr
)frame
, sizeof(*frame
)) &&
138 uhwptr pc1
= frame
[1];
140 trace
[size
++] = (uptr
) pc1
;
143 frame
= (uhwptr
*)frame
[0];
147 void StackTrace::PopStackFrames(uptr count
) {
148 CHECK(size
>= count
);
150 for (uptr i
= 0; i
< size
; i
++) {
151 trace
[i
] = trace
[i
+ count
];
155 static bool MatchPc(uptr cur_pc
, uptr trace_pc
, uptr threshold
) {
156 return cur_pc
- trace_pc
<= threshold
|| trace_pc
- cur_pc
<= threshold
;
159 uptr
StackTrace::LocatePcInTrace(uptr pc
) {
160 // Use threshold to find PC in stack trace, as PC we want to unwind from may
161 // slightly differ from return address in the actual unwinded stack trace.
162 const int kPcThreshold
= 192;
163 for (uptr i
= 0; i
< size
; ++i
) {
164 if (MatchPc(pc
, trace
[i
], kPcThreshold
))
170 } // namespace __sanitizer