stackwalker_arm.cc
1 // Copyright 2010 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // stackwalker_arm.cc: arm-specific stackwalker. 30 // 31 // See stackwalker_arm.h for documentation. 32 // 33 // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy 34 35 #ifdef HAVE_CONFIG_H 36 #include <config.h> // Must come first 37 #endif 38 39 #include <vector> 40 41 #include "common/scoped_ptr.h" 42 #include "google_breakpad/processor/call_stack.h" 43 #include "google_breakpad/processor/memory_region.h" 44 #include "google_breakpad/processor/source_line_resolver_interface.h" 45 #include "google_breakpad/processor/stack_frame_cpu.h" 46 #include "google_breakpad/processor/system_info.h" 47 #include "processor/cfi_frame_info.h" 48 #include "processor/logging.h" 49 #include "processor/stackwalker_arm.h" 50 51 namespace google_breakpad { 52 53 54 StackwalkerARM::StackwalkerARM(const SystemInfo* system_info, 55 const MDRawContextARM* context, 56 int fp_register, 57 MemoryRegion* memory, 58 const CodeModules* modules, 59 StackFrameSymbolizer* resolver_helper) 60 : Stackwalker(system_info, memory, modules, resolver_helper), 61 context_(context), fp_register_(fp_register), 62 context_frame_validity_(StackFrameARM::CONTEXT_VALID_ALL) { } 63 64 65 StackFrame* StackwalkerARM::GetContextFrame() { 66 if (!context_) { 67 BPLOG(ERROR) << "Can't get context frame without context"; 68 return NULL; 69 } 70 71 StackFrameARM* frame = new StackFrameARM(); 72 73 // The instruction pointer is stored directly in a register (r15), so pull it 74 // straight out of the CPU context structure. 75 frame->context = *context_; 76 frame->context_validity = context_frame_validity_; 77 frame->trust = StackFrame::FRAME_TRUST_CONTEXT; 78 frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC]; 79 80 return frame; 81 } 82 83 StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( 84 const vector<StackFrame*>& frames, 85 CFIFrameInfo* cfi_frame_info) { 86 StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 87 88 static const char* register_names[] = { 89 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 90 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", 91 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 92 "fps", "cpsr", 93 NULL 94 }; 95 96 // Populate a dictionary with the valid register values in last_frame. 97 CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; 98 for (int i = 0; register_names[i]; i++) 99 if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) 100 callee_registers[register_names[i]] = last_frame->context.iregs[i]; 101 102 // Use the STACK CFI data to recover the caller's register values. 103 CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 104 if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, 105 &caller_registers)) 106 return NULL; 107 108 // Construct a new stack frame given the values the CFI recovered. 109 scoped_ptr<StackFrameARM> frame(new StackFrameARM()); 110 for (int i = 0; register_names[i]; i++) { 111 CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 112 caller_registers.find(register_names[i]); 113 if (entry != caller_registers.end()) { 114 // We recovered the value of this register; fill the context with the 115 // value from caller_registers. 116 frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 117 frame->context.iregs[i] = entry->second; 118 } else if (4 <= i && i <= 11 && (last_frame->context_validity & 119 StackFrameARM::RegisterValidFlag(i))) { 120 // If the STACK CFI data doesn't mention some callee-saves register, and 121 // it is valid in the callee, assume the callee has not yet changed it. 122 // Registers r4 through r11 are callee-saves, according to the Procedure 123 // Call Standard for the ARM Architecture, which the Linux ABI follows. 124 frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 125 frame->context.iregs[i] = last_frame->context.iregs[i]; 126 } 127 } 128 // If the CFI doesn't recover the PC explicitly, then use .ra. 129 if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { 130 CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 131 caller_registers.find(".ra"); 132 if (entry != caller_registers.end()) { 133 if (fp_register_ == -1) { 134 frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 135 frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; 136 } else { 137 // The CFI updated the link register and not the program counter. 138 // Handle getting the program counter from the link register. 139 frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 140 frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; 141 frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; 142 frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = 143 last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; 144 } 145 } 146 } 147 // If the CFI doesn't recover the SP explicitly, then use .cfa. 148 if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { 149 CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 150 caller_registers.find(".cfa"); 151 if (entry != caller_registers.end()) { 152 frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; 153 frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; 154 } 155 } 156 157 // If we didn't recover the PC and the SP, then the frame isn't very useful. 158 static const int essentials = (StackFrameARM::CONTEXT_VALID_SP 159 | StackFrameARM::CONTEXT_VALID_PC); 160 if ((frame->context_validity & essentials) != essentials) 161 return NULL; 162 163 frame->trust = StackFrame::FRAME_TRUST_CFI; 164 return frame.release(); 165 } 166 167 StackFrameARM* StackwalkerARM::GetCallerByStackScan( 168 const vector<StackFrame*>& frames) { 169 StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 170 uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; 171 uint32_t caller_sp, caller_pc; 172 173 if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, 174 /*is_context_frame=*/last_frame->trust == 175 StackFrame::FRAME_TRUST_CONTEXT)) { 176 // No plausible return address was found. 177 return NULL; 178 } 179 180 // ScanForReturnAddress found a reasonable return address. Advance 181 // %sp to the location above the one where the return address was 182 // found. 183 caller_sp += 4; 184 185 // Create a new stack frame (ownership will be transferred to the caller) 186 // and fill it in. 187 StackFrameARM* frame = new StackFrameARM(); 188 189 frame->trust = StackFrame::FRAME_TRUST_SCAN; 190 frame->context = last_frame->context; 191 frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = caller_pc; 192 frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; 193 frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | 194 StackFrameARM::CONTEXT_VALID_SP; 195 196 return frame; 197 } 198 199 StackFrameARM* StackwalkerARM::GetCallerByFramePointer( 200 const vector<StackFrame*>& frames) { 201 StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 202 203 if (!(last_frame->context_validity & 204 StackFrameARM::RegisterValidFlag(fp_register_))) { 205 return NULL; 206 } 207 208 uint32_t last_fp = last_frame->context.iregs[fp_register_]; 209 210 uint32_t caller_fp = 0; 211 if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { 212 BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" 213 << std::hex << last_fp; 214 return NULL; 215 } 216 217 uint32_t caller_lr = 0; 218 if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { 219 BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" 220 << std::hex << (last_fp + 4); 221 return NULL; 222 } 223 224 uint32_t caller_sp = last_fp ? last_fp + 8 : 225 last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; 226 227 // Create a new stack frame (ownership will be transferred to the caller) 228 // and fill it in. 229 StackFrameARM* frame = new StackFrameARM(); 230 231 frame->trust = StackFrame::FRAME_TRUST_FP; 232 frame->context = last_frame->context; 233 frame->context.iregs[fp_register_] = caller_fp; 234 frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; 235 frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = 236 last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; 237 frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = caller_lr; 238 frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | 239 StackFrameARM::CONTEXT_VALID_LR | 240 StackFrameARM::RegisterValidFlag(fp_register_) | 241 StackFrameARM::CONTEXT_VALID_SP; 242 return frame; 243 } 244 245 StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, 246 bool stack_scan_allowed) { 247 if (!memory_ || !stack) { 248 BPLOG(ERROR) << "Can't get caller frame without memory or stack"; 249 return NULL; 250 } 251 252 const vector<StackFrame*>& frames = *stack->frames(); 253 StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 254 scoped_ptr<StackFrameARM> frame; 255 256 // See if there is DWARF call frame information covering this address. 257 // TODO(jperaza): Ignore iOS CFI info until it is properly collected. 258 // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764 259 if (!system_info_ || system_info_->os != "iOS") { 260 scoped_ptr<CFIFrameInfo> cfi_frame_info( 261 frame_symbolizer_->FindCFIFrameInfo(last_frame)); 262 if (cfi_frame_info.get()) 263 frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); 264 } 265 266 // If CFI failed, or there wasn't CFI available, fall back 267 // to frame pointer, if this is configured. 268 if (fp_register_ >= 0 && !frame.get()) 269 frame.reset(GetCallerByFramePointer(frames)); 270 271 // If everuthing failed, fall back to stack scanning. 272 if (stack_scan_allowed && !frame.get()) 273 frame.reset(GetCallerByStackScan(frames)); 274 275 // If nothing worked, tell the caller. 276 if (!frame.get()) 277 return NULL; 278 279 // Should we terminate the stack walk? (end-of-stack or broken invariant) 280 if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC], 281 frame->context.iregs[MD_CONTEXT_ARM_REG_SP], 282 last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP], 283 /*first_unwind=*/last_frame->trust == 284 StackFrame::FRAME_TRUST_CONTEXT)) { 285 return NULL; 286 } 287 288 // The new frame's context's PC is the return address, which is one 289 // instruction past the instruction that caused us to arrive at the 290 // callee. Set new_frame->instruction to one less than the PC. This won't 291 // reference the beginning of the call instruction, but it's at least 292 // within it, which is sufficient to get the source line information to 293 // match up with the line that contains the function call. Callers that 294 // require the exact return address value may access 295 // frame->context.iregs[MD_CONTEXT_ARM_REG_PC]. 296 frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 2; 297 298 return frame.release(); 299 } 300 301 302 } // namespace google_breakpad