mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-01 19:26:16 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user