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 #define GDI_STACK_LEVELS 20
21 static ULONG_PTR GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
22 static ULONG_PTR GDIHandleLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
23 static ULONG_PTR GDIHandleShareLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
24 static ULONG_PTR GDIHandleDeleter
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
25 struct DbgOpenGDIHandle
30 #define MAX_BACKTRACES 1024
31 static struct DbgOpenGDIHandle AllocatorTable
[MAX_BACKTRACES
];
35 CompareBacktraces(ULONG idx1
, ULONG idx2
)
39 /* Loop all stack levels */
40 for (iLevel
= 0; iLevel
< GDI_STACK_LEVELS
; iLevel
++)
42 if (GDIHandleAllocator
[idx1
][iLevel
]
43 != GDIHandleAllocator
[idx2
][iLevel
])
44 // if (GDIHandleShareLocker[idx1][iLevel]
45 // != GDIHandleShareLocker[idx2][iLevel])
54 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
56 static int leak_reported
= 0;
57 int i
, j
, idx
, nTraces
= 0;
62 DPRINT1("gdi handle abusers already reported!\n");
67 DPRINT1("reporting gdi handle abusers:\n");
69 /* We've got serious business to do */
70 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
72 /* Step through GDI handle table and find out who our culprit is... */
73 for (idx
= RESERVE_ENTRIES_COUNT
; idx
< GDI_HANDLE_COUNT
; idx
++)
75 /* If the handle is free, continue */
76 if (!IS_HANDLE_VALID(idx
)) continue;
78 /* Step through all previous backtraces */
79 for (j
= 0; j
< nTraces
; j
++)
81 /* Check if the backtrace matches */
82 if (CompareBacktraces(idx
, AllocatorTable
[j
].idx
))
84 /* It matches, increment count and break out */
85 AllocatorTable
[j
].count
++;
90 /* Did we find a new backtrace? */
93 /* Break out, if we reached the maximum */
94 if (nTraces
== MAX_BACKTRACES
) break;
96 /* Initialize this entry */
97 AllocatorTable
[j
].idx
= idx
;
98 AllocatorTable
[j
].count
= 1;
103 /* bubble sort time! weeeeee!! */
104 for (i
= 0; i
< nTraces
-1; i
++)
106 if (AllocatorTable
[i
].count
< AllocatorTable
[i
+1].count
)
108 struct DbgOpenGDIHandle temp
;
110 temp
= AllocatorTable
[i
+1];
111 AllocatorTable
[i
+1] = AllocatorTable
[i
];
113 while (j
> 0 && AllocatorTable
[j
-1].count
< temp
.count
)
115 AllocatorTable
[j
] = temp
;
119 /* Print the worst offenders... */
120 DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", nTraces
);
121 for (i
= 0; i
< nTraces
&& AllocatorTable
[i
].count
> 1; i
++)
123 /* Print out the allocation count */
124 DbgPrint(" %i allocs, type = 0x%lx:\n",
125 AllocatorTable
[i
].count
,
126 GdiHandleTable
->Entries
[AllocatorTable
[i
].idx
].Type
);
128 /* Dump the frames */
129 KeRosDumpStackFrames(GDIHandleAllocator
[AllocatorTable
[i
].idx
], GDI_STACK_LEVELS
);
130 //KeRosDumpStackFrames(GDIHandleShareLocker[AllocatorTable[i].idx], GDI_STACK_LEVELS);
132 /* Print new line for better readability */
137 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
139 KeLowerIrql(OldIrql
);
145 CaptureStackBackTace(PVOID
* pFrames
, ULONG nFramesToCapture
)
149 memset(pFrames
, 0x00, (nFramesToCapture
+ 1) * sizeof(PVOID
));
151 nFrameCount
= RtlWalkFrameChain(pFrames
, nFramesToCapture
, 0);
153 if (nFrameCount
< nFramesToCapture
)
155 nFrameCount
+= RtlWalkFrameChain(pFrames
+ nFrameCount
,
156 nFramesToCapture
- nFrameCount
,
164 GdiDbgHTIntegrityCheck()
166 ULONG i
, nDeleted
= 0, nFree
= 0, nUsed
= 0;
167 PGDI_TABLE_ENTRY pEntry
;
170 KeEnterCriticalRegion();
172 /* FIXME: check reserved entries */
174 /* Now go through the deleted objects */
175 i
= GdiHandleTable
->FirstFree
;
178 pEntry
= &GdiHandleTable
->Entries
[i
];
183 /* Check the entry */
184 if ((pEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
187 DPRINT1("Deleted Entry has a type != 0\n");
189 if ((ULONG_PTR
)pEntry
->KernelData
>= GDI_HANDLE_COUNT
)
192 DPRINT1("Deleted entries KernelPointer too big\n");
194 if (pEntry
->UserData
!= NULL
)
197 DPRINT1("Deleted entry has UserData != 0\n");
199 if (pEntry
->ProcessId
!= 0)
202 DPRINT1("Deleted entry has ProcessId != 0\n");
205 i
= (ULONG_PTR
)pEntry
->KernelData
;
210 pEntry
= &GdiHandleTable
->Entries
[i
];
214 for (i
= GdiHandleTable
->FirstUnused
;
215 i
< GDI_HANDLE_COUNT
;
218 pEntry
= &GdiHandleTable
->Entries
[i
];
220 if ((pEntry
->Type
) != 0)
223 DPRINT1("Free Entry has a type != 0\n");
225 if ((ULONG_PTR
)pEntry
->KernelData
!= 0)
228 DPRINT1("Free entries KernelPointer != 0\n");
230 if (pEntry
->UserData
!= NULL
)
233 DPRINT1("Free entry has UserData != 0\n");
235 if (pEntry
->ProcessId
!= 0)
238 DPRINT1("Free entry has ProcessId != 0\n");
243 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
248 pEntry
= &GdiHandleTable
->Entries
[i
];
250 Handle
= (HGDIOBJ
)((Type
<< GDI_ENTRY_UPPER_SHIFT
) + i
);
252 if (Type
& GDI_ENTRY_BASETYPE_MASK
)
254 if (pEntry
->KernelData
== NULL
)
257 DPRINT1("Used entry has KernelData == 0\n");
259 if (pEntry
->KernelData
<= MmHighestUserAddress
)
262 DPRINT1("Used entry invalid KernelData\n");
264 if (((POBJ
)(pEntry
->KernelData
))->hHmgr
!= Handle
)
267 DPRINT1("Used entry %ld, has invalid hHmg %p (expected: %p)\n",
268 i
, ((POBJ
)(pEntry
->KernelData
))->hHmgr
, Handle
);
274 if (RESERVE_ENTRIES_COUNT
+ nDeleted
+ nFree
+ nUsed
!= GDI_HANDLE_COUNT
)
277 DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %ld, nDeleted = %ld, nFree = %ld, nUsed = %ld\n",
278 RESERVE_ENTRIES_COUNT
, nDeleted
, nFree
, nUsed
);
281 KeLeaveCriticalRegion();
288 GDIOBJ_IncrementShareCount(POBJ Object
)
290 INT cLocks
= InterlockedIncrement((PLONG
)&Object
->ulShareCount
);
291 GDIDBG_CAPTURESHARELOCKER(Object
->hHmgr
);
296 #endif /* GDI_DEBUG */