- Fix IntDumpHandleTable, it was very broken.

svn path=/trunk/; revision=47067
This commit is contained in:
Timo Kreuzer 2010-04-30 22:48:43 +00:00
parent 8dc269c258
commit 9bb0bed655

View file

@ -3,23 +3,48 @@
#define KeRosDumpStackFrames(Frames, Count) KdSystemDebugControl('DsoR', (PVOID)Frames, Count, NULL, 0, NULL, KernelMode) #define KeRosDumpStackFrames(Frames, Count) KdSystemDebugControl('DsoR', (PVOID)Frames, Count, NULL, 0, NULL, KernelMode)
NTSYSAPI ULONG APIENTRY RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags); NTSYSAPI ULONG APIENTRY RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags);
static int leak_reported = 0; #define GDI_STACK_LEVELS 20
#define GDI_STACK_LEVELS 12 static ULONG_PTR GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1]; static ULONG_PTR GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
static ULONG GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1]; static ULONG_PTR GDIHandleShareLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
static ULONG GDIHandleShareLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1]; static ULONG_PTR GDIHandleDeleter[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
static ULONG GDIHandleDeleter[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
struct DbgOpenGDIHandle struct DbgOpenGDIHandle
{ {
ULONG idx; ULONG idx;
int count; int count;
}; };
#define H 1024 #define MAX_BACKTRACES 1024
static struct DbgOpenGDIHandle h[H]; static struct DbgOpenGDIHandle AllocatorTable[MAX_BACKTRACES];
static
BOOL
CompareBacktraces(ULONG idx1, ULONG idx2)
{
ULONG iLevel;
/* Loop all stack levels */
for (iLevel = 0; iLevel < GDI_STACK_LEVELS; iLevel++)
{
if (GDIHandleAllocator[idx1][iLevel]
!= GDIHandleAllocator[idx2][iLevel])
// if (GDIHandleShareLocker[idx1][iLevel]
// != GDIHandleShareLocker[idx2][iLevel])
{
return FALSE;
}
}
return TRUE;
}
#define IS_HANDLE_VALID(idx) \
((GdiHandleTable->Entries[idx].Type & GDI_ENTRY_BASETYPE_MASK) != 0)
void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable) void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
{ {
int i, n = 0, j, k, J; static int leak_reported = 0;
int i, j, idx, nTraces = 0;
KIRQL OldIrql;
if (leak_reported) if (leak_reported)
{ {
@ -30,68 +55,79 @@ void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
leak_reported = 1; leak_reported = 1;
DPRINT1("reporting gdi handle abusers:\n"); DPRINT1("reporting gdi handle abusers:\n");
/* step through GDI handle table and find out who our culprit is... */ /* We've got serious business to do */
for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++) KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
/* Step through GDI handle table and find out who our culprit is... */
for (idx = RESERVE_ENTRIES_COUNT; idx < GDI_HANDLE_COUNT; idx++)
{ {
for (j = 0; j < n; j++) /* If the handle is free, continue */
if (!IS_HANDLE_VALID(idx)) continue;
/* Step through all previous backtraces */
for (j = 0; j < nTraces; j++)
{ {
next: /* Check if the backtrace matches */
J = h[j].idx; if (CompareBacktraces(idx, AllocatorTable[j].idx))
for (k = 0; k < GDI_STACK_LEVELS; k++)
{ {
if (GDIHandleAllocator[i][k] /* It matches, increment count and break out */
!= GDIHandleAllocator[J][k]) AllocatorTable[j].count++;
{ break;
if (++j == n)
goto done;
else
goto next;
}
} }
goto done;
} }
done:
if (j < H) /* Did we find a new backtrace? */
if (j == nTraces)
{ {
if (j == n) /* Break out, if we reached the maximum */
{ if (nTraces == MAX_BACKTRACES) break;
h[j].idx = i;
h[j].count = 1; /* Initialize this entry */
n = n + 1; AllocatorTable[j].idx = idx;
} AllocatorTable[j].count = 1;
else nTraces++;
h[j].count++;
} }
} }
/* bubble sort time! weeeeee!! */ /* bubble sort time! weeeeee!! */
for (i = 0; i < n-1; i++) for (i = 0; i < nTraces-1; i++)
{ {
if (h[i].count < h[i+1].count) if (AllocatorTable[i].count < AllocatorTable[i+1].count)
{ {
struct DbgOpenGDIHandle t; struct DbgOpenGDIHandle temp;
t = h[i+1];
h[i+1] = h[i]; temp = AllocatorTable[i+1];
AllocatorTable[i+1] = AllocatorTable[i];
j = i; j = i;
while (j > 0 && h[j-1].count < t.count) while (j > 0 && AllocatorTable[j-1].count < temp.count)
j--; j--;
h[j] = t; AllocatorTable[j] = temp;
} }
} }
/* print the worst offenders... */
DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", n); /* Print the worst offenders... */
for (i = 0; i < n && h[i].count > 1; i++) DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", nTraces);
for (i = 0; i < nTraces && AllocatorTable[i].count > 1; i++)
{ {
/* Print out the allocation count */ /* Print out the allocation count */
DbgPrint(" %i allocs: ", h[i].count); DbgPrint(" %i allocs, type = 0x%lx:\n",
AllocatorTable[i].count,
GdiHandleTable->Entries[AllocatorTable[i].idx].Type);
/* Dump the frames */ /* Dump the frames */
KeRosDumpStackFrames(GDIHandleAllocator[h[i].idx], GDI_STACK_LEVELS); KeRosDumpStackFrames(GDIHandleAllocator[AllocatorTable[i].idx], GDI_STACK_LEVELS);
//KeRosDumpStackFrames(GDIHandleShareLocker[AllocatorTable[i].idx], GDI_STACK_LEVELS);
/* Print new line for better readability */ /* Print new line for better readability */
DbgPrint("\n"); DbgPrint("\n");
} }
if (i < n && h[i].count == 1)
if (i < nTraces)
DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n"); DbgPrint("(list terminated - the remaining entries have 1 allocation only)\n");
KeLowerIrql(OldIrql);
ASSERT(FALSE);
} }
ULONG ULONG
@ -101,11 +137,13 @@ CaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID)); memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
nFrameCount = RtlCaptureStackBackTrace(1, nFramesToCapture, pFrames, NULL); nFrameCount = RtlWalkFrameChain(pFrames, nFramesToCapture, 0);
if (nFrameCount < nFramesToCapture) if (nFrameCount < nFramesToCapture)
{ {
nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount, nFramesToCapture - nFrameCount, 1); nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount,
nFramesToCapture - nFrameCount,
1);
} }
return nFrameCount; return nFrameCount;