1 // Copyright (c) 2006, 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 
37 #include <cassert>
38 
39 #include "google_breakpad/processor/stackwalker.h"
40 #include "google_breakpad/processor/call_stack.h"
41 #include "google_breakpad/processor/code_module.h"
42 #include "google_breakpad/processor/code_modules.h"
43 #include "google_breakpad/processor/minidump.h"
44 #include "google_breakpad/processor/source_line_resolver_interface.h"
45 #include "google_breakpad/processor/stack_frame.h"
46 #include "google_breakpad/processor/symbol_supplier.h"
47 #include "processor/linked_ptr.h"
48 #include "processor/logging.h"
49 #include "processor/scoped_ptr.h"
50 #include "processor/stack_frame_info.h"
51 #include "processor/stackwalker_ppc.h"
52 #include "processor/stackwalker_sparc.h"
53 #include "processor/stackwalker_x86.h"
54 #include "processor/stackwalker_amd64.h"
55 
56 namespace google_breakpad {
57 
58 
Stackwalker(const SystemInfo * system_info,MemoryRegion * memory,const CodeModules * modules,SymbolSupplier * supplier,SourceLineResolverInterface * resolver)59 Stackwalker::Stackwalker(const SystemInfo *system_info,
60                          MemoryRegion *memory,
61                          const CodeModules *modules,
62                          SymbolSupplier *supplier,
63                          SourceLineResolverInterface *resolver)
64     : system_info_(system_info),
65       memory_(memory),
66       modules_(modules),
67       supplier_(supplier),
68       resolver_(resolver) {
69 }
70 
71 
Walk(CallStack * stack)72 bool Stackwalker::Walk(CallStack *stack) {
73   BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|";
74   assert(stack);
75   stack->Clear();
76 
77   // stack_frame_info parallels the CallStack.  The vector is passed to the
78   // GetCallerFrame function.  It contains information that may be helpful
79   // for stackwalking.
80   vector< linked_ptr<StackFrameInfo> > stack_frame_info;
81 
82   // Begin with the context frame, and keep getting callers until there are
83   // no more.
84 
85   // Take ownership of the pointer returned by GetContextFrame.
86   scoped_ptr<StackFrame> frame(GetContextFrame());
87 
88   while (frame.get()) {
89     // frame already contains a good frame with properly set instruction and
90     // frame_pointer fields.  The frame structure comes from either the
91     // context frame (above) or a caller frame (below).
92 
93     linked_ptr<StackFrameInfo> frame_info;
94 
95     // Resolve the module information, if a module map was provided.
96     if (modules_) {
97       const CodeModule *module =
98           modules_->GetModuleForAddress(frame->instruction);
99       if (module) {
100         frame->module = module;
101         if (resolver_ &&
102             !resolver_->HasModule(frame->module->code_file()) &&
103             supplier_) {
104           string symbol_data, symbol_file;
105           SymbolSupplier::SymbolResult symbol_result =
106               supplier_->GetSymbolFile(module, system_info_,
107                                        &symbol_file, &symbol_data);
108 
109           switch (symbol_result) {
110             case SymbolSupplier::FOUND:
111               resolver_->LoadModuleUsingMapBuffer(frame->module->code_file(),
112                                                   symbol_data);
113               break;
114             case SymbolSupplier::NOT_FOUND:
115               break;  // nothing to do
116             case SymbolSupplier::INTERRUPT:
117               return false;
118           }
119         }
120         frame_info.reset(resolver_->FillSourceLineInfo(frame.get()));
121       }
122     }
123 
124     // Add the frame to the call stack.  Relinquish the ownership claim
125     // over the frame, because the stack now owns it.
126     stack->frames_.push_back(frame.release());
127 
128     // Add the frame info to the parallel stack.
129     stack_frame_info.push_back(frame_info);
130     frame_info.reset(NULL);
131 
132     // Get the next frame and take ownership.
133     frame.reset(GetCallerFrame(stack, stack_frame_info));
134   }
135 
136   return true;
137 }
138 
139 
140 // static
StackwalkerForCPU(const SystemInfo * system_info,MinidumpContext * context,MemoryRegion * memory,const CodeModules * modules,SymbolSupplier * supplier,SourceLineResolverInterface * resolver)141 Stackwalker* Stackwalker::StackwalkerForCPU(
142     const SystemInfo *system_info,
143     MinidumpContext *context,
144     MemoryRegion *memory,
145     const CodeModules *modules,
146     SymbolSupplier *supplier,
147     SourceLineResolverInterface *resolver) {
148   if (!context) {
149     BPLOG(ERROR) << "Can't choose a stackwalker implementation without context";
150     return NULL;
151   }
152 
153   Stackwalker *cpu_stackwalker = NULL;
154 
155   u_int32_t cpu = context->GetContextCPU();
156   switch (cpu) {
157     case MD_CONTEXT_X86:
158       cpu_stackwalker = new StackwalkerX86(system_info,
159                                            context->GetContextX86(),
160                                            memory, modules, supplier,
161                                            resolver);
162       break;
163 
164     case MD_CONTEXT_PPC:
165       cpu_stackwalker = new StackwalkerPPC(system_info,
166                                            context->GetContextPPC(),
167                                            memory, modules, supplier,
168                                            resolver);
169       break;
170 
171     case MD_CONTEXT_AMD64:
172       cpu_stackwalker = new StackwalkerAMD64(system_info,
173                                              context->GetContextAMD64(),
174                                              memory, modules, supplier,
175                                              resolver);
176       break;
177 
178     case MD_CONTEXT_SPARC:
179       cpu_stackwalker = new StackwalkerSPARC(system_info,
180                                              context->GetContextSPARC(),
181                                              memory, modules, supplier,
182                                              resolver);
183       break;
184   }
185 
186   BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) <<
187                                        ", can't choose a stackwalker "
188                                        "implementation";
189   return cpu_stackwalker;
190 }
191 
InstructionAddressSeemsValid(u_int64_t address)192 bool Stackwalker::InstructionAddressSeemsValid(u_int64_t address) {
193   const CodeModule *module = modules_->GetModuleForAddress(address);
194   if (!module) {
195     // not inside any loaded module
196     return false;
197   }
198 
199   if (!resolver_ || !supplier_) {
200     // we don't have a resolver and or symbol supplier,
201     // but we're inside a known module
202     return true;
203   }
204 
205   if (!resolver_->HasModule(module->code_file())) {
206     string symbol_data, symbol_file;
207     SymbolSupplier::SymbolResult symbol_result =
208       supplier_->GetSymbolFile(module, system_info_,
209                                &symbol_file, &symbol_data);
210 
211     if (symbol_result != SymbolSupplier::FOUND ||
212         !resolver_->LoadModuleUsingMapBuffer(module->code_file(),
213                                              symbol_data)) {
214       // we don't have symbols, but we're inside a loaded module
215       return true;
216     }
217   }
218 
219   StackFrame frame;
220   frame.module = module;
221   frame.instruction = address;
222   resolver_->FillSourceLineInfo(&frame);
223   // we have symbols, so return true if inside a function
224   return !frame.function_name.empty();
225 }
226 
227 }  // namespace google_breakpad
228