[NTOSKRNL]

Implement Kdbg CLI callbacks. These callbacks can be registered from external modules and allow to process kdbg commands.

[WIN32K]
Implement kdbg callbacks for gdi: "gdi!dumpht <type>" dumps the handle table, "gdi!handle <x>" dumps information about a handle.

CORE-6650 #resolve

svn path=/trunk/; revision=57454
This commit is contained in:
Timo Kreuzer
2012-10-01 23:06:32 +00:00
parent af303e57f0
commit 3ab700cd66
9 changed files with 398 additions and 5 deletions
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#if 0
VOID
FORCEINLINE
KdRosDumpAllThreads(VOID)
{
KdSystemDebugControl(' soR', (PVOID)DumpAllThreads, 0, 0, 0, 0, 0);
}
VOID
FORCEINLINE
KdRosDumpUserThreads(VOID)
{
KdSystemDebugControl(' soR', (PVOID)DumpUserThreads, 0, 0, 0, 0, 0);
}
VOID
FORCEINLINE
KdRosDumpArmPfnDatabase(VOID)
{
KdSystemDebugControl(' soR', (PVOID)KdSpare3, 0, 0, 0, 0, 0);
}
#endif
VOID
FORCEINLINE
KdRosSetDebugCallback(
ULONG Id,
PVOID Callback)
{
KdSystemDebugControl('CsoR', Callback, Id, 0, 0, 0, 0);
}
VOID
FORCEINLINE
KdRosDumpStackFrames(
ULONG Count,
PULONG_PTR Backtrace)
{
KdSystemDebugControl('DsoR', Backtrace, Count, 0, 0, 0, 0);
}
#if KDBG
VOID
FORCEINLINE
KdRosRegisterCliCallback(
PVOID Callback)
{
KdSystemDebugControl('RbdK', Callback, FALSE, 0, 0, 0, 0);
}
VOID
FORCEINLINE
KdRosDeregisterCliCallback(
PVOID Callback)
{
KdSystemDebugControl('RbdK', Callback, TRUE, 0, 0, 0, 0);
}
#endif
+15
View File
@@ -68,6 +68,21 @@ KdPortPutByteEx(
#if defined(KDBG) || DBG
#if KDBG
typedef
BOOLEAN
(NTAPI *PKDBG_CLI_ROUTINE)(
IN PCHAR Command,
IN ULONG Argc,
IN PCH Argv[]);
BOOLEAN
NTAPI
KdbRegisterCliCallback(
PVOID Callback,
BOOLEAN Deregister);
#endif
VOID
KdbSymProcessSymbols(
IN PLDR_DATA_TABLE_ENTRY LdrEntry);
+9 -1
View File
@@ -97,7 +97,15 @@ KdpServiceDispatcher(ULONG Service,
KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length);
break;
}
#endif
#if KDBG
/* Register KDBG CLI callback */
case 'RbdK':
{
Result = KdbRegisterCliCallback(Buffer1, Buffer1Length);
}
#endif /* KDBG */
#endif /* DBG */
default:
HalDisplayString ("Invalid debug service call!\n");
break;
+84
View File
@@ -96,6 +96,7 @@ static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]);
/* GLOBALS *******************************************************************/
static PKDBG_CLI_ROUTINE KdbCliCallbacks[10];
static BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */
static BOOLEAN KdbBreakOnModuleLoad = FALSE; /* Set to TRUE to break into KDB when a module is loaded */
@@ -3266,6 +3267,82 @@ KdbpReadCommand(
}
}
BOOLEAN
NTAPI
KdbRegisterCliCallback(
PVOID Callback,
BOOLEAN Deregister)
{
ULONG i;
/* Loop all entries */
for (i = 0; i < _countof(KdbCliCallbacks); i++)
{
/* Check if deregistering was requested */
if (Deregister)
{
/* Check if this entry is the one that was registered */
if (KdbCliCallbacks[i] == Callback)
{
/* Delete it and report success */
KdbCliCallbacks[i] = NULL;
return TRUE;
}
}
else
{
/* Check if this entry is free */
if (KdbCliCallbacks[i] == NULL)
{
/* Set it and and report success */
KdbCliCallbacks[i] = Callback;
return TRUE;
}
}
}
/* Unsuccessful */
return FALSE;
}
/*! \brief Invokes registered CLI callbacks until one of them handled the
* Command.
*
* \param Command - Command line to parse and execute if possible.
* \param Argc - Number of arguments in Argv
* \param Argv - Array of strings, each of them containing one argument.
*
* \return TRUE, if the command was handled, FALSE if it was not handled.
*/
static
BOOLEAN
KdbpInvokeCliCallbacks(
IN PCHAR Command,
IN ULONG Argc,
IN PCH Argv[])
{
ULONG i;
/* Loop all entries */
for (i = 0; i < _countof(KdbCliCallbacks); i++)
{
/* Check if this entry is registered */
if (KdbCliCallbacks[i])
{
/* Invoke the callback and check if it handled the command */
if (KdbCliCallbacks[i](Command, Argc, Argv))
{
return TRUE;
}
}
}
/* None of the callbacks handled the command */
return FALSE;
}
/*!\brief Parses command line and executes command if found
*
* \param Command Command line to parse and execute if possible.
@@ -3280,6 +3357,7 @@ KdbpDoCommand(
ULONG i;
PCHAR p;
ULONG Argc;
// FIXME: for what do we need a 1024 characters command line and 256 tokens?
static PCH Argv[256];
static CHAR OrigCommand[1024];
@@ -3320,6 +3398,12 @@ KdbpDoCommand(
}
}
/* Now invoke the registered callbacks */
if (KdbpInvokeCliCallbacks(Command, Argc, Argv))
{
return TRUE;
}
KdbpPrint("Command '%s' is unknown.\n", OrigCommand);
return TRUE;
}
+32 -2
View File
@@ -118,7 +118,7 @@ CompareBacktraces(ULONG idx1, ULONG idx2)
VOID
NTAPI
DbgDumpGdiHandleTable(void)
DbgDumpGdiHandleTableWithBT(void)
{
static int leak_reported = 0;
int i, j, idx, nTraces = 0;
@@ -729,6 +729,36 @@ BOOL DbgInitDebugChannels()
return ret;
}
#endif
#if KDBG
BOOLEAN
NTAPI
DbgGdiKdbgCliCallback(
IN PCHAR pszCommand,
IN ULONG argc,
IN PCH argv[])
{
if (stricmp(argv[0], "gdi!dumpht") == 0)
{
DbgDumpGdiHandleTable(argc - 1, argv + 1);
}
else if (stricmp(argv[0], "gdi!handle") == 0)
{
DbgDumpHandleInfo(argv[1]);
}
else
{
/* Not handled */
return FALSE;
}
return TRUE;
}
#endif // KDBG
#endif // DBG
/* EOF */
+10 -1
View File
@@ -28,6 +28,15 @@ typedef struct _LOGENTRY
} data;
} LOGENTRY, *PLOGENTRY;
#if KDBG
BOOLEAN
NTAPI
DbgGdiKdbgCliCallback(
IN PCHAR Command,
IN ULONG Argc,
IN PCH Argv[]);
#endif
#if DBG_ENABLE_EVENT_LOGGING
VOID NTAPI DbgDumpEventList(PSLIST_HEADER pslh);
VOID NTAPI DbgLogEvent(PSLIST_HEADER pslh, LOG_EVENT_TYPE nEventType, LPARAM lParam);
@@ -44,7 +53,7 @@ VOID NTAPI DbgCleanupEventList(PSLIST_HEADER pslh);
#endif
VOID NTAPI DbgDumpGdiHandleTable(VOID);
VOID NTAPI DbgDumpGdiHandleTableWithBT(VOID);
ULONG NTAPI DbgCaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture);
BOOL NTAPI DbgGdiHTIntegrityCheck(VOID);
VOID NTAPI DbgDumpLockedGdiHandles(VOID);
+166
View File
@@ -1341,4 +1341,170 @@ GDI_CleanupForProcess(struct _EPROCESS *Process)
return TRUE;
}
#if DBG && KDBG
static const char * gpszObjectTypes[] =
{
"FREE", "DC", "UNUSED1", "UNUSED2", "RGN", "SURF", "CLIENTOBJ", "PATH",
"PAL", "ICMLCS", "LFONT", "RFONT", "PFE", "PFT", "ICMCXF", "SPRITE",
"BRUSH", "UMPD", "UNUSED4", "SPACE", "UNUSED5", "META", "EFSTATE",
"BMFD", "VTFD", "TTFD", "RC", "TEMP", "DRVOBJ", "DCIOBJ", "SPOOL",
"RESERVED", "ALL"
};
extern PEPROCESS gpepCSRSS;;
VOID
NTAPI
DbgDumpGdiHandleTable(ULONG argc, char *argv[])
{
ULONG i;
UCHAR Objt, jReqestedType;
PENTRY pentry;
POBJ pobj;
KAPC_STATE ApcState;
/* No CSRSS, no handle table */
if (!gpepCSRSS) return;
KeStackAttachProcess(&gpepCSRSS->Pcb, &ApcState);
if (argc == 0)
{
USHORT Counts[GDIObjType_MAX_TYPE + 2] = {0};
/* Loop all possibly used entries in the handle table */
for (i = RESERVE_ENTRIES_COUNT; i < gulFirstUnused; i++)
{
if (MmIsAddressValid(&gpentHmgr[i]))
{
Objt = gpentHmgr[i].Objt & 0x1F;
Counts[Objt]++;
}
}
DbgPrint("Type Count\n");
DbgPrint("-------------------\n");
for (i = 0; i <= GDIObjType_MAX_TYPE; i++)
{
DbgPrint("%02x %-9s %d\n",
i, gpszObjectTypes[i], Counts[i]);
}
DbgPrint("\n");
}
else
{
/* Loop all object types */
for (i = 0; i <= GDIObjType_MAX_TYPE + 1; i++)
{
/* Check if this object type was requested */
if (stricmp(argv[0], gpszObjectTypes[i]) == 0)
{
jReqestedType = i;
break;
}
}
/* Check if we didn't find it yet */
if (i > GDIObjType_MAX_TYPE)
{
/* Try if it's a number */
i = atoi(argv[0]);
/* Check for "0" */
if ((i > GDIObjType_MAX_TYPE) ||
((i == 0) && (stricmp(argv[0], "0") == 0)))
{
DbgPrint("Unknown object type: %s\n", argv[0]);
goto leave;
}
jReqestedType = i;
}
/* Print header */
DbgPrint("Index Handle Type ThreadId cLocks ulRefCount\n");
DbgPrint("----------------------------------------------------\n");
/* Loop all possibly used entries in the handle table */
for (i = RESERVE_ENTRIES_COUNT; i < gulFirstUnused; i++)
{
/* Get the entry and the object */
pentry = &gpentHmgr[i];
if (!MmIsAddressValid(pentry)) continue;
pobj = pentry->einfo.pobj;
Objt = pentry->Objt & 0x1F;
if ((jReqestedType == GDIObjType_MAX_TYPE + 1) ||
(Objt == jReqestedType))
{
DbgPrint("%04lx %p %-9s 0x%06lx %-7ld ",
i, pobj->hHmgr, gpszObjectTypes[Objt],
pobj->dwThreadId, pobj->cExclusiveLock);
if (MmIsAddressValid(&gpaulRefCount[i]))
DbgPrint("0x%06lx\n", gpaulRefCount[i]);
else
DbgPrint("????????\n");
}
}
}
leave:
KeUnstackDetachProcess(&ApcState);
}
VOID
NTAPI
DbgDumpHandleInfo(char *argv)
{
ULONG_PTR ulObject;
BASEOBJECT *pobj;
ENTRY *pentry;
USHORT usIndex;
char *endptr;
KAPC_STATE ApcState;
/* Skip optional '0x' prefix */
if ((argv[0] == '0') && ((argv[1] == 'x') || (argv[1] == 'X')))
argv += 2;
/* Make a number from the string (hex) */
ulObject = strtol(argv, &endptr, 16);
if (*endptr != '\0')
return;
/* No CSRSS, no handle table */
if (!gpepCSRSS) return;
KeStackAttachProcess(&gpepCSRSS->Pcb, &ApcState);
usIndex = ulObject & 0xFFFF;
pentry = &gpentHmgr[usIndex];
if (MmIsAddressValid(pentry))
{
pobj = pentry->einfo.pobj;
DbgPrint("GDI handle=%p, type=%s, index=0x%lx, pentry=%p.\n",
ulObject, gpszObjectTypes[(ulObject >> 16) & 0x1f],
usIndex, pentry);
DbgPrint(" ENTRY = {.pobj = %p, ObjectOwner = 0x%lx, FullUnique = 0x%04x,\n"
" Objt=0x%02x, Flags = 0x%02x, pUser = 0x%p}\n",
pentry->einfo.pobj, pentry->ObjectOwner.ulObj, pentry->FullUnique,
pentry->Objt, pentry->Flags, pentry->pUser);
DbgPrint(" BASEOBJECT = {hHmgr = %p, dwThreadId = 0x%lx,\n"
" cExclusiveLock = %ld, BaseFlags = 0x%lx}\n",
pobj->hHmgr, pobj->dwThreadId,
pobj->cExclusiveLock, pobj->BaseFlags);
if (MmIsAddressValid(&gpaulRefCount[usIndex]))
DbgPrint(" gpaulRefCount[idx] = %ld\n", gpaulRefCount[usIndex]);
}
else
{
DbgPrint("Coudn't access ENTRY. Probably paged out.\n");
}
KeUnstackDetachProcess(&ApcState);
}
#endif // DBG && KDBG
/* EOF */
+12
View File
@@ -180,3 +180,15 @@ POBJ NTAPI GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize);
PGDIOBJ NTAPI GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ObjectType);
PVOID NTAPI GDI_MapHandleTable(PEPROCESS Process);
#if DBG && KDBG
VOID
NTAPI
DbgDumpGdiHandleTable(
ULONG argc,
char *argv[]);
VOID
NTAPI
DbgDumpHandleInfo(
char *argv);
#endif
+5 -1
View File
@@ -11,6 +11,7 @@
#define NDEBUG
#include <debug.h>
#include <kdros.h>
HANDLE hModuleWin;
@@ -87,6 +88,9 @@ Win32kProcessCallback(struct _EPROCESS *Process,
#if DBG
DbgInitDebugChannels();
#if KDBG
KdRosRegisterCliCallback(DbgGdiKdbgCliCallback);
#endif
#endif
TRACE_CH(UserProcess,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent, HandleToUlong(Process->UniqueProcessId));
@@ -408,7 +412,7 @@ UserDestroyThreadInfo(struct _ETHREAD *Thread)
TRACE_CH(UserThread,"Attached Thread ptiTo is getting switched!\n");
UserAttachThreadInput(ptiFrom, ptiCurrent, FALSE);
}
// ptiFrom
if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue)
{