diff --git a/reactos/include/reactos/kdros.h b/reactos/include/reactos/kdros.h new file mode 100644 index 00000000000..49fce67c2f0 --- /dev/null +++ b/reactos/include/reactos/kdros.h @@ -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 + diff --git a/reactos/ntoskrnl/include/internal/kd.h b/reactos/ntoskrnl/include/internal/kd.h index 8e0530a89af..672234a596e 100644 --- a/reactos/ntoskrnl/include/internal/kd.h +++ b/reactos/ntoskrnl/include/internal/kd.h @@ -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); diff --git a/reactos/ntoskrnl/kd/kdmain.c b/reactos/ntoskrnl/kd/kdmain.c index bacb9b32d9e..336ea5563f3 100644 --- a/reactos/ntoskrnl/kd/kdmain.c +++ b/reactos/ntoskrnl/kd/kdmain.c @@ -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; diff --git a/reactos/ntoskrnl/kdbg/kdb_cli.c b/reactos/ntoskrnl/kdbg/kdb_cli.c index 3d2ee34c62b..ec0e53f89e3 100644 --- a/reactos/ntoskrnl/kdbg/kdb_cli.c +++ b/reactos/ntoskrnl/kdbg/kdb_cli.c @@ -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; } diff --git a/reactos/win32ss/gdi/ntgdi/gdidbg.c b/reactos/win32ss/gdi/ntgdi/gdidbg.c index 0d423e05e7f..6e683ad995c 100644 --- a/reactos/win32ss/gdi/ntgdi/gdidbg.c +++ b/reactos/win32ss/gdi/ntgdi/gdidbg.c @@ -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 */ diff --git a/reactos/win32ss/gdi/ntgdi/gdidebug.h b/reactos/win32ss/gdi/ntgdi/gdidebug.h index 9a656bc36ac..fd27537adf1 100644 --- a/reactos/win32ss/gdi/ntgdi/gdidebug.h +++ b/reactos/win32ss/gdi/ntgdi/gdidebug.h @@ -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); diff --git a/reactos/win32ss/gdi/ntgdi/gdiobj.c b/reactos/win32ss/gdi/ntgdi/gdiobj.c index 7d294c54497..8adec2e2f94 100644 --- a/reactos/win32ss/gdi/ntgdi/gdiobj.c +++ b/reactos/win32ss/gdi/ntgdi/gdiobj.c @@ -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 */ diff --git a/reactos/win32ss/gdi/ntgdi/gdiobj.h b/reactos/win32ss/gdi/ntgdi/gdiobj.h index 0d47a4834a3..eba7459265b 100644 --- a/reactos/win32ss/gdi/ntgdi/gdiobj.h +++ b/reactos/win32ss/gdi/ntgdi/gdiobj.h @@ -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 diff --git a/reactos/win32ss/user/ntuser/main.c b/reactos/win32ss/user/ntuser/main.c index 0e64b5cb5a1..6b9a5ed0ce1 100644 --- a/reactos/win32ss/user/ntuser/main.c +++ b/reactos/win32ss/user/ntuser/main.c @@ -11,6 +11,7 @@ #define NDEBUG #include +#include 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) {