Author: tkreuzer Date: Mon Oct 1 23:06:32 2012 New Revision: 57454
URL: http://svn.reactos.org/svn/reactos?rev=57454&view=rev Log: [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
Added: trunk/reactos/include/reactos/kdros.h (with props) Modified: trunk/reactos/ntoskrnl/include/internal/kd.h trunk/reactos/ntoskrnl/kd/kdmain.c trunk/reactos/ntoskrnl/kdbg/kdb_cli.c trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h trunk/reactos/win32ss/user/ntuser/main.c
Added: trunk/reactos/include/reactos/kdros.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/kdros.h?rev... ============================================================================== --- trunk/reactos/include/reactos/kdros.h (added) +++ trunk/reactos/include/reactos/kdros.h [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -1,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 +
Propchange: trunk/reactos/include/reactos/kdros.h ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/include/internal/kd.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/kd.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/kd.h [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -67,6 +67,21 @@ #ifdef __NTOSKRNL__
#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(
Modified: trunk/reactos/ntoskrnl/kd/kdmain.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/kd/kdmain.c?rev=57... ============================================================================== --- trunk/reactos/ntoskrnl/kd/kdmain.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/kd/kdmain.c [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -97,7 +97,15 @@ 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;
Modified: trunk/reactos/ntoskrnl/kdbg/kdb_cli.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/kdbg/kdb_cli.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/kdbg/kdb_cli.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/kdbg/kdb_cli.c [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -96,6 +96,7 @@
/* 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 @@ } }
+ +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 @@ 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];
@@ -3318,6 +3396,12 @@ { return KdbDebuggerCommands[i].Fn(Argc, Argv); } + } + + /* Now invoke the registered callbacks */ + if (KdbpInvokeCliCallbacks(Command, Argc, Argv)) + { + return TRUE; }
KdbpPrint("Command '%s' is unknown.\n", OrigCommand);
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c?... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -118,7 +118,7 @@
VOID NTAPI -DbgDumpGdiHandleTable(void) +DbgDumpGdiHandleTableWithBT(void) { static int leak_reported = 0; int i, j, idx, nTraces = 0; @@ -729,6 +729,36 @@ 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 */
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdidebug.... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -28,6 +28,15 @@ } 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 @@ #endif
-VOID NTAPI DbgDumpGdiHandleTable(VOID); +VOID NTAPI DbgDumpGdiHandleTableWithBT(VOID); ULONG NTAPI DbgCaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture); BOOL NTAPI DbgGdiHTIntegrityCheck(VOID); VOID NTAPI DbgDumpLockedGdiHandles(VOID);
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c?... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -1341,4 +1341,170 @@ 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 */
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h?... ============================================================================== --- trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -180,3 +180,15 @@ 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
Modified: trunk/reactos/win32ss/user/ntuser/main.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/main.c?... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/main.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/main.c [iso-8859-1] Mon Oct 1 23:06:32 2012 @@ -11,6 +11,7 @@
#define NDEBUG #include <debug.h> +#include <kdros.h>
HANDLE hModuleWin;
@@ -87,6 +88,9 @@
#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 @@ TRACE_CH(UserThread,"Attached Thread ptiTo is getting switched!\n"); UserAttachThreadInput(ptiFrom, ptiCurrent, FALSE); } - + // ptiFrom if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue) {