2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/gdikdbgext.c
5 * PURPOSE: KDBG extension for GDI
6 * PROGRAMMERS: Timo Kreuzer
9 /* INCLUDES ******************************************************************/
15 extern PENTRY gpentHmgr
;
16 extern PULONG gpaulRefCount
;
17 extern ULONG gulFirstUnused
;
20 static const char * gpszObjectTypes
[] =
22 "FREE", "DC", "UNUSED1", "UNUSED2", "RGN", "SURF", "CLIENTOBJ", "PATH",
23 "PAL", "ICMLCS", "LFONT", "RFONT", "PFE", "PFT", "ICMCXF", "SPRITE",
24 "BRUSH", "UMPD", "UNUSED4", "SPACE", "UNUSED5", "META", "EFSTATE",
25 "BMFD", "VTFD", "TTFD", "RC", "TEMP", "DRVOBJ", "DCIOBJ", "SPOOL",
31 KdbIsMemoryValid(PVOID pvBase
, ULONG cjSize
)
35 pjAddress
= ALIGN_DOWN_POINTER_BY(pvBase
, PAGE_SIZE
);
37 while (pjAddress
< (PUCHAR
)pvBase
+ cjSize
)
39 if (!MmIsAddressValid(pjAddress
)) return FALSE
;
40 pjAddress
+= PAGE_SIZE
;
48 KdbGetHexNumber(char *pszNum
, ULONG_PTR
*pulValue
)
52 /* Skip optional '0x' prefix */
53 if ((pszNum
[0] == '0') && ((pszNum
[1] == 'x') || (pszNum
[1] == 'X')))
56 /* Make a number from the string (hex) */
57 *pulValue
= strtoul(pszNum
, &endptr
, 16);
59 return (*endptr
== '\0');
64 KdbCommand_Gdi_help(VOID
)
66 DbgPrint("GDI KDBG extension.\nAvailable commands:\n"
67 "- help - Displays this screen.\n"
68 "- dumpht [<type>] - Dumps all handles of <type> or lists all types\n"
69 "- handle <handle> - Displays information about a handle\n"
70 "- entry <entry> - Displays an ENTRY, <entry> can be a pointer or index\n"
71 "- baseobject <object> - Displays a BASEOBJECT\n"
72 #if DBG_ENABLE_EVENT_LOGGING
73 "- eventlist <object> - Displays the eventlist for an object\n"
80 KdbCommand_Gdi_dumpht(ULONG argc
, char *argv
[])
83 UCHAR Objt
, jReqestedType
;
89 /* No CSRSS, no handle table */
90 if (!gpepCSRSS
) return;
91 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
95 USHORT Counts
[GDIObjType_MAX_TYPE
+ 2] = {0};
97 /* Loop all possibly used entries in the handle table */
98 for (i
= RESERVE_ENTRIES_COUNT
; i
< gulFirstUnused
; i
++)
100 if (KdbIsMemoryValid(&gpentHmgr
[i
], sizeof(ENTRY
)))
102 Objt
= gpentHmgr
[i
].Objt
& 0x1F;
107 DbgPrint("Type Count\n");
108 DbgPrint("-------------------\n");
109 for (i
= 0; i
<= GDIObjType_MAX_TYPE
; i
++)
111 DbgPrint("%02x %-9s %d\n",
112 i
, gpszObjectTypes
[i
], Counts
[i
]);
118 /* Loop all object types */
119 for (i
= 0; i
<= GDIObjType_MAX_TYPE
+ 1; i
++)
121 /* Check if this object type was requested */
122 if (stricmp(argv
[0], gpszObjectTypes
[i
]) == 0) break;
125 /* Check if we didn't find it yet */
126 if (i
> GDIObjType_MAX_TYPE
+ 1)
128 /* Try if it's a number */
129 if (!KdbGetHexNumber(argv
[0], &ulArg
))
131 DbgPrint("Invalid parameter: %s\n", argv
[0]);
135 /* Check if it's inside the allowed range */
136 if (i
> GDIObjType_MAX_TYPE
)
138 DbgPrint("Unknown object type: %s\n", argv
[0]);
146 DbgPrint("Index Handle Type pObject ThreadId cLocks ulRefCount\n");
147 DbgPrint("---------------------------------------------------------------\n");
149 /* Loop all possibly used entries in the handle table */
150 for (i
= RESERVE_ENTRIES_COUNT
; i
< gulFirstUnused
; i
++)
152 /* Get the entry and the object */
153 pentry
= &gpentHmgr
[i
];
155 if (!MmIsAddressValid(pentry
)) continue;
157 pobj
= pentry
->einfo
.pobj
;
158 Objt
= pentry
->Objt
& 0x1F;
160 /* Check if ALL objects are requested, or the object type matches */
161 if ((jReqestedType
== GDIObjType_MAX_TYPE
+ 1) ||
162 (Objt
== jReqestedType
))
164 DbgPrint("%04lx %p %-9s 0x%p 0x%06lx %-6ld ",
165 i
, pobj
->hHmgr
, gpszObjectTypes
[Objt
], pobj
,
166 pobj
->dwThreadId
, pobj
->cExclusiveLock
);
167 if (MmIsAddressValid(&gpaulRefCount
[i
]))
168 DbgPrint("0x%08lx\n", gpaulRefCount
[i
]);
170 DbgPrint("??????????\n");
176 KeUnstackDetachProcess(&ApcState
);
181 KdbCommand_Gdi_handle(char *argv
)
189 /* Convert the parameter into a number */
190 if (!KdbGetHexNumber(argv
, &ulObject
))
192 DbgPrint("Invalid parameter: %s\n", argv
);
196 /* No CSRSS, no handle table */
197 if (!gpepCSRSS
) return;
198 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
200 usIndex
= ulObject
& 0xFFFF;
201 pentry
= &gpentHmgr
[usIndex
];
203 if (MmIsAddressValid(pentry
))
205 pobj
= pentry
->einfo
.pobj
;
207 DbgPrint("GDI handle=%p, type=%s, index=0x%lx, pentry=%p.\n",
208 ulObject
, gpszObjectTypes
[(ulObject
>> 16) & 0x1f],
210 DbgPrint(" ENTRY = {.pobj = %p, ObjectOwner = 0x%lx, FullUnique = 0x%04x,\n"
211 " Objt=0x%02x, Flags = 0x%02x, pUser = 0x%p}\n",
212 pentry
->einfo
.pobj
, pentry
->ObjectOwner
.ulObj
, pentry
->FullUnique
,
213 pentry
->Objt
, pentry
->Flags
, pentry
->pUser
);
214 DbgPrint(" BASEOBJECT = {hHmgr = %p, dwThreadId = 0x%lx,\n"
215 " cExclusiveLock = %ld, BaseFlags = 0x%lx}\n",
216 pobj
->hHmgr
, pobj
->dwThreadId
,
217 pobj
->cExclusiveLock
, pobj
->BaseFlags
);
218 if (MmIsAddressValid(&gpaulRefCount
[usIndex
]))
219 DbgPrint(" gpaulRefCount[idx] = %ld\n", gpaulRefCount
[usIndex
]);
223 DbgPrint("Coudn't access ENTRY. Probably paged out.\n");
226 KeUnstackDetachProcess(&ApcState
);
231 KdbCommand_Gdi_entry(char *argv
)
237 /* Convert the parameter into a number */
238 if (!KdbGetHexNumber(argv
, &ulValue
))
240 DbgPrint("Invalid parameter: %s\n", argv
);
244 /* No CSRSS, no handle table */
245 if (!gpepCSRSS
) return;
246 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
248 /* If the parameter is smaller than 0x10000, it's an index */
249 pentry
= (ulValue
<= 0xFFFF) ? &gpentHmgr
[ulValue
] : (PENTRY
)ulValue
;
251 /* Check if the address is readable */
252 if (!MmIsAddressValid(pentry
))
254 DbgPrint("Cannot access entry at %p\n", pentry
);
258 /* print the entry */
259 DbgPrint("Dumping ENTRY #%ld, @%p:\n", (pentry
- gpentHmgr
), pentry
);
260 if (pentry
->Objt
!= 0)
261 DbgPrint(" pobj = 0x%p\n", pentry
->einfo
.pobj
);
263 DbgPrint(" hFree = 0x%p\n", pentry
->einfo
.hFree
);
264 DbgPrint(" ObjectOwner = 0x%p\n", pentry
->ObjectOwner
.ulObj
);
265 DbgPrint(" FullUnique = 0x%x\n", pentry
->FullUnique
);
266 DbgPrint(" Objt = 0x%x (%s)\n", pentry
->Objt
,
267 pentry
->Objt
<= 0x1E ? gpszObjectTypes
[pentry
->Objt
] : "invalid");
268 DbgPrint(" Flags = 0x%x\n", pentry
->Flags
);
269 DbgPrint(" pUser = 0x%p\n", pentry
->pUser
);
272 KeUnstackDetachProcess(&ApcState
);
277 KdbCommand_Gdi_baseobject(char *argv
)
281 #if DBG_ENABLE_EVENT_LOGGING
284 KdbCommand_Gdi_eventlist(char *argv
)
288 PSLIST_ENTRY psle
, psleFirst
;
291 /* Convert the parameter into a number */
292 if (!KdbGetHexNumber(argv
, &ulValue
))
294 DbgPrint("Invalid parameter: %s\n", argv
);
298 pobj
= (POBJ
)ulValue
;
300 /* Check if the address is readable */
301 if (!KdbIsMemoryValid(pobj
, sizeof(BASEOBJECT
)))
303 DbgPrint("Cannot access BASEOBJECT at %p\n", pobj
);
307 /* The kernel doesn't export RtlFirstEntrySList :( */
308 psleFirst
= InterlockedFlushSList(&pobj
->slhLog
);
310 /* Loop all events, but don't remove them */
311 for (psle
= psleFirst
; psle
!= NULL
; psle
= psle
->Next
)
313 pLogEntry
= CONTAINING_RECORD(psle
, LOGENTRY
, sleLink
);
314 DbgPrintEvent(pLogEntry
);
317 /* Put the log back in place */
318 InterlockedPushEntrySList(&pobj
->slhLog
, psleFirst
);
324 DbgGdiKdbgCliCallback(
330 if (stricmp(argv
[0], "!gdi.help") == 0)
332 KdbCommand_Gdi_help();
334 else if (stricmp(argv
[0], "!gdi.dumpht") == 0)
336 KdbCommand_Gdi_dumpht(argc
- 1, argv
+ 1);
338 else if (stricmp(argv
[0], "!gdi.handle") == 0)
340 KdbCommand_Gdi_handle(argv
[1]);
342 else if (stricmp(argv
[0], "!gdi.entry") == 0)
344 KdbCommand_Gdi_entry(argv
[1]);
346 else if (stricmp(argv
[0], "!gdi.baseobject") == 0)
348 KdbCommand_Gdi_baseobject(argv
[1]);
350 #if DBG_ENABLE_EVENT_LOGGING
351 else if (stricmp(argv
[0], "!gdi.eventlist") == 0)
353 KdbCommand_Gdi_eventlist(argv
[1]);