Home | History | Annotate | Download | only in sanitizer_common
      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 
     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 
     35 uptr StackTrace::GetCurrentPc() {
     36   return GET_CALLER_PC();
     37 }
     38 
     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 
     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 
     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 
     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