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/dump_context.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 #include "processor/stackwalker_arm64.h" 57 #include "processor/stackwalker_mips.h" 58 59 namespace google_breakpad { 60 61 const int Stackwalker::kRASearchWords = 30; 62 63 uint32_t Stackwalker::max_frames_ = 1024; 64 bool Stackwalker::max_frames_set_ = false; 65 66 uint32_t Stackwalker::max_frames_scanned_ = 1024; 67 68 Stackwalker::Stackwalker(const SystemInfo* system_info, 69 MemoryRegion* memory, 70 const CodeModules* modules, 71 StackFrameSymbolizer* frame_symbolizer) 72 : system_info_(system_info), 73 memory_(memory), 74 modules_(modules), 75 frame_symbolizer_(frame_symbolizer) { 76 assert(frame_symbolizer_); 77 } 78 79 void InsertSpecialAttentionModule( 80 StackFrameSymbolizer::SymbolizerResult symbolizer_result, 81 const CodeModule* module, 82 vector<const CodeModule*>* modules) { 83 if (!module) { 84 return; 85 } 86 assert(symbolizer_result == StackFrameSymbolizer::kError || 87 symbolizer_result == StackFrameSymbolizer::kWarningCorruptSymbols); 88 bool found = false; 89 vector<const CodeModule*>::iterator iter; 90 for (iter = modules->begin(); iter != modules->end(); ++iter) { 91 if (*iter == module) { 92 found = true; 93 break; 94 } 95 } 96 if (!found) { 97 BPLOG(INFO) << ((symbolizer_result == StackFrameSymbolizer::kError) ? 98 "Couldn't load symbols for: " : 99 "Detected corrupt symbols for: ") 100 << module->debug_file() << "|" << module->debug_identifier(); 101 modules->push_back(module); 102 } 103 } 104 105 bool Stackwalker::Walk( 106 CallStack* stack, 107 vector<const CodeModule*>* modules_without_symbols, 108 vector<const CodeModule*>* modules_with_corrupt_symbols) { 109 BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|"; 110 assert(stack); 111 stack->Clear(); 112 113 BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " 114 << "|modules_without_symbols|"; 115 BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " 116 << "|modules_with_corrupt_symbols|"; 117 assert(modules_without_symbols); 118 assert(modules_with_corrupt_symbols); 119 120 // Begin with the context frame, and keep getting callers until there are 121 // no more. 122 123 // Keep track of the number of scanned or otherwise dubious frames seen 124 // so far, as the caller may have set a limit. 125 uint32_t scanned_frames = 0; 126 127 // Take ownership of the pointer returned by GetContextFrame. 128 scoped_ptr<StackFrame> frame(GetContextFrame()); 129 130 while (frame.get()) { 131 // frame already contains a good frame with properly set instruction and 132 // frame_pointer fields. The frame structure comes from either the 133 // context frame (above) or a caller frame (below). 134 135 // Resolve the module information, if a module map was provided. 136 StackFrameSymbolizer::SymbolizerResult symbolizer_result = 137 frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, 138 frame.get()); 139 switch (symbolizer_result) { 140 case StackFrameSymbolizer::kInterrupt: 141 BPLOG(INFO) << "Stack walk is interrupted."; 142 return false; 143 break; 144 case StackFrameSymbolizer::kError: 145 InsertSpecialAttentionModule(symbolizer_result, frame->module, 146 modules_without_symbols); 147 break; 148 case StackFrameSymbolizer::kWarningCorruptSymbols: 149 InsertSpecialAttentionModule(symbolizer_result, frame->module, 150 modules_with_corrupt_symbols); 151 break; 152 case StackFrameSymbolizer::kNoError: 153 break; 154 default: 155 assert(false); 156 break; 157 } 158 159 // Keep track of the number of dubious frames so far. 160 switch (frame.get()->trust) { 161 case StackFrame::FRAME_TRUST_NONE: 162 case StackFrame::FRAME_TRUST_SCAN: 163 case StackFrame::FRAME_TRUST_CFI_SCAN: 164 scanned_frames++; 165 break; 166 default: 167 break; 168 } 169 170 // Add the frame to the call stack. Relinquish the ownership claim 171 // over the frame, because the stack now owns it. 172 stack->frames_.push_back(frame.release()); 173 if (stack->frames_.size() > max_frames_) { 174 // Only emit an error message in the case where the limit 175 // reached is the default limit, not set by the user. 176 if (!max_frames_set_) 177 BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames."; 178 break; 179 } 180 181 // Get the next frame and take ownership. 182 bool stack_scan_allowed = scanned_frames < max_frames_scanned_; 183 frame.reset(GetCallerFrame(stack, stack_scan_allowed)); 184 } 185 186 return true; 187 } 188 189 190 // static 191 Stackwalker* Stackwalker::StackwalkerForCPU( 192 const SystemInfo* system_info, 193 DumpContext* context, 194 MemoryRegion* memory, 195 const CodeModules* modules, 196 StackFrameSymbolizer* frame_symbolizer) { 197 if (!context) { 198 BPLOG(ERROR) << "Can't choose a stackwalker implementation without context"; 199 return NULL; 200 } 201 202 Stackwalker* cpu_stackwalker = NULL; 203 204 uint32_t cpu = context->GetContextCPU(); 205 switch (cpu) { 206 case MD_CONTEXT_X86: 207 cpu_stackwalker = new StackwalkerX86(system_info, 208 context->GetContextX86(), 209 memory, modules, frame_symbolizer); 210 break; 211 212 case MD_CONTEXT_PPC: 213 cpu_stackwalker = new StackwalkerPPC(system_info, 214 context->GetContextPPC(), 215 memory, modules, frame_symbolizer); 216 break; 217 218 case MD_CONTEXT_PPC64: 219 cpu_stackwalker = new StackwalkerPPC64(system_info, 220 context->GetContextPPC64(), 221 memory, modules, frame_symbolizer); 222 break; 223 224 case MD_CONTEXT_AMD64: 225 cpu_stackwalker = new StackwalkerAMD64(system_info, 226 context->GetContextAMD64(), 227 memory, modules, frame_symbolizer); 228 break; 229 230 case MD_CONTEXT_SPARC: 231 cpu_stackwalker = new StackwalkerSPARC(system_info, 232 context->GetContextSPARC(), 233 memory, modules, frame_symbolizer); 234 break; 235 236 case MD_CONTEXT_MIPS: 237 cpu_stackwalker = new StackwalkerMIPS(system_info, 238 context->GetContextMIPS(), 239 memory, modules, frame_symbolizer); 240 break; 241 242 case MD_CONTEXT_ARM: 243 { 244 int fp_register = -1; 245 if (system_info->os_short == "ios") 246 fp_register = MD_CONTEXT_ARM_REG_IOS_FP; 247 cpu_stackwalker = new StackwalkerARM(system_info, 248 context->GetContextARM(), 249 fp_register, memory, modules, 250 frame_symbolizer); 251 break; 252 } 253 254 case MD_CONTEXT_ARM64: 255 cpu_stackwalker = new StackwalkerARM64(system_info, 256 context->GetContextARM64(), 257 memory, modules, 258 frame_symbolizer); 259 break; 260 } 261 262 BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << 263 ", can't choose a stackwalker " 264 "implementation"; 265 return cpu_stackwalker; 266 } 267 268 bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) { 269 StackFrame frame; 270 frame.instruction = address; 271 StackFrameSymbolizer::SymbolizerResult symbolizer_result = 272 frame_symbolizer_->FillSourceLineInfo(modules_, system_info_, &frame); 273 274 if (!frame.module) { 275 // not inside any loaded module 276 return false; 277 } 278 279 if (!frame_symbolizer_->HasImplementation()) { 280 // No valid implementation to symbolize stack frame, but the address is 281 // within a known module. 282 return true; 283 } 284 285 if (symbolizer_result != StackFrameSymbolizer::kNoError && 286 symbolizer_result != StackFrameSymbolizer::kWarningCorruptSymbols) { 287 // Some error occurred during symbolization, but the address is within a 288 // known module 289 return true; 290 } 291 292 return !frame.function_name.empty(); 293 } 294 295 } // namespace google_breakpad 296