| Index: src/processor/stackwalker_mips.cc
|
| diff --git a/src/processor/stackwalker_mips.cc b/src/processor/stackwalker_mips.cc
|
| index 7db34219232363a48b7331bf92c31a44b3ee6903..db55d460c06d8ee666fe1a118e2abba1d7aee6df 100644
|
| --- a/src/processor/stackwalker_mips.cc
|
| +++ b/src/processor/stackwalker_mips.cc
|
| @@ -53,14 +53,25 @@ StackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info,
|
| MemoryRegion* memory,
|
| const CodeModules* modules,
|
| StackFrameSymbolizer* resolver_helper)
|
| - : Stackwalker(system_info, memory, modules, resolver_helper),
|
| - context_(context) {
|
| - if (memory_ && memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) {
|
| - BPLOG(ERROR) << "Memory out of range for stackwalking: "
|
| - << HexString(memory_->GetBase())
|
| - << "+"
|
| - << HexString(memory_->GetSize());
|
| - memory_ = NULL;
|
| +: Stackwalker(system_info, memory, modules, resolver_helper),
|
| + context_(context) {
|
| + if (context_->context_flags & MD_CONTEXT_MIPS64 ) {
|
| + if ((memory_ && memory_->GetBase() + memory_->GetSize() - 1)
|
| + > 0xffffffffffffffff) {
|
| + BPLOG(ERROR) << "Memory out of range for stackwalking mips64: "
|
| + << HexString(memory_->GetBase())
|
| + << "+"
|
| + << HexString(memory_->GetSize());
|
| + memory_ = NULL;
|
| + }
|
| + } else {
|
| + if ((memory_ && memory_->GetBase() + memory_->GetSize() - 1) > 0xffffffff) {
|
| + BPLOG(ERROR) << "Memory out of range for stackwalking mips32: "
|
| + << HexString(memory_->GetBase())
|
| + << "+"
|
| + << HexString(memory_->GetSize());
|
| + memory_ = NULL;
|
| + }
|
| }
|
| }
|
|
|
| @@ -96,73 +107,143 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo(
|
| CFIFrameInfo* cfi_frame_info) {
|
| StackFrameMIPS* last_frame = static_cast<StackFrameMIPS*>(frames.back());
|
|
|
| - uint32_t sp = 0, pc = 0;
|
| + if (context_->context_flags & MD_CONTEXT_MIPS) {
|
| + uint32_t sp = 0, pc = 0;
|
|
|
| - // Populate a dictionary with the valid register values in last_frame.
|
| - CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers;
|
| - // Use the STACK CFI data to recover the caller's register values.
|
| - CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
|
| + // Populate a dictionary with the valid register values in last_frame.
|
| + CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers;
|
| + // Use the STACK CFI data to recover the caller's register values.
|
| + CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
|
|
|
| - for (int i = 0; kRegisterNames[i]; ++i) {
|
| - caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| - callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| - }
|
| + for (int i = 0; kRegisterNames[i]; ++i) {
|
| + caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| + callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| + }
|
|
|
| - if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
|
| - &caller_registers)) {
|
| - return NULL;
|
| - }
|
| + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
|
| + &caller_registers)) {
|
| + return NULL;
|
| + }
|
|
|
| - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator entry =
|
| - caller_registers.find(".cfa");
|
| + CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator entry =
|
| + caller_registers.find(".cfa");
|
|
|
| - if (entry != caller_registers.end()) {
|
| - sp = entry->second;
|
| - caller_registers["$sp"] = entry->second;
|
| - }
|
| + if (entry != caller_registers.end()) {
|
| + sp = entry->second;
|
| + caller_registers["$sp"] = entry->second;
|
| + }
|
|
|
| - entry = caller_registers.find(".ra");
|
| - if (entry != caller_registers.end()) {
|
| - caller_registers["$ra"] = entry->second;
|
| - pc = entry->second - 2 * sizeof(pc);
|
| - }
|
| - caller_registers["$pc"] = pc;
|
| - // Construct a new stack frame given the values the CFI recovered.
|
| - scoped_ptr<StackFrameMIPS> frame(new StackFrameMIPS());
|
| -
|
| - for (int i = 0; kRegisterNames[i]; ++i) {
|
| - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator caller_entry =
|
| - caller_registers.find(kRegisterNames[i]);
|
| -
|
| - if (caller_entry != caller_registers.end()) {
|
| - // The value of this register is recovered; fill the context with the
|
| - // value from caller_registers.
|
| - frame->context.iregs[i] = caller_entry->second;
|
| - frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| - } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) ||
|
| - (i > INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) &&
|
| - (last_frame->context_validity &
|
| - StackFrameMIPS::RegisterValidFlag(i))) {
|
| - // If the STACK CFI data doesn't mention some callee-save register, and
|
| - // it is valid in the callee, assume the callee has not yet changed it.
|
| - // Calee-save registers according to the MIPS o32 ABI specification are:
|
| - // $s0 to $s7
|
| - // $sp, $s8
|
| - frame->context.iregs[i] = last_frame->context.iregs[i];
|
| - frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| + entry = caller_registers.find(".ra");
|
| + if (entry != caller_registers.end()) {
|
| + caller_registers["$ra"] = entry->second;
|
| + pc = entry->second - 2 * sizeof(pc);
|
| }
|
| - }
|
| + caller_registers["$pc"] = pc;
|
| + // Construct a new stack frame given the values the CFI recovered.
|
| + scoped_ptr<StackFrameMIPS> frame(new StackFrameMIPS());
|
| +
|
| + for (int i = 0; kRegisterNames[i]; ++i) {
|
| + CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator caller_entry =
|
| + caller_registers.find(kRegisterNames[i]);
|
| +
|
| + if (caller_entry != caller_registers.end()) {
|
| + // The value of this register is recovered; fill the context with the
|
| + // value from caller_registers.
|
| + frame->context.iregs[i] = caller_entry->second;
|
| + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| + } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) ||
|
| + (i > INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) &&
|
| + (last_frame->context_validity &
|
| + StackFrameMIPS::RegisterValidFlag(i))) {
|
| + // If the STACK CFI data doesn't mention some callee-save register, and
|
| + // it is valid in the callee, assume the callee has not yet changed it.
|
| + // Calee-save registers according to the MIPS o32 ABI specification are:
|
| + // $s0 to $s7
|
| + // $sp, $s8
|
| + frame->context.iregs[i] = last_frame->context.iregs[i];
|
| + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| + }
|
| + }
|
| +
|
| + frame->context.epc = caller_registers["$pc"];
|
| + frame->instruction = caller_registers["$pc"];
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"];
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
|
|
| - frame->context.epc = caller_registers["$pc"];
|
| - frame->instruction = caller_registers["$pc"];
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| -
|
| - frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"];
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
| + frame->trust = StackFrame::FRAME_TRUST_CFI;
|
|
|
| - frame->trust = StackFrame::FRAME_TRUST_CFI;
|
| + return frame.release();
|
| + } else {
|
| + uint64_t sp = 0, pc = 0;
|
| +
|
| + // Populate a dictionary with the valid register values in last_frame.
|
| + CFIFrameInfo::RegisterValueMap<uint64_t> callee_registers;
|
| + // Use the STACK CFI data to recover the caller's register values.
|
| + CFIFrameInfo::RegisterValueMap<uint64_t> caller_registers;
|
| +
|
| + for (int i = 0; kRegisterNames[i]; ++i) {
|
| + caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| + callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i];
|
| + }
|
|
|
| - return frame.release();
|
| + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
|
| + &caller_registers)) {
|
| + return NULL;
|
| + }
|
| +
|
| + CFIFrameInfo::RegisterValueMap<uint64_t>::const_iterator entry =
|
| + caller_registers.find(".cfa");
|
| +
|
| + if (entry != caller_registers.end()) {
|
| + sp = entry->second;
|
| + caller_registers["$sp"] = entry->second;
|
| + }
|
| +
|
| + entry = caller_registers.find(".ra");
|
| + if (entry != caller_registers.end()) {
|
| + caller_registers["$ra"] = entry->second;
|
| + pc = entry->second - 2 * sizeof(pc);
|
| + }
|
| + caller_registers["$pc"] = pc;
|
| + // Construct a new stack frame given the values the CFI recovered.
|
| + scoped_ptr<StackFrameMIPS> frame(new StackFrameMIPS());
|
| +
|
| + for (int i = 0; kRegisterNames[i]; ++i) {
|
| + CFIFrameInfo::RegisterValueMap<uint64_t>::const_iterator caller_entry =
|
| + caller_registers.find(kRegisterNames[i]);
|
| +
|
| + if (caller_entry != caller_registers.end()) {
|
| + // The value of this register is recovered; fill the context with the
|
| + // value from caller_registers.
|
| + frame->context.iregs[i] = caller_entry->second;
|
| + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| + } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) ||
|
| + (i >= INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) &&
|
| + (last_frame->context_validity &
|
| + StackFrameMIPS::RegisterValidFlag(i))) {
|
| + // If the STACK CFI data doesn't mention some callee-save register, and
|
| + // it is valid in the callee, assume the callee has not yet changed it.
|
| + // Calee-save registers according to the MIPS o32 ABI specification are:
|
| + // $s0 to $s7
|
| + // $sp, $s8
|
| + frame->context.iregs[i] = last_frame->context.iregs[i];
|
| + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i);
|
| + }
|
| + }
|
| +
|
| + frame->context.epc = caller_registers["$pc"];
|
| + frame->instruction = caller_registers["$pc"];
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"];
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
| +
|
| + frame->trust = StackFrame::FRAME_TRUST_CFI;
|
| +
|
| + return frame.release();
|
| + }
|
| }
|
|
|
| StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack,
|
| @@ -204,7 +285,7 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack,
|
| last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]) {
|
| return NULL;
|
| }
|
| -
|
| +
|
| return new_frame.release();
|
| }
|
|
|
| @@ -215,19 +296,20 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan(
|
|
|
| StackFrameMIPS* last_frame = static_cast<StackFrameMIPS*>(frames.back());
|
|
|
| - uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP];
|
| - uint32_t caller_pc, caller_sp, caller_fp;
|
| + if (context_->context_flags & MD_CONTEXT_MIPS) {
|
| + uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP];
|
| + uint32_t caller_pc, caller_sp, caller_fp;
|
|
|
| - // Return address cannot be obtained directly.
|
| - // Force stackwalking.
|
| + // Return address cannot be obtained directly.
|
| + // Force stackwalking.
|
|
|
| - // We cannot use frame pointer to get the return address.
|
| - // We'll scan the stack for a
|
| - // return address. This can happen if last_frame is executing code
|
| - // for a module for which we don't have symbols.
|
| - int count = kMaxFrameStackSize / sizeof(caller_pc);
|
| + // We cannot use frame pointer to get the return address.
|
| + // We'll scan the stack for a
|
| + // return address. This can happen if last_frame is executing code
|
| + // for a module for which we don't have symbols.
|
| + int count = kMaxFrameStackSize / sizeof(caller_pc);
|
|
|
| - if (frames.size() > 1) {
|
| + if (frames.size() > 1) {
|
| // In case of mips32 ABI stack frame of a nonleaf function
|
| // must have minimum stack frame assigned for 4 arguments (4 words).
|
| // Move stack pointer for 4 words to avoid reporting non-existing frames
|
| @@ -235,65 +317,131 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan(
|
| // There is no way of knowing if topmost frame belongs to a leaf or
|
| // a nonleaf function.
|
| last_sp += kMinArgsOnStack * sizeof(caller_pc);
|
| - // Adjust 'count' so that return address is scanned only in limits
|
| + // Adjust 'count' so that return address is scanned only in limits
|
| // of one stack frame.
|
| count -= kMinArgsOnStack;
|
| - }
|
| + }
|
|
|
| - do {
|
| - // Scanning for return address from stack pointer of the last frame.
|
| - if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) {
|
| - // If we can't find an instruction pointer even with stack scanning,
|
| - // give up.
|
| - BPLOG(ERROR) << " ScanForReturnAddress failed ";
|
| + do {
|
| + // Scanning for return address from stack pointer of the last frame.
|
| + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) {
|
| + // If we can't find an instruction pointer even with stack scanning,
|
| + // give up.
|
| + BPLOG(ERROR) << " ScanForReturnAddress failed ";
|
| + return NULL;
|
| + }
|
| + // Get $fp stored in the stack frame.
|
| + if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc),
|
| + &caller_fp)) {
|
| + BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ;
|
| + return NULL;
|
| + }
|
| +
|
| + count = count - (caller_sp - last_sp) / sizeof(caller_pc);
|
| + // Now scan the next address in the stack.
|
| + last_sp = caller_sp + sizeof(caller_pc);
|
| + } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0);
|
| +
|
| + if (!count) {
|
| + BPLOG(INFO) << " No frame found " ;
|
| return NULL;
|
| }
|
| - // Get $fp stored in the stack frame.
|
| - if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc),
|
| - &caller_fp)) {
|
| - BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ;
|
| +
|
| + // ScanForReturnAddress found a reasonable return address. Advance
|
| + // $sp to the location above the one where the return address was
|
| + // found.
|
| + caller_sp += sizeof(caller_pc);
|
| + // caller_pc is actually containing $ra value;
|
| + // $pc is two instructions before $ra,
|
| + // so the caller_pc needs to be decremented accordingly.
|
| + caller_pc -= 2 * sizeof(caller_pc);
|
| +
|
| + // Create a new stack frame (ownership will be transferred to the caller)
|
| + // and fill it in.
|
| + StackFrameMIPS* frame = new StackFrameMIPS();
|
| + frame->trust = StackFrame::FRAME_TRUST_SCAN;
|
| + frame->context = last_frame->context;
|
| + frame->context.epc = caller_pc;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| + frame->instruction = caller_pc;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP;
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] =
|
| + caller_pc + 2 * sizeof(caller_pc);
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
| +
|
| + return frame;
|
| + } else {
|
| + uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP];
|
| + uint64_t caller_pc, caller_sp, caller_fp;
|
| +
|
| + // Return address cannot be obtained directly.
|
| + // Force stackwalking.
|
| +
|
| + // We cannot use frame pointer to get the return address.
|
| + // We'll scan the stack for a
|
| + // return address. This can happen if last_frame is executing code
|
| + // for a module for which we don't have symbols.
|
| + int count = kMaxFrameStackSize / sizeof(caller_pc);
|
| +
|
| + do {
|
| + // Scanning for return address from stack pointer of the last frame.
|
| + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) {
|
| + // If we can't find an instruction pointer even with stack scanning,
|
| + // give up.
|
| + BPLOG(ERROR) << " ScanForReturnAddress failed ";
|
| + return NULL;
|
| + }
|
| + // Get $fp stored in the stack frame.
|
| + if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc),
|
| + &caller_fp)) {
|
| + BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ;
|
| + return NULL;
|
| + }
|
| +
|
| + count = count - (caller_sp - last_sp) / sizeof(caller_pc);
|
| + // Now scan the next address in the stack.
|
| + last_sp = caller_sp + sizeof(caller_pc);
|
| + } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0);
|
| +
|
| + if (!count) {
|
| + BPLOG(INFO) << " No frame found " ;
|
| return NULL;
|
| }
|
|
|
| - count = count - (caller_sp - last_sp) / sizeof(caller_pc);
|
| - // Now scan the next address in the stack.
|
| - last_sp = caller_sp + sizeof(caller_pc);
|
| - } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0);
|
| -
|
| - if (!count) {
|
| - BPLOG(INFO) << " No frame found " ;
|
| - return NULL;
|
| + // ScanForReturnAddress found a reasonable return address. Advance
|
| + // $sp to the location above the one where the return address was
|
| + // found.
|
| + caller_sp += sizeof(caller_pc);
|
| + // caller_pc is actually containing $ra value;
|
| + // $pc is two instructions before $ra,
|
| + // so the caller_pc needs to be decremented accordingly.
|
| + caller_pc -= 2 * sizeof(caller_pc);
|
| +
|
| + // Create a new stack frame (ownership will be transferred to the caller)
|
| + // and fill it in.
|
| + StackFrameMIPS* frame = new StackFrameMIPS();
|
| + frame->trust = StackFrame::FRAME_TRUST_SCAN;
|
| + frame->context = last_frame->context;
|
| + frame->context.epc = caller_pc;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| + frame->instruction = caller_pc;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP;
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp;
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP;
|
| +
|
| + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] =
|
| + caller_pc + 2 * sizeof(caller_pc);
|
| + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
| +
|
| + return frame;
|
| }
|
| -
|
| - // ScanForReturnAddress found a reasonable return address. Advance
|
| - // $sp to the location above the one where the return address was
|
| - // found.
|
| - caller_sp += sizeof(caller_pc);
|
| - // caller_pc is actually containing $ra value;
|
| - // $pc is two instructions before $ra,
|
| - // so the caller_pc needs to be decremented accordingly.
|
| - caller_pc -= 2 * sizeof(caller_pc);
|
| -
|
| -
|
| - // Create a new stack frame (ownership will be transferred to the caller)
|
| - // and fill it in.
|
| - StackFrameMIPS* frame = new StackFrameMIPS();
|
| - frame->trust = StackFrame::FRAME_TRUST_SCAN;
|
| - frame->context = last_frame->context;
|
| - frame->context.epc = caller_pc;
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC;
|
| - frame->instruction = caller_pc;
|
| -
|
| - frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp;
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP;
|
| - frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp;
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP;
|
| -
|
| - frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] =
|
| - caller_pc + 2 * sizeof(caller_pc);
|
| - frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA;
|
| -
|
| - return frame;
|
| }
|
|
|
| } // namespace google_breakpad
|
|
|