From c71622c072edd4ad2cf8d7e6194c3665bfbc13de Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Fri, 3 Feb 2012 15:13:24 -0500 Subject: [PATCH] Bug 724079. Add an internal stackwalk API. r=ehsan This will be used by the profiler to be able to unwind arbitrary threads. --- xpcom/base/Makefile.in | 1 + xpcom/base/StackWalk.h | 52 +++++++++++++++++++++++++++++++++++ xpcom/base/nsStackWalk.cpp | 56 +++++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 xpcom/base/StackWalk.h diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index ef64797b7c1a..85f1509b7376 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -103,6 +103,7 @@ EXPORTS_mozilla = \ MapsMemoryReporter.h \ ClearOnShutdown.h \ AvailableMemoryTracker.h \ + StackWalk.h \ $(NULL) ifeq (windows,$(MOZ_WIDGET_TOOLKIT)) diff --git a/xpcom/base/StackWalk.h b/xpcom/base/StackWalk.h new file mode 100644 index 000000000000..c0b81c3c7464 --- /dev/null +++ b/xpcom/base/StackWalk.h @@ -0,0 +1,52 @@ +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Muizelaar + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* API for getting a stack trace of the C/C++ */ + +#ifndef StackWalk_h_ +#define StackWalk_h_ + +// XXX: it would be nice to eventually remove this header dependency on nsStackWalk.h +#include "nsStackWalk.h" + +namespace mozilla { + +nsresult +FramePointerStackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure, void **bp); + +} + +#endif /* !defined(StackWalk_h_) */ diff --git a/xpcom/base/nsStackWalk.cpp b/xpcom/base/nsStackWalk.cpp index 3e9319974991..2c1d53eeea16 100644 --- a/xpcom/base/nsStackWalk.cpp +++ b/xpcom/base/nsStackWalk.cpp @@ -41,11 +41,14 @@ /* API for getting a stack trace of the C/C++ stack on the current thread */ #include "mozilla/Util.h" +#include "mozilla/StackWalk.h" #include "nsDebug.h" #include "nsStackWalkPrivate.h" #include "nsStackWalk.h" +using namespace mozilla; + // The presence of this address is the stack must stop the stack walk. If // there is no such address, the structure will be {NULL, true}. struct CriticalAddress { @@ -215,8 +218,6 @@ StackWalkInitCriticalAddress() #endif #endif -using namespace mozilla; - // Define these as static pointers so that we can load the DLL on the // fly (and not introduce a link-time dependency on it). Tip o' the // hat to Matt Pietrick for this idea. See: @@ -1572,9 +1573,6 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, #else // not __sun-specific -#define X86_OR_PPC (defined(__i386) || defined(PPC) || defined(__ppc__)) -#if X86_OR_PPC && (NSSTACKWALK_SUPPORTS_MACOSX || NSSTACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code - #if __GLIBC__ > 2 || __GLIBC_MINOR > 1 #define HAVE___LIBC_STACK_END 1 #else @@ -1584,26 +1582,13 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, #if HAVE___LIBC_STACK_END extern void *__libc_stack_end; // from ld-linux.so #endif - -EXPORT_XPCOM_API(nsresult) -NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, - void *aClosure, uintptr_t aThread) +namespace mozilla { +nsresult +FramePointerStackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure, void **bp) { - MOZ_ASSERT(gCriticalAddress.mInit); - MOZ_ASSERT(!aThread); // Stack walking code courtesy Kipp's "leaky". - // Get the frame pointer - void **bp; -#if defined(__i386) - __asm__( "movl %%ebp, %0" : "=g"(bp)); -#else - // It would be nice if this worked uniformly, but at least on i386 and - // x86_64, it stopped working with gcc 4.1, because it points to the - // end of the saved registers instead of the start. - bp = (void**) __builtin_frame_address(0); -#endif - int skip = aSkipFrames; while (1) { void **next = (void**)*bp; @@ -1636,6 +1621,33 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, return NS_OK; } +} + +#define X86_OR_PPC (defined(__i386) || defined(PPC) || defined(__ppc__)) +#if X86_OR_PPC && (NSSTACKWALK_SUPPORTS_MACOSX || NSSTACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code + +EXPORT_XPCOM_API(nsresult) +NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure, uintptr_t aThread) +{ + MOZ_ASSERT(gCriticalAddress.mInit); + MOZ_ASSERT(!aThread); + + // Get the frame pointer + void **bp; +#if defined(__i386) + __asm__( "movl %%ebp, %0" : "=g"(bp)); +#else + // It would be nice if this worked uniformly, but at least on i386 and + // x86_64, it stopped working with gcc 4.1, because it points to the + // end of the saved registers instead of the start. + bp = (void**) __builtin_frame_address(0); +#endif + return FramePointerStackWalk(aCallback, aSkipFrames, + aClosure, bp); + +} + #elif defined(HAVE__UNWIND_BACKTRACE) // libgcc_s.so symbols _Unwind_Backtrace@@GCC_3.3 and _Unwind_GetIP@@GCC_3.0