Bug 724079. Add an internal stackwalk API. r=ehsan

This will be used by the profiler to be able to unwind arbitrary threads.
This commit is contained in:
Jeff Muizelaar 2012-02-03 15:13:24 -05:00
Родитель 8e090a927a
Коммит c71622c072
3 изменённых файлов: 87 добавлений и 22 удалений

Просмотреть файл

@ -103,6 +103,7 @@ EXPORTS_mozilla = \
MapsMemoryReporter.h \
ClearOnShutdown.h \
AvailableMemoryTracker.h \
StackWalk.h \
$(NULL)
ifeq (windows,$(MOZ_WIDGET_TOOLKIT))

52
xpcom/base/StackWalk.h Normal file
Просмотреть файл

@ -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 <jmuizelaar@mozilla.com>
*
* 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_) */

Просмотреть файл

@ -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