toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial