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
18namespace __sanitizer {
19
20uptr 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
35uptr StackTrace::GetCurrentPc() {
36  return GET_CALLER_PC();
37}
38
39void 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
63static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
64  return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
65}
66
67void 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
75uptr 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