mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 20:56:04 +00:00
[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. svn path=/trunk/; revision=66374
This commit is contained in:
parent
e154160e2f
commit
ac84f94b5d
5 changed files with 251 additions and 127 deletions
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
extern ULONG gulFirstFree;
|
extern ULONG gulFirstFree;
|
||||||
extern ULONG gulFirstUnused;
|
extern ULONG gulFirstUnused;
|
||||||
|
extern PENTRY gpentHmgr;;
|
||||||
|
|
||||||
ULONG gulLogUnique = 0;
|
ULONG gulLogUnique = 0;
|
||||||
|
|
||||||
|
@ -94,21 +95,64 @@ DBG_CHANNEL DbgChannels[DbgChCount]={
|
||||||
{L"UserWnd", DbgChUserWnd}
|
{L"UserWnd", DbgChUserWnd}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef GDI_DEBUG
|
ULONG
|
||||||
#if 0
|
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
|
static
|
||||||
BOOL
|
BOOL
|
||||||
CompareBacktraces(ULONG idx1, ULONG idx2)
|
CompareBacktraces(
|
||||||
|
USHORT idx1,
|
||||||
|
USHORT idx2)
|
||||||
{
|
{
|
||||||
|
POBJ pobj1, pobj2;
|
||||||
ULONG iLevel;
|
ULONG iLevel;
|
||||||
|
|
||||||
|
/* Get the objects */
|
||||||
|
pobj1 = gpentHmgr[idx1].einfo.pobj;
|
||||||
|
pobj2 = gpentHmgr[idx2].einfo.pobj;
|
||||||
|
|
||||||
/* Loop all stack levels */
|
/* Loop all stack levels */
|
||||||
for (iLevel = 0; iLevel < GDI_STACK_LEVELS; iLevel++)
|
for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++)
|
||||||
{
|
{
|
||||||
if (GDIHandleAllocator[idx1][iLevel]
|
/* If one level doesn't match we are done */
|
||||||
!= GDIHandleAllocator[idx2][iLevel])
|
if (pobj1->apvBackTrace[iLevel] != pobj2->apvBackTrace[iLevel])
|
||||||
// if (GDIHandleShareLocker[idx1][iLevel]
|
|
||||||
// != GDIHandleShareLocker[idx2][iLevel])
|
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -117,23 +161,38 @@ CompareBacktraces(ULONG idx1, ULONG idx2)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
USHORT idx;
|
||||||
|
USHORT iCount;
|
||||||
|
} GDI_DBG_HANDLE_BT;
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
DbgDumpGdiHandleTableWithBT(void)
|
DbgDumpGdiHandleTableWithBT(void)
|
||||||
{
|
{
|
||||||
static int leak_reported = 0;
|
static BOOL bLeakReported = FALSE;
|
||||||
int i, j, idx, nTraces = 0;
|
ULONG idx, j;
|
||||||
|
BOOL bAlreadyPresent;
|
||||||
|
GDI_DBG_HANDLE_BT aBacktraceTable[GDI_DBG_MAX_BTS];
|
||||||
|
USHORT iCount;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
POBJ pobj;
|
||||||
|
ULONG iLevel, ulObj;
|
||||||
|
|
||||||
if (leak_reported)
|
/* Only report once */
|
||||||
|
if (bLeakReported)
|
||||||
{
|
{
|
||||||
DPRINT1("GDI handle abusers already reported!\n");
|
DPRINT1("GDI handle abusers already reported!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
leak_reported = 1;
|
bLeakReported = TRUE;
|
||||||
DPRINT1("Reporting GDI handle abusers:\n");
|
DPRINT1("Reporting GDI handle abusers:\n");
|
||||||
|
|
||||||
|
/* Zero out the table */
|
||||||
|
RtlZeroMemory(aBacktraceTable, sizeof(aBacktraceTable));
|
||||||
|
|
||||||
/* We've got serious business to do */
|
/* We've got serious business to do */
|
||||||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||||||
|
|
||||||
|
@ -141,94 +200,84 @@ DbgDumpGdiHandleTableWithBT(void)
|
||||||
for (idx = RESERVE_ENTRIES_COUNT; idx < GDI_HANDLE_COUNT; idx++)
|
for (idx = RESERVE_ENTRIES_COUNT; idx < GDI_HANDLE_COUNT; idx++)
|
||||||
{
|
{
|
||||||
/* If the handle is free, continue */
|
/* If the handle is free, continue */
|
||||||
if (!IS_HANDLE_VALID(idx)) continue;
|
if (gpentHmgr[idx].einfo.pobj == 0) continue;
|
||||||
|
|
||||||
/* Step through all previous backtraces */
|
/* Check if this backtrace is already covered */
|
||||||
for (j = 0; j < nTraces; j++)
|
bAlreadyPresent = FALSE;
|
||||||
|
for (j = RESERVE_ENTRIES_COUNT; j < idx; j++)
|
||||||
{
|
{
|
||||||
/* Check if the backtrace matches */
|
if (CompareBacktraces(idx, j))
|
||||||
if (CompareBacktraces(idx, AllocatorTable[j].idx))
|
|
||||||
{
|
{
|
||||||
/* It matches, increment count and break out */
|
bAlreadyPresent = TRUE;
|
||||||
AllocatorTable[j].count++;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Did we find a new backtrace? */
|
if (bAlreadyPresent) continue;
|
||||||
if (j == nTraces)
|
|
||||||
{
|
|
||||||
/* Break out, if we reached the maximum */
|
|
||||||
if (nTraces == MAX_BACKTRACES) break;
|
|
||||||
|
|
||||||
/* Initialize this entry */
|
/* We don't have this BT yet, count how often it is present */
|
||||||
AllocatorTable[j].idx = idx;
|
iCount = 1;
|
||||||
AllocatorTable[j].count = 1;
|
for (j = idx + 1; j < GDI_HANDLE_COUNT; j++)
|
||||||
nTraces++;
|
{
|
||||||
|
if (CompareBacktraces(idx, j))
|
||||||
|
{
|
||||||
|
iCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bubble sort time! weeeeee!! */
|
/* Now add this backtrace */
|
||||||
for (i = 0; i < nTraces-1; i++)
|
for (j = 0; j < GDI_DBG_MAX_BTS; j++)
|
||||||
{
|
{
|
||||||
if (AllocatorTable[i].count < AllocatorTable[i+1].count)
|
/* Insert it below the next smaller count */
|
||||||
|
if (aBacktraceTable[j].iCount < iCount)
|
||||||
{
|
{
|
||||||
struct DbgOpenGDIHandle temp;
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
temp = AllocatorTable[i+1];
|
/* Set this entry */
|
||||||
AllocatorTable[i+1] = AllocatorTable[i];
|
aBacktraceTable[j].idx = idx;
|
||||||
j = i;
|
aBacktraceTable[j].iCount = iCount;
|
||||||
while (j > 0 && AllocatorTable[j-1].count < temp.count)
|
|
||||||
j--;
|
/* We are done here */
|
||||||
AllocatorTable[j] = temp;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the worst offenders... */
|
/* Print the worst offenders... */
|
||||||
DbgPrint("Worst GDI Handle leak offenders (out of %i unique locations):\n", nTraces);
|
DbgPrint("Count Handle Backtrace\n");
|
||||||
for (i = 0; i < nTraces && AllocatorTable[i].count > 1; i++)
|
DbgPrint("------------------------------------------------\n");
|
||||||
|
for (j = 0; j < GDI_DBG_MAX_BTS; j++)
|
||||||
{
|
{
|
||||||
/* Print out the allocation count */
|
idx = aBacktraceTable[j].idx;
|
||||||
DbgPrint(" %i allocs, type = 0x%lx:\n",
|
if (idx == 0)
|
||||||
AllocatorTable[i].count,
|
break;
|
||||||
GdiHandleTable->Entries[AllocatorTable[i].idx].Type);
|
|
||||||
|
|
||||||
/* Dump the frames */
|
ulObj = ((ULONG)gpentHmgr[idx].FullUnique << 16) | idx;
|
||||||
KeRosDumpStackFrames(GDIHandleAllocator[AllocatorTable[i].idx], GDI_STACK_LEVELS);
|
pobj = gpentHmgr[idx].einfo.pobj;
|
||||||
//KeRosDumpStackFrames(GDIHandleShareLocker[AllocatorTable[i].idx], GDI_STACK_LEVELS);
|
|
||||||
|
|
||||||
/* Print new line for better readability */
|
DbgPrint("%5d %08lx ", aBacktraceTable[j].iCount, ulObj);
|
||||||
|
for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++)
|
||||||
|
{
|
||||||
|
DbgPrint("%p,", pobj->apvBackTrace[iLevel]);
|
||||||
|
}
|
||||||
DbgPrint("\n");
|
DbgPrint("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < nTraces)
|
__debugbreak();
|
||||||
DbgPrint("(List terminated - the remaining entries have 1 allocation only)\n");
|
|
||||||
|
|
||||||
KeLowerIrql(OldIrql);
|
KeLowerIrql(OldIrql);
|
||||||
|
|
||||||
ASSERT(FALSE);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
ULONG
|
#endif /* DBG_ENABLE_GDIOBJ_BACKTRACES */
|
||||||
NTAPI
|
|
||||||
DbgCaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
|
|
||||||
{
|
|
||||||
ULONG nFrameCount;
|
|
||||||
|
|
||||||
memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
|
#if DBG
|
||||||
|
|
||||||
nFrameCount = RtlWalkFrameChain(pFrames, nFramesToCapture, 0);
|
|
||||||
|
|
||||||
if (nFrameCount < nFramesToCapture)
|
|
||||||
{
|
|
||||||
nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount,
|
|
||||||
nFramesToCapture - nFrameCount,
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nFrameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -352,32 +401,10 @@ DbgGdiHTIntegrityCheck()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* GDI_DEBUG */
|
#endif /* DBG */
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
DbgDumpLockedGdiHandles()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
ULONG i;
|
|
||||||
|
|
||||||
for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++)
|
#if DBG_ENABLE_EVENT_LOGGING
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -400,7 +427,7 @@ DbgLogEvent(PSLIST_HEADER pslh, LOG_EVENT_TYPE nEventType, LPARAM lParam)
|
||||||
pLogEntry->lParam = lParam;
|
pLogEntry->lParam = lParam;
|
||||||
|
|
||||||
/* Capture a backtrace */
|
/* Capture a backtrace */
|
||||||
DbgCaptureStackBackTace(pLogEntry->apvBackTrace, 20);
|
DbgCaptureStackBackTace(pLogEntry->apvBackTrace, 1, 20);
|
||||||
|
|
||||||
switch (nEventType)
|
switch (nEventType)
|
||||||
{
|
{
|
||||||
|
@ -483,6 +510,33 @@ DbgCleanupEventList(PSLIST_HEADER pslh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
void
|
||||||
NTAPI
|
NTAPI
|
||||||
GdiDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
|
GdiDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
|
||||||
|
@ -513,6 +567,9 @@ GdiDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
|
||||||
return ulResult;
|
return ulResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* DBG_ENABLE_SERVICE_HOOKS */
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
QueryEnvironmentVariable(PUNICODE_STRING Name,
|
QueryEnvironmentVariable(PUNICODE_STRING Name,
|
||||||
PUNICODE_STRING Value)
|
PUNICODE_STRING Value)
|
||||||
|
|
|
@ -1,5 +1,62 @@
|
||||||
#pragma once
|
#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
|
typedef enum _LOG_EVENT_TYPE
|
||||||
{
|
{
|
||||||
EVENT_ALLOCATE,
|
EVENT_ALLOCATE,
|
||||||
|
@ -28,40 +85,42 @@ typedef struct _LOGENTRY
|
||||||
} data;
|
} data;
|
||||||
} LOGENTRY, *PLOGENTRY;
|
} LOGENTRY, *PLOGENTRY;
|
||||||
|
|
||||||
#if KDBG
|
VOID
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
NTAPI
|
||||||
DbgGdiKdbgCliCallback(
|
DbgDumpEventList(
|
||||||
IN PCHAR Command,
|
_Inout_ PSLIST_HEADER pslh);
|
||||||
IN ULONG Argc,
|
|
||||||
IN PCH Argv[]);
|
VOID
|
||||||
#endif
|
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);
|
||||||
|
|
||||||
#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);
|
|
||||||
#define DBG_LOGEVENT(pslh, type, val) DbgLogEvent(pslh, type, (ULONG_PTR)val)
|
#define DBG_LOGEVENT(pslh, type, val) DbgLogEvent(pslh, type, (ULONG_PTR)val)
|
||||||
#define DBG_INITLOG(pslh) InitializeSListHead(pslh)
|
#define DBG_INITLOG(pslh) InitializeSListHead(pslh)
|
||||||
#define DBG_DUMP_EVENT_LIST(pslh) DbgDumpEventList(pslh)
|
#define DBG_DUMP_EVENT_LIST(pslh) DbgDumpEventList(pslh)
|
||||||
#define DBG_CLEANUP_EVENT_LIST(pslh) DbgCleanupEventList(pslh)
|
#define DBG_CLEANUP_EVENT_LIST(pslh) DbgCleanupEventList(pslh)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DBG_LOGEVENT(pslh, type, val) ((void)(val))
|
#define DBG_LOGEVENT(pslh, type, val) ((void)(val))
|
||||||
#define DBG_INITLOG(pslh)
|
#define DBG_INITLOG(pslh)
|
||||||
#define DBG_DUMP_EVENT_LIST(pslh)
|
#define DBG_DUMP_EVENT_LIST(pslh)
|
||||||
#define DBG_CLEANUP_EVENT_LIST(pslh)
|
#define DBG_CLEANUP_EVENT_LIST(pslh)
|
||||||
|
|
||||||
#endif
|
#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
|
#if DBG
|
||||||
void
|
void
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -88,9 +147,6 @@ GdiDbgAssertNoLocks(char * pszFile, ULONG nLine)
|
||||||
ASSERT(FALSE);
|
ASSERT(FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASSERT_NOGDILOCKS() GdiDbgAssertNoLocks(__FILE__,__LINE__)
|
|
||||||
#else
|
|
||||||
#define ASSERT_NOGDILOCKS()
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -339,6 +339,10 @@ ENTRY_pentPopFreeEntry(VOID)
|
||||||
if (iFirst >= GDI_HANDLE_COUNT)
|
if (iFirst >= GDI_HANDLE_COUNT)
|
||||||
{
|
{
|
||||||
DPRINT1("No more GDI handles left!\n");
|
DPRINT1("No more GDI handles left!\n");
|
||||||
|
#if DBG_ENABLE_GDIOBJ_BACKTRACES
|
||||||
|
DbgDumpGdiHandleTableWithBT();
|
||||||
|
#endif
|
||||||
|
InterlockedDecrement((LONG*)&gulFirstUnused);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +354,7 @@ ENTRY_pentPopFreeEntry(VOID)
|
||||||
pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
|
pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
|
||||||
|
|
||||||
/* Create a new value with an increased sequence number */
|
/* 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;
|
iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
|
||||||
|
|
||||||
/* Try to exchange the FirstFree value */
|
/* Try to exchange the FirstFree value */
|
||||||
|
@ -516,6 +520,9 @@ GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
|
||||||
pobj->BaseFlags = fl & 0xffff;
|
pobj->BaseFlags = fl & 0xffff;
|
||||||
DBG_INITLOG(&pobj->slhLog);
|
DBG_INITLOG(&pobj->slhLog);
|
||||||
DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
|
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;
|
return pobj;
|
||||||
}
|
}
|
||||||
|
@ -1497,9 +1504,7 @@ GDI_CleanupForProcess(struct _EPROCESS *Process)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DBG
|
#if DBG
|
||||||
//#ifdef GDI_DEBUG
|
|
||||||
DbgGdiHTIntegrityCheck();
|
DbgGdiHTIntegrityCheck();
|
||||||
//#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ppi = PsGetCurrentProcessWin32Process();
|
ppi = PsGetCurrentProcessWin32Process();
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define GDI_OBJECT_STACK_LEVELS 10
|
||||||
|
|
||||||
/* The first 10 entries are never used in windows, they are empty */
|
/* The first 10 entries are never used in windows, they are empty */
|
||||||
static const unsigned RESERVE_ENTRIES_COUNT = 10;
|
static const unsigned RESERVE_ENTRIES_COUNT = 10;
|
||||||
|
|
||||||
|
@ -42,6 +44,9 @@ typedef struct _BASEOBJECT
|
||||||
USHORT cExclusiveLock;
|
USHORT cExclusiveLock;
|
||||||
USHORT BaseFlags;
|
USHORT BaseFlags;
|
||||||
EX_PUSH_LOCK pushlock;
|
EX_PUSH_LOCK pushlock;
|
||||||
|
#if DBG_ENABLE_GDIOBJ_BACKTRACES
|
||||||
|
PVOID apvBackTrace[GDI_OBJECT_STACK_LEVELS];
|
||||||
|
#endif
|
||||||
#if DBG_ENABLE_EVENT_LOGGING
|
#if DBG_ENABLE_EVENT_LOGGING
|
||||||
SLIST_HEADER slhLog;
|
SLIST_HEADER slhLog;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
/* Enable debugging features */
|
/* Enable debugging features */
|
||||||
#define GDI_DEBUG 0
|
#define GDI_DEBUG 0
|
||||||
|
#define DBG_ENABLE_GDIOBJ_BACKTRACES 0
|
||||||
#define DBG_ENABLE_EVENT_LOGGING 0
|
#define DBG_ENABLE_EVENT_LOGGING 0
|
||||||
#define DBG_ENABLE_SERVICE_HOOKS 0
|
#define DBG_ENABLE_SERVICE_HOOKS 0
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue