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
59namespace google_breakpad {
60
61const int Stackwalker::kRASearchWords = 30;
62
63uint32_t Stackwalker::max_frames_ = 1024;
64bool Stackwalker::max_frames_set_ = false;
65
66uint32_t Stackwalker::max_frames_scanned_ = 1024;
67
68Stackwalker::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
79void 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
105bool 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
191Stackwalker* 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
268bool 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