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_stacktrace.h"
16 namespace __sanitizer
{
18 uptr
StackTrace::GetPreviousInstructionPc(uptr pc
) {
23 #if defined(__powerpc__) || defined(__powerpc64__)
24 // PCs are always 4 byte aligned.
26 #elif defined(__sparc__)
33 uptr
StackTrace::GetCurrentPc() {
34 return GET_CALLER_PC();
37 // Check if given pointer points into allocated stack area.
38 static inline bool IsValidFrame(uptr frame
, uptr stack_top
, uptr stack_bottom
) {
39 return frame
> stack_bottom
&& frame
< stack_top
- 2 * sizeof (uhwptr
);
42 // In GCC on ARM bp points to saved lr, not fp, so we should check the next
43 // cell in stack to be a saved frame pointer. GetCanonicFrame returns the
44 // pointer to saved frame pointer in any case.
45 static inline uhwptr
*GetCanonicFrame(uptr bp
,
49 if (!IsValidFrame(bp
, stack_top
, stack_bottom
)) return 0;
50 uhwptr
*bp_prev
= (uhwptr
*)bp
;
51 if (IsValidFrame((uptr
)bp_prev
[0], stack_top
, stack_bottom
)) return bp_prev
;
58 void StackTrace::FastUnwindStack(uptr pc
, uptr bp
,
59 uptr stack_top
, uptr stack_bottom
,
61 CHECK_GE(max_depth
, 2);
64 if (stack_top
< 4096) return; // Sanity check for stack top.
65 uhwptr
*frame
= GetCanonicFrame(bp
, stack_top
, stack_bottom
);
66 uhwptr
*prev_frame
= 0;
67 // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
68 while (frame
> prev_frame
&&
69 IsValidFrame((uptr
)frame
, stack_top
, stack_bottom
) &&
70 IsAligned((uptr
)frame
, sizeof(*frame
)) &&
72 uhwptr pc1
= frame
[1];
74 trace
[size
++] = (uptr
) pc1
;
77 frame
= GetCanonicFrame((uptr
)frame
[0], stack_top
, stack_bottom
);
81 static bool MatchPc(uptr cur_pc
, uptr trace_pc
, uptr threshold
) {
82 return cur_pc
- trace_pc
<= threshold
|| trace_pc
- cur_pc
<= threshold
;
85 void StackTrace::PopStackFrames(uptr count
) {
86 CHECK_LT(count
, size
);
88 for (uptr i
= 0; i
< size
; ++i
) {
89 trace
[i
] = trace
[i
+ count
];
93 uptr
StackTrace::LocatePcInTrace(uptr pc
) {
94 // Use threshold to find PC in stack trace, as PC we want to unwind from may
95 // slightly differ from return address in the actual unwinded stack trace.
96 const int kPcThreshold
= 288;
97 for (uptr i
= 0; i
< size
; ++i
) {
98 if (MatchPc(pc
, trace
[i
], kPcThreshold
))
104 } // namespace __sanitizer