PageRenderTime 21ms CodeModel.GetById 1ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/processor/stackwalker_selftest.cc

http://github.com/tomahawk-player/tomahawk
C++ | 425 lines | 236 code | 62 blank | 127 comment | 11 complexity | 23215b834268bf369611c9d4b14fba4d MD5 | raw file
  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_selftest.cc: Tests StackwalkerX86 or StackwalkerPPC using the
 31// running process' stack as test data, if running on an x86 or ppc and
 32// compiled with gcc.  This test is not enabled in the "make check" suite
 33// by default, because certain optimizations interfere with its proper
 34// operation.  To turn it on, configure with --enable-selftest.
 35//
 36// Optimizations that cause problems:
 37//  - stack frame reuse.  The Recursor function here calls itself with
 38//    |return Recursor|.  When the caller's frame is reused, it will cause
 39//    CountCallerFrames to correctly return the same number of frames
 40//    in both the caller and callee.  This is considered an unexpected
 41//    condition in the test, which expects a callee to have one more
 42//    caller frame in the stack than its caller.
 43//  - frame pointer omission.  Even with a stackwalker that understands
 44//    this optimization, the code to harness debug information currently
 45//    only exists to retrieve it from minidumps, not the current process.
 46//
 47// This test can also serve as a developmental and debugging aid if
 48// PRINT_STACKS is defined.
 49//
 50// Author: Mark Mentovai
 51
 52#include "processor/logging.h"
 53
 54#if defined(__i386) && !defined(__i386__)
 55#define __i386__
 56#endif
 57#if defined(__sparc) && !defined(__sparc__)
 58#define __sparc__
 59#endif
 60 
 61#if (defined(__SUNPRO_CC) || defined(__GNUC__)) && \
 62    (defined(__i386__) || defined(__ppc__) || defined(__sparc__))
 63
 64
 65#include <stdio.h>
 66
 67#include "google_breakpad/common/breakpad_types.h"
 68#include "google_breakpad/common/minidump_format.h"
 69#include "google_breakpad/processor/basic_source_line_resolver.h"
 70#include "google_breakpad/processor/call_stack.h"
 71#include "google_breakpad/processor/memory_region.h"
 72#include "google_breakpad/processor/stack_frame.h"
 73#include "google_breakpad/processor/stack_frame_cpu.h"
 74#include "processor/scoped_ptr.h"
 75
 76using google_breakpad::BasicSourceLineResolver;
 77using google_breakpad::CallStack;
 78using google_breakpad::MemoryRegion;
 79using google_breakpad::scoped_ptr;
 80using google_breakpad::StackFrame;
 81using google_breakpad::StackFramePPC;
 82using google_breakpad::StackFrameX86;
 83using google_breakpad::StackFrameSPARC;
 84
 85#if defined(__i386__)
 86#include "processor/stackwalker_x86.h"
 87using google_breakpad::StackwalkerX86;
 88#elif defined(__ppc__)
 89#include "processor/stackwalker_ppc.h"
 90using google_breakpad::StackwalkerPPC;
 91#elif defined(__sparc__)
 92#include "processor/stackwalker_sparc.h"
 93using google_breakpad::StackwalkerSPARC;
 94#endif  // __i386__ || __ppc__ || __sparc__
 95
 96#define RECURSION_DEPTH 100
 97
 98
 99// A simple MemoryRegion subclass that provides direct access to this
100// process' memory space by pointer.
101class SelfMemoryRegion : public MemoryRegion {
102 public:
103  virtual u_int64_t GetBase() { return 0; }
104  virtual u_int32_t GetSize() { return 0xffffffff; }
105
106  bool GetMemoryAtAddress(u_int64_t address, u_int8_t*  value) {
107      return GetMemoryAtAddressInternal(address, value); }
108  bool GetMemoryAtAddress(u_int64_t address, u_int16_t* value) {
109      return GetMemoryAtAddressInternal(address, value); }
110  bool GetMemoryAtAddress(u_int64_t address, u_int32_t* value) {
111      return GetMemoryAtAddressInternal(address, value); }
112  bool GetMemoryAtAddress(u_int64_t address, u_int64_t* value) {
113      return GetMemoryAtAddressInternal(address, value); }
114
115 private:
116  template<typename T> bool GetMemoryAtAddressInternal(u_int64_t address,
117                                                       T*        value) {
118    // Without knowing what addresses are actually mapped, just assume that
119    // everything low is not mapped.  This helps the stackwalker catch the
120    // end of a stack when it tries to dereference a null or low pointer
121    // in an attempt to find the caller frame.  Other unmapped accesses will
122    // cause the program to crash, but that would properly be a test failure.
123    if (address < 0x100)
124      return false;
125
126    u_int8_t* memory = 0;
127    *value = *reinterpret_cast<const T*>(&memory[address]);
128    return true;
129  }
130};
131
132
133#if defined(__GNUC__)
134
135
136#if defined(__i386__)
137
138// GetEBP returns the current value of the %ebp register.  Because it's
139// implemented as a function, %ebp itself contains GetEBP's frame pointer
140// and not the caller's frame pointer.  Dereference %ebp to obtain the
141// caller's frame pointer, which the compiler-generated preamble stored
142// on the stack (provided frame pointers are not being omitted.)  Because
143// this function depends on the compiler-generated preamble, inlining is
144// disabled.
145static u_int32_t GetEBP() __attribute__((noinline));
146static u_int32_t GetEBP() {
147  u_int32_t ebp;
148  __asm__ __volatile__(
149    "movl (%%ebp), %0"
150    : "=a" (ebp)
151  );
152  return ebp;
153}
154
155
156// The caller's %esp is 8 higher than the value of %ebp in this function,
157// assuming that it's not inlined and that the standard prolog is used.
158// The CALL instruction places a 4-byte return address on the stack above
159// the caller's %esp, and this function's prolog will save the caller's %ebp
160// on the stack as well, for another 4 bytes, before storing %esp in %ebp.
161static u_int32_t GetESP() __attribute__((noinline));
162static u_int32_t GetESP() {
163  u_int32_t ebp;
164  __asm__ __volatile__(
165    "movl %%ebp, %0"
166    : "=a" (ebp)
167  );
168  return ebp + 8;
169}
170
171
172// GetEIP returns the instruction pointer identifying the next instruction
173// to execute after GetEIP returns.  It obtains this information from the
174// stack, where it was placed by the call instruction that called GetEIP.
175// This function depends on frame pointers not being omitted.  It is possible
176// to write a pure asm version of this routine that has no compiler-generated
177// preamble and uses %esp instead of %ebp; that would function in the
178// absence of frame pointers.  However, the simpler approach is used here
179// because GetEBP and stackwalking necessarily depends on access to frame
180// pointers.  Because this function depends on a call instruction and the
181// compiler-generated preamble, inlining is disabled.
182static u_int32_t GetEIP() __attribute__((noinline));
183static u_int32_t GetEIP() {
184  u_int32_t eip;
185  __asm__ __volatile__(
186    "movl 4(%%ebp), %0"
187    : "=a" (eip)
188  );
189  return eip;
190}
191
192
193#elif defined(__ppc__)
194
195
196// GetSP returns the current value of the %r1 register, which by convention,
197// is the stack pointer on ppc.  Because it's implemented as a function,
198// %r1 itself contains GetSP's own stack pointer and not the caller's stack
199// pointer.  Dereference %r1 to obtain the caller's stack pointer, which the
200// compiler-generated prolog stored on the stack.  Because this function
201// depends on the compiler-generated prolog, inlining is disabled.
202static u_int32_t GetSP() __attribute__((noinline));
203static u_int32_t GetSP() {
204  u_int32_t sp;
205  __asm__ __volatile__(
206    "lwz %0, 0(r1)"
207    : "=r" (sp)
208  );
209  return sp;
210}
211
212
213// GetPC returns the program counter identifying the next instruction to
214// execute after GetPC returns.  It obtains this information from the
215// link register, where it was placed by the branch instruction that called
216// GetPC.  Because this function depends on the caller's use of a branch
217// instruction, inlining is disabled.
218static u_int32_t GetPC() __attribute__((noinline));
219static u_int32_t GetPC() {
220  u_int32_t lr;
221  __asm__ __volatile__(
222    "mflr %0"
223    : "=r" (lr)
224  );
225  return lr;
226}
227
228
229#elif defined(__sparc__)
230
231
232// GetSP returns the current value of the %sp/%o6/%g_r[14] register, which 
233// by convention, is the stack pointer on sparc.  Because it's implemented
234// as a function, %sp itself contains GetSP's own stack pointer and not 
235// the caller's stack pointer.  Dereference  to obtain the caller's stack 
236// pointer, which the compiler-generated prolog stored on the stack.
237// Because this function depends on the compiler-generated prolog, inlining
238// is disabled.
239static u_int32_t GetSP() __attribute__((noinline));
240static u_int32_t GetSP() {
241  u_int32_t sp;
242  __asm__ __volatile__(
243    "mov %%fp, %0"
244    : "=r" (sp)
245  );
246  return sp;
247}
248
249// GetFP returns the current value of the %fp register.  Because it's
250// implemented as a function, %fp itself contains GetFP's frame pointer
251// and not the caller's frame pointer.  Dereference %fp to obtain the
252// caller's frame pointer, which the compiler-generated preamble stored
253// on the stack (provided frame pointers are not being omitted.)  Because
254// this function depends on the compiler-generated preamble, inlining is
255// disabled.
256static u_int32_t GetFP() __attribute__((noinline));
257static u_int32_t GetFP() {
258  u_int32_t fp;
259  __asm__ __volatile__(
260    "ld [%%fp+56], %0"
261    : "=r" (fp)
262  );
263  return fp;
264}
265
266// GetPC returns the program counter identifying the next instruction to
267// execute after GetPC returns.  It obtains this information from the
268// link register, where it was placed by the branch instruction that called
269// GetPC.  Because this function depends on the caller's use of a branch
270// instruction, inlining is disabled.
271static u_int32_t GetPC() __attribute__((noinline));
272static u_int32_t GetPC() {
273  u_int32_t pc;
274  __asm__ __volatile__(
275    "mov %%i7, %0"
276    : "=r" (pc)
277  );
278  return pc + 8;
279}
280
281#endif  // __i386__ || __ppc__ || __sparc__
282
283#elif defined(__SUNPRO_CC)
284
285#if defined(__i386__)
286extern "C" {
287extern u_int32_t GetEIP();
288extern u_int32_t GetEBP();
289extern u_int32_t GetESP();
290}
291#elif defined(__sparc__)
292extern "C" {
293extern u_int32_t GetPC();
294extern u_int32_t GetFP();
295extern u_int32_t GetSP();
296}
297#endif // __i386__ || __sparc__
298
299#endif // __GNUC__ || __SUNPRO_CC
300
301// CountCallerFrames returns the number of stack frames beneath the function
302// that called CountCallerFrames.  Because this function's return value
303// is dependent on the size of the stack beneath it, inlining is disabled,
304// and any function that calls this should not be inlined either.
305#if defined(__GNUC__)
306static unsigned int CountCallerFrames() __attribute__((noinline));
307#elif defined(__SUNPRO_CC)
308static unsigned int CountCallerFrames();
309#endif
310static unsigned int CountCallerFrames() {
311  SelfMemoryRegion memory;
312  BasicSourceLineResolver resolver;
313
314#if defined(__i386__)
315  MDRawContextX86 context = MDRawContextX86();
316  context.eip = GetEIP();
317  context.ebp = GetEBP();
318  context.esp = GetESP();
319
320  StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL,
321                                              NULL, &resolver);
322#elif defined(__ppc__)
323  MDRawContextPPC context = MDRawContextPPC();
324  context.srr0 = GetPC();
325  context.gpr[1] = GetSP();
326
327  StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL,
328                                              NULL, &resolver);
329#elif defined(__sparc__)
330  MDRawContextSPARC context = MDRawContextSPARC();
331  context.pc = GetPC();
332  context.g_r[14] = GetSP();
333  context.g_r[30] = GetFP();
334
335  StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory,
336                                                  NULL, NULL, &resolver);
337#endif  // __i386__ || __ppc__ || __sparc__
338
339  CallStack stack;
340  stackwalker.Walk(&stack);
341
342#ifdef PRINT_STACKS
343  printf("\n");
344  for (unsigned int frame_index = 0;
345      frame_index < stack.frames()->size();
346      ++frame_index) {
347    StackFrame *frame = stack.frames()->at(frame_index);
348    printf("frame %-3d  instruction = 0x%08" PRIx64,
349           frame_index, frame->instruction);
350#if defined(__i386__)
351    StackFrameX86 *frame_x86 = reinterpret_cast<StackFrameX86*>(frame);
352    printf("  esp = 0x%08x  ebp = 0x%08x\n",
353           frame_x86->context.esp, frame_x86->context.ebp);
354#elif defined(__ppc__)
355    StackFramePPC *frame_ppc = reinterpret_cast<StackFramePPC*>(frame);
356    printf("  gpr[1] = 0x%08x\n", frame_ppc->context.gpr[1]);
357#elif defined(__sparc__)
358    StackFrameSPARC *frame_sparc = reinterpret_cast<StackFrameSPARC*>(frame);
359    printf("  sp = 0x%08x  fp = 0x%08x\n",
360           frame_sparc->context.g_r[14], frame_sparc->context.g_r[30]);
361#endif  // __i386__ || __ppc__ || __sparc__
362  }
363#endif  // PRINT_STACKS
364
365  // Subtract 1 because the caller wants the number of frames beneath
366  // itself.  Because the caller called us, subract two for our frame and its
367  // frame, which are included in stack.size().
368  return stack.frames()->size() - 2;
369}
370
371
372// Recursor verifies that the number stack frames beneath itself is one more
373// than the number of stack frames beneath its parent.  When depth frames
374// have been reached, Recursor stops checking and returns success.  If the
375// frame count check fails at any depth, Recursor will stop and return false.
376// Because this calls CountCallerFrames, inlining is disabled.
377#if defined(__GNUC__)
378static bool Recursor(unsigned int depth, unsigned int parent_callers)
379    __attribute__((noinline));
380#elif defined(__SUNPRO_CC)
381static bool Recursor(unsigned int depth, unsigned int parent_callers);
382#endif
383static bool Recursor(unsigned int depth, unsigned int parent_callers) {
384  unsigned int callers = CountCallerFrames();
385  if (callers != parent_callers + 1)
386    return false;
387
388  if (depth)
389    return Recursor(depth - 1, callers);
390
391  // depth == 0
392  return true;
393}
394
395
396// Because this calls CountCallerFrames, inlining is disabled - but because
397// it's main (and nobody calls it other than the entry point), it wouldn't
398// be inlined anyway.
399#if defined(__GNUC__)
400int main(int argc, char** argv) __attribute__((noinline));
401#elif defined(__SUNPRO_CC)
402int main(int argc, char** argv);
403#endif
404int main(int argc, char** argv) {
405  BPLOG_INIT(&argc, &argv);
406
407  return Recursor(RECURSION_DEPTH, CountCallerFrames()) ? 0 : 1;
408}
409
410
411#else
412// Not i386 or ppc or sparc?  We can only test stacks we know how to walk.
413
414
415int main(int argc, char **argv) {
416  BPLOG_INIT(&argc, &argv);
417
418  // "make check" interprets an exit status of 77 to mean that the test is
419  // not supported.
420  BPLOG(ERROR) << "Selftest not supported here";
421  return 77;
422}
423
424
425#endif  // (__GNUC__ || __SUNPRO_CC) && (__i386__ || __ppc__ || __sparc__)