#include "windows.h" #include "sxstypes.h" #define KDEXT_64BIT #include "wdbgexts.h" #include "fusiondbgext.h" #define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION (0x00000001) #define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE (0x00000002) #define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST (0x00000004) #define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED (0x00000008) BOOL DumpActivationContextStackFrame( PCSTR pcsLineHeader, ULONG64 ulStackFrameAddress, ULONG ulDepth, DWORD dwFlags ) { ULONG64 ulPreviousPtr = 0; ULONG64 ulActivationContextPointer = 0; ULONG ulFrameFlags = 0; if (!pcsLineHeader) pcsLineHeader = ""; GetFieldValue(ulStackFrameAddress, "nt!_RTL_ACTIVATION_CONTEXT_STACK_FRAME", "Previous", ulPreviousPtr); GetFieldValue(ulStackFrameAddress, "nt!_RTL_ACTIVATION_CONTEXT_STACK_FRAME", "ActivationContext", ulActivationContextPointer); GetFieldValue(ulStackFrameAddress, "nt!_RTL_ACTIVATION_CONTEXT_STACK_FRAME", "Flags", ulFrameFlags); dprintf( "%sActivation stack frame @ 0x%p (depth %ld):\n" "%s Previous : 0x%p\n" "%s ActivationContext : 0x%p\n" "%s Flags : 0x%08lx ", pcsLineHeader, ulStackFrameAddress, ulDepth, pcsLineHeader, ulPreviousPtr, pcsLineHeader, ulActivationContextPointer, pcsLineHeader, ulFrameFlags); if (ulFrameFlags != 0) { dprintf("("); if (ulFrameFlags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION) dprintf("ReleaseOnDeactivate "); if (ulFrameFlags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE) dprintf("NoDeactivate "); if (ulFrameFlags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST) dprintf("OnFreeList"); if (ulFrameFlags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) dprintf("HeapAllocated "); dprintf(")"); } dprintf ("\n"); return 0; } BOOL DumpActCtxStackFullStack( ULONG64 ulFirstStackFramePointer ) { ULONG ulDepth = 0; ULONG64 ulStackFramePtr = ulFirstStackFramePointer; while (ulStackFramePtr) { DumpActivationContextStackFrame(" ", ulStackFramePtr, ulDepth++, 0xffff); GetFieldValue(ulStackFramePtr, "nt!_RTL_ACTIVATION_CONTEXT_STACK_FRAME", "Previous", ulStackFramePtr); if (CheckControlC() || (ulStackFramePtr == 0)) break; } return TRUE; } BOOL DumpActCtxData( PCSTR LineHeader, const ULONG64 ActCtxDataAddressInDebugeeSpace, ULONG ulFlags ) { // // ACTIVATION_CONTEXT_DATA is a self-referential type, so dumping it is // easy once it's all in memory. // ACTIVATION_CONTEXT_DATA ActData; BYTE *pbActualData = NULL; BOOL fOk = FALSE; ULONG cbRead = 0; if (!LineHeader) LineHeader = ""; if (!ReadMemory(ActCtxDataAddressInDebugeeSpace, &ActData, sizeof(ActData), &cbRead) || (cbRead != sizeof(ActData))) { dprintf( "%sFailed reading ACTIVATION_CONTEXT_DATA @ %p , or wrong kind of block is there.\n", LineHeader, ActCtxDataAddressInDebugeeSpace); goto Exit; } // // Let's create a blob of memory that can hold the whole thing, then // pbActualData = new BYTE[ActData.TotalSize]; if (!pbActualData) { dprintf( "%sUnable to allocate %d bytes to store activation context data\n", LineHeader, ActData.TotalSize); goto Exit; } // // And re-read from the debugee // if (!ReadMemory(ActCtxDataAddressInDebugeeSpace, pbActualData, ActData.TotalSize, &cbRead) || (cbRead != ActData.TotalSize)) { dprintf( "%sUnable to read in %d bytes from %p as an activation context object?\n", LineHeader, ActData.TotalSize, ActCtxDataAddressInDebugeeSpace); goto Exit; } DbgExtPrintActivationContextData( (ulFlags & DUMPACTCTXDATA_FLAG_FULL) == DUMPACTCTXDATA_FLAG_FULL, (PCACTIVATION_CONTEXT_DATA)pbActualData, L" " ); fOk = TRUE; Exit: if (pbActualData) delete[] pbActualData; return fOk; } BOOL DumpActCtx( const ULONG64 ActCtxAddressInDebugeeSpace, ULONG ulFlags ) { ULONG64 ActCtxAddr = ActCtxAddressInDebugeeSpace; ULONG64 ulSymbolOffset = 0; PRIVATE_ACTIVATION_CONTEXT prvContextFilled = { 0 }; CHAR NotificationSymbol[1024] = { 0 }; BOOL fOk = FALSE; int i = 0; #define GET_FIELD(a, fn, dst) { GetFieldData((a), "nt!_ACTIVATION_CONTEXT", #fn, sizeof((dst).##fn), (PVOID)&((dst).##fn)); } GET_FIELD(ActCtxAddr, Flags, prvContextFilled); GET_FIELD(ActCtxAddr, RefCount, prvContextFilled); GET_FIELD(ActCtxAddr, ActivationContextData, prvContextFilled); GET_FIELD(ActCtxAddr, NotificationRoutine, prvContextFilled); GET_FIELD(ActCtxAddr, NotificationContext, prvContextFilled); // GET_FIELD(ActCtxAddr, SentNotifications, prvContextFilled); // GET_FIELD(ActCtxAddr, DisabledNotifications, prvContextFilled); // GET_FIELD(ActCtxAddr, StorageMap, prvContextFilled); // GET_FIELD(ActCtxAddr, InlineStorageMapEntries, prvContextFilled); #undef GET_FIELD dprintf( "Activation context structure @ 0x%p\n" " RefCount %d\n" " Flags 0x%08x\n" " ActivationContextData 0x%p\n", ActCtxAddressInDebugeeSpace, (LONG)prvContextFilled.RefCount, (ULONG)prvContextFilled.Flags, (PVOID)prvContextFilled.ActivationContextData); if (ulFlags & DUMPACTCTX_DATA) { // if (!DumpActCtxData(" ", (ULONG64)prvContextFilled.ActivationContextData, ulFlags)) // goto Exit; DumpActCtxData(" ", (ULONG64)prvContextFilled.ActivationContextData, ulFlags); } // // This icky gunk is to print out a symbol name properly... // dprintf(" NotificationRoutine 0x%p ", prvContextFilled.NotificationRoutine); GetSymbol((ULONG64)prvContextFilled.NotificationRoutine, NotificationSymbol, &ulSymbolOffset); if (strlen(NotificationSymbol)) { dprintf("(%s" , NotificationSymbol); if (ulSymbolOffset) dprintf("+0x%p", ulSymbolOffset); dprintf(")"); } dprintf("\n"); dprintf(" NotificationContext 0x%p\n", prvContextFilled.NotificationContext); dprintf(" SentNotifications ["); for (i = 0; i < NUMBER_OF(prvContextFilled.SentNotifications); i++) { if (i) dprintf(" "); dprintf("%d", prvContextFilled.SentNotifications[i]); } dprintf("]\n"); dprintf(" DisabledNotifications ["); for (i = 0; i < NUMBER_OF(prvContextFilled.DisabledNotifications); i++) { if (i) dprintf(" "); dprintf("%d", prvContextFilled.DisabledNotifications[i]); } dprintf("]\n"); { ULONG ulStorageMapFlags, ulCount; ULONG64 ulMapAddress; GetFieldValue(ActCtxAddressInDebugeeSpace, "_ACTIVATION_CONTEXT", "StorageMap.Flags", ulStorageMapFlags); GetFieldValue(ActCtxAddressInDebugeeSpace, "_ACTIVATION_CONTEXT", "StorageMap.AssemblyCount", ulCount); GetFieldValue(ActCtxAddressInDebugeeSpace, "_ACTIVATION_CONTEXT", "StorageMap.AssemblyArray", ulMapAddress); dprintf( " StorageMap (Flags = 0x%08lx Count = %d MapArray = %p)\n", ulStorageMapFlags, ulCount, ulMapAddress); } fOk = TRUE; return fOk; } BOOL GetActiveActivationContextData( PULONG64 pulActiveActCtx ) { ULONG64 ulTebAddress = 0, ulPebAddress = 0; ULONG64 ulTebActiveFrameAddress = 0; // // The algorithm is like this: // - Look at Teb.ActivationContextStack.ActiveFrame.ActivationContext. If this is // nonzero, stop looking. // - Now look at the process default activation context in Peb.ActivationContextData. // If this is nonzero, stop looking. // - Look at the system default act ctx data, in Peb.SystemDefaultActivationContextData // If this is nonzero, stop looking. // - Didn't find any active activation context data? Fooey. // *pulActiveActCtx = 0; GetTebAddress(&ulTebAddress); GetPebAddress(0, &ulPebAddress); if (ulTebAddress != NULL) { // Look at the active stack frame in the teb GetFieldValue(ulTebAddress, "nt!TEB", "ActivationContextStack.ActiveFrame", ulTebActiveFrameAddress); if (ulTebActiveFrameAddress) { ULONG64 ulActivationContextFrame; // Get the pointer to the active activation context itself GetFieldValue( ulTebActiveFrameAddress, "ntdll!_RTL_ACTIVATION_CONTEXT_STACK_FRAME", "ActivationContext", ulActivationContextFrame); // If that was valid, then ask for the pointer to the activation context data if (ulActivationContextFrame) { GetFieldValue( ulActivationContextFrame, "ntdll!ACTIVATION_CONTEXT", "ActivationContextData", *pulActiveActCtx); return TRUE; } // Is this really requesting the process default? else if (ulActivationContextFrame == NULL) { // Then get it and return GetFieldValue(ulPebAddress, "nt!PEB", "ActivationContextData", *pulActiveActCtx); return TRUE; } } } // // Still nothing, so go look at the process default directly // { ULONG ActCtxDataOffset; ULONG64 PebData; GetFieldOffset("nt!_PEB", "ActivationContextData", &ActCtxDataOffset); if ((ReadPtr(ulPebAddress + ActCtxDataOffset, &PebData) == 0) && PebData) { *pulActiveActCtx = PebData; return TRUE; } } // // Otherwise... // GetFieldValue(ulPebAddress, "nt!PEB", "SystemDefaultActivationContextData", *pulActiveActCtx); return (*pulActiveActCtx ? TRUE : FALSE); }