2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/gdikdbgext.x
5 * PURPOSE: KDBG extension for GDI
6 * PROGRAMMERS: Timo Kreuzer
9 /* INCLUDES ******************************************************************/
15 extern PENTRY gpentHmgr
;
16 extern PULONG gpaulRefCount
;
17 extern PEPROCESS gpepCSRSS
;
18 extern ULONG gulFirstUnused
;
21 static const char * gpszObjectTypes
[] =
23 "FREE", "DC", "UNUSED1", "UNUSED2", "RGN", "SURF", "CLIENTOBJ", "PATH",
24 "PAL", "ICMLCS", "LFONT", "RFONT", "PFE", "PFT", "ICMCXF", "SPRITE",
25 "BRUSH", "UMPD", "UNUSED4", "SPACE", "UNUSED5", "META", "EFSTATE",
26 "BMFD", "VTFD", "TTFD", "RC", "TEMP", "DRVOBJ", "DCIOBJ", "SPOOL",
32 KdbIsMemoryValid(PVOID pvBase
, ULONG cjSize
)
36 pjAddress
= ALIGN_DOWN_POINTER_BY(pvBase
, PAGE_SIZE
);
38 while (pjAddress
< (PUCHAR
)pvBase
+ cjSize
)
40 if (!MmIsAddressValid(pjAddress
)) return FALSE
;
41 pjAddress
+= PAGE_SIZE
;
49 KdbGetHexNumber(char *pszNum
, ULONG_PTR
*pulValue
)
53 /* Skip optional '0x' prefix */
54 if ((pszNum
[0] == '0') && ((pszNum
[1] == 'x') || (pszNum
[1] == 'X')))
57 /* Make a number from the string (hex) */
58 *pulValue
= strtoul(pszNum
, &endptr
, 16);
60 return (*endptr
== '\0');
65 KdbCommand_Gdi_help(VOID
)
67 DbgPrint("GDI KDBG extension.\nAvailable commands:\n"
68 "- help - Displays this screen.\n"
69 "- dumpht [<type>] - Dumps all handles of <type> or lists all types\n"
70 "- handle <handle> - Displays information about a handle\n"
71 "- entry <entry> - Displays an ENTRY, <entry> can be a pointer or index\n"
72 "- baseobject <object> - Displays a BASEOBJECT\n"
73 #if DBG_ENABLE_EVENT_LOGGING
74 "- eventlist <object> - Displays the eventlist for an object\n"
81 KdbCommand_Gdi_dumpht(ULONG argc
, char *argv
[])
84 UCHAR Objt
, jReqestedType
;
90 /* No CSRSS, no handle table */
91 if (!gpepCSRSS
) return;
92 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
96 USHORT Counts
[GDIObjType_MAX_TYPE
+ 2] = {0};
98 /* Loop all possibly used entries in the handle table */
99 for (i
= RESERVE_ENTRIES_COUNT
; i
< gulFirstUnused
; i
++)
101 if (KdbIsMemoryValid(&gpentHmgr
[i
], sizeof(ENTRY
)))
103 Objt
= gpentHmgr
[i
].Objt
& 0x1F;
108 DbgPrint("Type Count\n");
109 DbgPrint("-------------------\n");
110 for (i
= 0; i
<= GDIObjType_MAX_TYPE
; i
++)
112 DbgPrint("%02x %-9s %d\n",
113 i
, gpszObjectTypes
[i
], Counts
[i
]);
119 /* Loop all object types */
120 for (i
= 0; i
<= GDIObjType_MAX_TYPE
+ 1; i
++)
122 /* Check if this object type was requested */
123 if (stricmp(argv
[0], gpszObjectTypes
[i
]) == 0) break;
126 /* Check if we didn't find it yet */
127 if (i
> GDIObjType_MAX_TYPE
+ 1)
129 /* Try if it's a number */
130 if (!KdbGetHexNumber(argv
[0], &ulArg
))
132 DbgPrint("Invalid parameter: %s\n", argv
[0]);
136 /* Check if it's inside the allowed range */
137 if (i
> GDIObjType_MAX_TYPE
)
139 DbgPrint("Unknown object type: %s\n", argv
[0]);
147 DbgPrint("Index Handle Type pObject ThreadId cLocks ulRefCount\n");
148 DbgPrint("---------------------------------------------------------------\n");
150 /* Loop all possibly used entries in the handle table */
151 for (i
= RESERVE_ENTRIES_COUNT
; i
< gulFirstUnused
; i
++)
153 /* Get the entry and the object */
154 pentry
= &gpentHmgr
[i
];
156 if (!MmIsAddressValid(pentry
)) continue;
158 pobj
= pentry
->einfo
.pobj
;
159 Objt
= pentry
->Objt
& 0x1F;
161 /* Check if ALL objects are requested, or the object type matches */
162 if ((jReqestedType
== GDIObjType_MAX_TYPE
+ 1) ||
163 (Objt
== jReqestedType
))
165 DbgPrint("%04lx %p %-9s 0x%p 0x%06lx %-6ld ",
166 i
, pobj
->hHmgr
, gpszObjectTypes
[Objt
], pobj
,
167 pobj
->dwThreadId
, pobj
->cExclusiveLock
);
168 if (MmIsAddressValid(&gpaulRefCount
[i
]))
169 DbgPrint("0x%08lx\n", gpaulRefCount
[i
]);
171 DbgPrint("??????????\n");
177 KeUnstackDetachProcess(&ApcState
);
182 KdbCommand_Gdi_handle(char *argv
)
190 /* Convert the parameter into a number */
191 if (!KdbGetHexNumber(argv
, &ulObject
))
193 DbgPrint("Invalid parameter: %s\n", argv
);
197 /* No CSRSS, no handle table */
198 if (!gpepCSRSS
) return;
199 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
201 usIndex
= ulObject
& 0xFFFF;
202 pentry
= &gpentHmgr
[usIndex
];
204 if (MmIsAddressValid(pentry
))
206 pobj
= pentry
->einfo
.pobj
;
208 DbgPrint("GDI handle=%p, type=%s, index=0x%lx, pentry=%p.\n",
209 ulObject
, gpszObjectTypes
[(ulObject
>> 16) & 0x1f],
211 DbgPrint(" ENTRY = {.pobj = %p, ObjectOwner = 0x%lx, FullUnique = 0x%04x,\n"
212 " Objt=0x%02x, Flags = 0x%02x, pUser = 0x%p}\n",
213 pentry
->einfo
.pobj
, pentry
->ObjectOwner
.ulObj
, pentry
->FullUnique
,
214 pentry
->Objt
, pentry
->Flags
, pentry
->pUser
);
215 DbgPrint(" BASEOBJECT = {hHmgr = %p, dwThreadId = 0x%lx,\n"
216 " cExclusiveLock = %ld, BaseFlags = 0x%lx}\n",
217 pobj
->hHmgr
, pobj
->dwThreadId
,
218 pobj
->cExclusiveLock
, pobj
->BaseFlags
);
219 if (MmIsAddressValid(&gpaulRefCount
[usIndex
]))
220 DbgPrint(" gpaulRefCount[idx] = %ld\n", gpaulRefCount
[usIndex
]);
224 DbgPrint("Coudn't access ENTRY. Probably paged out.\n");
227 KeUnstackDetachProcess(&ApcState
);
232 KdbCommand_Gdi_entry(char *argv
)
238 /* Convert the parameter into a number */
239 if (!KdbGetHexNumber(argv
, &ulValue
))
241 DbgPrint("Invalid parameter: %s\n", argv
);
245 /* No CSRSS, no handle table */
246 if (!gpepCSRSS
) return;
247 KeStackAttachProcess(&gpepCSRSS
->Pcb
, &ApcState
);
249 /* If the parameter is smaller than 0x10000, it's an index */
250 pentry
= (ulValue
<= 0xFFFF) ? &gpentHmgr
[ulValue
] : (PENTRY
)ulValue
;
252 /* Check if the address is readable */
253 if (!MmIsAddressValid(pentry
))
255 DbgPrint("Cannot access entry at %p\n", pentry
);
259 /* print the entry */
260 DbgPrint("Dumping ENTRY #%ld, @%p:\n", (pentry
- gpentHmgr
), pentry
);
261 if (pentry
->Objt
!= 0)
262 DbgPrint(" pobj = 0x%p\n", pentry
->einfo
.pobj
);
264 DbgPrint(" hFree = 0x%p\n", pentry
->einfo
.hFree
);
265 DbgPrint(" ObjectOwner = 0x%p\n", pentry
->ObjectOwner
.ulObj
);
266 DbgPrint(" FullUnique = 0x%x\n", pentry
->FullUnique
);
267 DbgPrint(" Objt = 0x%x (%s)\n", pentry
->Objt
,
268 pentry
->Objt
<= 0x1E ? gpszObjectTypes
[pentry
->Objt
] : "invalid");
269 DbgPrint(" Flags = 0x%x\n", pentry
->Flags
);
270 DbgPrint(" pUser = 0x%p\n", pentry
->pUser
);
273 KeUnstackDetachProcess(&ApcState
);
278 KdbCommand_Gdi_baseobject(char *argv
)
282 #if DBG_ENABLE_EVENT_LOGGING
285 KdbCommand_Gdi_eventlist(char *argv
)
289 PSLIST_ENTRY psle
, psleFirst
;
292 /* Convert the parameter into a number */
293 if (!KdbGetHexNumber(argv
, &ulValue
))
295 DbgPrint("Invalid parameter: %s\n", argv
);
299 pobj
= (POBJ
)ulValue
;
301 /* Check if the address is readable */
302 if (!KdbIsMemoryValid(pobj
, sizeof(BASEOBJECT
)))
304 DbgPrint("Cannot access BASEOBJECT at %p\n", pobj
);
308 /* The kernel doesn't export RtlFirstEntrySList :( */
309 psleFirst
= InterlockedFlushSList(&pobj
->slhLog
);
311 /* Loop all events, but don't remove them */
312 for (psle
= psleFirst
; psle
!= NULL
; psle
= psle
->Next
)
314 pLogEntry
= CONTAINING_RECORD(psle
, LOGENTRY
, sleLink
);
315 DbgPrintEvent(pLogEntry
);
318 /* Put the log back in place */
319 InterlockedPushEntrySList(&pobj
->slhLog
, psleFirst
);
325 DbgGdiKdbgCliCallback(
331 if (stricmp(argv
[0], "!gdi.help") == 0)
333 KdbCommand_Gdi_help();
335 else if (stricmp(argv
[0], "!gdi.dumpht") == 0)
337 KdbCommand_Gdi_dumpht(argc
- 1, argv
+ 1);
339 else if (stricmp(argv
[0], "!gdi.handle") == 0)
341 KdbCommand_Gdi_handle(argv
[1]);
343 else if (stricmp(argv
[0], "!gdi.entry") == 0)
345 KdbCommand_Gdi_entry(argv
[1]);
347 else if (stricmp(argv
[0], "!gdi.baseobject") == 0)
349 KdbCommand_Gdi_baseobject(argv
[1]);
351 #if DBG_ENABLE_EVENT_LOGGING
352 else if (stricmp(argv
[0], "!gdi.eventlist") == 0)
354 KdbCommand_Gdi_eventlist(argv
[1]);