summaryrefslogtreecommitdiff
path: root/src/stacktrace_powerpc-inl.h
diff options
context:
space:
mode:
authorcsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2008-02-13 00:55:09 +0000
committercsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2008-02-13 00:55:09 +0000
commit8a0a3101bc6a7d56ac04b278f28bdf3f95b00a3c (patch)
tree46f871a3160a4023201d72b1b04a9a88e3d88b78 /src/stacktrace_powerpc-inl.h
parentb43ba444fcd74fa7c3260f6b2494dcbaa3fdb296 (diff)
downloadgperftools-8a0a3101bc6a7d56ac04b278f28bdf3f95b00a3c.tar.gz
Tue Feb 12 12:28:32 2008 Google Inc. <opensource@google.com>
* google-perftools: version 0.95 release * Better -- not perfect -- support for linux-ppc (csilvers) * Fix race condition in libunwind stacktrace (aruns) * Speed up x86 spinlock locking (m3b) * Improve heap-checker performance (maxim) * Heap checker traverses more ptrs inside heap-alloced objects (maxim) * Remove deprecated ProfilerThreadState function (cgd) * Update libunwind documentation for statically linked binaries (aruns) git-svn-id: http://gperftools.googlecode.com/svn/trunk@44 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
Diffstat (limited to 'src/stacktrace_powerpc-inl.h')
-rw-r--r--src/stacktrace_powerpc-inl.h80
1 files changed, 52 insertions, 28 deletions
diff --git a/src/stacktrace_powerpc-inl.h b/src/stacktrace_powerpc-inl.h
index bf64284..5631e49 100644
--- a/src/stacktrace_powerpc-inl.h
+++ b/src/stacktrace_powerpc-inl.h
@@ -68,6 +68,10 @@ static void **NextStackFrame(void **old_sp) {
return new_sp;
}
+// This ensures that GetStackTrace stes up the Link Register properly.
+void StacktracePowerPCDummyFunction() __attribute__((noinline));
+void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
+
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
@@ -82,23 +86,40 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
__asm__ volatile ("mr %0,1" : "=r" (sp));
#endif
+ // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
+ // entry that holds 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. While the compiler will always(?) set up LR for
+ // subroutine calls, it may not for leaf functions (such as this one).
+ // This routine forces the compiler (at least gcc) to push it anyway.
+ StacktracePowerPCDummyFunction();
+
+ // The LR save area is used by the callee, so the top entry is bogus.
+ skip_count++;
+
int n = 0;
while (sp && n < max_depth) {
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:
- // result[n++] = NextStackFrame(sp)[-18]
- // 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)
+ // PowerPC has 3 main ABIs, which say where in the stack the
+ // Link Register is. For DARWIN and AIX (used by apple and
+ // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
+ // it's in sp[1].
+#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
+ result[n++] = *(sp+2);
+#elif defined(_CALL_SYSV)
+ result[n++] = *(sp+1);
+#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
+ // This check is in case the compiler doesn't define _CALL_AIX/etc.
+ result[n++] = *(sp+2);
+#elif defined(__linux)
+ // This check is in case the compiler doesn't define _CALL_SYSV.
+ result[n++] = *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
@@ -135,16 +156,18 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// 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
+ StacktracePowerPCDummyFunction();
+ // Note we do *not* increment skip_count here for the SYSV ABI. If
+ // we did, the list of stack frames wouldn't properly match up with
+ // the list of return addresses. Note this means the top pc entry
+ // is probably bogus for linux/ppc (and other SYSV-ABI systems).
+
int n = 0;
while (sp && n < max_depth) {
// The GetStackFrames routine is called when we are in some
@@ -156,18 +179,19 @@ int GetStackFrames(void** pcs, int *sizes, int max_depth, int skip_count) {
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 defined(_CALL_AIX) || defined(_CALL_DARWIN)
+ pcs[n++] = *(sp+2);
+#elif defined(_CALL_SYSV)
+ pcs[n++] = *(sp+1);
+#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
+ // This check is in case the compiler doesn't define _CALL_AIX/etc.
+ pcs[n++] = *(sp+2);
+#elif defined(__linux)
+ // This check is in case the compiler doesn't define _CALL_SYSV.
+ pcs[n++] = *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
if (next_sp > sp) {
sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
} else {