1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,246 @@ 1.4 +// Copyright (c) 2010 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// stackwalker.cc: Generic stackwalker. 1.34 +// 1.35 +// See stackwalker.h for documentation. 1.36 +// 1.37 +// Author: Mark Mentovai 1.38 + 1.39 +#include "google_breakpad/processor/stackwalker.h" 1.40 + 1.41 +#include <assert.h> 1.42 + 1.43 +#include "common/scoped_ptr.h" 1.44 +#include "google_breakpad/processor/call_stack.h" 1.45 +#include "google_breakpad/processor/code_module.h" 1.46 +#include "google_breakpad/processor/code_modules.h" 1.47 +#include "google_breakpad/processor/minidump.h" 1.48 +#include "google_breakpad/processor/stack_frame.h" 1.49 +#include "google_breakpad/processor/stack_frame_symbolizer.h" 1.50 +#include "google_breakpad/processor/system_info.h" 1.51 +#include "processor/linked_ptr.h" 1.52 +#include "common/logging.h" 1.53 +#include "processor/stackwalker_ppc.h" 1.54 +#include "processor/stackwalker_sparc.h" 1.55 +#include "processor/stackwalker_x86.h" 1.56 +#include "processor/stackwalker_amd64.h" 1.57 +#include "processor/stackwalker_arm.h" 1.58 + 1.59 +namespace google_breakpad { 1.60 + 1.61 +const int Stackwalker::kRASearchWords = 30; 1.62 + 1.63 +uint32_t Stackwalker::max_frames_ = 1024; 1.64 +bool Stackwalker::max_frames_set_ = false; 1.65 + 1.66 +uint32_t Stackwalker::max_frames_scanned_ = 1024; 1.67 + 1.68 +Stackwalker::Stackwalker(const SystemInfo* system_info, 1.69 + MemoryRegion* memory, 1.70 + const CodeModules* modules, 1.71 + StackFrameSymbolizer* frame_symbolizer) 1.72 + : system_info_(system_info), 1.73 + memory_(memory), 1.74 + modules_(modules), 1.75 + frame_symbolizer_(frame_symbolizer) { 1.76 + assert(frame_symbolizer_); 1.77 +} 1.78 + 1.79 + 1.80 +bool Stackwalker::Walk(CallStack* stack, 1.81 + vector<const CodeModule*>* modules_without_symbols) { 1.82 + BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|"; 1.83 + assert(stack); 1.84 + stack->Clear(); 1.85 + 1.86 + BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " 1.87 + << "|modules_without_symbols|"; 1.88 + assert(modules_without_symbols); 1.89 + 1.90 + // Begin with the context frame, and keep getting callers until there are 1.91 + // no more. 1.92 + 1.93 + // Keep track of the number of scanned or otherwise dubious frames seen 1.94 + // so far, as the caller may have set a limit. 1.95 + uint32_t n_scanned_frames = 0; 1.96 + 1.97 + // Take ownership of the pointer returned by GetContextFrame. 1.98 + scoped_ptr<StackFrame> frame(GetContextFrame()); 1.99 + 1.100 + while (frame.get()) { 1.101 + // frame already contains a good frame with properly set instruction and 1.102 + // frame_pointer fields. The frame structure comes from either the 1.103 + // context frame (above) or a caller frame (below). 1.104 + 1.105 + // Resolve the module information, if a module map was provided. 1.106 + StackFrameSymbolizer::SymbolizerResult symbolizer_result = 1.107 + frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, 1.108 + frame.get()); 1.109 + if (symbolizer_result == StackFrameSymbolizer::kInterrupt) { 1.110 + BPLOG(INFO) << "Stack walk is interrupted."; 1.111 + return false; 1.112 + } 1.113 + 1.114 + // Keep track of modules that have no symbols. 1.115 + if (symbolizer_result == StackFrameSymbolizer::kError && 1.116 + frame->module != NULL) { 1.117 + bool found = false; 1.118 + vector<const CodeModule*>::iterator iter; 1.119 + for (iter = modules_without_symbols->begin(); 1.120 + iter != modules_without_symbols->end(); 1.121 + ++iter) { 1.122 + if (*iter == frame->module) { 1.123 + found = true; 1.124 + break; 1.125 + } 1.126 + } 1.127 + if (!found) { 1.128 + BPLOG(INFO) << "Couldn't load symbols for: " 1.129 + << frame->module->debug_file() << "|" 1.130 + << frame->module->debug_identifier(); 1.131 + modules_without_symbols->push_back(frame->module); 1.132 + } 1.133 + } 1.134 + 1.135 + // Keep track of the number of dubious frames so far. 1.136 + switch (frame.get()->trust) { 1.137 + case StackFrame::FRAME_TRUST_NONE: 1.138 + case StackFrame::FRAME_TRUST_SCAN: 1.139 + case StackFrame::FRAME_TRUST_CFI_SCAN: 1.140 + n_scanned_frames++; 1.141 + break; 1.142 + default: 1.143 + break; 1.144 + } 1.145 + 1.146 + // Add the frame to the call stack. Relinquish the ownership claim 1.147 + // over the frame, because the stack now owns it. 1.148 + stack->frames_.push_back(frame.release()); 1.149 + if (stack->frames_.size() > max_frames_) { 1.150 + // Only emit an error message in the case where the limit that we 1.151 + // reached is the default limit, not set by the user. 1.152 + if (!max_frames_set_) 1.153 + BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames."; 1.154 + break; 1.155 + } 1.156 + 1.157 + // Get the next frame and take ownership. 1.158 + bool stack_scan_allowed = n_scanned_frames < max_frames_scanned_; 1.159 + frame.reset(GetCallerFrame(stack, stack_scan_allowed)); 1.160 + } 1.161 + 1.162 + return true; 1.163 +} 1.164 + 1.165 + 1.166 +// static 1.167 +Stackwalker* Stackwalker::StackwalkerForCPU( 1.168 + const SystemInfo* system_info, 1.169 + MinidumpContext* context, 1.170 + MemoryRegion* memory, 1.171 + const CodeModules* modules, 1.172 + StackFrameSymbolizer* frame_symbolizer) { 1.173 + if (!context) { 1.174 + BPLOG(ERROR) << "Can't choose a stackwalker implementation without context"; 1.175 + return NULL; 1.176 + } 1.177 + 1.178 + Stackwalker* cpu_stackwalker = NULL; 1.179 + 1.180 + uint32_t cpu = context->GetContextCPU(); 1.181 + switch (cpu) { 1.182 + case MD_CONTEXT_X86: 1.183 + cpu_stackwalker = new StackwalkerX86(system_info, 1.184 + context->GetContextX86(), 1.185 + memory, modules, frame_symbolizer); 1.186 + break; 1.187 + 1.188 + case MD_CONTEXT_PPC: 1.189 + cpu_stackwalker = new StackwalkerPPC(system_info, 1.190 + context->GetContextPPC(), 1.191 + memory, modules, frame_symbolizer); 1.192 + break; 1.193 + 1.194 + case MD_CONTEXT_AMD64: 1.195 + cpu_stackwalker = new StackwalkerAMD64(system_info, 1.196 + context->GetContextAMD64(), 1.197 + memory, modules, frame_symbolizer); 1.198 + break; 1.199 + 1.200 + case MD_CONTEXT_SPARC: 1.201 + cpu_stackwalker = new StackwalkerSPARC(system_info, 1.202 + context->GetContextSPARC(), 1.203 + memory, modules, frame_symbolizer); 1.204 + break; 1.205 + 1.206 + case MD_CONTEXT_ARM: 1.207 + int fp_register = -1; 1.208 + if (system_info->os_short == "ios") 1.209 + fp_register = MD_CONTEXT_ARM_REG_IOS_FP; 1.210 + cpu_stackwalker = new StackwalkerARM(system_info, 1.211 + context->GetContextARM(), 1.212 + fp_register, memory, modules, 1.213 + frame_symbolizer); 1.214 + break; 1.215 + } 1.216 + 1.217 + BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << 1.218 + ", can't choose a stackwalker " 1.219 + "implementation"; 1.220 + return cpu_stackwalker; 1.221 +} 1.222 + 1.223 +bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) { 1.224 + StackFrame frame; 1.225 + frame.instruction = address; 1.226 + StackFrameSymbolizer::SymbolizerResult symbolizer_result = 1.227 + frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, &frame); 1.228 + 1.229 + if (!frame.module) { 1.230 + // not inside any loaded module 1.231 + return false; 1.232 + } 1.233 + 1.234 + if (!frame_symbolizer_->HasImplementation()) { 1.235 + // No valid implementation to symbolize stack frame, but the address is 1.236 + // within a known module. 1.237 + return true; 1.238 + } 1.239 + 1.240 + if (symbolizer_result != StackFrameSymbolizer::kNoError) { 1.241 + // Some error occurred during symbolization, but the address is within a 1.242 + // known module 1.243 + return true; 1.244 + } 1.245 + 1.246 + return !frame.function_name.empty(); 1.247 +} 1.248 + 1.249 +} // namespace google_breakpad