xref: /aosp_15_r20/external/google-breakpad/src/processor/stackwalker.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // stackwalker.cc: Generic stackwalker.
30 //
31 // See stackwalker.h for documentation.
32 //
33 // Author: Mark Mentovai
34 
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>  // Must come first
37 #endif
38 
39 #include "google_breakpad/processor/stackwalker.h"
40 
41 #include <assert.h>
42 
43 #include "common/scoped_ptr.h"
44 #include "google_breakpad/processor/call_stack.h"
45 #include "google_breakpad/processor/code_module.h"
46 #include "google_breakpad/processor/code_modules.h"
47 #include "google_breakpad/processor/dump_context.h"
48 #include "google_breakpad/processor/stack_frame.h"
49 #include "google_breakpad/processor/stack_frame_symbolizer.h"
50 #include "google_breakpad/processor/system_info.h"
51 #include "processor/linked_ptr.h"
52 #include "processor/logging.h"
53 #include "processor/stackwalker_ppc.h"
54 #include "processor/stackwalker_ppc64.h"
55 #include "processor/stackwalker_sparc.h"
56 #include "processor/stackwalker_x86.h"
57 #include "processor/stackwalker_amd64.h"
58 #include "processor/stackwalker_arm.h"
59 #include "processor/stackwalker_arm64.h"
60 #include "processor/stackwalker_mips.h"
61 #include "processor/stackwalker_riscv.h"
62 #include "processor/stackwalker_riscv64.h"
63 
64 namespace google_breakpad {
65 
66 const int Stackwalker::kRASearchWords = 40;
67 
68 // This default is just a sanity check: a large enough value
69 // that allow capturing unbounded recursion traces, yet provide a
70 // guardrail against stack walking bugs. The stack walking invariants
71 // guarantee that the unwinding process is strictly monotonic and
72 // practically bounded by the size of the stack memory range.
73 uint32_t Stackwalker::max_frames_ = 1 << 20;  // 1M
74 bool Stackwalker::max_frames_set_ = false;
75 
76 uint32_t Stackwalker::max_frames_scanned_ = 1 << 14;  // 16k
77 
Stackwalker(const SystemInfo * system_info,MemoryRegion * memory,const CodeModules * modules,StackFrameSymbolizer * frame_symbolizer)78 Stackwalker::Stackwalker(const SystemInfo* system_info,
79                          MemoryRegion* memory,
80                          const CodeModules* modules,
81                          StackFrameSymbolizer* frame_symbolizer)
82     : system_info_(system_info),
83       memory_(memory),
84       modules_(modules),
85       unloaded_modules_(NULL),
86       frame_symbolizer_(frame_symbolizer) {
87   assert(frame_symbolizer_);
88 }
89 
InsertSpecialAttentionModule(StackFrameSymbolizer::SymbolizerResult symbolizer_result,const CodeModule * module,vector<const CodeModule * > * modules)90 void InsertSpecialAttentionModule(
91     StackFrameSymbolizer::SymbolizerResult symbolizer_result,
92     const CodeModule* module,
93     vector<const CodeModule*>* modules) {
94   if (!module) {
95     return;
96   }
97   assert(symbolizer_result == StackFrameSymbolizer::kError ||
98          symbolizer_result == StackFrameSymbolizer::kWarningCorruptSymbols);
99   bool found = false;
100   vector<const CodeModule*>::iterator iter;
101   for (iter = modules->begin(); iter != modules->end(); ++iter) {
102     if (*iter == module) {
103       found = true;
104       break;
105     }
106   }
107   if (!found) {
108     BPLOG(INFO) << ((symbolizer_result == StackFrameSymbolizer::kError) ?
109                        "Couldn't load symbols for: " :
110                        "Detected corrupt symbols for: ")
111                 << module->debug_file() << "|" << module->debug_identifier();
112     modules->push_back(module);
113   }
114 }
115 
Walk(CallStack * stack,vector<const CodeModule * > * modules_without_symbols,vector<const CodeModule * > * modules_with_corrupt_symbols)116 bool Stackwalker::Walk(
117     CallStack* stack,
118     vector<const CodeModule*>* modules_without_symbols,
119     vector<const CodeModule*>* modules_with_corrupt_symbols) {
120   BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|";
121   assert(stack);
122   stack->Clear();
123 
124   BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires "
125                                             << "|modules_without_symbols|";
126   BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires "
127                                             << "|modules_with_corrupt_symbols|";
128   assert(modules_without_symbols);
129   assert(modules_with_corrupt_symbols);
130 
131   // Begin with the context frame, and keep getting callers until there are
132   // no more.
133 
134   // Keep track of the number of scanned or otherwise dubious frames seen
135   // so far, as the caller may have set a limit.
136   uint32_t scanned_frames = 0;
137 
138   // Take ownership of the pointer returned by GetContextFrame.
139   scoped_ptr<StackFrame> frame(GetContextFrame());
140 
141   while (frame.get()) {
142     // frame already contains a good frame with properly set instruction and
143     // frame_pointer fields.  The frame structure comes from either the
144     // context frame (above) or a caller frame (below).
145 
146     std::deque<std::unique_ptr<StackFrame>> inlined_frames;
147     // Resolve the module information, if a module map was provided.
148     StackFrameSymbolizer::SymbolizerResult symbolizer_result =
149         frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_,
150                                               system_info_,
151                                               frame.get(), &inlined_frames);
152     switch (symbolizer_result) {
153       case StackFrameSymbolizer::kInterrupt:
154         BPLOG(INFO) << "Stack walk is interrupted.";
155         return false;
156         break;
157       case StackFrameSymbolizer::kError:
158         InsertSpecialAttentionModule(symbolizer_result, frame->module,
159                                      modules_without_symbols);
160         break;
161       case StackFrameSymbolizer::kWarningCorruptSymbols:
162         InsertSpecialAttentionModule(symbolizer_result, frame->module,
163                                      modules_with_corrupt_symbols);
164         break;
165       case StackFrameSymbolizer::kNoError:
166         break;
167       default:
168         assert(false);
169         break;
170     }
171 
172     // Keep track of the number of dubious frames so far.
173     switch (frame.get()->trust) {
174        case StackFrame::FRAME_TRUST_NONE:
175        case StackFrame::FRAME_TRUST_SCAN:
176        case StackFrame::FRAME_TRUST_CFI_SCAN:
177          scanned_frames++;
178          break;
179       default:
180         break;
181     }
182     // Add all nested inlined frames belonging to this frame from the innermost
183     // frame to the outermost frame.
184     while (!inlined_frames.empty()) {
185       stack->frames_.push_back(inlined_frames.front().release());
186       inlined_frames.pop_front();
187     }
188     // Add the frame to the call stack.  Relinquish the ownership claim
189     // over the frame, because the stack now owns it.
190     stack->frames_.push_back(frame.release());
191     if (stack->frames_.size() > max_frames_) {
192       // Only emit an error message in the case where the limit
193       // reached is the default limit, not set by the user.
194       if (!max_frames_set_)
195         BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames.";
196       break;
197     }
198 
199     // Get the next frame and take ownership.
200     bool stack_scan_allowed = scanned_frames < max_frames_scanned_;
201     frame.reset(GetCallerFrame(stack, stack_scan_allowed));
202   }
203 
204   return true;
205 }
206 
207 // static
StackwalkerForCPU(const SystemInfo * system_info,DumpContext * context,MemoryRegion * memory,const CodeModules * modules,const CodeModules * unloaded_modules,StackFrameSymbolizer * frame_symbolizer)208 Stackwalker* Stackwalker::StackwalkerForCPU(
209     const SystemInfo* system_info,
210     DumpContext* context,
211     MemoryRegion* memory,
212     const CodeModules* modules,
213     const CodeModules* unloaded_modules,
214     StackFrameSymbolizer* frame_symbolizer) {
215   if (!context) {
216     BPLOG(ERROR) << "Can't choose a stackwalker implementation without context";
217     return NULL;
218   }
219 
220   Stackwalker* cpu_stackwalker = NULL;
221 
222   uint32_t cpu = context->GetContextCPU();
223   switch (cpu) {
224     case MD_CONTEXT_X86:
225       cpu_stackwalker = new StackwalkerX86(system_info,
226                                            context->GetContextX86(),
227                                            memory, modules, frame_symbolizer);
228       break;
229 
230     case MD_CONTEXT_PPC:
231       cpu_stackwalker = new StackwalkerPPC(system_info,
232                                            context->GetContextPPC(),
233                                            memory, modules, frame_symbolizer);
234       break;
235 
236     case MD_CONTEXT_PPC64:
237       cpu_stackwalker = new StackwalkerPPC64(system_info,
238                                              context->GetContextPPC64(),
239                                              memory, modules, frame_symbolizer);
240       break;
241 
242     case MD_CONTEXT_AMD64:
243       cpu_stackwalker = new StackwalkerAMD64(system_info,
244                                              context->GetContextAMD64(),
245                                              memory, modules, frame_symbolizer);
246       break;
247 
248     case MD_CONTEXT_SPARC:
249       cpu_stackwalker = new StackwalkerSPARC(system_info,
250                                              context->GetContextSPARC(),
251                                              memory, modules, frame_symbolizer);
252       break;
253 
254     case MD_CONTEXT_MIPS:
255     case MD_CONTEXT_MIPS64:
256       cpu_stackwalker = new StackwalkerMIPS(system_info,
257                                             context->GetContextMIPS(),
258                                             memory, modules, frame_symbolizer);
259       break;
260 
261     case MD_CONTEXT_ARM:
262     {
263       int fp_register = -1;
264       if (system_info->os_short == "ios")
265         fp_register = MD_CONTEXT_ARM_REG_IOS_FP;
266       cpu_stackwalker = new StackwalkerARM(system_info,
267                                            context->GetContextARM(),
268                                            fp_register, memory, modules,
269                                            frame_symbolizer);
270       break;
271     }
272 
273     case MD_CONTEXT_ARM64:
274       cpu_stackwalker = new StackwalkerARM64(system_info,
275                                              context->GetContextARM64(),
276                                              memory, modules,
277                                              frame_symbolizer);
278       break;
279 
280     case MD_CONTEXT_RISCV:
281       cpu_stackwalker = new StackwalkerRISCV(system_info,
282                                              context->GetContextRISCV(),
283                                              memory, modules,
284                                              frame_symbolizer);
285       break;
286 
287     case MD_CONTEXT_RISCV64:
288       cpu_stackwalker = new StackwalkerRISCV64(system_info,
289                                                context->GetContextRISCV64(),
290                                                memory, modules,
291                                                frame_symbolizer);
292       break;
293   }
294 
295   BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) <<
296                                        ", can't choose a stackwalker "
297                                        "implementation";
298   if (cpu_stackwalker) {
299     cpu_stackwalker->unloaded_modules_ = unloaded_modules;
300   }
301   return cpu_stackwalker;
302 }
303 
304 // CONSIDER: check stack alignment?
TerminateWalk(uint64_t caller_ip,uint64_t caller_sp,uint64_t callee_sp,bool first_unwind) const305 bool Stackwalker::TerminateWalk(uint64_t caller_ip,
306                                 uint64_t caller_sp,
307                                 uint64_t callee_sp,
308                                 bool first_unwind) const {
309   // Treat an instruction address less than 4k as end-of-stack.
310   // (using InstructionAddressSeemsValid() here is very tempting,
311   // but we need to handle JITted code)
312   if (caller_ip < (1 << 12)) {
313     return true;
314   }
315 
316   // NOTE: The stack address range is implicitly checked
317   //   when the stack memory is accessed.
318 
319   // The stack pointer should monotonically increase. For first unwind
320   // we allow caller_sp == callee_sp to account for architectures where
321   // the return address is stored in a register (so it's possible to have
322   // leaf functions which don't move the stack pointer)
323   if (first_unwind ? (caller_sp < callee_sp) : (caller_sp <= callee_sp)) {
324     return true;
325   }
326 
327   return false;
328 }
329 
InstructionAddressSeemsValid(uint64_t address) const330 bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) const {
331   StackFrame frame;
332   frame.instruction = address;
333   StackFrameSymbolizer::SymbolizerResult symbolizer_result =
334       frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_,
335                                             system_info_, &frame, nullptr);
336 
337   if (!frame.module) {
338     // not inside any loaded module
339     return false;
340   }
341 
342   if (!frame_symbolizer_->HasImplementation()) {
343     // No valid implementation to symbolize stack frame, but the address is
344     // within a known module.
345     return true;
346   }
347 
348   if (symbolizer_result != StackFrameSymbolizer::kNoError &&
349       symbolizer_result != StackFrameSymbolizer::kWarningCorruptSymbols) {
350     // Some error occurred during symbolization, but the address is within a
351     // known module
352     return true;
353   }
354 
355   return !frame.function_name.empty();
356 }
357 
358 }  // namespace google_breakpad
359