• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 // stackwalker_arm64.cc: arm64-specific stackwalker.
31 //
32 // See stackwalker_arm64.h for documentation.
33 //
34 // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy, Colin Blundell
35 
36 #include <vector>
37 
38 #include "common/scoped_ptr.h"
39 #include "google_breakpad/processor/call_stack.h"
40 #include "google_breakpad/processor/memory_region.h"
41 #include "google_breakpad/processor/source_line_resolver_interface.h"
42 #include "google_breakpad/processor/stack_frame_cpu.h"
43 #include "processor/cfi_frame_info.h"
44 #include "processor/logging.h"
45 #include "processor/stackwalker_arm64.h"
46 
47 namespace google_breakpad {
48 
49 
StackwalkerARM64(const SystemInfo * system_info,const MDRawContextARM64 * context,MemoryRegion * memory,const CodeModules * modules,StackFrameSymbolizer * resolver_helper)50 StackwalkerARM64::StackwalkerARM64(const SystemInfo* system_info,
51                                    const MDRawContextARM64* context,
52                                    MemoryRegion* memory,
53                                    const CodeModules* modules,
54                                    StackFrameSymbolizer* resolver_helper)
55     : Stackwalker(system_info, memory, modules, resolver_helper),
56       context_(context),
57       context_frame_validity_(StackFrameARM64::CONTEXT_VALID_ALL),
58       address_range_mask_(0xffffffffffffffff) {
59   if (modules && modules->module_count() > 0) {
60     // ARM64 supports storing pointer authentication codes in the upper bits of
61     // a pointer. Make a best guess at the range of valid addresses based on the
62     // range of loaded modules.
63     const CodeModule *high_module =
64         modules->GetModuleAtSequence(modules->module_count() - 1);
65     uint64_t mask = high_module->base_address() + high_module->size();
66     mask |= mask >> 1;
67     mask |= mask >> 2;
68     mask |= mask >> 4;
69     mask |= mask >> 8;
70     mask |= mask >> 16;
71     mask |= mask >> 32;
72     address_range_mask_ = mask;
73   }
74 }
75 
PtrauthStrip(uint64_t ptr)76 uint64_t StackwalkerARM64::PtrauthStrip(uint64_t ptr) {
77   uint64_t stripped = ptr & address_range_mask_;
78   return modules_ && modules_->GetModuleForAddress(stripped) ? stripped : ptr;
79 }
80 
GetContextFrame()81 StackFrame* StackwalkerARM64::GetContextFrame() {
82   if (!context_) {
83     BPLOG(ERROR) << "Can't get context frame without context";
84     return NULL;
85   }
86 
87   StackFrameARM64* frame = new StackFrameARM64();
88 
89   // The instruction pointer is stored directly in a register (x32), so pull it
90   // straight out of the CPU context structure.
91   frame->context = *context_;
92   frame->context_validity = context_frame_validity_;
93   frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
94   frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC];
95   frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] =
96       PtrauthStrip(frame->context.iregs[MD_CONTEXT_ARM64_REG_LR]);
97 
98   return frame;
99 }
100 
GetCallerByCFIFrameInfo(const vector<StackFrame * > & frames,CFIFrameInfo * cfi_frame_info)101 StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo(
102     const vector<StackFrame*> &frames,
103     CFIFrameInfo* cfi_frame_info) {
104   StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
105 
106   static const char* register_names[] = {
107     "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
108     "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
109     "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
110     "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
111     "pc",  NULL
112   };
113 
114   // Populate a dictionary with the valid register values in last_frame.
115   CFIFrameInfo::RegisterValueMap<uint64_t> callee_registers;
116   for (int i = 0; register_names[i]; i++) {
117     if (last_frame->context_validity & StackFrameARM64::RegisterValidFlag(i))
118       callee_registers[register_names[i]] = last_frame->context.iregs[i];
119   }
120 
121   // Use the STACK CFI data to recover the caller's register values.
122   CFIFrameInfo::RegisterValueMap<uint64_t> caller_registers;
123   if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
124                                       &caller_registers)) {
125     return NULL;
126   }
127   // Construct a new stack frame given the values the CFI recovered.
128   scoped_ptr<StackFrameARM64> frame(new StackFrameARM64());
129   for (int i = 0; register_names[i]; i++) {
130     CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry =
131       caller_registers.find(register_names[i]);
132     if (entry != caller_registers.end()) {
133       // We recovered the value of this register; fill the context with the
134       // value from caller_registers.
135       frame->context_validity |= StackFrameARM64::RegisterValidFlag(i);
136       frame->context.iregs[i] = entry->second;
137     } else if (19 <= i && i <= 29 && (last_frame->context_validity &
138                                       StackFrameARM64::RegisterValidFlag(i))) {
139       // If the STACK CFI data doesn't mention some callee-saves register, and
140       // it is valid in the callee, assume the callee has not yet changed it.
141       // Registers r19 through r29 are callee-saves, according to the Procedure
142       // Call Standard for the ARM AARCH64 Architecture, which the Linux ABI
143       // follows.
144       frame->context_validity |= StackFrameARM64::RegisterValidFlag(i);
145       frame->context.iregs[i] = last_frame->context.iregs[i];
146     }
147   }
148   // If the CFI doesn't recover the PC explicitly, then use .ra.
149   if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_PC)) {
150     CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry =
151       caller_registers.find(".ra");
152     if (entry != caller_registers.end()) {
153       frame->context_validity |= StackFrameARM64::CONTEXT_VALID_PC;
154       frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = entry->second;
155     }
156   }
157   // If the CFI doesn't recover the SP explicitly, then use .cfa.
158   if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_SP)) {
159     CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry =
160       caller_registers.find(".cfa");
161     if (entry != caller_registers.end()) {
162       frame->context_validity |= StackFrameARM64::CONTEXT_VALID_SP;
163       frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = entry->second;
164     }
165   }
166 
167   // If we didn't recover the PC and the SP, then the frame isn't very useful.
168   static const uint64_t essentials = (StackFrameARM64::CONTEXT_VALID_SP
169                                      | StackFrameARM64::CONTEXT_VALID_PC);
170   if ((frame->context_validity & essentials) != essentials)
171     return NULL;
172 
173   frame->trust = StackFrame::FRAME_TRUST_CFI;
174   return frame.release();
175 }
176 
GetCallerByStackScan(const vector<StackFrame * > & frames)177 StackFrameARM64* StackwalkerARM64::GetCallerByStackScan(
178     const vector<StackFrame*> &frames) {
179   StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
180   uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP];
181   uint64_t caller_sp, caller_pc;
182 
183   if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
184                             frames.size() == 1 /* is_context_frame */)) {
185     // No plausible return address was found.
186     return NULL;
187   }
188 
189   // ScanForReturnAddress found a reasonable return address. Advance
190   // %sp to the location above the one where the return address was
191   // found.
192   caller_sp += 8;
193 
194   // Create a new stack frame (ownership will be transferred to the caller)
195   // and fill it in.
196   StackFrameARM64* frame = new StackFrameARM64();
197 
198   frame->trust = StackFrame::FRAME_TRUST_SCAN;
199   frame->context = last_frame->context;
200   frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = caller_pc;
201   frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp;
202   frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC |
203                             StackFrameARM64::CONTEXT_VALID_SP;
204 
205   return frame;
206 }
207 
GetCallerByFramePointer(const vector<StackFrame * > & frames)208 StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer(
209     const vector<StackFrame*> &frames) {
210   StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
211   if (!(last_frame->context_validity & StackFrameARM64::CONTEXT_VALID_LR)) {
212     CorrectRegLRByFramePointer(frames, last_frame);
213   }
214 
215   uint64_t last_fp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP];
216 
217   uint64_t caller_fp = 0;
218   if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) {
219     BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x"
220                  << std::hex << last_fp;
221     return NULL;
222   }
223 
224   uint64_t caller_lr = 0;
225   if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_lr)) {
226     BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 8: 0x"
227                  << std::hex << (last_fp + 8);
228     return NULL;
229   }
230 
231   caller_lr = PtrauthStrip(caller_lr);
232 
233   uint64_t caller_sp = last_fp ? last_fp + 16 :
234       last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP];
235 
236   // Create a new stack frame (ownership will be transferred to the caller)
237   // and fill it in.
238   StackFrameARM64* frame = new StackFrameARM64();
239 
240   frame->trust = StackFrame::FRAME_TRUST_FP;
241   frame->context = last_frame->context;
242   frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] = caller_fp;
243   frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp;
244   frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] =
245       last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR];
246   frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = caller_lr;
247   frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC |
248                             StackFrameARM64::CONTEXT_VALID_LR |
249                             StackFrameARM64::CONTEXT_VALID_FP |
250                             StackFrameARM64::CONTEXT_VALID_SP;
251   return frame;
252 }
253 
CorrectRegLRByFramePointer(const vector<StackFrame * > & frames,StackFrameARM64 * last_frame)254 void StackwalkerARM64::CorrectRegLRByFramePointer(
255     const vector<StackFrame*>& frames,
256     StackFrameARM64* last_frame) {
257   // Need at least two frames to correct and
258   // register $FP should always be greater than register $SP.
259   if (frames.size() < 2 || !last_frame ||
260       last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] <=
261           last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP])
262     return;
263 
264   StackFrameARM64* last_last_frame =
265       static_cast<StackFrameARM64*>(*(frames.end() - 2));
266   uint64_t last_last_fp =
267       last_last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP];
268 
269   uint64_t last_fp = 0;
270   if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp, &last_fp)) {
271     BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x"
272                  << std::hex << last_last_fp;
273     return;
274   }
275   // Give up if STACK CFI doesn't agree with frame pointer.
276   if (last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] != last_fp)
277     return;
278 
279   uint64_t last_lr = 0;
280   if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp + 8, &last_lr)) {
281     BPLOG(ERROR) << "Unable to read last_lr from (last_last_fp + 8): 0x"
282                  << std::hex << (last_last_fp + 8);
283     return;
284   }
285   last_lr = PtrauthStrip(last_lr);
286 
287   last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = last_lr;
288 }
289 
GetCallerFrame(const CallStack * stack,bool stack_scan_allowed)290 StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack,
291                                              bool stack_scan_allowed) {
292   if (!memory_ || !stack) {
293     BPLOG(ERROR) << "Can't get caller frame without memory or stack";
294     return NULL;
295   }
296 
297   const vector<StackFrame*> &frames = *stack->frames();
298   StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
299   scoped_ptr<StackFrameARM64> frame;
300 
301   // See if there is DWARF call frame information covering this address.
302   scoped_ptr<CFIFrameInfo> cfi_frame_info(
303       frame_symbolizer_->FindCFIFrameInfo(last_frame));
304   if (cfi_frame_info.get())
305     frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
306 
307   // If CFI failed, or there wasn't CFI available, fall back to frame pointer.
308   if (!frame.get())
309     frame.reset(GetCallerByFramePointer(frames));
310 
311   // If everything failed, fall back to stack scanning.
312   if (stack_scan_allowed && !frame.get())
313     frame.reset(GetCallerByStackScan(frames));
314 
315   // If nothing worked, tell the caller.
316   if (!frame.get())
317     return NULL;
318 
319   // Should we terminate the stack walk? (end-of-stack or broken invariant)
320   if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC],
321                     frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
322                     last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
323                     frames.size() == 1)) {
324     return NULL;
325   }
326 
327   // The new frame's context's PC is the return address, which is one
328   // instruction past the instruction that caused us to arrive at the callee.
329   // ARM64 instructions have a uniform 4-byte encoding, so subtracting 4 off
330   // the return address gets back to the beginning of the call instruction.
331   // Callers that require the exact return address value may access
332   // frame->context.iregs[MD_CONTEXT_ARM64_REG_PC].
333   frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] - 4;
334 
335   return frame.release();
336 }
337 
338 
339 }  // namespace google_breakpad
340