/* -*- 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, ("")); 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