gecko-dev/ef/Runtime/System/StackWalker.cpp

249 строки
5.9 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
//
// StackWalker.cpp
//
// Simon Holmes a Court
// Scott M. Silver
//
// Routines for walking and printing out the stack.
//
// Interesting debug routines are listed at the end of this function
#include "Fundamentals.h"
#include "StackWalker.h"
// Assembly guff to return the EBP
#if defined(_WIN32) && !defined(__GNUC__)
#define INLINE_GET_EBP(inEBPVariableName) \
__asm mov inEBPVariableName, ebp
#elif defined(__i386__)
#define INLINE_GET_EBP(inEBPVariableName) \
({ register __typeof__(inEBPVariableName) ebp_ __asm__("ebp"); \
(inEBPVariableName) = ebp_; })
#else
#error Nothing else in this file is right either.
#endif
// Frame
//
// ACHTUNG ADVENTURER: Be careful of changing the inlining
// of this constructor, it assumes it is called on real frame down
// from the scope where the Frame object is.
Frame::
Frame()
{
Uint8 **foo;
INLINE_GET_EBP(foo); // inline assembly to grab our base pointer
pFrame = foo;
// skip over the constructor frame and return the caller's frame
moveToPrevFrame();
}
// moveToPrevFrame
//
// Set the cursor for this frame to the previous frame
void Frame::
moveToPrevFrame()
{
pMethodAddress = (Uint8*) *(pFrame + 1);
pFrame = (Uint8**) *pFrame;
}
// Compute the number of stack frames on the stack
int Frame::
getStackDepth()
{
Frame frame;
int depth = -1;
do {
frame.moveToPrevFrame();
depth++;
} while (frame.getBase());
return depth;
}
// getCallingJavaMethod
//
// Identify caller stack frames that correspond to non-native Java methods.
// Use the climbDepth argument to determine how many such stack frames
// should be skipped over and return the method corresponding to the final
// such frame, e.g. a climbDepth of 1 means that we should return the
// immediate enclosing non-native Java calling method.
Method &Frame::getCallingJavaMethod(int climbDepth)
{
Method *m;
do {
m = 0;
while (!m) {
pMethodAddress = (Uint8*) *(pFrame + 1);
pFrame = (Uint8**) *pFrame;
m = getMethodForPC(pMethodAddress);
}
} while ((m->getModifiers() & CR_METHOD_NATIVE) || --climbDepth);
return *m;
}
// getMethod
//
// get Method* or NULL associated with this Frame
Method* Frame::
getMethod()
{
return (getMethodForPC(pMethodAddress));
}
// getCallerPC
//
// Return the address of the function that called the getCallerPC
extern Uint8* getCallerPC()
{
#ifdef GENERATE_FOR_X86
Uint8** myEBP;
INLINE_GET_EBP(myEBP);
Uint8** calleeEBP = (Uint8**) *myEBP; // get the callee's EBP
Uint8* retAddress = (Uint8*) *(calleeEBP + 1);
return retAddress;
#else // !GENERATE_FOR_X86
return 0;
#endif
}
// setCalleeReturnAddress
//
// change the return address of the callee's callee to the passed in pointer
// FIX-ME huh??
extern void setCalleeReturnAddress(Uint8* retAddress)
{
#ifdef WIN32
Uint8** myEBP;
INLINE_GET_EBP(myEBP); // myEBP is the EBP of getCallerPC
Uint8** calleeEBP = (Uint8**) *myEBP; // get the callee's EBP
(Uint8*) *(calleeEBP + 1) = retAddress;
#else // non WIN32
retAddress;
trespass("not implemented");
#endif
}
// getMethodForPC
//
// Return Method* or NULL associated with this PC
extern Method* getMethodForPC(void* inCurPC)
{
CacheEntry* ce = NativeCodeCache::getCache().lookupByRange((Uint8*) inCurPC);
return (ce ? ce->descriptor.method : 0);
}
#ifdef DEBUG_LOG
UT_DEFINE_LOG_MODULE(StackWalker);
extern "C"
void NS_EXTERN stackWalker(void* inCurPC)
{
UT_SET_LOG_LEVEL(StackWalker, PR_LOG_DEBUG);
UT_LOG(StackWalker, PR_LOG_ALWAYS, ("\n\n_____________________Top of stack______________________\n"));
UT_LOG(StackWalker, PR_LOG_ALWAYS, ("%10s %10s\n", " Frame", "Return Addr"));
if (inCurPC)
Frame::printOne(UT_LOG_MODULE(StackWalker), 0, inCurPC);
Frame frame;
do
{
frame.print(UT_LOG_MODULE(StackWalker));
frame.moveToPrevFrame();
}
while (frame.hasPreviousFrame());
UT_LOG(StackWalker, PR_LOG_ALWAYS, ("____________________Bottom of Stack____________________\n\n"));
}
#include "prprf.h"
void Frame::
printWithArgs(LogModuleObject &f, Uint8* inFrame, Method* inMethod)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%s(", inMethod->toString()));
const Signature& ourSignature = inMethod->getSignature();
Uint16 numArgs = ourSignature.nArguments;
const Type** ourArgs = ourSignature.argumentTypes;
// calc arg size
Uint16 i;
Uint8* argListPtr = ((Uint8*) inFrame + 8); // just beyond first argument
for(i = 0; i < numArgs; i++)
{
if (inFrame)
printValue(f, argListPtr, *ourArgs[i]);
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<frameless>"));
argListPtr += nTypeKindSlots(ourArgs[i]->typeKind) * 4;
if(i < (numArgs - 1))
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", "));
}
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (")"));
}
void Frame::
printOne(LogModuleObject &f, void* inFrame, void* inMethodAddress)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("0x%08x (0x%08x) ", inFrame, inMethodAddress));
Method* method = getMethodForPC(inMethodAddress);
if(method)
printWithArgs(f, (Uint8*)inFrame, method);
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("anonymous"));
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
}
void Frame::
print(LogModuleObject &f)
{
printOne(f, pFrame, pMethodAddress);
}
#endif