15f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// Copyright (c) 2013 Google Inc. 25f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// All rights reserved. 35f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// 45f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// Redistribution and use in source and binary forms, with or without 55f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// modification, are permitted provided that the following conditions are 65f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// met: 75f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// 85f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// * Redistributions of source code must retain the above copyright 95f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// notice, this list of conditions and the following disclaimer. 105f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// * Redistributions in binary form must reproduce the above 115f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// copyright notice, this list of conditions and the following disclaimer 125f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// in the documentation and/or other materials provided with the 135f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// distribution. 145f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// * Neither the name of Google Inc. nor the names of its 155f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// contributors may be used to endorse or promote products derived from 165f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// this software without specific prior written permission. 175f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// 185f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 305f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// stackwalker_mips.cc: MIPS-specific stackwalker. 315f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// 325f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// See stackwalker_mips.h for documentation. 335f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// 345f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// Author: Tata Elxsi 355f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 365f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "common/scoped_ptr.h" 375f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/processor/call_stack.h" 385f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/processor/code_modules.h" 395f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/processor/memory_region.h" 405f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/processor/source_line_resolver_interface.h" 415f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/processor/stack_frame_cpu.h" 425f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "processor/cfi_frame_info.h" 435f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "processor/logging.h" 445f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "processor/postfix_evaluator-inl.h" 455f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "processor/stackwalker_mips.h" 465f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "processor/windows_frame_info.h" 475f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#include "google_breakpad/common/minidump_cpu_mips.h" 485f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 495f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comnamespace google_breakpad { 505f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 515f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comStackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info, 525f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const MDRawContextMIPS* context, 535f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com MemoryRegion* memory, 545f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const CodeModules* modules, 555f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameSymbolizer* resolver_helper) 565f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com : Stackwalker(system_info, memory, modules, resolver_helper), 575f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com context_(context) { 585f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (memory_ && memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { 595f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(ERROR) << "Memory out of range for stackwalking: " 605f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com << HexString(memory_->GetBase()) 615f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com << "+" 625f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com << HexString(memory_->GetSize()); 635f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com memory_ = NULL; 645f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 655f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} 665f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 675f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comStackFrame* StackwalkerMIPS::GetContextFrame() { 685f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!context_) { 695f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(ERROR) << "Can't get context frame without context."; 705f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 715f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 725f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 735f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS* frame = new StackFrameMIPS(); 745f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 755f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // The instruction pointer is stored directly in a register, so pull it 765f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // straight out of the CPU context structure. 775f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context = *context_; 785f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity = StackFrameMIPS::CONTEXT_VALID_ALL; 795f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->trust = StackFrame::FRAME_TRUST_CONTEXT; 805f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->instruction = frame->context.epc; 815f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 825f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return frame; 835f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} 845f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 855f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com// Register names for mips. 865f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comstatic const char* const kRegisterNames[] = { 875f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$to", "$t1", 885f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", 895f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", 905f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com "$fp", "$ra", NULL 915f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // TODO(gordanac): add float point save registers 925f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com}; 935f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 945f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comStackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( 955f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const vector<StackFrame*>& frames, 965f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com CFIFrameInfo* cfi_frame_info) { 975f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS* last_frame = static_cast<StackFrameMIPS*>(frames.back()); 985f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 99f1b5421da522c879c1f3c3e4fb1ba8cc0af67f16gordana.cmiljanovic@imgtec.com uint32_t sp = 0, pc = 0; 1005f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1015f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Populate a dictionary with the valid register values in last_frame. 1025f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; 1035f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Use the STACK CFI data to recover the caller's register values. 1045f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 1055f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1065f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com for (int i = 0; kRegisterNames[i]; ++i) { 1075f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; 1085f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; 1095f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1105f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1115f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, 1125f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com &caller_registers)) { 1135f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 1145f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1155f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1165f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator entry = 1175f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers.find(".cfa"); 1185f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1195f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (entry != caller_registers.end()) { 1205f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com sp = entry->second; 1215f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers["$sp"] = entry->second; 1225f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1235f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1245f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com entry = caller_registers.find(".ra"); 1255f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (entry != caller_registers.end()) { 1265f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers["$ra"] = entry->second; 1275f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com pc = entry->second - 2 * sizeof(pc); 1285f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1295f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers["$pc"] = pc; 1305f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Construct a new stack frame given the values the CFI recovered. 1315f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com scoped_ptr<StackFrameMIPS> frame(new StackFrameMIPS()); 1325f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1335f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com for (int i = 0; kRegisterNames[i]; ++i) { 1345f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator caller_entry = 1355f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_registers.find(kRegisterNames[i]); 1365f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1375f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (caller_entry != caller_registers.end()) { 1385f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // The value of this register is recovered; fill the context with the 1395f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // value from caller_registers. 1405f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[i] = caller_entry->second; 1415f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); 142ef85cf97b96b051078ef13fb19c17f7c5515e610gordana.cmiljanovic@imgtec.com } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) || 143ef85cf97b96b051078ef13fb19c17f7c5515e610gordana.cmiljanovic@imgtec.com (i > INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) && 1445f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com (last_frame->context_validity & 1455f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS::RegisterValidFlag(i))) { 1465f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // If the STACK CFI data doesn't mention some callee-save register, and 1475f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // it is valid in the callee, assume the callee has not yet changed it. 1485f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Calee-save registers according to the MIPS o32 ABI specification are: 1495f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // $s0 to $s7 1505f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // $sp, $s8 1515f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[i] = last_frame->context.iregs[i]; 1525f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); 1535f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1545f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1555f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1565f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.epc = caller_registers["$pc"]; 1575f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->instruction = caller_registers["$pc"]; 1585f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; 1595f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1605f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"]; 1615f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; 1625f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1635f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->trust = StackFrame::FRAME_TRUST_CFI; 1645f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1655f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return frame.release(); 1665f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} 1675f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1685f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comStackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack, 1695f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com bool stack_scan_allowed) { 1705f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!memory_ || !stack) { 1715f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(ERROR) << "Can't get caller frame without memory or stack"; 1725f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 1735f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1745f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1755f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const vector<StackFrame*>& frames = *stack->frames(); 1765f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS* last_frame = static_cast<StackFrameMIPS*>(frames.back()); 1775f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com scoped_ptr<StackFrameMIPS> new_frame; 1785f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1795f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // See if there is DWARF call frame information covering this address. 1805f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com scoped_ptr<CFIFrameInfo> cfi_frame_info( 1815f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame_symbolizer_->FindCFIFrameInfo(last_frame)); 1825f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (cfi_frame_info.get()) 1835f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); 1845f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1855f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // If caller frame is not found in CFI try analyzing the stack. 1865f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (stack_scan_allowed && !new_frame.get()) { 1875f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com new_frame.reset(GetCallerByStackScan(frames)); 1885f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1895f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1905f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // If nothing worked, tell the caller. 1915f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!new_frame.get()) { 1925f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 1935f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1945f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 1955f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Treat an instruction address of 0 as end-of-stack. 1965f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (new_frame->context.epc == 0) { 1975f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 1985f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 1995f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2005f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // If the new stack pointer is at a lower address than the old, then 2015f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // that's clearly incorrect. Treat this as end-of-stack to enforce 2025f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // progress and avoid infinite loops. 2035f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] <= 2045f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]) { 2055f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 2065f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 2075f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2085f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return new_frame.release(); 2095f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} 2105f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2115f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.comStackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( 2125f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const vector<StackFrame*>& frames) { 2135f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const uint32_t kMaxFrameStackSize = 1024; 2145f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com const uint32_t kMinArgsOnStack = 4; 2155f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2165f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS* last_frame = static_cast<StackFrameMIPS*>(frames.back()); 2175f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2185f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]; 2195f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com uint32_t caller_pc, caller_sp, caller_fp; 2205f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2215f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Return address cannot be obtained directly. 2225f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Force stackwalking. 2235f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2245f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // We cannot use frame pointer to get the return address. 2255f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // We'll scan the stack for a 2265f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // return address. This can happen if last_frame is executing code 2275f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // for a module for which we don't have symbols. 2285f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com int count = kMaxFrameStackSize / sizeof(caller_pc); 2295f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2305f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (frames.size() > 1) { 2315f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // In case of mips32 ABI stack frame of a nonleaf function 2325f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // must have minimum stack frame assigned for 4 arguments (4 words). 2335f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Move stack pointer for 4 words to avoid reporting non-existing frames 2345f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // for all frames except the topmost one. 2355f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // There is no way of knowing if topmost frame belongs to a leaf or 2365f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // a nonleaf function. 2375f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com last_sp += kMinArgsOnStack * sizeof(caller_pc); 2385f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Adjust 'count' so that return address is scanned only in limits 2395f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // of one stack frame. 2405f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com count -= kMinArgsOnStack; 2415f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 2425f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2435f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com do { 2445f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Scanning for return address from stack pointer of the last frame. 2455f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) { 2465f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // If we can't find an instruction pointer even with stack scanning, 2475f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // give up. 2485f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(ERROR) << " ScanForReturnAddress failed "; 2495f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 2505f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 2515f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Get $fp stored in the stack frame. 2525f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc), 2535f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com &caller_fp)) { 2545f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ; 2555f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 2565f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 2575f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2585f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com count = count - (caller_sp - last_sp) / sizeof(caller_pc); 2595f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Now scan the next address in the stack. 2605f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com last_sp = caller_sp + sizeof(caller_pc); 2615f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0); 2625f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2635f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com if (!count) { 2645f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com BPLOG(INFO) << " No frame found " ; 2655f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return NULL; 2665f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com } 2675f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2685f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // ScanForReturnAddress found a reasonable return address. Advance 2695f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // $sp to the location above the one where the return address was 2705f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // found. 2715f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_sp += sizeof(caller_pc); 2725f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // caller_pc is actually containing $ra value; 2735f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // $pc is two instructions before $ra, 2745f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // so the caller_pc needs to be decremented accordingly. 2755f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_pc -= 2 * sizeof(caller_pc); 2765f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2775f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2785f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // Create a new stack frame (ownership will be transferred to the caller) 2795f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com // and fill it in. 2805f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com StackFrameMIPS* frame = new StackFrameMIPS(); 2815f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->trust = StackFrame::FRAME_TRUST_SCAN; 2825f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context = last_frame->context; 2835f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.epc = caller_pc; 2845f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; 2855f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->instruction = caller_pc; 2865f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2875f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp; 2885f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP; 2895f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp; 2905f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP; 2915f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2925f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = 2935f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com caller_pc + 2 * sizeof(caller_pc); 2945f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; 2955f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2965f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com return frame; 2975f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} 2985f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 2995f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com} // namespace google_breakpad 3005f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com 301