summaryrefslogtreecommitdiff
path: root/src/stacktrace_powerpc-inl.h
diff options
context:
space:
mode:
authorcsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2007-11-29 23:39:24 +0000
committercsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2007-11-29 23:39:24 +0000
commit11b02f7aebd05cf39f6f93bdd48786909f99f34e (patch)
tree660c613e74cffd643ee4a7d0f0cb170057abbf7d /src/stacktrace_powerpc-inl.h
parent49b74b9508797f8aafe6b86e62e7efc4ec200e48 (diff)
downloadgperftools-11b02f7aebd05cf39f6f93bdd48786909f99f34e.tar.gz
Thu Nov 29 07:59:43 2007 Google Inc. <opensource@google.com>
* google-perftools: version 0.94 release * PORTING: MinGW/Msys support -- runs same code as MSVC does (csilvers) * PORTING: Add NumCPUs support for Mac OS X (csilvers) * Work around a sscanf bug in glibc(?) (waldemar) * Fix Windows MSVC bug triggered by thread deletion (csilvers) * Fix bug that triggers in MSVC /O2: missing volatile (gpike) * March-of-time support: quiet warnings/errors for gcc 4.2, OS X 10.5 * Modify pprof so it works without nm: useful for windows (csilvers) * pprof: Support filtering for CPU profiles (cgd) * Bugfix: have realloc report to hooks in all situations (maxim) * Speed improvement: replace slow memcpy with std::copy (soren) * Speed: better iterator efficiency in RecordRegionRemoval (soren) * Speed: minor speed improvements via better bitfield alignment (gpike) * Documentation: add documentation of binary profile output (cgd) git-svn-id: http://gperftools.googlecode.com/svn/trunk@40 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
Diffstat (limited to 'src/stacktrace_powerpc-inl.h')
-rw-r--r--src/stacktrace_powerpc-inl.h132
1 files changed, 126 insertions, 6 deletions
diff --git a/src/stacktrace_powerpc-inl.h b/src/stacktrace_powerpc-inl.h
index a3be131..bf64284 100644
--- a/src/stacktrace_powerpc-inl.h
+++ b/src/stacktrace_powerpc-inl.h
@@ -1,4 +1,33 @@
-// Copyright 2007 and onwards Google Inc.
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
// Author: Craig Silverstein
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
@@ -12,19 +41,34 @@
#include <google/stacktrace.h>
// Given a pointer to a stack frame, locate and return the calling
-// stackframe, or return NULL if no stackframe can be found. Perform
-// sanity checks to reduce the chance that a bad pointer is returned.
+// stackframe, or return NULL if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = (void **) *old_sp;
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
- if (new_sp <= old_sp) return NULL;
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return NULL;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return NULL;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ }
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
- if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
return new_sp;
}
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
@@ -56,7 +100,83 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// But I'm not sure what this is doing, exactly, or how reliable it is.
result[n++] = *(sp+2); // sp[2] holds the Link Record (return address)
}
- sp = NextStackFrame(sp);
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true>(sp);
+ }
+ return n;
+}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int *sizes, int max_depth, int skip_count) {
+ void **sp;
+ // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+ // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
+ // different asm syntax. I don't know quite the best way to discriminate
+ // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+ __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+ __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ // The GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_sp = NextStackFrame<false>(sp);
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ // sp[2] holds the "Link Record", according to RTArch-59.html.
+ // On PPC, the Link Record is the return address of the
+ // subroutine call (what instruction we run after our function
+ // finishes). This is the same as the stack-pointer of our
+ // parent routine, which is what we want here. We believe that
+ // the compiler will always set up the LR for subroutine calls.
+ //
+ // It may be possible to get the stack-pointer of the parent
+ // routine directly. In my experiments, this code works:
+ // pcs[n] = NextStackFrame(sp)[-18]
+ // But I'm not sure what this is doing, exactly, or how reliable it is.
+ pcs[n] = *(sp+2); // sp[2] holds the Link Record (return address)
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ n++;
+ }
+ sp = next_sp;
}
return n;
}