1db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// Copyright (c) 2006, Google Inc.
2db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// All rights reserved.
30dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
4db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// Redistribution and use in source and binary forms, with or without
5db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// modification, are permitted provided that the following conditions are
6db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// met:
70dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
8db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai//     * Redistributions of source code must retain the above copyright
9db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// notice, this list of conditions and the following disclaimer.
10db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai//     * Redistributions in binary form must reproduce the above
11db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// copyright notice, this list of conditions and the following disclaimer
12db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// in the documentation and/or other materials provided with the
13db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// distribution.
14db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai//     * Neither the name of Google Inc. nor the names of its
15db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// contributors may be used to endorse or promote products derived from
16db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// this software without specific prior written permission.
170dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
18db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28db3342a10ec30902aa9018b80e1d9a40bd01c487mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
290dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
300dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// stackwalker_selftest.cc: Tests StackwalkerX86 or StackwalkerPPC using the
310dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// running process' stack as test data, if running on an x86 or ppc and
320dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// compiled with gcc.  This test is not enabled in the "make check" suite
330dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// by default, because certain optimizations interfere with its proper
340dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// operation.  To turn it on, configure with --enable-selftest.
350dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
360dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// Optimizations that cause problems:
370dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//  - stack frame reuse.  The Recursor function here calls itself with
380dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    |return Recursor|.  When the caller's frame is reused, it will cause
390dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    CountCallerFrames to correctly return the same number of frames
400dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    in both the caller and callee.  This is considered an unexpected
410dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    condition in the test, which expects a callee to have one more
420dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    caller frame in the stack than its caller.
430dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//  - frame pointer omission.  Even with a stackwalker that understands
440dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    this optimization, the code to harness debug information currently
450dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//    only exists to retrieve it from minidumps, not the current process.
460dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
470dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// This test can also serve as a developmental and debugging aid if
480dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// PRINT_STACKS is defined.
490dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai//
500dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// Author: Mark Mentovai
510dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
52c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org#include <assert.h>
53c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org
54ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#include "processor/logging.h"
55ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
56ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__i386) && !defined(__i386__)
57ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#define __i386__
58ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif
59ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__sparc) && !defined(__sparc__)
60ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#define __sparc__
61ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif
62ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
63ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if (defined(__SUNPRO_CC) || defined(__GNUC__)) && \
64ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    (defined(__i386__) || defined(__ppc__) || defined(__sparc__))
650dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
660dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
67e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek#include <stdio.h>
680dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
692cc15ba4327831f917ff55b87e6d5fc3c7750085ted.mielczarek@gmail.com#include "common/scoped_ptr.h"
70e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/common/breakpad_types.h"
71e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/common/minidump_format.h"
72e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/basic_source_line_resolver.h"
73e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/call_stack.h"
745a2106b5f95f3232ac0e9aab5f081eb04313a8b6ivan.penkov@gmail.com#include "google_breakpad/processor/code_module.h"
75e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/memory_region.h"
76e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/stack_frame.h"
77e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/stack_frame_cpu.h"
780dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
79e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::BasicSourceLineResolver;
80e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::CallStack;
815a2106b5f95f3232ac0e9aab5f081eb04313a8b6ivan.penkov@gmail.comusing google_breakpad::CodeModule;
82e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::MemoryRegion;
83e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::scoped_ptr;
84e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::StackFrame;
85e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::StackFramePPC;
86e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::StackFrameX86;
87ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaiusing google_breakpad::StackFrameSPARC;
880dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
890dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#if defined(__i386__)
900dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#include "processor/stackwalker_x86.h"
91e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::StackwalkerX86;
920dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#elif defined(__ppc__)
930dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#include "processor/stackwalker_ppc.h"
94e5dc60822e5938fea2ae892ccddb906641ba174emmentovaiusing google_breakpad::StackwalkerPPC;
95ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__sparc__)
96ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#include "processor/stackwalker_sparc.h"
97ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaiusing google_breakpad::StackwalkerSPARC;
98ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif  // __i386__ || __ppc__ || __sparc__
990dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1000dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#define RECURSION_DEPTH 100
1010dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1020dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1030dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// A simple MemoryRegion subclass that provides direct access to this
1040dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// process' memory space by pointer.
1050dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaiclass SelfMemoryRegion : public MemoryRegion {
1060dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai public:
107c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  virtual uint64_t GetBase() const { return 0; }
108c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  virtual uint32_t GetSize() const { return 0xffffffff; }
1090dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
110c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  bool GetMemoryAtAddress(uint64_t address, uint8_t*  value) const {
1110dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai      return GetMemoryAtAddressInternal(address, value); }
112c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
1130dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai      return GetMemoryAtAddressInternal(address, value); }
114c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
1150dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai      return GetMemoryAtAddressInternal(address, value); }
116c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
1170dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai      return GetMemoryAtAddressInternal(address, value); }
118c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  void Print() const {
119c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org    assert(false);
120c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  }
1210dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1220dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai private:
1236162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  template<typename T> bool GetMemoryAtAddressInternal(uint64_t address,
1240dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai                                                       T*        value) {
125246f4068280b5b191303ff13671e43a0522987demmentovai    // Without knowing what addresses are actually mapped, just assume that
126246f4068280b5b191303ff13671e43a0522987demmentovai    // everything low is not mapped.  This helps the stackwalker catch the
127246f4068280b5b191303ff13671e43a0522987demmentovai    // end of a stack when it tries to dereference a null or low pointer
128246f4068280b5b191303ff13671e43a0522987demmentovai    // in an attempt to find the caller frame.  Other unmapped accesses will
129246f4068280b5b191303ff13671e43a0522987demmentovai    // cause the program to crash, but that would properly be a test failure.
130246f4068280b5b191303ff13671e43a0522987demmentovai    if (address < 0x100)
131246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
132246f4068280b5b191303ff13671e43a0522987demmentovai
1336162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    uint8_t* memory = 0;
1340dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    *value = *reinterpret_cast<const T*>(&memory[address]);
1350dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    return true;
1360dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  }
1370dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai};
1380dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1390dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
140ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__GNUC__)
141ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
142ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
1430dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#if defined(__i386__)
1440dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1450dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// GetEBP returns the current value of the %ebp register.  Because it's
1460dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// implemented as a function, %ebp itself contains GetEBP's frame pointer
1470dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// and not the caller's frame pointer.  Dereference %ebp to obtain the
1480dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// caller's frame pointer, which the compiler-generated preamble stored
1490dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// on the stack (provided frame pointers are not being omitted.)  Because
1500dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// this function depends on the compiler-generated preamble, inlining is
1510dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// disabled.
1526162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetEBP() __attribute__((noinline));
1536162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetEBP() {
1546162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t ebp;
1550dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  __asm__ __volatile__(
1560dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    "movl (%%ebp), %0"
1570dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    : "=a" (ebp)
1580dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  );
1590dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return ebp;
1600dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
1610dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1620dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
163246f4068280b5b191303ff13671e43a0522987demmentovai// The caller's %esp is 8 higher than the value of %ebp in this function,
164246f4068280b5b191303ff13671e43a0522987demmentovai// assuming that it's not inlined and that the standard prolog is used.
165246f4068280b5b191303ff13671e43a0522987demmentovai// The CALL instruction places a 4-byte return address on the stack above
166246f4068280b5b191303ff13671e43a0522987demmentovai// the caller's %esp, and this function's prolog will save the caller's %ebp
167246f4068280b5b191303ff13671e43a0522987demmentovai// on the stack as well, for another 4 bytes, before storing %esp in %ebp.
1686162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetESP() __attribute__((noinline));
1696162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetESP() {
1706162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t ebp;
171246f4068280b5b191303ff13671e43a0522987demmentovai  __asm__ __volatile__(
172246f4068280b5b191303ff13671e43a0522987demmentovai    "movl %%ebp, %0"
173246f4068280b5b191303ff13671e43a0522987demmentovai    : "=a" (ebp)
174246f4068280b5b191303ff13671e43a0522987demmentovai  );
175246f4068280b5b191303ff13671e43a0522987demmentovai  return ebp + 8;
176246f4068280b5b191303ff13671e43a0522987demmentovai}
177246f4068280b5b191303ff13671e43a0522987demmentovai
178246f4068280b5b191303ff13671e43a0522987demmentovai
1790dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// GetEIP returns the instruction pointer identifying the next instruction
1800dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// to execute after GetEIP returns.  It obtains this information from the
1810dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// stack, where it was placed by the call instruction that called GetEIP.
1820dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// This function depends on frame pointers not being omitted.  It is possible
1830dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// to write a pure asm version of this routine that has no compiler-generated
1840dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// preamble and uses %esp instead of %ebp; that would function in the
1850dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// absence of frame pointers.  However, the simpler approach is used here
1860dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// because GetEBP and stackwalking necessarily depends on access to frame
1870dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// pointers.  Because this function depends on a call instruction and the
1880dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// compiler-generated preamble, inlining is disabled.
1896162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetEIP() __attribute__((noinline));
1906162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetEIP() {
1916162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t eip;
1920dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  __asm__ __volatile__(
1930dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    "movl 4(%%ebp), %0"
1940dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    : "=a" (eip)
1950dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  );
1960dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return eip;
1970dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
1980dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
1990dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2000dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#elif defined(__ppc__)
2010dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2020dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2030dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// GetSP returns the current value of the %r1 register, which by convention,
2040dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// is the stack pointer on ppc.  Because it's implemented as a function,
20580e98391dc7ff361355e72c24c0fb222518bcdfcmmentovai// %r1 itself contains GetSP's own stack pointer and not the caller's stack
2060dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// pointer.  Dereference %r1 to obtain the caller's stack pointer, which the
2070dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// compiler-generated prolog stored on the stack.  Because this function
2080dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// depends on the compiler-generated prolog, inlining is disabled.
2096162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetSP() __attribute__((noinline));
2106162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetSP() {
2116162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t sp;
2120dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  __asm__ __volatile__(
2130dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    "lwz %0, 0(r1)"
2140dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    : "=r" (sp)
2150dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  );
2160dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return sp;
2170dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
2180dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2190dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2200dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// GetPC returns the program counter identifying the next instruction to
2210dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// execute after GetPC returns.  It obtains this information from the
2220dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// link register, where it was placed by the branch instruction that called
2230dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// GetPC.  Because this function depends on the caller's use of a branch
2240dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// instruction, inlining is disabled.
2256162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetPC() __attribute__((noinline));
2266162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetPC() {
2276162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t lr;
2280dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  __asm__ __volatile__(
2290dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    "mflr %0"
2300dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    : "=r" (lr)
2310dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  );
2320dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return lr;
2330dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
2340dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2350dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
236ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__sparc__)
2370dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
2380dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
239ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// GetSP returns the current value of the %sp/%o6/%g_r[14] register, which
240ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// by convention, is the stack pointer on sparc.  Because it's implemented
241ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// as a function, %sp itself contains GetSP's own stack pointer and not
242ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// the caller's stack pointer.  Dereference  to obtain the caller's stack
243ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// pointer, which the compiler-generated prolog stored on the stack.
244ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// Because this function depends on the compiler-generated prolog, inlining
245ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// is disabled.
2466162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetSP() __attribute__((noinline));
2476162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetSP() {
2486162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t sp;
249ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  __asm__ __volatile__(
250ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    "mov %%fp, %0"
251ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    : "=r" (sp)
252ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  );
253ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  return sp;
254ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai}
255ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
256ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// GetFP returns the current value of the %fp register.  Because it's
257ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// implemented as a function, %fp itself contains GetFP's frame pointer
258ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// and not the caller's frame pointer.  Dereference %fp to obtain the
259ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// caller's frame pointer, which the compiler-generated preamble stored
260ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// on the stack (provided frame pointers are not being omitted.)  Because
261ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// this function depends on the compiler-generated preamble, inlining is
262ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// disabled.
2636162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetFP() __attribute__((noinline));
2646162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetFP() {
2656162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t fp;
266ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  __asm__ __volatile__(
267ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    "ld [%%fp+56], %0"
268ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    : "=r" (fp)
269ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  );
270ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  return fp;
271ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai}
272ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
273ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// GetPC returns the program counter identifying the next instruction to
274ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// execute after GetPC returns.  It obtains this information from the
275ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// link register, where it was placed by the branch instruction that called
276ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// GetPC.  Because this function depends on the caller's use of a branch
277ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// instruction, inlining is disabled.
2786162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetPC() __attribute__((noinline));
2796162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comstatic uint32_t GetPC() {
2806162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t pc;
281ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  __asm__ __volatile__(
282ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    "mov %%i7, %0"
283ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    : "=r" (pc)
284ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  );
285ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  return pc + 8;
286ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai}
287ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
288ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif  // __i386__ || __ppc__ || __sparc__
289ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
290ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__SUNPRO_CC)
291ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
292ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__i386__)
293ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaiextern "C" {
2946162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetEIP();
2956162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetEBP();
2966162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetESP();
297ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai}
298ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__sparc__)
299ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaiextern "C" {
3006162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetPC();
3016162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetFP();
3026162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comextern uint32_t GetSP();
303ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai}
304ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif // __i386__ || __sparc__
305ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
306ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif // __GNUC__ || __SUNPRO_CC
307ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
3080dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// CountCallerFrames returns the number of stack frames beneath the function
3090dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// that called CountCallerFrames.  Because this function's return value
3100dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// is dependent on the size of the stack beneath it, inlining is disabled,
3110dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// and any function that calls this should not be inlined either.
312ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__GNUC__)
3130dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaistatic unsigned int CountCallerFrames() __attribute__((noinline));
314ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__SUNPRO_CC)
315ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaistatic unsigned int CountCallerFrames();
316ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif
3170dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaistatic unsigned int CountCallerFrames() {
3180dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  SelfMemoryRegion memory;
319fd38d48e6d5e56cb66b0fa0f7e25f840a83dac5cbryner  BasicSourceLineResolver resolver;
3200dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3210dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#if defined(__i386__)
3220dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  MDRawContextX86 context = MDRawContextX86();
3230dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  context.eip = GetEIP();
3240dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  context.ebp = GetEBP();
325246f4068280b5b191303ff13671e43a0522987demmentovai  context.esp = GetESP();
3260dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
32797d392dc4b60f0099cd7ad8c8a5f06581a532392mmentovai  StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL,
32897d392dc4b60f0099cd7ad8c8a5f06581a532392mmentovai                                              NULL, &resolver);
3290dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#elif defined(__ppc__)
3300dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  MDRawContextPPC context = MDRawContextPPC();
3310dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  context.srr0 = GetPC();
3320dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  context.gpr[1] = GetSP();
3330dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
33497d392dc4b60f0099cd7ad8c8a5f06581a532392mmentovai  StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL,
33597d392dc4b60f0099cd7ad8c8a5f06581a532392mmentovai                                              NULL, &resolver);
336ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__sparc__)
337ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  MDRawContextSPARC context = MDRawContextSPARC();
338ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  context.pc = GetPC();
339ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  context.g_r[14] = GetSP();
340ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  context.g_r[30] = GetFP();
341ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai
342ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai  StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory,
343ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai                                                  NULL, NULL, &resolver);
344ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif  // __i386__ || __ppc__ || __sparc__
3450dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
346fb35cf79e290fc14b544f41157231d36d57dd213mmentovai  CallStack stack;
3475a2106b5f95f3232ac0e9aab5f081eb04313a8b6ivan.penkov@gmail.com  vector<const CodeModule*> modules_without_symbols;
3485a2106b5f95f3232ac0e9aab5f081eb04313a8b6ivan.penkov@gmail.com  stackwalker.Walk(&stack, &modules_without_symbols);
3490dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3500dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#ifdef PRINT_STACKS
3510dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  printf("\n");
35280e98391dc7ff361355e72c24c0fb222518bcdfcmmentovai  for (unsigned int frame_index = 0;
353fb35cf79e290fc14b544f41157231d36d57dd213mmentovai      frame_index < stack.frames()->size();
3540dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai      ++frame_index) {
355fb35cf79e290fc14b544f41157231d36d57dd213mmentovai    StackFrame *frame = stack.frames()->at(frame_index);
356c27cf3e3959189f78fe2de40405987c3f33488cemmentovai    printf("frame %-3d  instruction = 0x%08" PRIx64,
357246f4068280b5b191303ff13671e43a0522987demmentovai           frame_index, frame->instruction);
358246f4068280b5b191303ff13671e43a0522987demmentovai#if defined(__i386__)
359d119a921ea611dc38cfcb7411759ddf2c688603fmmentovai    StackFrameX86 *frame_x86 = reinterpret_cast<StackFrameX86*>(frame);
360246f4068280b5b191303ff13671e43a0522987demmentovai    printf("  esp = 0x%08x  ebp = 0x%08x\n",
361246f4068280b5b191303ff13671e43a0522987demmentovai           frame_x86->context.esp, frame_x86->context.ebp);
362246f4068280b5b191303ff13671e43a0522987demmentovai#elif defined(__ppc__)
363d119a921ea611dc38cfcb7411759ddf2c688603fmmentovai    StackFramePPC *frame_ppc = reinterpret_cast<StackFramePPC*>(frame);
364246f4068280b5b191303ff13671e43a0522987demmentovai    printf("  gpr[1] = 0x%08x\n", frame_ppc->context.gpr[1]);
365ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__sparc__)
366ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    StackFrameSPARC *frame_sparc = reinterpret_cast<StackFrameSPARC*>(frame);
367ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai    printf("  sp = 0x%08x  fp = 0x%08x\n",
368ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai           frame_sparc->context.g_r[14], frame_sparc->context.g_r[30]);
369ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif  // __i386__ || __ppc__ || __sparc__
3700dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  }
3710dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai#endif  // PRINT_STACKS
3720dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3730dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  // Subtract 1 because the caller wants the number of frames beneath
3740dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  // itself.  Because the caller called us, subract two for our frame and its
375fb35cf79e290fc14b544f41157231d36d57dd213mmentovai  // frame, which are included in stack.size().
376fb35cf79e290fc14b544f41157231d36d57dd213mmentovai  return stack.frames()->size() - 2;
3770dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
3780dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3790dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3800dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// Recursor verifies that the number stack frames beneath itself is one more
3810dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// than the number of stack frames beneath its parent.  When depth frames
3820dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// have been reached, Recursor stops checking and returns success.  If the
3830dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// frame count check fails at any depth, Recursor will stop and return false.
3840dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// Because this calls CountCallerFrames, inlining is disabled.
385ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__GNUC__)
3860dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaistatic bool Recursor(unsigned int depth, unsigned int parent_callers)
3870dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    __attribute__((noinline));
388ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__SUNPRO_CC)
389ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaistatic bool Recursor(unsigned int depth, unsigned int parent_callers);
390ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif
3910dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaistatic bool Recursor(unsigned int depth, unsigned int parent_callers) {
3920dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  unsigned int callers = CountCallerFrames();
3930dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  if (callers != parent_callers + 1)
3940dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    return false;
3950dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3960dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  if (depth)
3970dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai    return Recursor(depth - 1, callers);
3980dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
3990dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  // depth == 0
4000dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return true;
4010dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
4020dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4030dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4040dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// Because this calls CountCallerFrames, inlining is disabled - but because
4050dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// it's main (and nobody calls it other than the entry point), it wouldn't
4060dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai// be inlined anyway.
407ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#if defined(__GNUC__)
4080dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaiint main(int argc, char** argv) __attribute__((noinline));
409ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#elif defined(__SUNPRO_CC)
410ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovaiint main(int argc, char** argv);
411ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif
4120dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaiint main(int argc, char** argv) {
41332b802dba3d49880a0414d066e71cdc20ab09901mmentovai  BPLOG_INIT(&argc, &argv);
41432b802dba3d49880a0414d066e71cdc20ab09901mmentovai
4150dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return Recursor(RECURSION_DEPTH, CountCallerFrames()) ? 0 : 1;
4160dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
4170dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4180dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
419ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#else
420ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai// Not i386 or ppc or sparc?  We can only test stacks we know how to walk.
4210dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4220dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4230dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovaiint main(int argc, char **argv) {
42432b802dba3d49880a0414d066e71cdc20ab09901mmentovai  BPLOG_INIT(&argc, &argv);
42532b802dba3d49880a0414d066e71cdc20ab09901mmentovai
4260dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  // "make check" interprets an exit status of 77 to mean that the test is
4270dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  // not supported.
42832b802dba3d49880a0414d066e71cdc20ab09901mmentovai  BPLOG(ERROR) << "Selftest not supported here";
4290dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai  return 77;
4300dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai}
4310dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
4320dbedc973d5ce1e2c6924a144b3ac02ee4283091mmentovai
433ea2bba970675e01f9964f82d3f44960c1aad05dcmmentovai#endif  // (__GNUC__ || __SUNPRO_CC) && (__i386__ || __ppc__ || __sparc__)
434