Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1709 lines
29 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
dbgrm.c - DbgExtension Structure information specific to RM APIs
Abstract:
Revision History:
Who When What
-------- -------- ----------------------------------------------
josephj 03-01-99 Created
Notes:
--*/
#ifdef TESTPROGRAM
#include "c.h"
#else
#include "precomp.h"
#endif
#include "util.h"
#include "parse.h"
#include "dbgrm.h"
enum
{
typeid_NULL,
typeid_RM_OBJECT_HEADER,
typeid_RM_TASK,
typeid_RM_ASSOCIATIONS,
typeid_RM_GROUP,
typeid_RM_STACK_RECORD,
typeid_RM_OBJECT_LOG,
typeid_RM_OBJECT_TREE
};
//
// STRUCTURES CONCERNING TYPE "OBJECT_HEADER"
//
// Actually handles dumping of object info.
//
void
RmDumpObj(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of task info.
//
void
RmDumpTask(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of task info.
//
void
RmDumpGroup(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of task info.
//
void
RmDumpAssociations(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of task info.
//
void
RmDumpStackRecord(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of object log info.
//
void
RmDumpObjectLog(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Actually handles dumping of object decendents tree
//
void
RmDumpObjectTree(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
);
// Node function for dumping one node of the list of children.
//
ULONG
NodeFunc_DumpObjectTree (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
);
BITFIELD_INFO rgRM_OBJECT_STATE[] =
{
{
"O_ALLOC",
RMOBJSTATE_ALLOCMASK,
RMOBJSTATE_ALLOCATED
},
{
"O_DEALLOC",
RMOBJSTATE_ALLOCMASK,
RMOBJSTATE_DEALLOCATED
},
#if 0 // don't want this -- as it gets displayed for non-task, looking wierd.
{
"T_IDLE",
RMTSKSTATE_MASK,
RMTSKSTATE_IDLE
},
#endif // 0
{
"T_STARTING",
RMTSKSTATE_MASK,
RMTSKSTATE_STARTING
},
{
"T_ACTIVE",
RMTSKSTATE_MASK,
RMTSKSTATE_ACTIVE
},
{
"T_PENDING",
RMTSKSTATE_MASK,
RMTSKSTATE_PENDING
},
{
"T_ENDING",
RMTSKSTATE_MASK,
RMTSKSTATE_ENDING
},
{
"T_DELAYED",
RMTSKDELSTATE_MASK,
RMTSKDELSTATE_DELAYED
},
{
"T_ABORT_DELAY",
RMTSKABORTSTATE_MASK,
RMTSKABORTSTATE_ABORT_DELAY
},
{
NULL
}
};
TYPE_INFO type_RM_OBJECT_HEADER = {
"RM_OBJECT_HEADER",
"obj",
typeid_RM_OBJECT_HEADER,
0, //fTYPEINFO_ISLIST, // Flags
sizeof(RM_OBJECT_HEADER),
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpObj // pfnSpecializedDump
};
TYPE_INFO type_RM_TASK = {
"RM_TASK",
"tsk",
typeid_RM_TASK,
0, //fTYPEINFO_ISLIST, // Flags
sizeof(RM_TASK),
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpTask // pfnSpecializedDump
};
TYPE_INFO type_RM_GROUP = {
"RM_GROUP",
"grp",
typeid_RM_GROUP,
0, //fTYPEINFO_ISLIST, // Flags
sizeof(RM_GROUP),
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpGroup // pfnSpecializedDump
};
TYPE_INFO type_RM_ASSOCIATIONS = {
"RM_ASSOCIATIONS",
"asc",
typeid_RM_ASSOCIATIONS,
0, //fTYPEINFO_ISLIST, // Flags
1, //This is not really an object, but we must have nonzero size.
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpAssociations // pfnSpecializedDump
};
TYPE_INFO type_RM_STACK_RECORD = {
"RM_STACK_RECORD",
"sr",
typeid_RM_STACK_RECORD,
0, //fTYPEINFO_ISLIST, // Flags
sizeof(RM_STACK_RECORD),
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpStackRecord // pfnSpecializedDump
};
TYPE_INFO type_RM_OBJECT_LOG = {
"RM_OBJECT_LOG",
"log",
//typeid_RM_STACK_RECORD,
typeid_RM_OBJECT_LOG,
0, //fTYPEINFO_ISLIST, // Flags
1, //This is not really an object, but we must have nonzero size.
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpObjectLog // pfnSpecializedDump
};
TYPE_INFO type_RM_OBJECT_TREE = {
"RM_OBJECT_TREE",
"tree",
typeid_RM_OBJECT_TREE,
0, //fTYPEINFO_ISLIST, // Flags
1, //This is not really an object, but we must have nonzero size.
NULL, // FIELD_INFO
0, // offset to next object.
NULL, // rgBitFieldInfo
RmDumpObjectTree // pfnSpecializedDump
};
TYPE_INFO *g_rgRM_Types[] =
{
&type_RM_OBJECT_HEADER,
&type_RM_TASK,
&type_RM_GROUP,
&type_RM_ASSOCIATIONS,
&type_RM_STACK_RECORD,
&type_RM_OBJECT_LOG,
&type_RM_OBJECT_TREE,
NULL
};
UINT_PTR
RM_ResolveAddress(
TYPE_INFO *pType
);
NAMESPACE RM_NameSpace = {
g_rgRM_Types,
NULL, // g_rgRM_Globals,
RM_ResolveAddress
};
UINT_PTR
RM_ResolveAddress(
TYPE_INFO *pType
)
{
return 0;
}
void
do_rm(PCSTR args)
{
DBGCOMMAND *pCmd = Parse(args, &RM_NameSpace);
if (pCmd)
{
DumpCommand(pCmd);
DoCommand(pCmd, NULL);
FreeCommand(pCmd);
pCmd = NULL;
}
return;
}
void
do_help(PCSTR args)
{
return;
}
void
dump_object_fields(UINT_PTR uAddr, PRM_OBJECT_HEADER pObj);
// Actually handles dumping of object info.
//
void
RmDumpObj(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
/*++
!rm obj 0x838c7560
Object 0x838c7560 (LocalIP)
Hdr
Sig :A13L State:0xc4db69b3 Refs:990
pLock: 0x838c7560 pSIinfo:0xfdd0a965 pDInfo :0xd54d947c
pParent: 0x2995941a pRoot:0x060af4a8 pHLink :0xce4294fe
HdrSize: 0x123 Assoc:909
--*/
{
RM_OBJECT_HEADER Obj;
bool fRet;
do
{
char rgDescriptionBuf[256];
// First let's read the pObj structure.
//
fRet = dbgextReadMemory(
uAddr,
&Obj,
sizeof(Obj),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Obj.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
MyDbgPrintf("\nObject 0x%p (%s)\n", uAddr, rgDescriptionBuf);
dump_object_fields(uAddr, &Obj);
} while(FALSE);
}
// Actually handles dumping of task info.
//
void
RmDumpTask(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
{
RM_TASK Task;
bool fRet;
do
{
char rgDescriptionBuf[256];
// First let's read the pObj structure.
//
fRet = dbgextReadMemory(
uAddr,
&Task,
sizeof(Task),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Task.Hdr.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Task.Hdr.szDescription"
);
if (!fRet) break;
// Dump the object header
//
{
MyDbgPrintf("\nTask 0x%p (%s)\n", uAddr, rgDescriptionBuf);
dump_object_fields(uAddr, &Task.Hdr);
}
//
// Now Dump the task-specific fields...
//
{
/*
TskHdr
pfn: 0x5399424c State:0x812d7211(IDLE) SCtxt:0x050eefc4
pBlkTsk:0x377c74bc lnkFellows:0x2b88126f
Pending Tasks
0x84215fa5 0xb51f9e9e 0x9e954e81 0x696095b9
0x0c07aeff
*/
MyDbgPrintf(
" TaskHdr:\n"
" pfn:0x%p SCtxt:0x%08lx\n",
Task.pfnHandler,
Task.SuspendContext
);
MyDbgPrintf(
" pBlkTsk:0x%p lnkFellows:0x%p\n",
Task.pTaskIAmPendingOn,
&(((PRM_TASK) uAddr)->linkFellowPendingTasks)
);
// Note we can't use IsListEmpty because of the different address space.
//
if (Task.listTasksPendingOnMe.Flink == Task.listTasksPendingOnMe.Blink)
{
MyDbgPrintf(" No pending tasks.\n");
}
else
{
MyDbgPrintf(" Pending tasks:\n");
dbgextDumpDLlist(
(UINT_PTR) &(((PRM_TASK) uAddr)->listTasksPendingOnMe),
FIELD_OFFSET(RM_TASK, linkFellowPendingTasks),
"Pending tasks list"
);
}
}
} while(FALSE);
}
void
dbg_walk_rm_hash_table(
PRM_HASH_TABLE pTable,
UINT uContainingOffset,
char *szDescription
);
#if RM_EXTRA_CHECKING
void
dbg_print_rm_associations(
PRM_HASH_TABLE pRmAssociationHashTable,
UINT MaxToPrint
);
void
dbg_print_object_log_entries(
UINT_PTR uObjectListOffset,
UINT MaxToPrint
);
#endif // RM_EXTRA_CHECKING
// Actually handles dumping of task info.
//
void
RmDumpGroup(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
/*
!rm grp 0x838c7560
Group 0x4d650b98 (LocalIP Group) of object 0x11eafd78 (Interface)
Num:11 State:ENABLED pSInfo: 0x944b6d1b pULTsk: 0x8c312bca
Members:
0x8db3267c 0xa639f663 0x8f3530a6 0xa4bfe0b9
0x995dd9bf 0x61e1344b 0xd6323f50 0x606339fd
0x2e8ed2a4 0x62e52f27 0xa82b59ab
*/
{
RM_GROUP Group;
bool fRet;
do
{
char rgDescriptionBuf[256];
char rgOwningObjectDescriptionBuf[256];
// First let's read the Group structure.
//
fRet = dbgextReadMemory(
uAddr,
&Group,
sizeof(Group),
"RM_GROUP"
);
if (!fRet) break;
// Try to read the group's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Group.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
// Try to read the owning object's description.
//
do {
UINT_PTR uAddress;
fRet = dbgextReadUINT_PTR(
(UINT_PTR) &(Group.pOwningObject->szDescription),
&uAddress,
"Owning Obj.szDescription ptr"
);
if (!fRet) break;
fRet = dbgextReadSZ(
uAddress,
rgOwningObjectDescriptionBuf,
sizeof(rgOwningObjectDescriptionBuf),
"Owning Obj.szDescription"
);
} while (FALSE);
if (!fRet)
{
*rgOwningObjectDescriptionBuf = 0;
}
MyDbgPrintf(
"\nGroup 0x%p (%s) of object 0x%p (%s)\n",
uAddr,
rgDescriptionBuf,
Group.pOwningObject,
rgOwningObjectDescriptionBuf
);
MyDbgPrintf(
" Num:0x%08x State:%s pSInfo:0x%08x\n",
Group.HashTable.NumItems,
(Group.fEnabled) ? "ENABLED " : "DISABLED",
Group.pStaticInfo
);
MyDbgPrintf(
" pULTsk:0x%08x\n",
Group.pUnloadTask
);
if (Group.HashTable.NumItems==0)
{
MyDbgPrintf(" No members.\n");
}
else
{
MyDbgPrintf(" Members:\n");
dbg_walk_rm_hash_table(
&Group.HashTable,
FIELD_OFFSET(RM_OBJECT_HEADER, HashLink),
"Group members"
);
}
} while(FALSE);
}
// Actually handles dumping of task info.
//
void
RmDumpAssociations(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
{
/*
!rm asc 0x9ba265f8
Associations for object 0x838c7560 (LocalIP):
Child of 0x010091A0 (Globals)
Parent of 0x00073558 (Task2)
Parent of 0x00073920 (Task3a)
Parent of 0x000739F8 (Task3b)
*/
RM_OBJECT_HEADER Obj;
bool fRet;
UINT uNumAssociations = -1;
do
{
char rgDescriptionBuf[256];
// First let's read the pObj structure.
//
fRet = dbgextReadMemory(
uAddr,
&Obj,
sizeof(Obj),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Obj.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
// Try to get the number of associations field in the diag info struct.
//
if (Obj.pDiagInfo != NULL)
{
bool fRet;
UINT_PTR uNumItemsOffset =
(UINT_PTR) &(Obj.pDiagInfo->AssociationTable.NumItems);
fRet = dbgextReadUINT(
uNumItemsOffset,
&uNumAssociations,
"pDiagInfo->AssociationTable.NumItems"
);
if (!fRet)
{
uNumAssociations = (UINT) -1;
}
}
if (uNumAssociations == 0)
{
MyDbgPrintf(
"\nObject 0x%p (%s) has no associations.\n",
uAddr,
rgDescriptionBuf
);
}
else if (uNumAssociations == (UINT)-1)
{
MyDbgPrintf(
"\nObject 0x%p (%s) associations are not available.\n",
uAddr,
rgDescriptionBuf
);
}
else
{
#if RM_EXTRA_CHECKING
// Get the association hash table table.
//
RM_HASH_TABLE AssociationTable;
MyDbgPrintf(
"\nAssociations (50 max) for 0x%p (%s):\n",
uAddr,
rgDescriptionBuf
);
fRet = dbgextReadMemory(
(UINT_PTR) &(Obj.pDiagInfo->AssociationTable),
&AssociationTable,
sizeof(AssociationTable),
"Association Table"
);
if (!fRet) break;
dbg_print_rm_associations(
&AssociationTable,
50
);
#endif // RM_EXTRA_CHECKING
}
} while(FALSE);
}
// Actually handles dumping of task info.
//
void
RmDumpStackRecord(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
{
/*
!rm sr 0x838c7560
Stack Record 0x838c7560
TmpRefs: 2
HeldLocks:
0xe916a45f 0x23d8d2d3 0x5f47a2f2
*/
RM_STACK_RECORD sr;
bool fRet;
do
{
// First let's read the RM_STACK_RECORD structure.
//
fRet = dbgextReadMemory(
uAddr,
&sr,
sizeof(sr),
"RM_STACK_RECORD"
);
if (!fRet) break;
MyDbgPrintf( "\nStack Record 0x%p\n", uAddr);
MyDbgPrintf(
" TmpRefs:0x%08x LockLevel:0x%08lx pFirst:0x%08lx NumHeld=%lu\n",
sr.TmpRefs,
sr.LockInfo.CurrentLevel,
sr.LockInfo.pFirst,
sr.LockInfo.pNextFree-sr.LockInfo.pFirst
);
// Display held locks.
//
if (sr.LockInfo.CurrentLevel==0)
{
MyDbgPrintf(" No held locks.\n");
}
else
{
// MyDbgPrintf(" Held locks:<unimplemented>\n");
}
} while(FALSE);
}
// Actually handles dumping of the object log
//
void
RmDumpObjectLog(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
{
/*
!rm log 0x9ba265f8
Log for object 0x838c7560 (LocalIP):
Added association X
Deleted association Y
...
*/
RM_OBJECT_HEADER Obj;
bool fRet;
UINT uNumEntries = 0;
do
{
char rgDescriptionBuf[256];
// First let's read the pObj structure.
//
fRet = dbgextReadMemory(
uAddr,
&Obj,
sizeof(Obj),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Obj.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
// Try to get the number of log entries field in the diag info struct.
//
if (Obj.pDiagInfo != NULL)
{
bool fRet;
UINT_PTR uNumItemsOffset =
(UINT_PTR) &(Obj.pDiagInfo->NumObjectLogEntries);
fRet = dbgextReadUINT(
uNumItemsOffset,
&uNumEntries,
"pDiagInfo->NumObjectLogEntries"
);
if (!fRet)
{
uNumEntries = (UINT) -1;
}
}
if (uNumEntries == 0)
{
MyDbgPrintf(
"\nObject 0x%p (%s) has no log entries.\n",
uAddr,
rgDescriptionBuf
);
}
else if (uNumEntries == (UINT)-1)
{
MyDbgPrintf(
"\nObject 0x%p (%s) log entries are not available.\n",
uAddr,
rgDescriptionBuf
);
}
else
{
#if RM_EXTRA_CHECKING
UINT uNumToDump = uNumEntries;
if (uNumToDump > 50)
{
uNumToDump = 50;
}
MyDbgPrintf(
"\nLog entries for 0x%p (%s) (%lu of %lu):\n",
uAddr,
rgDescriptionBuf,
uNumToDump,
uNumEntries
);
dbg_print_object_log_entries(
(UINT_PTR) &(Obj.pDiagInfo->listObjectLog),
uNumToDump
);
#endif // RM_EXTRA_CHECKING
}
} while(FALSE);
}
// Actually handles dumping of the object tree
//
void
RmDumpObjectTree(
struct _TYPE_INFO *pType,
UINT_PTR uAddr,
char *szFieldSpec,
UINT uFlags
)
{
/*
!rm tree 0x9ba265f8
Tree for object 0x838c7560 (LocalIP) (Parent 0x82222222)
Display sample:
0x2222222(RemoteIp)
|---0x22222222(Dest)
|---|---0x22222222(Dest)
|---|---|---0x22222222(Dest)
|---|---0x22222222(pTask)
|---0x11111111(RemoteIp)
*/
RM_OBJECT_HEADER Obj;
RM_OBJECT_HEADER ParentObj;
bool fRet;
UINT uNumEntries = 0;
do
{
char rgDescriptionBuf[256];
char rgParentDescriptionBuf[256];
// First let's read the pObj structure.
//
fRet = dbgextReadMemory(
uAddr,
&Obj,
sizeof(Obj),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Obj.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
// Try to read the parent's object.
//
if (Obj.pParentObject!=NULL && (UINT_PTR) Obj.pParentObject != uAddr)
{
fRet = dbgextReadMemory(
(UINT_PTR) Obj.pParentObject,
&ParentObj,
sizeof(ParentObj),
"RM_OBJECT_HEADER"
);
if (!fRet) break;
// Try to get pParent's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) ParentObj.szDescription,
rgParentDescriptionBuf,
sizeof(rgParentDescriptionBuf),
"ParentObj.szDescription"
);
if (!fRet) break;
}
else
{
strcpy(rgParentDescriptionBuf, "<root>");
}
MyDbgPrintf(
"\nObject Tree for 0x%p(%s) with parent 0x%p(%s):\n",
uAddr,
rgDescriptionBuf,
Obj.pParentObject,
rgParentDescriptionBuf
);
NodeFunc_DumpObjectTree(
(UINT_PTR) &(((PRM_OBJECT_HEADER)uAddr)->linkSiblings),
0, // Index (unused)
(void *)0 // pvContext == level
);
} while(FALSE);
}
void
dump_object_fields(UINT_PTR uAddr, PRM_OBJECT_HEADER pObj)
{
UINT uNumAssociations = (UINT) -1;
// Try to get the number of associations field in the diag info struct.
//
if (pObj->pDiagInfo != NULL)
{
bool fRet;
UINT_PTR uNumItemsOffset =
(UINT_PTR) &(pObj->pDiagInfo->AssociationTable.NumItems);
fRet = dbgextReadUINT(
uNumItemsOffset,
&uNumAssociations,
"pDiagInfo->AssociationTable.NumItems"
);
if (!fRet)
{
uNumAssociations = (UINT) -1;
}
}
MyDbgPrintf(
" Hdr:\n"
" Sig:0x%08x State:0x%08x Refs:0x%08x\n",
pObj->Sig,
pObj->State,
pObj->TotRefs
);
MyDbgPrintf(
" pLock:0x%p pSInfo:0x%p pDInfo:0x%p\n",
pObj->pLock,
pObj->pStaticInfo,
pObj->pDiagInfo
);
MyDbgPrintf(
" pParent:0x%p pRoot:0x%p pHLink:0x%p\n",
pObj->pParentObject,
pObj->pRootObject,
&(((PRM_OBJECT_HEADER) uAddr)->HashLink)
);
MyDbgPrintf(
" HdrSize:0x%08lx Assoc:%d\n",
sizeof(*pObj),
uNumAssociations
);
MyDbgPrintf( " RmState: ");
DumpBitFields(
pObj->RmState,
rgRM_OBJECT_STATE
);
MyDbgPrintf( "\n");
}
void
dbg_walk_rm_hash_table(
PRM_HASH_TABLE pRmHashTable,
UINT uContainingOffset,
char *szDescription
)
{
// For now, we get the whole hash table array in one fell swoop...
//
PRM_HASH_LINK rgTable[512];
UINT TableLength = pRmHashTable->TableLength;
bool fRet;
do
{
// Sanity check.
//
if (TableLength > sizeof(rgTable)/sizeof(*rgTable))
{
MyDbgPrintf(
" HashTable length %lu too large\n",
TableLength
);
break;
}
// Read the whole hash table.
//
fRet = dbgextReadMemory(
(UINT_PTR) pRmHashTable->pTable,
rgTable,
TableLength * sizeof(*rgTable),
"Hash Table"
);
if (!fRet) break;
// Now go through the table visiting each list...
//
{
PRM_HASH_LINK *ppLink, *ppLinkEnd;
UINT uCount = 0;
UINT uMax = 15;
ppLink = rgTable;
ppLinkEnd = ppLink + TableLength;
for ( ; ppLink < ppLinkEnd; ppLink++)
{
PRM_HASH_LINK pLink = *ppLink;
for (;pLink != NULL; uCount++)
{
char *szPrefix;
char *szSuffix;
RM_HASH_LINK Link;
szPrefix = " ";
szSuffix = "";
if (uCount%4)
{
szPrefix = " ";
if ((uCount%4)==3)
{
szSuffix = "\n";
}
}
if (uCount >= uMax) break;
MyDbgPrintf(
"%s0x%p%s",
szPrefix,
((char *) pLink) - uContainingOffset,
szSuffix
);
// Let's try to read this link.
//
fRet = dbgextReadMemory(
(UINT_PTR) pLink,
&Link,
sizeof(Link),
"Hash Link"
);
if (!fRet) break;
pLink = Link.pNext;
}
if (!fRet || (uCount >= uMax)) break;
}
{
MyDbgPrintf("\n");
}
if (uCount < pRmHashTable->NumItems)
{
MyDbgPrintf(" ...\n");
}
}
} while (FALSE);
}
#if RM_EXTRA_CHECKING
void
dbg_dump_one_association(
RM_PRIVATE_DBG_ASSOCIATION *pAssoc
);
void
dbg_print_rm_associations(
PRM_HASH_TABLE pRmAssociationHashTable,
UINT MaxToPrint
)
{
// For now, we get the whole hash table array in one fell swoop...
//
PRM_HASH_LINK rgTable[512];
UINT TableLength = pRmAssociationHashTable->TableLength;
bool fRet;
do
{
// Sanity check.
//
if (TableLength > sizeof(rgTable)/sizeof(*rgTable))
{
MyDbgPrintf(
" HashTable length %lu too large\n",
TableLength
);
break;
}
// Read the whole hash table.
//
fRet = dbgextReadMemory(
(UINT_PTR) pRmAssociationHashTable->pTable,
rgTable,
TableLength * sizeof(*rgTable),
"Hash Table"
);
if (!fRet) break;
// Now go through the table visiting each list...
//
{
PRM_HASH_LINK *ppLink, *ppLinkEnd;
UINT uCount = 0;
UINT uMax = MaxToPrint;
ppLink = rgTable;
ppLinkEnd = ppLink + TableLength;
for ( ; ppLink < ppLinkEnd; ppLink++)
{
PRM_HASH_LINK pLink = *ppLink;
for (;pLink != NULL; uCount++)
{
RM_PRIVATE_DBG_ASSOCIATION Assoc;
UINT_PTR uAssocOffset =
(UINT_PTR) CONTAINING_RECORD(
pLink,
RM_PRIVATE_DBG_ASSOCIATION,
HashLink
);
if (uCount >= uMax) break;
// Let's try to read this association...
//
fRet = dbgextReadMemory(
uAssocOffset,
&Assoc,
sizeof(Assoc),
"Association"
);
if (!fRet) break;
dbg_dump_one_association(&Assoc);
pLink = Assoc.HashLink.pNext;
}
if (!fRet || (uCount >= uMax)) break;
}
if (uCount < pRmAssociationHashTable->NumItems)
{
MyDbgPrintf(" ...\n");
}
}
} while (FALSE);
}
void
dbg_dump_one_association(
RM_PRIVATE_DBG_ASSOCIATION *pAssoc
)
/*++
Dump the information on the specific association.
pAssoc is valid memory, however anything it points to is not in
our address space.
Since the association contains a format string, which may have
"%s"s in it, we need scan this format string and read any strings
referenced.
All this effort is well worth it. Check out the sample output!
Associations for 0x01023A40 (Globals):
Owns group 0x01023AC4 (O1 Group)
Parent of 0x00073240 (O2)
Parent of 0x00073488 (O2)
Associations for 0x000736D0 (Task3a):
Child of 0x00073240 (O2)
Pending on 0x000732C8 (TaskO2)
--*/
{
char rgFormatString[256];
char rgStrings[3][256];
char *szFormatString;
ULONG_PTR Args[3];
char *szDefaultFormatString = "\tAssociation (E1=0x%x, E2=0x%x, T=0x%x)\n";
bool fRet = FALSE;
do
{
// Try to read the format string.
//
{
fRet = dbgextReadSZ(
(UINT_PTR) pAssoc->szFormatString,
rgFormatString,
sizeof(rgFormatString),
"Association format"
);
if (fRet)
{
szFormatString = rgFormatString;
}
else
{
break;
}
}
// Now run through the format string, looking for "%s"s.
// and munging as required.
//
{
char *pc = rgFormatString;
UINT uCount=0;
Args[0] = pAssoc->Entity1;
Args[1] = pAssoc->Entity2;
Args[2] = pAssoc->AssociationID;
while (uCount<3 && pc[0]!=0 && pc[1]!=0)
{
if (pc[0]=='%')
{
if (pc[1]=='s')
{
// pc[1]='p';
fRet = dbgextReadSZ(
(UINT_PTR) Args[uCount],
rgStrings[uCount],
sizeof(rgStrings[uCount]),
"Association format"
);
if (fRet)
{
Args[uCount] = (ULONG_PTR) rgStrings[uCount];
}
else
{
break;
}
}
pc++; // we want to end up skipping past both chars.
uCount++;
}
pc++;
}
}
}
while (FALSE);
if (!fRet)
{
// Back off to the defaults..
//
szFormatString = szDefaultFormatString;
Args[0] = pAssoc->Entity1;
Args[1] = pAssoc->Entity2;
Args[2] = pAssoc->AssociationID;
}
MyDbgPrintf(
szFormatString,
Args[0],
Args[1],
Args[2]
);
}
ULONG
NodeFunc_DumpObjectLogFromObjectLink (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
)
{
RM_DBG_LOG_ENTRY LE;
LIST_ENTRY *pLink = (LIST_ENTRY*) uNodeAddr;
UINT_PTR uLEOffset = (UINT_PTR) CONTAINING_RECORD(
pLink,
RM_DBG_LOG_ENTRY,
linkObjectLog
);
char rgPrefixString[256];
char rgFormatString[256];
char rgStrings[4][256];
char *szPrefixString;
char *szFormatString;
ULONG_PTR Args[4];
char *szDefaultFormatString =
"Log Entry (P1=%p, P2=%p, P3=%p, P4=%p, szFmt=%p)\n";
bool fRet = FALSE;
// Read the containing record.
//
fRet = dbgextReadMemory(
uLEOffset,
&LE,
sizeof(LE),
"Log Entry"
);
if (!fRet) return 0; // EARLY RETURN;
#if 0
if (LE.pfnDumpEntry != NULL)
{
//
// TODO we need to get the corresponding function to dump this
// specialized entry.
//
MyDbgPrintf(
"Specialized (pfn=%p szFmt=%p, P1=%p, P2=%p, P3=%p, P4=%p)\n",
LE.pfnDumpEntry,
LE.szFormatString,
LE.Param1,
LE.Param2,
LE.Param3,
LE.Param4
);
return 0; // EARLY RETURN
}
#else
//
// Above check is invalid, because in all cases there is a pfnDump function.
//
#endif
//
// TODO -- following code is very similar to the dump-association code --
// move common stuff to some utility function.
//
do
{
// Try to read the prefix string.
//
{
fRet = FALSE;
if (LE.szPrefix != NULL)
{
fRet = dbgextReadSZ(
(UINT_PTR) LE.szPrefix,
rgPrefixString,
sizeof(rgPrefixString),
"Prefix String"
);
}
if (fRet)
{
szPrefixString = rgPrefixString;
}
else
{
szPrefixString = "";
}
}
// Try to read the format string.
//
{
fRet = dbgextReadSZ(
(UINT_PTR) LE.szFormatString,
rgFormatString,
sizeof(rgFormatString),
"Log entry format"
);
if (fRet)
{
szFormatString = rgFormatString;
}
else
{
break;
}
}
// Now run through the format string, looking for "%s"s.
// and munging as required.
//
{
char *pc = rgFormatString;
UINT uCount=0;
Args[0] = LE.Param1;
Args[1] = LE.Param2;
Args[2] = LE.Param3;
Args[3] = LE.Param4;
while (uCount<4 && pc[0]!=0 && pc[1]!=0)
{
if (pc[0]=='%')
{
if (pc[1]=='s')
{
// pc[1]='p';
fRet = dbgextReadSZ(
(UINT_PTR) Args[uCount],
rgStrings[uCount],
sizeof(rgStrings[uCount]),
"Log entry param"
);
if (fRet)
{
Args[uCount] = (ULONG_PTR) rgStrings[uCount];
}
else
{
break;
}
}
pc++; // we want to end up skipping past both chars.
uCount++;
}
pc++;
}
}
} while (FALSE);
if (!fRet)
{
// Back off to the defaults..
//
szPrefixString = "";
szFormatString = szDefaultFormatString;
Args[0] = LE.Param1;
Args[1] = LE.Param2;
Args[2] = LE.Param3;
Args[3] = LE.Param4;
}
MyDbgPrintf(szPrefixString);
MyDbgPrintf(
szFormatString,
Args[0],
Args[1],
Args[2],
Args[3],
LE.szFormatString
);
return 0;
}
void
dbg_print_object_log_entries(
UINT_PTR uObjectListOffset,
UINT MaxToPrint
)
{
WalkDLlist(
uObjectListOffset,
0, //uOffsetStartLink
NULL, // pvContext
NodeFunc_DumpObjectLogFromObjectLink,
MaxToPrint,
"Object log"
);
}
#endif // RM_EXTRA_CHECKING
char szDumpTreePrefix[] = "|---|---|---|---|---|---|---|---|---|---"
"|---|---|---|---|---|---|---|---|---|---";
ULONG
NodeFunc_DumpObjectTree (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
)
{
bool fRet = FALSE;
do
{
char rgDescriptionBuf[256];
LIST_ENTRY *pLink = (LIST_ENTRY*) uNodeAddr;
UINT_PTR uObjOffset = (UINT_PTR) CONTAINING_RECORD(
pLink,
RM_OBJECT_HEADER,
linkSiblings
);
UINT Level = (UINT) (UINT_PTR) pvContext; // we put the level in the context.
RM_OBJECT_HEADER Obj;
char *szPrefix;
// First make szPrefix point to the end (trailing zero) of the prefix string.
//
szPrefix = szDumpTreePrefix + sizeof(szDumpTreePrefix)-1;
// Now back up "Level" times.
//
if (Level < ((sizeof(szDumpTreePrefix)-1)/4))
{
szPrefix -= Level*4;
}
else
{
// Level is too large -- don't display anything.
//
MyDbgPrintf("Dump Tree depth(%d) is too large.\n", Level);
break;
}
// Read the containing record.
//
fRet = dbgextReadMemory(
uObjOffset,
&Obj,
sizeof(Obj),
"Object"
);
if (!fRet) break;
// Try to read the object's description.
//
fRet = dbgextReadSZ(
(UINT_PTR) Obj.szDescription,
rgDescriptionBuf,
sizeof(rgDescriptionBuf),
"Obj.szDescription"
);
if (!fRet) break;
// Display the object info.
//
MyDbgPrintf(
"%s%p(%s)\n",
szPrefix,
uObjOffset,
rgDescriptionBuf
);
//
// Now walk the list of children, displaying each of them.
//
WalkDLlist(
(UINT_PTR) &(((PRM_OBJECT_HEADER)uObjOffset)->listChildren),
0, //uOffsetStartLink
(void*) (Level+1), // pvContext
NodeFunc_DumpObjectTree,
50, // Max children per node to dump
"Object children"
);
} while (FALSE);
return 0;
}