Author: tkreuzer
Date: Fri Feb 20 21:25:10 2015
New Revision: 66374
URL:
http://svn.reactos.org/svn/reactos?rev=66374&view=rev
Log:
[WIN32K]
Add back support for allocator stack backtraces for GDI objects and dump a list of BTs,
when the GDI object table is exhausted. Disabled by default.
Modified:
trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c
trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h
trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c
trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h
trunk/reactos/win32ss/win32kp.h
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c…
==============================================================================
--- trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/ntgdi/gdidbg.c [iso-8859-1] Fri Feb 20 21:25:10 2015
@@ -15,6 +15,7 @@
extern ULONG gulFirstFree;
extern ULONG gulFirstUnused;
+extern PENTRY gpentHmgr;;
ULONG gulLogUnique = 0;
@@ -94,21 +95,64 @@
{L"UserWnd", DbgChUserWnd}
};
-#ifdef GDI_DEBUG
-#if 0
+ULONG
+NTAPI
+DbgCaptureStackBackTace(
+ _Out_writes_(cFramesToCapture) PVOID* ppvFrames,
+ _In_ ULONG cFramesToSkip,
+ _In_ ULONG cFramesToCapture)
+{
+ ULONG cFrameCount;
+ PVOID apvTemp[30];
+ NT_ASSERT(cFramesToCapture <= _countof(apvTemp));
+
+ /* Zero it out */
+ RtlZeroMemory(ppvFrames, cFramesToCapture * sizeof(PVOID));
+
+ /* Capture kernel stack */
+ cFrameCount = RtlWalkFrameChain(apvTemp, _countof(apvTemp), 0);
+
+ /* If we should skip more than we have, we are done */
+ if (cFramesToSkip > cFrameCount)
+ return 0;
+
+ /* Copy, but skip frames */
+ cFrameCount -= cFramesToSkip;
+ cFrameCount = min(cFrameCount, cFramesToCapture);
+ RtlCopyMemory(ppvFrames, &apvTemp[cFramesToSkip], cFrameCount * sizeof(PVOID));
+
+ /* Check if there is still space left */
+ if (cFrameCount < cFramesToCapture)
+ {
+ /* Capture user stack */
+ cFrameCount += RtlWalkFrameChain(&ppvFrames[cFrameCount],
+ cFramesToCapture - cFrameCount,
+ 1);
+ }
+
+ return cFrameCount;
+}
+
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+
static
BOOL
-CompareBacktraces(ULONG idx1, ULONG idx2)
-{
+CompareBacktraces(
+ USHORT idx1,
+ USHORT idx2)
+{
+ POBJ pobj1, pobj2;
ULONG iLevel;
+ /* Get the objects */
+ pobj1 = gpentHmgr[idx1].einfo.pobj;
+ pobj2 = gpentHmgr[idx2].einfo.pobj;
+
/* 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])
+ for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++)
+ {
+ /* If one level doesn't match we are done */
+ if (pobj1->apvBackTrace[iLevel] != pobj2->apvBackTrace[iLevel])
{
return FALSE;
}
@@ -117,22 +161,37 @@
return TRUE;
}
+typedef struct
+{
+ USHORT idx;
+ USHORT iCount;
+} GDI_DBG_HANDLE_BT;
+
VOID
NTAPI
DbgDumpGdiHandleTableWithBT(void)
{
- static int leak_reported = 0;
- int i, j, idx, nTraces = 0;
+ static BOOL bLeakReported = FALSE;
+ ULONG idx, j;
+ BOOL bAlreadyPresent;
+ GDI_DBG_HANDLE_BT aBacktraceTable[GDI_DBG_MAX_BTS];
+ USHORT iCount;
KIRQL OldIrql;
-
- if (leak_reported)
+ POBJ pobj;
+ ULONG iLevel, ulObj;
+
+ /* Only report once */
+ if (bLeakReported)
{
DPRINT1("GDI handle abusers already reported!\n");
return;
}
- leak_reported = 1;
+ bLeakReported = TRUE;
DPRINT1("Reporting GDI handle abusers:\n");
+
+ /* Zero out the table */
+ RtlZeroMemory(aBacktraceTable, sizeof(aBacktraceTable));
/* We've got serious business to do */
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
@@ -141,94 +200,84 @@
for (idx = RESERVE_ENTRIES_COUNT; idx < GDI_HANDLE_COUNT; idx++)
{
/* If the handle is free, continue */
- if (!IS_HANDLE_VALID(idx)) continue;
-
- /* Step through all previous backtraces */
- for (j = 0; j < nTraces; j++)
- {
- /* Check if the backtrace matches */
- if (CompareBacktraces(idx, AllocatorTable[j].idx))
+ if (gpentHmgr[idx].einfo.pobj == 0) continue;
+
+ /* Check if this backtrace is already covered */
+ bAlreadyPresent = FALSE;
+ for (j = RESERVE_ENTRIES_COUNT; j < idx; j++)
+ {
+ if (CompareBacktraces(idx, j))
{
- /* It matches, increment count and break out */
- AllocatorTable[j].count++;
+ bAlreadyPresent = TRUE;
break;
}
}
- /* Did we find a new backtrace? */
- if (j == nTraces)
- {
- /* Break out, if we reached the maximum */
- if (nTraces == MAX_BACKTRACES) break;
-
- /* Initialize this entry */
- AllocatorTable[j].idx = idx;
- AllocatorTable[j].count = 1;
- nTraces++;
- }
- }
-
- /* bubble sort time! weeeeee!! */
- for (i = 0; i < nTraces-1; i++)
- {
- if (AllocatorTable[i].count < AllocatorTable[i+1].count)
- {
- struct DbgOpenGDIHandle temp;
-
- temp = AllocatorTable[i+1];
- AllocatorTable[i+1] = AllocatorTable[i];
- j = i;
- while (j > 0 && AllocatorTable[j-1].count < temp.count)
- j--;
- AllocatorTable[j] = temp;
+ if (bAlreadyPresent) continue;
+
+ /* We don't have this BT yet, count how often it is present */
+ iCount = 1;
+ for (j = idx + 1; j < GDI_HANDLE_COUNT; j++)
+ {
+ if (CompareBacktraces(idx, j))
+ {
+ iCount++;
+ }
+ }
+
+ /* Now add this backtrace */
+ for (j = 0; j < GDI_DBG_MAX_BTS; j++)
+ {
+ /* Insert it below the next smaller count */
+ if (aBacktraceTable[j].iCount < iCount)
+ {
+ /* Check if there are entries above */
+ if (j < GDI_DBG_MAX_BTS - 1)
+ {
+ /* Move the following entries up by 1 */
+ RtlMoveMemory(&aBacktraceTable[j],
+ &aBacktraceTable[j + 1],
+ GDI_DBG_MAX_BTS - j - 1);
+ }
+
+ /* Set this entry */
+ aBacktraceTable[j].idx = idx;
+ aBacktraceTable[j].iCount = iCount;
+
+ /* We are done here */
+ break;
+ }
}
}
/* Print the worst offenders... */
- 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 */
- DbgPrint(" %i allocs, type = 0x%lx:\n",
- AllocatorTable[i].count,
- GdiHandleTable->Entries[AllocatorTable[i].idx].Type);
-
- /* Dump the frames */
- KeRosDumpStackFrames(GDIHandleAllocator[AllocatorTable[i].idx],
GDI_STACK_LEVELS);
- //KeRosDumpStackFrames(GDIHandleShareLocker[AllocatorTable[i].idx],
GDI_STACK_LEVELS);
-
- /* Print new line for better readability */
+ DbgPrint("Count Handle Backtrace\n");
+ DbgPrint("------------------------------------------------\n");
+ for (j = 0; j < GDI_DBG_MAX_BTS; j++)
+ {
+ idx = aBacktraceTable[j].idx;
+ if (idx == 0)
+ break;
+
+ ulObj = ((ULONG)gpentHmgr[idx].FullUnique << 16) | idx;
+ pobj = gpentHmgr[idx].einfo.pobj;
+
+ DbgPrint("%5d %08lx ", aBacktraceTable[j].iCount, ulObj);
+ for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++)
+ {
+ DbgPrint("%p,", pobj->apvBackTrace[iLevel]);
+ }
DbgPrint("\n");
}
- if (i < nTraces)
- DbgPrint("(List terminated - the remaining entries have 1 allocation
only)\n");
+ __debugbreak();
KeLowerIrql(OldIrql);
-
- ASSERT(FALSE);
-}
-#endif
-
-ULONG
-NTAPI
-DbgCaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
-{
- ULONG nFrameCount;
-
- memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
-
- nFrameCount = RtlWalkFrameChain(pFrames, nFramesToCapture, 0);
-
- if (nFrameCount < nFramesToCapture)
- {
- nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount,
- nFramesToCapture - nFrameCount,
- 1);
- }
-
- return nFrameCount;
-}
+}
+
+#endif /* DBG_ENABLE_GDIOBJ_BACKTRACES */
+
+#if DBG
BOOL
NTAPI
@@ -352,32 +401,10 @@
return r;
}
-#endif /* GDI_DEBUG */
-
-VOID
-NTAPI
-DbgDumpLockedGdiHandles()
-{
-#if 0
- ULONG i;
-
- for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
- {
- PENTRY pentry = &gpentHmgr[i];
-
- if (pentry->Objt)
- {
- POBJ pobj = pentry->einfo.pobj;
- if (pobj->cExclusiveLock > 0)
- {
- DPRINT1("Locked object: %lx, type = %lx. allocated from:\n",
- i, pentry->Objt);
- DBG_DUMP_EVENT_LIST(&pobj->slhLog);
- }
- }
- }
-#endif
-}
+#endif /* DBG */
+
+
+#if DBG_ENABLE_EVENT_LOGGING
VOID
NTAPI
@@ -400,7 +427,7 @@
pLogEntry->lParam = lParam;
/* Capture a backtrace */
- DbgCaptureStackBackTace(pLogEntry->apvBackTrace, 20);
+ DbgCaptureStackBackTace(pLogEntry->apvBackTrace, 1, 20);
switch (nEventType)
{
@@ -483,6 +510,33 @@
}
}
+#endif /* DBG_ENABLE_EVENT_LOGGING */
+
+#if 1 || DBG_ENABLE_SERVICE_HOOKS
+
+VOID
+NTAPI
+DbgDumpLockedGdiHandles()
+{
+ ULONG i;
+
+ for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
+ {
+ PENTRY pentry = &gpentHmgr[i];
+
+ if (pentry->Objt)
+ {
+ POBJ pobj = pentry->einfo.pobj;
+ if (pobj->cExclusiveLock > 0)
+ {
+ DPRINT1("Locked object: %lx, type = %lx. allocated from:\n",
+ i, pentry->Objt);
+ DBG_DUMP_EVENT_LIST(&pobj->slhLog);
+ }
+ }
+ }
+}
+
void
NTAPI
GdiDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
@@ -512,6 +566,9 @@
}
return ulResult;
}
+
+#endif /* DBG_ENABLE_SERVICE_HOOKS */
+
NTSTATUS NTAPI
QueryEnvironmentVariable(PUNICODE_STRING Name,
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdidebug…
==============================================================================
--- trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/ntgdi/gdidebug.h [iso-8859-1] Fri Feb 20 21:25:10 2015
@@ -1,4 +1,61 @@
#pragma once
+
+#define GDI_DBG_MAX_BTS 10
+
+#if DBG
+#define ASSERT_NOGDILOCKS() GdiDbgAssertNoLocks(__FILE__,__LINE__)
+#define KeRosDumpStackFrames(Frames, Count) \
+ KdSystemDebugControl('DsoR', (PVOID)Frames, Count, NULL, 0, NULL,
KernelMode)
+#else
+#define ASSERT_NOGDILOCKS()
+#define KeRosDumpStackFrames(Frames, Count)
+#endif
+
+NTSYSAPI
+ULONG
+APIENTRY
+RtlWalkFrameChain(
+ _Out_ PVOID *Callers,
+ _In_ ULONG Count,
+ _In_ ULONG Flags);
+
+ULONG
+NTAPI
+DbgCaptureStackBackTace(
+ _Out_writes_(cFramesToCapture) PVOID* ppvFrames,
+ _In_ ULONG cFramesToSkip,
+ _In_ ULONG cFramesToCapture);
+
+BOOL
+NTAPI
+DbgGdiHTIntegrityCheck(
+ VOID);
+
+VOID
+NTAPI
+DbgDumpLockedGdiHandles(
+ VOID);
+
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+
+VOID
+NTAPI
+DbgDumpGdiHandleTableWithBT(VOID);
+
+#endif
+
+#if KDBG
+
+BOOLEAN
+NTAPI
+DbgGdiKdbgCliCallback(
+ _In_ PCHAR Command,
+ _In_ ULONG Argc,
+ _In_ PCH Argv[]);
+
+#endif
+
+#if DBG_ENABLE_EVENT_LOGGING
typedef enum _LOG_EVENT_TYPE
{
@@ -28,39 +85,41 @@
} data;
} LOGENTRY, *PLOGENTRY;
-#if KDBG
-BOOLEAN
+VOID
NTAPI
-DbgGdiKdbgCliCallback(
- IN PCHAR Command,
- IN ULONG Argc,
- IN PCH Argv[]);
-#endif
+DbgDumpEventList(
+ _Inout_ PSLIST_HEADER pslh);
-#if DBG_ENABLE_EVENT_LOGGING
-VOID NTAPI DbgDumpEventList(PSLIST_HEADER pslh);
-VOID NTAPI DbgLogEvent(PSLIST_HEADER pslh, LOG_EVENT_TYPE nEventType, LPARAM lParam);
-VOID NTAPI DbgCleanupEventList(PSLIST_HEADER pslh);
-VOID NTAPI DbgPrintEvent(PLOGENTRY pLogEntry);
+VOID
+NTAPI
+DbgLogEvent(
+ _Inout_ PSLIST_HEADER pslh,
+ _In_ LOG_EVENT_TYPE nEventType,
+ _In_ LPARAM lParam);
+
+VOID
+NTAPI
+DbgCleanupEventList(
+ _Inout_ PSLIST_HEADER pslh);
+
+VOID
+NTAPI
+DbgPrintEvent(
+ _Inout_ PLOGENTRY pLogEntry);
+
#define DBG_LOGEVENT(pslh, type, val) DbgLogEvent(pslh, type, (ULONG_PTR)val)
#define DBG_INITLOG(pslh) InitializeSListHead(pslh)
#define DBG_DUMP_EVENT_LIST(pslh) DbgDumpEventList(pslh)
#define DBG_CLEANUP_EVENT_LIST(pslh) DbgCleanupEventList(pslh)
+
#else
+
#define DBG_LOGEVENT(pslh, type, val) ((void)(val))
#define DBG_INITLOG(pslh)
#define DBG_DUMP_EVENT_LIST(pslh)
#define DBG_CLEANUP_EVENT_LIST(pslh)
+
#endif
-
-
-VOID NTAPI DbgDumpGdiHandleTableWithBT(VOID);
-ULONG NTAPI DbgCaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture);
-BOOL NTAPI DbgGdiHTIntegrityCheck(VOID);
-VOID NTAPI DbgDumpLockedGdiHandles(VOID);
-
-#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);
#if DBG
void
@@ -88,9 +147,6 @@
ASSERT(FALSE);
}
}
-
-#define ASSERT_NOGDILOCKS() GdiDbgAssertNoLocks(__FILE__,__LINE__)
-#else
-#define ASSERT_NOGDILOCKS()
#endif
+
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c…
==============================================================================
--- trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/ntgdi/gdiobj.c [iso-8859-1] Fri Feb 20 21:25:10 2015
@@ -339,6 +339,10 @@
if (iFirst >= GDI_HANDLE_COUNT)
{
DPRINT1("No more GDI handles left!\n");
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+ DbgDumpGdiHandleTableWithBT();
+#endif
+ InterlockedDecrement((LONG*)&gulFirstUnused);
return 0;
}
@@ -350,7 +354,7 @@
pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
/* Create a new value with an increased sequence number */
- iNext = (USHORT)(ULONG_PTR)pentFree->einfo.pobj;
+ iNext = GDI_HANDLE_GET_INDEX(pentFree->einfo.hFree);
iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
/* Try to exchange the FirstFree value */
@@ -516,6 +520,9 @@
pobj->BaseFlags = fl & 0xffff;
DBG_INITLOG(&pobj->slhLog);
DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+ DbgCaptureStackBackTace(pobj->apvBackTrace, 1, GDI_OBJECT_STACK_LEVELS);
+#endif /* GDI_DEBUG */
return pobj;
}
@@ -1497,9 +1504,7 @@
}
#if DBG
-//#ifdef GDI_DEBUG
- DbgGdiHTIntegrityCheck();
-//#endif
+ DbgGdiHTIntegrityCheck();
#endif
ppi = PsGetCurrentProcessWin32Process();
Modified: trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h…
==============================================================================
--- trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/ntgdi/gdiobj.h [iso-8859-1] Fri Feb 20 21:25:10 2015
@@ -4,6 +4,8 @@
*/
#pragma once
+
+#define GDI_OBJECT_STACK_LEVELS 10
/* The first 10 entries are never used in windows, they are empty */
static const unsigned RESERVE_ENTRIES_COUNT = 10;
@@ -42,6 +44,9 @@
USHORT cExclusiveLock;
USHORT BaseFlags;
EX_PUSH_LOCK pushlock;
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+ PVOID apvBackTrace[GDI_OBJECT_STACK_LEVELS];
+#endif
#if DBG_ENABLE_EVENT_LOGGING
SLIST_HEADER slhLog;
#endif
Modified: trunk/reactos/win32ss/win32kp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/win32kp.h?rev=6637…
==============================================================================
--- trunk/reactos/win32ss/win32kp.h [iso-8859-1] (original)
+++ trunk/reactos/win32ss/win32kp.h [iso-8859-1] Fri Feb 20 21:25:10 2015
@@ -23,6 +23,7 @@
/* Enable debugging features */
#define GDI_DEBUG 0
+#define DBG_ENABLE_GDIOBJ_BACKTRACES 0
#define DBG_ENABLE_EVENT_LOGGING 0
#define DBG_ENABLE_SERVICE_HOOKS 0