stackwalker.cc revision 42b91fbbf30f8a6d900d1fb97e96394dbb363890
1// Copyright (c) 2010 Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30// stackwalker.cc: Generic stackwalker. 31// 32// See stackwalker.h for documentation. 33// 34// Author: Mark Mentovai 35 36#include "google_breakpad/processor/stackwalker.h" 37 38#include <assert.h> 39 40#include "common/scoped_ptr.h" 41#include "google_breakpad/processor/call_stack.h" 42#include "google_breakpad/processor/code_module.h" 43#include "google_breakpad/processor/code_modules.h" 44#include "google_breakpad/processor/minidump.h" 45#include "google_breakpad/processor/stack_frame.h" 46#include "google_breakpad/processor/stack_frame_symbolizer.h" 47#include "google_breakpad/processor/system_info.h" 48#include "processor/linked_ptr.h" 49#include "processor/logging.h" 50#include "processor/stackwalker_ppc.h" 51#include "processor/stackwalker_ppc64.h" 52#include "processor/stackwalker_sparc.h" 53#include "processor/stackwalker_x86.h" 54#include "processor/stackwalker_amd64.h" 55#include "processor/stackwalker_arm.h" 56 57namespace google_breakpad { 58 59const int Stackwalker::kRASearchWords = 30; 60 61uint32_t Stackwalker::max_frames_ = 1024; 62bool Stackwalker::max_frames_set_ = false; 63 64uint32_t Stackwalker::max_frames_scanned_ = 1024; 65 66Stackwalker::Stackwalker(const SystemInfo* system_info, 67 MemoryRegion* memory, 68 const CodeModules* modules, 69 StackFrameSymbolizer* frame_symbolizer) 70 : system_info_(system_info), 71 memory_(memory), 72 modules_(modules), 73 frame_symbolizer_(frame_symbolizer) { 74 assert(frame_symbolizer_); 75} 76 77void InsertSpecialAttentionModule( 78 StackFrameSymbolizer::SymbolizerResult symbolizer_result, 79 const CodeModule* module, 80 vector<const CodeModule*>* modules) { 81 if (!module) { 82 return; 83 } 84 assert(symbolizer_result == StackFrameSymbolizer::kError || 85 symbolizer_result == StackFrameSymbolizer::kWarningCorruptSymbols); 86 bool found = false; 87 vector<const CodeModule*>::iterator iter; 88 for (iter = modules->begin(); iter != modules->end(); ++iter) { 89 if (*iter == module) { 90 found = true; 91 break; 92 } 93 } 94 if (!found) { 95 BPLOG(INFO) << ((symbolizer_result == StackFrameSymbolizer::kError) ? 96 "Couldn't load symbols for: " : 97 "Detected corrupt symbols for: ") 98 << module->debug_file() << "|" << module->debug_identifier(); 99 modules->push_back(module); 100 } 101} 102 103bool Stackwalker::Walk( 104 CallStack* stack, 105 vector<const CodeModule*>* modules_without_symbols, 106 vector<const CodeModule*>* modules_with_corrupt_symbols) { 107 BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|"; 108 assert(stack); 109 stack->Clear(); 110 111 BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " 112 << "|modules_without_symbols|"; 113 BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " 114 << "|modules_with_corrupt_symbols|"; 115 assert(modules_without_symbols); 116 assert(modules_with_corrupt_symbols); 117 118 // Begin with the context frame, and keep getting callers until there are 119 // no more. 120 121 // Keep track of the number of scanned or otherwise dubious frames seen 122 // so far, as the caller may have set a limit. 123 uint32_t scanned_frames = 0; 124 125 // Take ownership of the pointer returned by GetContextFrame. 126 scoped_ptr<StackFrame> frame(GetContextFrame()); 127 128 while (frame.get()) { 129 // frame already contains a good frame with properly set instruction and 130 // frame_pointer fields. The frame structure comes from either the 131 // context frame (above) or a caller frame (below). 132 133 // Resolve the module information, if a module map was provided. 134 StackFrameSymbolizer::SymbolizerResult symbolizer_result = 135 frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, 136 frame.get()); 137 switch (symbolizer_result) { 138 case StackFrameSymbolizer::kInterrupt: 139 BPLOG(INFO) << "Stack walk is interrupted."; 140 return false; 141 break; 142 case StackFrameSymbolizer::kError: 143 InsertSpecialAttentionModule(symbolizer_result, frame->module, 144 modules_without_symbols); 145 break; 146 case StackFrameSymbolizer::kWarningCorruptSymbols: 147 InsertSpecialAttentionModule(symbolizer_result, frame->module, 148 modules_with_corrupt_symbols); 149 break; 150 case StackFrameSymbolizer::kNoError: 151 break; 152 default: 153 assert(false); 154 break; 155 } 156 157 // Keep track of the number of dubious frames so far. 158 switch (frame.get()->trust) { 159 case StackFrame::FRAME_TRUST_NONE: 160 case StackFrame::FRAME_TRUST_SCAN: 161 case StackFrame::FRAME_TRUST_CFI_SCAN: 162 scanned_frames++; 163 break; 164 default: 165 break; 166 } 167 168 // Add the frame to the call stack. Relinquish the ownership claim 169 // over the frame, because the stack now owns it. 170 stack->frames_.push_back(frame.release()); 171 if (stack->frames_.size() > max_frames_) { 172 // Only emit an error message in the case where the limit 173 // reached is the default limit, not set by the user. 174 if (!max_frames_set_) 175 BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames."; 176 break; 177 } 178 179 // Get the next frame and take ownership. 180 bool stack_scan_allowed = scanned_frames < max_frames_scanned_; 181 frame.reset(GetCallerFrame(stack, stack_scan_allowed)); 182 } 183 184 return true; 185} 186 187 188// static 189Stackwalker* Stackwalker::StackwalkerForCPU( 190 const SystemInfo* system_info, 191 MinidumpContext* context, 192 MemoryRegion* memory, 193 const CodeModules* modules, 194 StackFrameSymbolizer* frame_symbolizer) { 195 if (!context) { 196 BPLOG(ERROR) << "Can't choose a stackwalker implementation without context"; 197 return NULL; 198 } 199 200 Stackwalker* cpu_stackwalker = NULL; 201 202 uint32_t cpu = context->GetContextCPU(); 203 switch (cpu) { 204 case MD_CONTEXT_X86: 205 cpu_stackwalker = new StackwalkerX86(system_info, 206 context->GetContextX86(), 207 memory, modules, frame_symbolizer); 208 break; 209 210 case MD_CONTEXT_PPC: 211 cpu_stackwalker = new StackwalkerPPC(system_info, 212 context->GetContextPPC(), 213 memory, modules, frame_symbolizer); 214 break; 215 216 case MD_CONTEXT_PPC64: 217 cpu_stackwalker = new StackwalkerPPC64(system_info, 218 context->GetContextPPC64(), 219 memory, modules, frame_symbolizer); 220 break; 221 222 case MD_CONTEXT_AMD64: 223 cpu_stackwalker = new StackwalkerAMD64(system_info, 224 context->GetContextAMD64(), 225 memory, modules, frame_symbolizer); 226 break; 227 228 case MD_CONTEXT_SPARC: 229 cpu_stackwalker = new StackwalkerSPARC(system_info, 230 context->GetContextSPARC(), 231 memory, modules, frame_symbolizer); 232 break; 233 234 case MD_CONTEXT_ARM: 235 int fp_register = -1; 236 if (system_info->os_short == "ios") 237 fp_register = MD_CONTEXT_ARM_REG_IOS_FP; 238 cpu_stackwalker = new StackwalkerARM(system_info, 239 context->GetContextARM(), 240 fp_register, memory, modules, 241 frame_symbolizer); 242 break; 243 } 244 245 BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << 246 ", can't choose a stackwalker " 247 "implementation"; 248 return cpu_stackwalker; 249} 250 251bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) { 252 StackFrame frame; 253 frame.instruction = address; 254 StackFrameSymbolizer::SymbolizerResult symbolizer_result = 255 frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, &frame); 256 257 if (!frame.module) { 258 // not inside any loaded module 259 return false; 260 } 261 262 if (!frame_symbolizer_->HasImplementation()) { 263 // No valid implementation to symbolize stack frame, but the address is 264 // within a known module. 265 return true; 266 } 267 268 if (symbolizer_result != StackFrameSymbolizer::kNoError && 269 symbolizer_result != StackFrameSymbolizer::kWarningCorruptSymbols) { 270 // Some error occurred during symbolization, but the address is within a 271 // known module 272 return true; 273 } 274 275 return !frame.function_name.empty(); 276} 277 278} // namespace google_breakpad 279