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