Index: src/processor/stackwalker_MIPS.cc |
=================================================================== |
--- src/processor/stackwalker_MIPS.cc (revision 0) |
+++ src/processor/stackwalker_MIPS.cc (revision 0) |
@@ -0,0 +1,490 @@ |
+// Copyright (c) 2010 Google Inc. |
Ted Mielczarek
2012/09/28 12:44:08
1) The filename of this (and the matching header f
|
+// All rights reserved. |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following disclaimer |
+// in the documentation and/or other materials provided with the |
+// distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived from |
+// this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+// stackwalker_MIPS.cc: MIPS-specific stackwalker. |
+// |
+// See stackwalker_MIPS.h for documentation. |
+// |
+// Author: Tata Elxsi |
Ted Mielczarek
2012/09/28 12:44:08
Do you have an email address for this person? It's
|
+ |
+#include "processor/postfix_evaluator-inl.h" |
Ted Mielczarek
2012/09/28 12:44:08
Include lines should be ordered by filename unles
|
+#include "google_breakpad/processor/call_stack.h" |
+#include "google_breakpad/processor/code_modules.h" |
+#include "google_breakpad/processor/memory_region.h" |
+#include "google_breakpad/processor/source_line_resolver_interface.h" |
+#include "google_breakpad/processor/stack_frame_cpu.h" |
+#include "processor/logging.h" |
+#include "processor/scoped_ptr.h" |
+#include "processor/stackwalker_x86.h" |
+#include "processor/windows_frame_info.h" |
+#include "processor/cfi_frame_info.h" |
+#include "processor/stackwalker_MIPS.h" |
+#include "google_breakpad/common/minidump_cpu_mips.h" |
Ted Mielczarek
2012/09/28 12:44:08
This include shouldn't be necessary.
|
+ |
+using std::hex; |
+using std::dec; |
+namespace google_breakpad { |
+ |
+ |
+StackwalkerMIPS::StackwalkerMIPS (const SystemInfo *system_info, |
Ted Mielczarek
2012/09/28 12:44:08
Here (and elsewhere), the * should be next to the
|
+ const MDRawContextMIPS *context, |
+ MemoryRegion *memory, |
+ const CodeModules *modules, |
+ SymbolSupplier *supplier, |
+ SourceLineResolverInterface *resolver) |
+ : Stackwalker(system_info, memory, modules, supplier, resolver), |
+ context_(context) { |
+ if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { |
+ BPLOG(ERROR) << "Memory out of range for stackwalking: " << |
+ HexString(memory_->GetBase()) << "+" << |
+ HexString(memory_->GetSize()); |
+ memory_ = NULL; |
Ted Mielczarek
2012/09/28 12:44:08
You're asserting that the stack addresses will alw
|
+ } |
+} |
+ |
+StackFrameMIPS::~StackFrameMIPS() { |
+ if (cfi_frame_info) |
+ delete cfi_frame_info; |
+ cfi_frame_info = NULL; |
+} |
+ |
+StackFrame *StackwalkerMIPS::GetContextFrame() { |
+ if (!context_ || !memory_) { |
+ BPLOG(ERROR) << "Can't get context frame without context or memory"; |
+ return NULL; |
+ } |
+ |
+ StackFrameMIPS *frame = new StackFrameMIPS(); |
+ |
+ // The instruction pointer is stored directly in a register, so pull it |
+ // straight out of the CPU context structure. |
+ frame->context = *context_; |
+ frame->context_validity = StackFrameMIPS::CONTEXT_VALID_ALL; |
+ frame->trust = StackFrame::FRAME_TRUST_CONTEXT; |
+ frame->instruction = frame->context.epc; |
+ |
+ return frame; |
+} |
+ |
+// Register names for mips |
+ |
+static const char *register_names[] = { |
digit
2013/03/21 08:28:43
Please use:
static const char* const register_n
|
+ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$to", "$t1", |
+ "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", |
+ "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", |
+ "$fp", "$ra", NULL |
+}; |
+ |
+// Return address register $ra is updated by the processor on calling |
+// JAL instruction [ Jump and link ]. It is the responsiblity of a |
+// subroutine to save it's return address before calling any other |
+// subroutine. To get the pc of the caller, $ra at the start of |
+// current subroutine is requied. To find this parsing and handling |
+// of CFI of current frame is required. On doing this, we will get all |
Ted Mielczarek
2012/09/28 12:44:08
Don't use "we" in comments.
|
+// the registers except $ra updated to the values at the point |
+// when current subroutine is invoked. |
+// We can use the current $ra to find the $pc of the caller. |
+// And then process the CFI of caller frame to find $ra at beginning |
+// of the caller function. Frame obtained in previous step and |
+// current $ra gives the caller frame. |
+// Thus processing of two CFI frames are required to find caller frame |
+// in case of MIPS. |
+ |
+StackFrameMIPS *StackwalkerMIPS::GetCallerByCFIFrameInfo ( |
Ted Mielczarek
2012/09/28 12:44:08
I don't have the mental energy to review the actua
|
+ const vector<StackFrame *> &frames, |
+ CFIFrameInfo *cfi_frame_info) { |
+ StackFrameMIPS *last_frame = static_cast<StackFrameMIPS *>(frames.back()); |
+ |
+ unsigned long sp = 0, pc = 0; |
+ |
+ // Populate a dictionary with the valid register values in last_frame. |
+ CFIFrameInfo::RegisterValueMap<u_int32_t> callee_registers; |
+ // Use the STACK CFI data to recover the caller's register values. |
+ CFIFrameInfo::RegisterValueMap<u_int32_t> caller_registers; |
+ // Register map to save callee frame map at beginning of the frame. |
+ CFIFrameInfo::RegisterValueMap<u_int32_t> callee_registers_start; |
+ |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << "Entering "<< __FUNCTION__ << " Populating previous frame"; |
+ #endif |
Ted Mielczarek
2012/09/28 12:44:08
These debug messages don't seem terribly valuable
|
+ |
+ for (int i = 0; register_names[i]; i++) { |
+ callee_registers_start[register_names[i]] = last_frame->context.iregs[i]; |
+ callee_registers[register_names[i]] = last_frame->context.iregs[i]; |
+ } |
+ |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<" Populating previous frame complete." ; |
+ #endif |
+ |
+ if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, |
+ &callee_registers_start)) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " FindCallerRegs failed for callee_registers_start"; |
+ #endif |
+ |
+ return NULL; |
+ } |
+ |
+ CFIFrameInfo::RegisterValueMap<u_int32_t>::iterator entry1 = |
+ callee_registers_start.find(".cfa"); |
+ |
+ if (entry1 != callee_registers_start.end()) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<"After FindCallerRegs:cfa = " |
+ <<hex<<entry1->second ; |
+ #endif |
+ sp = entry1->second; |
+ callee_registers_start["$sp"] = entry1->second; |
+ } |
+ |
+ entry1 = callee_registers_start.find(".ra"); |
+ if (entry1 != callee_registers_start.end()) { |
+ |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<"After FindCallerRegs:ra = " |
+ <<hex<<entry1->second ; |
+ #endif |
+ |
+ callee_registers_start["$ra"] = entry1->second; |
+ pc = entry1->second - 8; |
+ } |
+ |
+ callee_registers_start["$pc"] = pc; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<" Callee frame start populated cfa = " |
+ <<hex<<callee_registers_start[".cfa"]<<" $ra = " |
+ << callee_registers_start["$ra"] |
+ << "$pc = " <<callee_registers_start["$pc"]<< "$sp = " |
+ <<callee_registers_start["$sp"]<<dec; |
+ #endif |
+ |
+ StackFrameMIPS * new_frame = new StackFrameMIPS(*last_frame); |
+ |
+ // If the resolver has DWARF CFI information, use that. |
+ |
+ for (int i = 0; register_names[i]; i++) { |
+ CFIFrameInfo::RegisterValueMap<u_int32_t>::iterator entry = |
+ callee_registers_start.find(register_names[i]); |
+ if (entry != caller_registers.end()) { |
+ // We recovered the value of this register; fill the context with the |
+ // value from caller_registers. |
+ new_frame->context.iregs[i] = entry->second; |
+ } |
+ else { |
+ callee_registers_start[register_names[i]] = |
+ callee_registers[register_names[i]]; |
+ new_frame->context.iregs[i] = last_frame->context.iregs[i] ; |
+ } |
+ } |
+ |
+ new_frame->context.epc = callee_registers_start["$pc"]; |
+ new_frame->instruction = callee_registers_start["$pc"]; |
+ |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<hex<<" Calling FindCFIFrameInfo, sp : " |
+ << callee_registers_start["$sp"] << "$zero = " |
+ <<callee_registers_start["$zero"] <<dec; |
+ #endif |
+ |
+ CFIFrameInfo *cfi_frame_info_new = |
+ resolver_ ? resolver_->FindCFIFrameInfo(new_frame) : NULL; |
+ |
+ if (cfi_frame_info_new) { |
+ if (!cfi_frame_info_new->FindCallerRegs(callee_registers_start, |
+ *memory_,&caller_registers)) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " FindCallerRegs failed Returning NULL "; |
+ #endif |
+ |
+ return NULL; |
+ } |
+ } |
+ |
+ else { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " cfi_frame_info_new NULL "; |
+ #endif |
+ if (!resolver_) |
+ BPLOG(INFO) << " resolver NULL "; |
+ } |
+ |
+ entry1 = callee_registers_start.find(".ra"); |
+ if (entry1 != callee_registers_start.end()) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<" After FindCallerRegs,ra = " |
+ <<hex<<entry1->second ; |
+ #endif |
+ callee_registers_start["$ra"] = entry1->second; |
+ } |
+ |
+ // Construct a new stack frame given the values the CFI recovered. |
+ scoped_ptr<StackFrameMIPS> frame(new StackFrameMIPS()); |
+ |
+ for (int i = 0; register_names[i]; i++) { |
+ CFIFrameInfo::RegisterValueMap<u_int32_t>::iterator entry = |
+ callee_registers_start.find(register_names[i]); |
+ if (entry != callee_registers_start.end()) { |
+ // We recovered the value of this register; fill the context with the |
+ // value from caller_registers. |
+ // frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); |
+ frame->context.iregs[i] = entry->second; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Entry recovered "<<register_names[i] << " val " |
+ << hex << frame->context.iregs[i] <<dec; |
+ #endif |
+ } else if (0 <= i && i <= 31 ) { |
+ // If the STACK CFI data doesn't mention some callee-saves register, and |
+ // it is valid in the callee, assume the callee has not yet changed it. |
+ // Registers r4 through r11 are callee-saves, according to the Procedure |
+ // Call Standard for the ARM Architecture, which the Linux ABI follows. |
+ //frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); |
+ |
+ frame->context.iregs[i] = last_frame->context.iregs[i]; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Entry copied "<<register_names[i] << " val " |
+ <<hex << frame->context.iregs[i] << "\tindex " <<dec << i; |
+ #endif |
+ } |
+ } |
+ |
+ CFIFrameInfo::RegisterValueMap<u_int32_t>::iterator entry = |
+ caller_registers.find(".cfa"); |
+ if (entry != caller_registers.end()) { |
+ BPLOG(INFO) << " .cfa : " <<hex << entry->second; |
+ } |
+ else { |
+ BPLOG(INFO) << " .cfa not found: " ; |
+ } |
+ entry = caller_registers.find(".ra"); |
+ if (entry != caller_registers.end()) { |
+ BPLOG(INFO) << " .ra : " << entry->second; |
+ } |
+ else { |
+ BPLOG(INFO) << " .ra not found: " ; |
+ } |
+ entry = callee_registers_start.find("$pc"); |
+ if (entry != callee_registers_start.end()) { |
+ frame->context.epc = entry->second; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " .epc : " << entry->second; |
+ #endif |
+ } |
+ entry = caller_registers.find("$ra"); |
+ if (entry == caller_registers.end()) |
+ { |
+ frame->context.iregs[31/*RA_INDEX*/] = entry->second; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << "ra copied : " << entry->second; |
+ #endif |
+ } |
+ frame->trust = StackFrame::FRAME_TRUST_CFI; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << "Returning frame pc = 0x"<< caller_registers["$pc"] <<dec; |
+ #endif |
+ |
+ return frame.release(); |
+} |
+ |
+StackFrame *StackwalkerMIPS::GetCallerFrame(const CallStack *stack) { |
+ if (!memory_ || !stack) { |
+ BPLOG(ERROR) << "Can't get caller frame without memory or stack"; |
+ return NULL; |
+ } |
+ |
+ const vector<StackFrame *> &frames = *stack->frames(); |
+ StackFrameMIPS *last_frame = static_cast<StackFrameMIPS *>(frames.back()); |
+ scoped_ptr<StackFrameMIPS> new_frame; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Entering " << __FUNCTION__; |
+ #endif |
+ // If the resolver has DWARF CFI information, use that. |
+ if (!new_frame.get()) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<"Calling FindCFIFrameInfo for last frame"; |
+ #endif |
+ CFIFrameInfo *cfi_frame_info = |
+ resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL; |
+ if (cfi_frame_info) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << __FUNCTION__ <<" FindCFIFrameInfo completed" ; |
+ #endif |
+ new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info)); |
+ } |
+ } |
+ |
+ if (!new_frame.get()) { |
+ #ifdef SW_DEBUG |
+ printf("Entering GetCallerByFPAtBase %s %d\n",__FILE__,__LINE__); |
+ #endif |
+ new_frame.reset(GetCallerByFPAtBase(frames)); |
+ } |
+ // If nothing worked, tell the caller. |
+ if (!new_frame.get()) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Returning NULL "; |
+ #endif |
+ return NULL; |
+ } |
+ |
+ // Treat an instruction address of 0 as end-of-stack. |
+ if (new_frame->context.epc== 0) { |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " EPC 0 Returning NULL "; |
+ #endif |
+ return NULL; |
+ } |
+ |
+ // If the new stack pointer is at a lower address than the old, then |
+ // that's clearly incorrect. Treat this as end-of-stack to enforce |
+ // progress and avoid infinite loops. |
+ |
+ if (new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]<= |
+ last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]){ |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Stack pointer issue old " << hex << |
+ last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]<<" new " |
+ <<new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]<<dec<< |
+ "Returning NULL "; |
+ #endif |
+ } |
+ |
+ // new_frame->context.epc is the return address, which is one instruction |
+ // past the CALL that caused us to arrive at the callee. Set |
+ // new_frame->instruction to one less than that. This won't reference the |
+ // beginning of the CALL instruction, but it's guaranteed to be within |
+ // the CALL, which is sufficient to get the source line information to |
+ // match up with the line that contains a function call. Callers that |
+ // require the exact return address value may access the context.epc |
+ // field of StackFrameMIPS. |
+ new_frame->instruction = new_frame->context.epc; |
+ |
+ return new_frame.release(); |
+} |
+ |
+ // In the prologue of mips, Frame Pointer is updated only after stacksize |
+ // is updated. $ra can be found by content of address ($s8+variable_offest) |
+ // So we cannot obtain $ra by dereferencing frame pointer + a fixed offset. |
+ // Previous implementation was using frame pointer to get $ra |
+ // which resulted in junk frames. |
+ |
+#define MAX_FRAME_STACK_SIZE 1024 |
+StackFrameMIPS *StackwalkerMIPS::GetCallerByFPAtBase( |
+ const vector<StackFrame *> &frames) { |
+ StackFrame::FrameTrust trust; |
+ StackFrameMIPS *last_frame = static_cast<StackFrameMIPS *>(frames.back()); |
+ u_int32_t last_esp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]; |
+ u_int32_t last_efp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_FP]; |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << " Entering GetCallerByFPAtBase"; |
+ #endif |
+ |
+ u_int32_t caller_epc, caller_esp, caller_efp; |
+ // Return address pc cannot be obtained directly. |
+ // So commenting this and forcing stackwalking |
+#if 0 |
+ if (memory_->GetMemoryAtAddress(last_efp + 4, &caller_epc) && |
+ memory_->GetMemoryAtAddress(last_efp, &caller_efp)) { |
+ caller_esp = last_efp + 8; |
+ trust = StackFrame::FRAME_TRUST_FP; |
+ } else |
+#endif |
+ { |
+ // 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 = MAX_FRAME_STACK_SIZE/sizeof(caller_epc); |
+ do |
+ { |
+ /*Scanning for return address from stack pointer of last frame*/ |
+ if (!ScanForReturnAddress(last_esp, &caller_esp, &caller_epc, count)) { |
+ // if we can't find an instruction pointer even with stack scanning, |
+ // give up. |
+ BPLOG(ERROR) << " ScanForReturnAddress failed " ; |
+ return NULL; |
+ } |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << "count "<<count<< std::hex<<" last_esp: " |
+ <<last_esp<< " caller_esp: " <<caller_esp<<" caller_epc: " |
+ <<caller_epc<< std::dec; |
+ if (caller_esp == last_esp) { |
+ BPLOG(INFO) << " Retrieved caller_esp and last_esp are same." ; |
+ } |
+ #endif |
+ if (!memory_->GetMemoryAtAddress(caller_esp-4, &caller_efp)) |
+ { |
+ BPLOG(INFO) << " GetMemoryAtAddress failed " ; |
+ return NULL; |
+ } |
+ #ifdef SW_DEBUG |
+ BPLOG(INFO) << std::hex<< " caller_efp: " <<caller_efp<< std::dec; |
+ #endif |
+ |
+ count = count - ( caller_esp - last_esp)/sizeof(caller_epc); |
+ /* Now scan the next address in the stack*/ |
+ last_esp = caller_esp+sizeof(caller_epc); |
+ }while (caller_efp - caller_esp >= MAX_FRAME_STACK_SIZE && count > 0); |
+ |
+ if (!count) |
+ { |
+ BPLOG(INFO) << " No frame found " ; |
+ return NULL; |
+ } |
+ |
+ // ScanForReturnAddress found a reasonable return address. Advance |
+ // %esp to the location above the one where the return address was |
+ // found. Assume that %ebp is unchanged. |
+ caller_esp += 4; |
+ caller_efp = last_efp; |
+ trust = StackFrame::FRAME_TRUST_SCAN; |
+ } |
+ |
+ // Create a new stack frame (ownership will be transferred to the caller) |
+ // and fill it in. |
+ StackFrameMIPS *frame = new StackFrameMIPS(); |
+ frame->trust = trust; |
+ frame->context = last_frame->context; |
+ frame->context.epc = caller_epc; |
+ frame->instruction = caller_epc; |
+ frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_esp; |
+ frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_efp; |
+ frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_epc; |
+ #ifdef SW_DEBUG |
+ for (int i = 0; register_names[i]; i++) { |
+ BPLOG(INFO) << register_names[i] << " :0x" |
+ <<hex << frame->context.iregs[i]<<dec; |
+ } |
+ #endif |
+ |
+ return frame; |
+ } |
+ |
+ |
+} // namespace google_breakpad |
Property changes on: src/processor/stackwalker_MIPS.cc |
___________________________________________________________________ |
Added: svn:executable |
+ * |