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