Jeffrey Morlan (mrnobo1024 at yahoo.com) - Fix ModifyWorldTransform multiplies. See...
[reactos.git] / reactos / subsystems / win32 / win32k / objects / gdidbg.c
1 #ifdef GDI_DEBUG
2
3 NTSYSAPI VOID NTAPI KeRosDumpStackFrames(PULONG, ULONG);
4 NTSYSAPI ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags);
5
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
12 {
13 ULONG idx;
14 int count;
15 };
16 #define H 1024
17 static struct DbgOpenGDIHandle h[H];
18
19 void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
20 {
21 int i, n = 0, j, k, J;
22
23 if (leak_reported)
24 {
25 DPRINT1("gdi handle abusers already reported!\n");
26 return;
27 }
28
29 leak_reported = 1;
30 DPRINT1("reporting gdi handle abusers:\n");
31
32 /* step through GDI handle table and find out who our culprit is... */
33 for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
34 {
35 for (j = 0; j < n; j++)
36 {
37 next:
38 J = h[j].idx;
39 for (k = 0; k < GDI_STACK_LEVELS; k++)
40 {
41 if (GDIHandleAllocator[i][k]
42 != GDIHandleAllocator[J][k])
43 {
44 if (++j == n)
45 goto done;
46 else
47 goto next;
48 }
49 }
50 goto done;
51 }
52 done:
53 if (j < H)
54 {
55 if (j == n)
56 {
57 h[j].idx = i;
58 h[j].count = 1;
59 n = n + 1;
60 }
61 else
62 h[j].count++;
63 }
64 }
65 /* bubble sort time! weeeeee!! */
66 for (i = 0; i < n-1; i++)
67 {
68 if (h[i].count < h[i+1].count)
69 {
70 struct DbgOpenGDIHandle t;
71 t = h[i+1];
72 h[i+1] = h[i];
73 j = i;
74 while (j > 0 && h[j-1].count < t.count)
75 j--;
76 h[j] = t;
77 }
78 }
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++)
82 {
83 /* Print out the allocation count */
84 DbgPrint(" %i allocs: ", h[i].count);
85
86 /* Dump the frames */
87 KeRosDumpStackFrames(GDIHandleAllocator[h[i].idx], GDI_STACK_LEVELS);
88
89 /* Print new line for better readability */
90 DbgPrint("\n");
91 }
92 if (i < n && h[i].count == 1)
93 DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
94 }
95
96 ULONG
97 CaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
98 {
99 ULONG nFrameCount;
100
101 memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
102
103 nFrameCount = RtlCaptureStackBackTrace(1, nFramesToCapture, pFrames, NULL);
104
105 if (nFrameCount < nFramesToCapture)
106 {
107 nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount, nFramesToCapture - nFrameCount, 1);
108 }
109
110 return nFrameCount;
111 }
112
113 BOOL
114 GdiDbgHTIntegrityCheck()
115 {
116 ULONG i, nDeleted = 0, nFree = 0, nUsed = 0;
117 PGDI_TABLE_ENTRY pEntry;
118 BOOL r = 1;
119
120 KeEnterCriticalRegion();
121
122 /* FIXME: check reserved entries */
123
124 /* Now go through the deleted objects */
125 i = GdiHandleTable->FirstFree;
126 if (i)
127 {
128 pEntry = &GdiHandleTable->Entries[i];
129 for (;;)
130 {
131 nDeleted++;
132
133 /* Check the entry */
134 if ((pEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
135 {
136 r = 0;
137 DPRINT1("Deleted Entry has a type != 0\n");
138 }
139 if ((ULONG_PTR)pEntry->KernelData >= GDI_HANDLE_COUNT)
140 {
141 r = 0;
142 DPRINT1("Deleted entries KernelPointer too big\n");
143 }
144 if (pEntry->UserData != NULL)
145 {
146 r = 0;
147 DPRINT1("Deleted entry has UserData != 0\n");
148 }
149 if (pEntry->ProcessId != 0)
150 {
151 r = 0;
152 DPRINT1("Deleted entry has ProcessId != 0\n");
153 }
154
155 i = (ULONG_PTR)pEntry->KernelData;
156 if (!i)
157 {
158 break;
159 }
160 pEntry = &GdiHandleTable->Entries[i];
161 }
162 }
163
164 for (i = GdiHandleTable->FirstUnused;
165 i < GDI_HANDLE_COUNT;
166 i++)
167 {
168 pEntry = &GdiHandleTable->Entries[i];
169
170 if ((pEntry->Type) != 0)
171 {
172 r = 0;
173 DPRINT1("Free Entry has a type != 0\n");
174 }
175 if ((ULONG_PTR)pEntry->KernelData != 0)
176 {
177 r = 0;
178 DPRINT1("Free entries KernelPointer != 0\n");
179 }
180 if (pEntry->UserData != NULL)
181 {
182 r = 0;
183 DPRINT1("Free entry has UserData != 0\n");
184 }
185 if (pEntry->ProcessId != 0)
186 {
187 r = 0;
188 DPRINT1("Free entry has ProcessId != 0\n");
189 }
190 nFree++;
191 }
192
193 for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
194 {
195 HGDIOBJ Handle;
196 ULONG Type;
197
198 pEntry = &GdiHandleTable->Entries[i];
199 Type = pEntry->Type;
200 Handle = (HGDIOBJ)((Type << GDI_ENTRY_UPPER_SHIFT) + i);
201
202 if (Type & GDI_ENTRY_BASETYPE_MASK)
203 {
204 if (pEntry->KernelData == NULL)
205 {
206 r = 0;
207 DPRINT1("Used entry has KernelData == 0\n");
208 }
209 if (pEntry->KernelData <= MmHighestUserAddress)
210 {
211 r = 0;
212 DPRINT1("Used entry invalid KernelData\n");
213 }
214 if (((POBJ)(pEntry->KernelData))->hHmgr != Handle)
215 {
216 r = 0;
217 DPRINT1("Used entry %ld, has invalid hHmg %p (expected: %p)\n",
218 i, ((POBJ)(pEntry->KernelData))->hHmgr, Handle);
219 }
220 nUsed++;
221 }
222 }
223
224 if (RESERVE_ENTRIES_COUNT + nDeleted + nFree + nUsed != GDI_HANDLE_COUNT)
225 {
226 r = 0;
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);
229 }
230
231 KeLeaveCriticalRegion();
232
233 return r;
234 }
235
236
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() \
258 ULONG Attempts = 0;
259 #define GDIDBG_TRACELOOP(Handle, PrevThread, Thread) \
260 if ((++Attempts % 20) == 0) \
261 { \
262 DPRINT1("[%d] Handle 0x%p Locked by 0x%x (we're 0x%x)\n", Attempts, Handle, PrevThread, Thread); \
263 }
264
265 #else
266
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)
277
278 #endif /* GDI_DEBUG */
279