• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- sanitizer_stacktrace.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"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_stacktrace.h"
17 
18 namespace __sanitizer {
19 
GetPreviousInstructionPc(uptr pc)20 uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
21 #if defined(__arm__)
22   // Cancel Thumb bit.
23   pc = pc & (~1);
24 #endif
25 #if defined(__powerpc__) || defined(__powerpc64__)
26   // PCs are always 4 byte aligned.
27   return pc - 4;
28 #elif defined(__sparc__)
29   return pc - 8;
30 #else
31   return pc - 1;
32 #endif
33 }
34 
GetCurrentPc()35 uptr StackTrace::GetCurrentPc() {
36   return GET_CALLER_PC();
37 }
38 
FastUnwindStack(uptr pc,uptr bp,uptr stack_top,uptr stack_bottom,uptr max_depth)39 void StackTrace::FastUnwindStack(uptr pc, uptr bp,
40                                  uptr stack_top, uptr stack_bottom,
41                                  uptr max_depth) {
42   CHECK_GE(max_depth, 2);
43   trace[0] = pc;
44   size = 1;
45   uhwptr *frame = (uhwptr *)bp;
46   uhwptr *prev_frame = frame - 1;
47   if (stack_top < 4096) return;  // Sanity check for stack top.
48   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
49   while (frame > prev_frame &&
50          frame < (uhwptr *)stack_top - 2 &&
51          frame > (uhwptr *)stack_bottom &&
52          IsAligned((uptr)frame, sizeof(*frame)) &&
53          size < max_depth) {
54     uhwptr pc1 = frame[1];
55     if (pc1 != pc) {
56       trace[size++] = (uptr) pc1;
57     }
58     prev_frame = frame;
59     frame = (uhwptr *)frame[0];
60   }
61 }
62 
MatchPc(uptr cur_pc,uptr trace_pc,uptr threshold)63 static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
64   return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
65 }
66 
PopStackFrames(uptr count)67 void StackTrace::PopStackFrames(uptr count) {
68   CHECK_LT(count, size);
69   size -= count;
70   for (uptr i = 0; i < size; ++i) {
71     trace[i] = trace[i + count];
72   }
73 }
74 
LocatePcInTrace(uptr pc)75 uptr StackTrace::LocatePcInTrace(uptr pc) {
76   // Use threshold to find PC in stack trace, as PC we want to unwind from may
77   // slightly differ from return address in the actual unwinded stack trace.
78   const int kPcThreshold = 288;
79   for (uptr i = 0; i < size; ++i) {
80     if (MatchPc(pc, trace[i], kPcThreshold))
81       return i;
82   }
83   return 0;
84 }
85 
86 }  // namespace __sanitizer
87