diff options
Diffstat (limited to 'src/processor/stackwalker_arm.cc')
-rw-r--r-- | src/processor/stackwalker_arm.cc | 79 |
1 files changed, 69 insertions, 10 deletions
diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc index 3b91caff..0a3c522d 100644 --- a/src/processor/stackwalker_arm.cc +++ b/src/processor/stackwalker_arm.cc @@ -33,7 +33,6 @@ // // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy - #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/source_line_resolver_interface.h" @@ -48,12 +47,13 @@ namespace google_breakpad { StackwalkerARM::StackwalkerARM(const SystemInfo *system_info, const MDRawContextARM *context, + int fp_register, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver) : Stackwalker(system_info, memory, modules, supplier, resolver), - context_(context), + context_(context), fp_register_(fp_register), context_frame_validity_(StackFrameARM::CONTEXT_VALID_ALL) { } @@ -70,7 +70,7 @@ StackFrame* StackwalkerARM::GetContextFrame() { frame->context = *context_; frame->context_validity = context_frame_validity_; frame->trust = StackFrame::FRAME_TRUST_CONTEXT; - frame->instruction = frame->context.iregs[15]; + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC]; return frame; } @@ -125,8 +125,18 @@ StackFrameARM *StackwalkerARM::GetCallerByCFIFrameInfo( CFIFrameInfo::RegisterValueMap<u_int32_t>::iterator entry = caller_registers.find(".ra"); if (entry != caller_registers.end()) { - frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; - frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; + if (fp_register_ == -1) { + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; + } else { + // The CFI updated the link register and not the program counter. + // Handle getting the program counter from the link register. + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; + frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; + frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; + } } } // If the CFI doesn't recover the SP explicitly, then use .cfa. @@ -154,7 +164,7 @@ StackFrameARM *StackwalkerARM::GetCallerByStackScan( StackFrameARM *last_frame = static_cast<StackFrameARM *>(frames.back()); u_int32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; u_int32_t caller_sp, caller_pc; - + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc)) { // No plausible return address was found. return NULL; @@ -179,6 +189,52 @@ StackFrameARM *StackwalkerARM::GetCallerByStackScan( return frame; } +StackFrameARM *StackwalkerARM::GetCallerByFramePointer( + const vector<StackFrame *> &frames) { + StackFrameARM *last_frame = static_cast<StackFrameARM *>(frames.back()); + + if (!(last_frame->context_validity & + StackFrameARM::RegisterValidFlag(fp_register_))) { + return NULL; + } + + u_int32_t last_fp = last_frame->context.iregs[fp_register_]; + + u_int32_t caller_fp = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { + BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" + << std::hex << last_fp; + return NULL; + } + + u_int32_t caller_lr = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { + BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" + << std::hex << (last_fp + 4); + return NULL; + } + + u_int32_t caller_sp = last_fp ? last_fp + 8 : + last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameARM *frame = new StackFrameARM(); + + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.iregs[fp_register_] = caller_fp; + frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; + frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = caller_lr; + frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(fp_register_) | + StackFrameARM::CONTEXT_VALID_SP; + return frame; +} + StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; @@ -196,10 +252,13 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) { frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); // If CFI failed, or there wasn't CFI available, fall back - // to stack scanning. - if (!frame.get()) { + // to frame pointer, if this is configured. + if (fp_register_ >= 0 && !frame.get()) + frame.reset(GetCallerByFramePointer(frames)); + + // If everuthing failed, fall back to stack scanning. + if (!frame.get()) frame.reset(GetCallerByStackScan(frames)); - } // If nothing worked, tell the caller. if (!frame.get()) @@ -225,7 +284,7 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) { // match up with the line that contains the function call. Callers that // require the exact return address value may access // frame->context.iregs[MD_CONTEXT_ARM_REG_PC]. - frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 1; + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 2; return frame.release(); } |