00001 // Copyright 2007 and onwards Google Inc. 00002 // Author: Craig Silverstein 00003 // 00004 // Produce stack trace. I'm guessing (hoping!) the code is much like 00005 // for x86. For apple machines, at least, it seems to be; see 00006 // http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html 00007 // http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK 00008 // Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882 00009 00010 #include <stdint.h> // for uintptr_t 00011 #include <stdlib.h> // for NULL 00012 #include <google/stacktrace.h> 00013 00014 // Given a pointer to a stack frame, locate and return the calling 00015 // stackframe, or return NULL if no stackframe can be found. Perform 00016 // sanity checks to reduce the chance that a bad pointer is returned. 00017 static void **NextStackFrame(void **old_sp) { 00018 void **new_sp = (void **) *old_sp; 00019 00020 // Check that the transition from frame pointer old_sp to frame 00021 // pointer new_sp isn't clearly bogus 00022 if (new_sp <= old_sp) return NULL; 00023 if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; 00024 if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; 00025 return new_sp; 00026 } 00027 00028 int GetStackTrace(void** result, int max_depth, int skip_count) { 00029 void **sp; 00030 // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther) 00031 // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a 00032 // different asm syntax. I don't know quite the best way to discriminate 00033 // systems using the old as from the new one; I've gone with __APPLE__. 00034 // TODO(csilvers): use autoconf instead, to look for 'as --version' == 1 or 2 00035 #ifdef __APPLE__ 00036 __asm__ volatile ("mr %0,r1" : "=r" (sp)); 00037 #else 00038 __asm__ volatile ("mr %0,1" : "=r" (sp)); 00039 #endif 00040 00041 int n = 0; 00042 while (sp && n < max_depth) { 00043 if (skip_count > 0) { 00044 skip_count--; 00045 } else { 00046 // sp[2] holds the "Link Record", according to RTArch-59.html. 00047 // On PPC, the Link Record is the return address of the 00048 // subroutine call (what instruction we run after our function 00049 // finishes). This is the same as the stack-pointer of our 00050 // parent routine, which is what we want here. We believe that 00051 // the compiler will always set up the LR for subroutine calls. 00052 // 00053 // It may be possible to get the stack-pointer of the parent 00054 // routine directly. In my experiments, this code works: 00055 // result[n++] = NextStackFrame(sp)[-18] 00056 // But I'm not sure what this is doing, exactly, or how reliable it is. 00057 result[n++] = *(sp+2); // sp[2] holds the Link Record (return address) 00058 } 00059 sp = NextStackFrame(sp); 00060 } 00061 return n; 00062 }