summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/breakpad-patches/13-improve-arm64-stack-walking.patch
blob: b9c6f82799253334274d4a4d8076886c9e57fc9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc
--- a/src/processor/stackwalker_arm64.cc
+++ b/src/processor/stackwalker_arm64.cc
@@ -282,16 +282,27 @@ void StackwalkerARM64::CorrectRegLRByFra
                  << std::hex << (last_last_fp + 8);
     return;
   }
   last_lr = PtrauthStrip(last_lr);
 
   last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = last_lr;
 }
 
+bool StackwalkerARM64::ValidInstructionPointerInFrame(const StackFrameARM64& frame) {
+  const uint64_t ip = frame.context.iregs[MD_CONTEXT_ARM64_REG_PC];
+
+  if ((ip < 0x1000) || (ip > 0x000fffffffffffff)) {
+    // The IP points into the first page or above the user space threshold
+    return false;
+  }
+
+  return true;
+}
+
 StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack,
                                              bool stack_scan_allowed) {
   if (!memory_ || !stack) {
     BPLOG(ERROR) << "Can't get caller frame without memory or stack";
     return NULL;
   }
 
   const vector<StackFrame*> &frames = *stack->frames();
@@ -300,21 +311,22 @@ StackFrame* StackwalkerARM64::GetCallerF
 
   // See if there is DWARF call frame information covering this address.
   scoped_ptr<CFIFrameInfo> cfi_frame_info(
       frame_symbolizer_->FindCFIFrameInfo(last_frame));
   if (cfi_frame_info.get())
     frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
 
   // If CFI failed, or there wasn't CFI available, fall back to frame pointer.
-  if (!frame.get())
+  if (!frame.get() || !ValidInstructionPointerInFrame(*frame))
     frame.reset(GetCallerByFramePointer(frames));
 
   // If everything failed, fall back to stack scanning.
-  if (stack_scan_allowed && !frame.get())
+  if (stack_scan_allowed &&
+      (!frame.get() || !ValidInstructionPointerInFrame(*frame)))
     frame.reset(GetCallerByStackScan(frames));
 
   // If nothing worked, tell the caller.
   if (!frame.get())
     return NULL;
 
   // Should we terminate the stack walk? (end-of-stack or broken invariant)
   if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC],
diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h
--- a/src/processor/stackwalker_arm64.h
+++ b/src/processor/stackwalker_arm64.h
@@ -92,16 +92,19 @@ class StackwalkerARM64 : public Stackwal
 
   // GetCallerByFramePointer() depends on the previous frame having recovered
   // x30($LR) which may not have been done when using CFI.
   // This function recovers $LR in the previous frame by using the frame-pointer
   // two frames back to read it from the stack.
   void CorrectRegLRByFramePointer(const vector<StackFrame*>& frames,
                                   StackFrameARM64* last_frame);
 
+  // Return true if the instruction pointer points into the first 4KiB of memory
+  bool ValidInstructionPointerInFrame(const StackFrameARM64& frame);
+
   // Stores the CPU context corresponding to the youngest stack frame, to
   // be returned by GetContextFrame.
   const MDRawContextARM64* context_;
 
   // Validity mask for youngest stack frame. This is always
   // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of
   // unit tests.
   uint64_t context_frame_validity_;