windows-nt/Source/XPSP1/NT/base/tools/kdexts2/stacks.c
2020-09-26 16:20:57 +08:00

1073 lines
26 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
stacks.c
Abstract:
WinDbg Extension Api
Author:
Adrian J. Oney (adriao) 07-28-1998
Environment:
User Mode.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
typedef enum _KTHREAD_STATE {
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition
} KTHREAD_STATE;
typedef enum {
NO_STACK_ACTION = 0,
SKIP_FRAME,
SKIP_THREAD
} STACKS_ACTION, *PSTACKS_ACTION;
#define ETHREAD_NOT_READABLE 1
#define THREAD_VALID 2
#define FIRST_THREAD_VALID 3
#define NO_THREADS 4
struct _BLOCKER_TREE ;
typedef struct _BLOCKER_TREE BLOCKER_TREE, *PBLOCKER_TREE ;
BOOL
StacksValidateProcess(
IN ULONG64 RealProcessBase
);
BOOL
StacksValidateThread(
IN ULONG64 RealThreadBase
);
VOID StacksDumpProcessAndThread(
IN ULONG64 RealProcessBase,
IN ULONG ThreadDesc,
IN ULONG64 RealThreadBase,
IN PBLOCKER_TREE BlockerTree,
IN ULONG Verbosity,
IN char * Filter
);
VOID StacksGetThreadStateName(
IN ULONG ThreadState,
OUT PCHAR Dest
);
VOID
DumpThreadBlockageInfo (
IN char *pad,
IN ULONG64 RealThreadBase,
IN ULONG Verbosity
);
typedef enum {
STACK_WALK_DUMP_STARTING = 0,
STACK_WALK_DUMP_NOT_RESIDENT,
STACK_WALK_DUMP_ENTRY,
STACK_WALK_DUMP_FINISHED
} WALK_STAGE;
typedef struct {
ULONG Verbosity;
BOOLEAN FirstEntry;
char* ThreadState;
char* ThreadBlocker;
ULONG ProcessCid;
ULONG ThreadCid;
ULONG64 ThreadBlockerDisplacement;
} STACK_DUMP_CONTEXT, *PSTACK_DUMP_CONTEXT;
typedef BOOLEAN (*PFN_FRAME_WALK_CALLBACK)(
IN WALK_STAGE WalkStage,
IN ULONG64 RealThreadBase,
IN PVOID Context,
IN char * Buffer,
IN ULONG64 Offset
);
VOID
ForEachFrameOnThread(
IN ULONG64 RealThreadBase,
IN PFN_FRAME_WALK_CALLBACK Callback,
IN PVOID Context
);
BOOLEAN
StacksDumpStackCallback(
IN WALK_STAGE WalkStage,
IN ULONG64 RealThreadBase,
IN PVOID Context,
IN char * Buffer,
IN ULONG64 Offset
);
extern ULONG64 STeip, STebp, STesp;
static ULONG64 PspCidTable;
ULONG64 ProcessLastDump;
ULONG64 ThreadLastDump;
ULONG TotalProcessCommit;
struct _BLOCKER_TREE {
char const *Symbolic ;
STACKS_ACTION Action ;
PBLOCKER_TREE Child ;
PBLOCKER_TREE Sibling ;
PBLOCKER_TREE Parent ;
BOOL Nested ;
} ;
VOID
AnalyzeThread(
IN ULONG64 RealThreadBase,
IN PBLOCKER_TREE BlockerTree,
IN char * Filter,
OUT PCHAR BlockSymbol,
OUT ULONG64 *BlockDisplacement,
OUT BOOLEAN *SkipThread
);
BOOL
BlockerTreeWalk(
IN OUT PBLOCKER_TREE *blockerHead,
IN char *szSymbolic,
IN STACKS_ACTION Action
);
PBLOCKER_TREE
BlockerTreeBuild(
VOID
) ;
VOID
BlockerTreeFree(
IN PBLOCKER_TREE BlockerTree
) ;
DECLARE_API( stacks )
/*++
Routine Description:
Dumps the active process list.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Result;
ULONG64 Next;
ULONG64 NextThread;
ULONG64 ProcessHead;
ULONG64 Process;
ULONG64 Thread;
ULONG64 UserProbeAddress;
ULONG Verbosity = 0, ThreadCount = 0;
ULONG ActProcOffset, ThrdListOffset, ThrdEntryOffset;
PBLOCKER_TREE blockerTree ;
char szFilter[256];
blockerTree = BlockerTreeBuild() ;
if (sscanf(args, "%x %s", &Verbosity, szFilter) < 2) {
szFilter[0] = '\0';
}
dprintf("Proc.Thread .Thread ThreadState Blocker\n") ;
UserProbeAddress = GetNtDebuggerDataValue(MmUserProbeAddress);
ProcessHead = GetNtDebuggerData( PsActiveProcessHead );
if (!ProcessHead) {
dprintf("Unable to get value of PsActiveProcessHead!\n");
goto Exit;
}
if (GetFieldValue( ProcessHead, "nt!_LIST_ENTRY", "Flink", Next )) {
dprintf("Unable to get value of PsActiveProcessHead.Flink\n");
goto Exit ;
}
if (Next == 0) {
dprintf("PsActiveProcessHead is NULL!\n");
goto Exit;
}
GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActProcOffset);
GetFieldOffset("nt!_EPROCESS", "Pcb.ThreadListHead", &ThrdListOffset);
GetFieldOffset("nt!_KTHREAD", "ThreadListEntry", &ThrdEntryOffset);
while(Next != ProcessHead) {
ULONG64 FirstThread;
Process = Next - ActProcOffset;
if (GetFieldValue( Process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", FirstThread )) {
dprintf("Unable to read nt!_EPROCESS at %p\n",Process);
goto Exit;
}
NextThread = FirstThread;
if (!StacksValidateProcess(Process)) {
dprintf("Process list damaged, or maybe symbols are incorrect?\n%p\n",Process);
goto Exit;
}
if (NextThread == Process + ThrdListOffset) {
StacksDumpProcessAndThread(Process, NO_THREADS, 0, blockerTree, Verbosity, szFilter) ;
} else {
while ( NextThread != Process + ThrdListOffset) {
ULONG64 ThreadFlink;
Thread = NextThread - ThrdEntryOffset;
if (GetFieldValue(Thread,
"nt!_ETHREAD",
"Tcb.ThreadListEntry.Flink",
ThreadFlink)) {
StacksDumpProcessAndThread(Process, ETHREAD_NOT_READABLE, 0, blockerTree, Verbosity, szFilter) ;
dprintf("Unable to read _ETHREAD at %lx\n",Thread);
break;
}
if (!StacksValidateThread(Thread)) {
StacksDumpProcessAndThread( Process, ETHREAD_NOT_READABLE, 0, blockerTree, Verbosity, szFilter) ;
} else if (NextThread == FirstThread) {
ThreadCount++;
StacksDumpProcessAndThread(Process, FIRST_THREAD_VALID, Thread, blockerTree, Verbosity, szFilter) ;
} else {
ThreadCount++;
StacksDumpProcessAndThread(Process, THREAD_VALID, Thread, blockerTree, Verbosity, szFilter) ;
}
NextThread = ThreadFlink;
if (CheckControlC()) {
goto Exit;
}
}
}
EXPRLastDump = Process;
ProcessLastDump = Process;
dprintf("\n");
GetFieldValue( Process, "nt!_EPROCESS", "ActiveProcessLinks.Flink", Next);
if (CheckControlC()) {
goto Exit;
}
}
Exit:
BlockerTreeFree(blockerTree) ;
dprintf("\nThreads Processed: %d\n", ThreadCount);
return S_OK;
}
BOOL
StacksValidateProcess(
IN ULONG64 RealProcessBase
)
{
ULONG Type;
GetFieldValue(RealProcessBase, "nt!_EPROCESS", "Pcb.Header.Type", Type);
if (Type != ProcessObject) {
dprintf("TYPE mismatch for process object at %p\n",RealProcessBase);
return FALSE;
}
return TRUE ;
}
VOID StacksDumpProcessAndThread(
IN ULONG64 RealProcessBase,
IN ULONG ThreadDesc,
IN ULONG64 RealThreadBase,
IN PBLOCKER_TREE BlockerTree,
IN ULONG Verbosity,
IN char * Filter
)
{
ULONG NumberOfHandles;
ULONG Result;
CHAR Buf[512];
CHAR ThreadState[13] ;
CHAR ThreadBlocker[256] ;
UINT i ;
ULONG64 ObjectTable, ThreadBlockerDisplacement;
CHAR *ThreadStateName ;
ULONG UniqueProcessCid;
STACK_DUMP_CONTEXT dumpData;
BOOLEAN SkipThread;
NumberOfHandles = 0;
GetFieldValue(RealProcessBase, "nt!_EPROCESS", "ImageFileName", Buf);
InitTypeRead(RealProcessBase, nt!_EPROCESS);
if (ObjectTable = ReadField(ObjectTable)) {
GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "HandleCount", NumberOfHandles);
}
if (Buf[0] == '\0' ) {
strcpy((char *)Buf,"System Process");
}
UniqueProcessCid = (ULONG) ReadField(UniqueProcessId);
if (!RealThreadBase) {
switch(ThreadDesc) {
case NO_THREADS:
dprintf(" [%p %s]\n", RealProcessBase, Buf) ;
if ((Verbosity > 0) && (Filter[0] == '\0')) {
dprintf("%4lx.------ NOTHREADS\n",
UniqueProcessCid
);
}
break ;
case ETHREAD_NOT_READABLE:
dprintf("%4lx.------ NO ETHREAD DATA\n",
UniqueProcessCid
);
break ;
}
return;
}
InitTypeRead(RealThreadBase, nt!_ETHREAD);
ASSERT(((ULONG) ReadField(Cid.UniqueProcess)) == UniqueProcessCid);
StacksGetThreadStateName((ULONG) ReadField(Tcb.State), ThreadState) ;
i=strlen(ThreadState) ;
while(i<11) ThreadState[i++]=' ' ;
ThreadState[i]='\0' ;
AnalyzeThread(
RealThreadBase,
BlockerTree,
Filter,
ThreadBlocker,
&ThreadBlockerDisplacement,
&SkipThread
);
if (ThreadDesc == FIRST_THREAD_VALID) {
dprintf(" [%p %s]\n", RealProcessBase, Buf) ;
}
if (SkipThread && ((Verbosity == 0) || (Filter[0]))) {
return;
}
dumpData.Verbosity = Verbosity;
dumpData.ThreadState = ThreadState;
dumpData.ThreadBlocker = ThreadBlocker;
dumpData.ThreadBlockerDisplacement = ThreadBlockerDisplacement;
dumpData.ProcessCid = UniqueProcessCid;
dumpData.ThreadCid = (ULONG) ReadField(Cid.UniqueThread);
ForEachFrameOnThread(
RealThreadBase,
StacksDumpStackCallback,
(PVOID) &dumpData
);
}
BOOLEAN
StacksDumpStackCallback(
IN WALK_STAGE WalkStage,
IN ULONG64 RealThreadBase,
IN PVOID Context,
IN char * Buffer,
IN ULONG64 Offset
)
{
PSTACK_DUMP_CONTEXT dumpData = (PSTACK_DUMP_CONTEXT) Context;
switch(WalkStage) {
case STACK_WALK_DUMP_STARTING:
dprintf("%4lx.%06lx %08p %s",
dumpData->ProcessCid,
dumpData->ThreadCid,
RealThreadBase,
dumpData->ThreadState
);
dumpData->FirstEntry = TRUE;
return TRUE;
case STACK_WALK_DUMP_FINISHED:
dumpData->FirstEntry = FALSE;
dprintf("\n");
return TRUE;
case STACK_WALK_DUMP_NOT_RESIDENT:
case STACK_WALK_DUMP_ENTRY:
if (dumpData->FirstEntry) {
dumpData->FirstEntry = FALSE;
} else {
dprintf("\n ");
}
break;
default:
return FALSE;
}
if (WalkStage == STACK_WALK_DUMP_NOT_RESIDENT) {
switch(dumpData->Verbosity) {
case 0:
case 1:
case 2:
dprintf("Stack paged out");
break;
}
return FALSE;
}
switch(dumpData->Verbosity) {
case 0:
case 1:
dprintf("%s", dumpData->ThreadBlocker);
if (dumpData->ThreadBlockerDisplacement) {
dprintf( "+0x%1p", dumpData->ThreadBlockerDisplacement );
}
dprintf("\n");
return FALSE;
case 2:
dprintf("%s", Buffer);
if (Offset) {
dprintf( "+0x%1p", Offset );
}
break;
}
return TRUE;
}
UCHAR *StacksWaitReasonList[] = {
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"WrExecutive",
"WrFreePage",
"WrPageIn",
"WrPoolAllocation",
"WrDelayExecution",
"WrSuspended",
"WrUserRequest",
"WrEventPairHigh",
"WrEventPairLow",
"WrLpcReceive",
"WrLpcReply",
"WrVirtualMemory",
"WrPageOut",
"Spare1",
"Spare2",
"Spare3",
"Spare4",
"Spare5",
"Spare6",
"Spare7"};
VOID StacksGetThreadStateName(
IN ULONG ThreadState,
OUT PCHAR Dest
)
{
switch (ThreadState) {
case Initialized: strcpy(Dest, "INITIALIZED"); break;
case Ready: strcpy(Dest, "READY"); break;
case Running: strcpy(Dest, "RUNNING"); break;
case Standby: strcpy(Dest, "STANDBY"); break;
case Terminated: strcpy(Dest, "TERMINATED"); break;
case Waiting: strcpy(Dest, "Blocked"); break;
case Transition: strcpy(Dest, "TRANSITION"); break;
default: strcpy(Dest, "????") ; break ;
}
}
BOOL
StacksValidateThread (
IN ULONG64 RealThreadBase
)
{
ULONG Type;
GetFieldValue(RealThreadBase, "nt!_ETHREAD", "Tcb.Header.Type", Type);
if (Type != ThreadObject) {
dprintf("TYPE mismatch for thread object at %p\n",RealThreadBase);
return FALSE;
}
return TRUE ;
}
VOID
DumpThreadBlockageInfo (
IN char *Pad,
IN ULONG64 RealThreadBase,
IN ULONG Verbosity
)
{
#define MAX_STACK_FRAMES 40
TIME_FIELDS Times;
LARGE_INTEGER RunTime;
ULONG64 Address;
ULONG Result;
ULONG64 WaitBlock;
ULONG WaitOffset;
ULONG64 Process;
CHAR Buffer[80];
ULONG KeTimeIncrement;
ULONG TimeIncrement;
ULONG frames = 0;
ULONG i;
ULONG displacement;
ULONG64 WaitBlockList;
ULONG IrpOffset;
InitTypeRead(RealThreadBase, nt!_ETHREAD);
if ((ULONG) ReadField(Tcb.State) == Waiting) {
dprintf("%s (%s) %s %s\n",
Pad,
StacksWaitReasonList[(ULONG) ReadField(Tcb.WaitReason)],
((ULONG) ReadField(Tcb.WaitMode)==KernelMode) ? "KernelMode" : "UserMode",(ULONG) ReadField(Tcb.Alertable) ? "Alertable" : "Non-Alertable");
if ( ReadField(Tcb.SuspendCount) ) {
dprintf("SuspendCount %lx\n",(ULONG) ReadField(Tcb.SuspendCount));
}
if ( ReadField(Tcb.FreezeCount) ) {
dprintf("FreezeCount %lx\n",(ULONG) ReadField(Tcb.FreezeCount));
}
WaitBlockList = ReadField(Tcb.WaitBlockList);
if (InitTypeRead(WaitBlockList,nt!KWAIT_BLOCK)) {
dprintf("%sunable to get Wait object\n",Pad);
goto BadWaitBlock;
}
do {
ULONG64 Object, NextWaitBlock, OwnerThread;
ULONG Limit;
dprintf("%s %lx ",Pad, Object = ReadField(Object));
NextWaitBlock = ReadField(NextWaitBlock);
if (InitTypeRead(Object,nt!KMUTANT)) {
dprintf("%sunable to get Wait object\n",Pad);
break;
}
GetFieldValue(Object, "nt!KSEMAPHORE", "Limit", Limit);
GetFieldValue(Object, "nt!KSEMAPHORE", "OwnerThread",OwnerThread);
switch (ReadField(Header.Type)) {
case EventNotificationObject:
dprintf("NotificationEvent\n");
break;
case EventSynchronizationObject:
dprintf("SynchronizationEvent\n");
break;
case SemaphoreObject:
dprintf("Semaphore Limit 0x%p\n",
Limit);
break;
case ThreadObject:
dprintf("Thread\n");
break;
case TimerNotificationObject:
dprintf("NotificationTimer\n");
break;
case TimerSynchronizationObject:
dprintf("SynchronizationTimer\n");
break;
case EventPairObject:
dprintf("EventPair\n");
break;
case ProcessObject:
dprintf("ProcessObject\n");
break;
case MutantObject:
dprintf("Mutant - owning thread %p\n",
OwnerThread);
break;
default:
dprintf("Unknown\n");
break;
}
if (NextWaitBlock == WaitBlockList) {
break;
}
if (InitTypeRead(NextWaitBlock,nt!KWAIT_BLOCK)) {
dprintf("%sunable to get Wait object\n",Pad);
break;
}
} while ( TRUE );
}
BadWaitBlock:
//
// Re-intialize thread read
//
InitTypeRead(RealThreadBase, nt!_ETHREAD);
if ( ReadField(LpcReplyMessageId) != 0) {
dprintf("%sWaiting for reply to LPC MessageId %08x:\n",Pad, (ULONG) ReadField(LpcReplyMessageId));
}
if (Address = ReadField(LpcReplyMessage)) {
ULONG64 Entry_Flink, Entry_Blink;
dprintf("%sPending LPC Reply Message:\n",Pad);
if (GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Blink", Entry_Blink)) {
dprintf("unable to get LPC msg\n");
} else {
GetFieldValue(Address, "nt!_LPCP_MESSAGE", "Entry.Flink", Entry_Flink);
dprintf("%s %08p: [%08p,%08p]\n",
Pad, Address, Entry_Blink, Entry_Flink
);
}
}
GetFieldOffset("nt!_ETHREAD", "IrpList", &IrpOffset);
if (ReadField(IrpList.Flink) != ReadField(IrpList.Blink) ||
ReadField(IrpList.Flink) != RealThreadBase + IrpOffset
) {
ULONG64 IrpListHead = RealThreadBase + IrpOffset;
ULONG64 Next;
ULONG Counter = 0;
ULONG IrpThrdOff;
Next = ReadField(IrpList.Flink);
GetFieldOffset("nt!_IRP", "ThreadListEntry", &IrpThrdOff);
dprintf("%sIRP List:\n",Pad);
while ((Next != IrpListHead) && (Counter < 17)) {
ULONG Irp_Type=0, Irp_Size=0, Irp_Flags=0;
ULONG64 Irp_MdlAddress=0;
Counter += 1;
Address = Next - IrpThrdOff;
GetFieldValue(Address, "nt!_IRP", "Type", Irp_Type);
GetFieldValue(Address, "nt!_IRP", "Size", Irp_Size);
GetFieldValue(Address, "nt!_IRP", "Flags", Irp_Flags);
GetFieldValue(Address, "nt!_IRP", "MdlAddress", Irp_MdlAddress);
GetFieldValue(Address, "nt!_IRP", "ThreadListEntry.Flink", Next);
dprintf("%s %08p: (%04x,%04x) Flags: %08lx Mdl: %08lp\n",
Pad,Address,Irp_Type,Irp_Size,Irp_Flags,Irp_MdlAddress);
}
}
}
VOID
ForEachFrameOnThread(
IN ULONG64 RealThreadBase,
IN PFN_FRAME_WALK_CALLBACK Callback,
IN PVOID Context
)
{
#define MAX_STACK_FRAMES 40
TIME_FIELDS Times;
LARGE_INTEGER RunTime;
ULONG Address;
ULONG Result;
CHAR Buffer[256];
ULONG KeTimeIncrement;
ULONG TimeIncrement;
ULONG frames = 0;
ULONG i;
ULONG64 displacement, tcb_KernelStackResident;
EXTSTACKTRACE64 stk[MAX_STACK_FRAMES];
InitTypeRead(RealThreadBase, nt!_ETHREAD);
tcb_KernelStackResident = ReadField(Tcb.KernelStackResident);
if (!tcb_KernelStackResident) {
if (Callback(STACK_WALK_DUMP_STARTING, RealThreadBase, Context, NULL, 0)) {
Callback(STACK_WALK_DUMP_NOT_RESIDENT, RealThreadBase, Context, NULL, 0);
Callback(STACK_WALK_DUMP_FINISHED, RealThreadBase, Context, NULL, 0);
}
return;
}
SetThreadForOperation64( &RealThreadBase );
frames = StackTrace( 0, 0, 0, stk, MAX_STACK_FRAMES );
if (!Callback(STACK_WALK_DUMP_STARTING, RealThreadBase, Context, NULL, 0)) {
return;
}
for (i=0; i<frames; i++) {
Buffer[0] = '!';
GetSymbol(stk[i].ProgramCounter, Buffer, &displacement);
if (!Callback(
STACK_WALK_DUMP_ENTRY,
RealThreadBase,
Context,
Buffer,
displacement)) {
return;
}
}
Callback(STACK_WALK_DUMP_FINISHED, RealThreadBase, Context, NULL, 0);
}
VOID
AnalyzeThread(
IN ULONG64 RealThreadBase,
IN PBLOCKER_TREE BlockerTree,
IN char * Filter,
OUT PCHAR BlockBuffer,
OUT ULONG64 *BlockerDisplacement,
OUT BOOLEAN *SkipThread
)
{
#define MAX_STACK_FRAMES 40
TIME_FIELDS Times;
LARGE_INTEGER RunTime;
ULONG Address;
ULONG Result;
ULONG WaitOffset;
ULONG KeTimeIncrement;
ULONG TimeIncrement;
ULONG frames = 0;
ULONG i;
ULONG64 displacement, tcb_KernelStackResident;
PBLOCKER_TREE blockerCur ;
EXTSTACKTRACE64 stk[MAX_STACK_FRAMES];
BOOLEAN filterMatch, blockerMatch;
CHAR tempFrame[256], lcFilter[256], lcFrame[256];
InitTypeRead(RealThreadBase, nt!_ETHREAD);
tcb_KernelStackResident = ReadField(Tcb.KernelStackResident);
if (!tcb_KernelStackResident) {
*SkipThread = TRUE;
*BlockerDisplacement = 0;
BlockBuffer[0] = '\0';
return;
}
SetThreadForOperation64( &RealThreadBase );
frames = StackTrace( 0, 0, 0, stk, MAX_STACK_FRAMES );
*SkipThread = FALSE;
BlockBuffer[0] = '!';
if (Filter[0]) {
strcpy(lcFilter, Filter);
_strlwr(lcFilter);
}
if (frames == 0) {
strcpy(BlockBuffer, "?? Kernel stack not resident ??") ;
*SkipThread = TRUE;
} else {
if (ReadField(Tcb.State) == Running) {
GetSymbol(stk[0].ProgramCounter, BlockBuffer, &displacement);
*BlockerDisplacement = displacement;
} else {
blockerMatch = FALSE;
filterMatch = FALSE;
for(i=0; i<frames; i++) {
GetSymbol(stk[i].ProgramCounter, tempFrame, &displacement);
if ((!filterMatch) && Filter[0]) {
strcpy(lcFrame, tempFrame);
_strlwr(lcFrame);
if (strstr(lcFrame, lcFilter)) {
filterMatch = TRUE;
}
}
blockerCur = BlockerTree;
if ((!blockerMatch) &&
(!BlockerTreeWalk(&blockerCur, tempFrame, SKIP_FRAME))) {
blockerMatch = TRUE;
strcpy(BlockBuffer, tempFrame);
*BlockerDisplacement = displacement;
if (filterMatch || (Filter[0]=='\0')) {
break;
}
}
}
blockerCur = BlockerTree;
if (Filter[0]) {
if (!filterMatch) {
*SkipThread = TRUE;
}
} else {
if (BlockerTreeWalk(&blockerCur, BlockBuffer, SKIP_THREAD)) {
*SkipThread = TRUE;
}
}
}
}
}
#define BEGIN_TREE()
#define END_TREE()
#define DECLARE_ENTRY(foo, action) BlockerTreeDeclareEntry(foo, action)
#define BEGIN_LIST() BlockerTreeListBegin()
#define END_LIST() BlockerTreeListEnd()
PBLOCKER_TREE gpCurrentBlocker ;
VOID
BlockerTreeListBegin(
VOID
)
{
//dprintf("Nest for %x\n", gpCurrentBlocker) ;
ASSERT(!gpCurrentBlocker->Nested) ;
gpCurrentBlocker->Nested = TRUE ;
}
VOID
BlockerTreeListEnd(
VOID
)
{
//dprintf("Unnest for %x\n", gpCurrentBlocker) ;
gpCurrentBlocker = gpCurrentBlocker->Parent ;
ASSERT(gpCurrentBlocker->Nested) ;
gpCurrentBlocker->Nested = FALSE ;
}
VOID
BlockerTreeDeclareEntry(
const char *szSymbolic,
STACKS_ACTION StacksAction
)
{
PBLOCKER_TREE blockerEntry ;
blockerEntry = (PBLOCKER_TREE) malloc(sizeof(BLOCKER_TREE)) ;
if (!blockerEntry) {
return ;
}
memset(blockerEntry, 0, sizeof(BLOCKER_TREE)) ;
blockerEntry->Symbolic = szSymbolic ;
blockerEntry->Action = StacksAction;
if (gpCurrentBlocker->Nested) {
ASSERT(!gpCurrentBlocker->Child) ;
//dprintf("Child %x for %x\n", blockerEntry, gpCurrentBlocker) ;
blockerEntry->Parent = gpCurrentBlocker ;
gpCurrentBlocker->Child = blockerEntry ;
} else {
ASSERT(!gpCurrentBlocker->Sibling) ;
//dprintf("sibling %x for %x\n", blockerEntry, gpCurrentBlocker) ;
blockerEntry->Parent = gpCurrentBlocker->Parent ;
gpCurrentBlocker->Sibling = blockerEntry ;
}
gpCurrentBlocker = blockerEntry ;
}
PBLOCKER_TREE
BlockerTreeBuild(
VOID
)
{
BLOCKER_TREE blockerHead ;
memset(&blockerHead, 0, sizeof(BLOCKER_TREE)) ;
gpCurrentBlocker = &blockerHead ;
//
// Generate the list...
//
#include "stacks.h"
//
// And return it.
//
return blockerHead.Sibling ;
}
VOID BlockerTreeFree(
PBLOCKER_TREE BlockerHead
)
{
PBLOCKER_TREE blockerCur, blockerNext ;
for(blockerCur = BlockerHead; blockerCur; blockerCur = blockerNext) {
if (blockerCur->Child) {
BlockerTreeFree(blockerCur->Child) ;
}
blockerNext = blockerCur->Sibling ;
free(blockerCur) ;
}
}
BOOL
BlockerTreeWalk(
IN OUT PBLOCKER_TREE *blockerHead,
IN char *szSymbolic,
IN STACKS_ACTION Action
)
{
PBLOCKER_TREE blockerCur ;
const char *blockString, *curString, *strptr;
char szStringCopy[512];
for(blockerCur = *blockerHead; blockerCur; blockerCur = blockerCur->Sibling) {
if (Action != blockerCur->Action) {
continue;
}
blockString = blockerCur->Symbolic;
curString = szSymbolic;
strptr = strstr(curString, "!.");
if (strptr) {
//
// This must be an ia64 symbol. Replace the !. with a nice simple !
//
strcpy(szStringCopy, curString);
strcpy(szStringCopy + (strptr - curString) + 1, strptr + 2);
curString = szStringCopy;
}
//
// Special case "Our Kernel of Many Names"
//
if (!_strnicmp(blockString, "nt!", 3)) {
if ((!_strnicmp(curString, "ntoskrnl!", 9)) ||
(!_strnicmp(curString, "ntkrnlmp!", 9)) ||
(!_strnicmp(curString, "ntkrpamp!", 9)) ||
(!_strnicmp(curString, "ntkrnlpa!", 9))) {
blockString += 3;
curString += 9;
}
}
if (!_strcmpi(blockString, curString)) {
*blockerHead = blockerCur->Child;
return TRUE;
}
}
return FALSE;
}