2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/gdidbg.c
5 * PURPOSE: Special debugging functions for gdi
6 * PROGRAMMERS: Timo Kreuzer
9 /** INCLUDES ******************************************************************/
16 ULONG gulDebugChannels
= 0;
20 ULONG_PTR GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
21 ULONG_PTR GDIHandleLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
22 ULONG_PTR GDIHandleShareLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
23 ULONG_PTR GDIHandleDeleter
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
24 struct DbgOpenGDIHandle
29 #define MAX_BACKTRACES 1024
30 static struct DbgOpenGDIHandle AllocatorTable
[MAX_BACKTRACES
];
34 CompareBacktraces(ULONG idx1
, ULONG idx2
)
38 /* Loop all stack levels */
39 for (iLevel
= 0; iLevel
< GDI_STACK_LEVELS
; iLevel
++)
41 if (GDIHandleAllocator
[idx1
][iLevel
]
42 != GDIHandleAllocator
[idx2
][iLevel
])
43 // if (GDIHandleShareLocker[idx1][iLevel]
44 // != GDIHandleShareLocker[idx2][iLevel])
53 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
55 static int leak_reported
= 0;
56 int i
, j
, idx
, nTraces
= 0;
61 DPRINT1("gdi handle abusers already reported!\n");
66 DPRINT1("reporting gdi handle abusers:\n");
68 /* We've got serious business to do */
69 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
71 /* Step through GDI handle table and find out who our culprit is... */
72 for (idx
= RESERVE_ENTRIES_COUNT
; idx
< GDI_HANDLE_COUNT
; idx
++)
74 /* If the handle is free, continue */
75 if (!IS_HANDLE_VALID(idx
)) continue;
77 /* Step through all previous backtraces */
78 for (j
= 0; j
< nTraces
; j
++)
80 /* Check if the backtrace matches */
81 if (CompareBacktraces(idx
, AllocatorTable
[j
].idx
))
83 /* It matches, increment count and break out */
84 AllocatorTable
[j
].count
++;
89 /* Did we find a new backtrace? */
92 /* Break out, if we reached the maximum */
93 if (nTraces
== MAX_BACKTRACES
) break;
95 /* Initialize this entry */
96 AllocatorTable
[j
].idx
= idx
;
97 AllocatorTable
[j
].count
= 1;
102 /* bubble sort time! weeeeee!! */
103 for (i
= 0; i
< nTraces
-1; i
++)
105 if (AllocatorTable
[i
].count
< AllocatorTable
[i
+1].count
)
107 struct DbgOpenGDIHandle temp
;
109 temp
= AllocatorTable
[i
+1];
110 AllocatorTable
[i
+1] = AllocatorTable
[i
];
112 while (j
> 0 && AllocatorTable
[j
-1].count
< temp
.count
)
114 AllocatorTable
[j
] = temp
;
118 /* Print the worst offenders... */
119 DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", nTraces
);
120 for (i
= 0; i
< nTraces
&& AllocatorTable
[i
].count
> 1; i
++)
122 /* Print out the allocation count */
123 DbgPrint(" %i allocs, type = 0x%lx:\n",
124 AllocatorTable
[i
].count
,
125 GdiHandleTable
->Entries
[AllocatorTable
[i
].idx
].Type
);
127 /* Dump the frames */
128 KeRosDumpStackFrames(GDIHandleAllocator
[AllocatorTable
[i
].idx
], GDI_STACK_LEVELS
);
129 //KeRosDumpStackFrames(GDIHandleShareLocker[AllocatorTable[i].idx], GDI_STACK_LEVELS);
131 /* Print new line for better readability */
136 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
138 KeLowerIrql(OldIrql
);
144 CaptureStackBackTace(PVOID
* pFrames
, ULONG nFramesToCapture
)
148 memset(pFrames
, 0x00, (nFramesToCapture
+ 1) * sizeof(PVOID
));
150 nFrameCount
= RtlWalkFrameChain(pFrames
, nFramesToCapture
, 0);
152 if (nFrameCount
< nFramesToCapture
)
154 nFrameCount
+= RtlWalkFrameChain(pFrames
+ nFrameCount
,
155 nFramesToCapture
- nFrameCount
,
163 GdiDbgHTIntegrityCheck()
165 ULONG i
, nDeleted
= 0, nFree
= 0, nUsed
= 0;
166 PGDI_TABLE_ENTRY pEntry
;
169 KeEnterCriticalRegion();
171 /* FIXME: check reserved entries */
173 /* Now go through the deleted objects */
174 i
= GdiHandleTable
->FirstFree
& 0xffff;
177 pEntry
= &GdiHandleTable
->Entries
[i
];
178 if (i
> GDI_HANDLE_COUNT
)
180 DPRINT1("nDeleted=%ld\n", nDeleted
);
186 /* Check the entry */
187 if ((pEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
190 DPRINT1("Deleted Entry has a type != 0\n");
192 if ((ULONG_PTR
)pEntry
->KernelData
>= GDI_HANDLE_COUNT
)
195 DPRINT1("Deleted entries KernelPointer too big\n");
197 if (pEntry
->UserData
!= NULL
)
200 DPRINT1("Deleted entry has UserData != 0\n");
202 if (pEntry
->ProcessId
!= 0)
205 DPRINT1("Deleted entry has ProcessId != 0\n");
208 i
= (ULONG_PTR
)pEntry
->KernelData
& 0xffff;
211 for (i
= GdiHandleTable
->FirstUnused
;
212 i
< GDI_HANDLE_COUNT
;
215 pEntry
= &GdiHandleTable
->Entries
[i
];
217 if ((pEntry
->Type
) != 0)
220 DPRINT1("Free Entry has a type != 0\n");
222 if ((ULONG_PTR
)pEntry
->KernelData
!= 0)
225 DPRINT1("Free entries KernelPointer != 0\n");
227 if (pEntry
->UserData
!= NULL
)
230 DPRINT1("Free entry has UserData != 0\n");
232 if (pEntry
->ProcessId
!= 0)
235 DPRINT1("Free entry has ProcessId != 0\n");
240 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
245 pEntry
= &GdiHandleTable
->Entries
[i
];
247 Handle
= (HGDIOBJ
)((Type
<< GDI_ENTRY_UPPER_SHIFT
) + i
);
249 if (Type
& GDI_ENTRY_BASETYPE_MASK
)
251 if (pEntry
->KernelData
== NULL
)
254 DPRINT1("Used entry has KernelData == 0\n");
256 if (pEntry
->KernelData
<= MmHighestUserAddress
)
259 DPRINT1("Used entry invalid KernelData\n");
261 if (((POBJ
)(pEntry
->KernelData
))->hHmgr
!= Handle
)
264 DPRINT1("Used entry %ld, has invalid hHmg %p (expected: %p)\n",
265 i
, ((POBJ
)(pEntry
->KernelData
))->hHmgr
, Handle
);
271 if (RESERVE_ENTRIES_COUNT
+ nDeleted
+ nFree
+ nUsed
!= GDI_HANDLE_COUNT
)
274 DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %ld, nDeleted = %ld, nFree = %ld, nUsed = %ld\n",
275 RESERVE_ENTRIES_COUNT
, nDeleted
, nFree
, nUsed
);
278 KeLeaveCriticalRegion();
285 GDIOBJ_IncrementShareCount(POBJ Object
)
287 INT cLocks
= InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
288 GDIDBG_CAPTURESHARELOCKER(Object
->hHmgr
);
293 #endif /* GDI_DEBUG */
296 GdiDbgDumpLockedHandles()
300 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
302 PGDI_TABLE_ENTRY pEntry
= &GdiHandleTable
->Entries
[i
];
304 if (pEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
)
306 BASEOBJECT
*pObject
= pEntry
->KernelData
;
307 if (pObject
->cExclusiveLock
> 0)
309 DPRINT1("Locked object: %lx, type = %lx. allocated from:\n",
311 GDIDBG_TRACEALLOCATOR(i
);
312 DPRINT1("Locked from:\n");
313 GDIDBG_TRACELOCKER(i
);
321 DbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
323 PTHREADINFO pti
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
324 if (pti
&& pti
->cExclusiveLocks
!= 0)
326 DbgPrint("FATAL: Win32DbgPreServiceHook(%ld): There are %ld exclusive locks!\n",
327 ulSyscallId
, pti
->cExclusiveLocks
);
335 DbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
337 PTHREADINFO pti
= (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
338 if (pti
&& pti
->cExclusiveLocks
!= 0)
340 DbgPrint("FATAL: Win32DbgPostServiceHook(%ld): There are %ld exclusive locks!\n",
341 ulSyscallId
, pti
->cExclusiveLocks
);