3 NTSYSAPI VOID NTAPI
KeRosDumpStackFrames(PULONG
, ULONG
);
4 NTSYSAPI ULONG NTAPI
RtlWalkFrameChain(OUT PVOID
*Callers
, IN ULONG Count
, IN ULONG Flags
);
6 static int leak_reported
= 0;
7 #define GDI_STACK_LEVELS 12
8 static ULONG GDIHandleAllocator
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
9 static ULONG GDIHandleLocker
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
10 static ULONG GDIHandleDeleter
[GDI_HANDLE_COUNT
][GDI_STACK_LEVELS
+1];
11 struct DbgOpenGDIHandle
17 static struct DbgOpenGDIHandle h
[H
];
19 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable
)
21 int i
, n
= 0, j
, k
, J
;
25 DPRINT1("gdi handle abusers already reported!\n");
30 DPRINT1("reporting gdi handle abusers:\n");
32 /* step through GDI handle table and find out who our culprit is... */
33 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
35 for (j
= 0; j
< n
; j
++)
39 for (k
= 0; k
< GDI_STACK_LEVELS
; k
++)
41 if (GDIHandleAllocator
[i
][k
]
42 != GDIHandleAllocator
[J
][k
])
65 /* bubble sort time! weeeeee!! */
66 for (i
= 0; i
< n
-1; i
++)
68 if (h
[i
].count
< h
[i
+1].count
)
70 struct DbgOpenGDIHandle t
;
74 while (j
> 0 && h
[j
-1].count
< t
.count
)
79 /* print the worst offenders... */
80 DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", n
);
81 for (i
= 0; i
< n
&& h
[i
].count
> 1; i
++)
83 /* Print out the allocation count */
84 DbgPrint(" %i allocs: ", h
[i
].count
);
87 KeRosDumpStackFrames(GDIHandleAllocator
[h
[i
].idx
], GDI_STACK_LEVELS
);
89 /* Print new line for better readability */
92 if (i
< n
&& h
[i
].count
== 1)
93 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
97 CaptureStackBackTace(PVOID
* pFrames
, ULONG nFramesToCapture
)
101 memset(pFrames
, 0x00, (nFramesToCapture
+ 1) * sizeof(PVOID
));
103 nFrameCount
= RtlCaptureStackBackTrace(1, nFramesToCapture
, pFrames
, NULL
);
105 if (nFrameCount
< nFramesToCapture
)
107 nFrameCount
+= RtlWalkFrameChain(pFrames
+ nFrameCount
, nFramesToCapture
- nFrameCount
, 1);
114 GdiDbgHTIntegrityCheck()
116 ULONG i
, nDeleted
= 0, nFree
= 0, nUsed
= 0;
117 PGDI_TABLE_ENTRY pEntry
;
120 KeEnterCriticalRegion();
122 /* FIXME: check reserved entries */
124 /* Now go through the deleted objects */
125 i
= GdiHandleTable
->FirstFree
;
128 pEntry
= &GdiHandleTable
->Entries
[i
];
133 /* Check the entry */
134 if ((pEntry
->Type
& GDI_ENTRY_BASETYPE_MASK
) != 0)
137 DPRINT1("Deleted Entry has a type != 0\n");
139 if ((ULONG_PTR
)pEntry
->KernelData
>= GDI_HANDLE_COUNT
)
142 DPRINT1("Deleted entries KernelPointer too big\n");
144 if (pEntry
->UserData
!= NULL
)
147 DPRINT1("Deleted entry has UserData != 0\n");
149 if (pEntry
->ProcessId
!= 0)
152 DPRINT1("Deleted entry has ProcessId != 0\n");
155 i
= (ULONG_PTR
)pEntry
->KernelData
;
160 pEntry
= &GdiHandleTable
->Entries
[i
];
164 for (i
= GdiHandleTable
->FirstUnused
;
165 i
< GDI_HANDLE_COUNT
;
168 pEntry
= &GdiHandleTable
->Entries
[i
];
170 if ((pEntry
->Type
) != 0)
173 DPRINT1("Free Entry has a type != 0\n");
175 if ((ULONG_PTR
)pEntry
->KernelData
!= 0)
178 DPRINT1("Free entries KernelPointer != 0\n");
180 if (pEntry
->UserData
!= NULL
)
183 DPRINT1("Free entry has UserData != 0\n");
185 if (pEntry
->ProcessId
!= 0)
188 DPRINT1("Free entry has ProcessId != 0\n");
193 for (i
= RESERVE_ENTRIES_COUNT
; i
< GDI_HANDLE_COUNT
; i
++)
198 pEntry
= &GdiHandleTable
->Entries
[i
];
200 Handle
= (HGDIOBJ
)((Type
<< GDI_ENTRY_UPPER_SHIFT
) + i
);
202 if (Type
& GDI_ENTRY_BASETYPE_MASK
)
204 if (pEntry
->KernelData
== NULL
)
207 DPRINT1("Used entry has KernelData == 0\n");
209 if (pEntry
->KernelData
<= MmHighestUserAddress
)
212 DPRINT1("Used entry invalid KernelData\n");
214 if (((POBJ
)(pEntry
->KernelData
))->hHmgr
!= Handle
)
217 DPRINT1("Used entry %ld, has invalid hHmg %p (expected: %p)\n",
218 i
, ((POBJ
)(pEntry
->KernelData
))->hHmgr
, Handle
);
224 if (RESERVE_ENTRIES_COUNT
+ nDeleted
+ nFree
+ nUsed
!= GDI_HANDLE_COUNT
)
227 DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %ld, nDeleted = %ld, nFree = %ld, nUsed = %ld\n",
228 RESERVE_ENTRIES_COUNT
, nDeleted
, nFree
, nUsed
);
231 KeLeaveCriticalRegion();
237 #define GDIDBG_TRACECALLER() \
238 DPRINT1("-> called from:\n"); \
239 KeRosDumpStackFrames(NULL, 20);
240 #define GDIDBG_TRACEALLOCATOR(handle) \
241 DPRINT1("-> allocated from:\n"); \
242 KeRosDumpStackFrames(GDIHandleAllocator[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
243 #define GDIDBG_TRACELOCKER(handle) \
244 DPRINT1("-> locked from:\n"); \
245 KeRosDumpStackFrames(GDIHandleLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
246 #define GDIDBG_TRACEDELETER(handle) \
247 DPRINT1("-> deleted from:\n"); \
248 KeRosDumpStackFrames(GDIHandleDeleter[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
249 #define GDIDBG_CAPTUREALLOCATOR(handle) \
250 CaptureStackBackTace((PVOID*)GDIHandleAllocator[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
251 #define GDIDBG_CAPTURELOCKER(handle) \
252 CaptureStackBackTace((PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
253 #define GDIDBG_CAPTUREDELETER(handle) \
254 CaptureStackBackTace((PVOID*)GDIHandleDeleter[GDI_HANDLE_GET_INDEX(handle)], GDI_STACK_LEVELS);
255 #define GDIDBG_DUMPHANDLETABLE() \
256 IntDumpHandleTable(GdiHandleTable)
257 #define GDIDBG_INITLOOPTRACE() \
259 #define GDIDBG_TRACELOOP(Handle, PrevThread, Thread) \
260 if ((++Attempts % 20) == 0) \
262 DPRINT1("[%d] Handle 0x%p Locked by 0x%x (we're 0x%x)\n", Attempts, Handle, PrevThread, Thread); \
267 #define GDIDBG_TRACECALLER()
268 #define GDIDBG_TRACEALLOCATOR(index)
269 #define GDIDBG_TRACELOCKER(index)
270 #define GDIDBG_CAPTUREALLOCATOR(index)
271 #define GDIDBG_CAPTURELOCKER(index)
272 #define GDIDBG_CAPTUREDELETER(handle)
273 #define GDIDBG_DUMPHANDLETABLE()
274 #define GDIDBG_INITLOOPTRACE()
275 #define GDIDBG_TRACELOOP(Handle, PrevThread, Thread)
276 #define GDIDBG_TRACEDELETER(handle)
278 #endif /* GDI_DEBUG */