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