You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1277 lines
33 KiB
1277 lines
33 KiB
|
|
/******************************Module*Header*******************************\
|
|
* Module Name: callback.cxx
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
#include "precomp.hxx"
|
|
|
|
|
|
BOOL gbCallbacksPrintNewline = FALSE;
|
|
int gCallbacksPrintNameWidth = -1;
|
|
NTSTATUS gCallbackReturnValue = STATUS_SUCCESS;
|
|
|
|
|
|
ULONG FieldCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
dprintf(" ** FieldCallback(%lx, %lx) **\n", pField, UserContext);
|
|
if (pField)
|
|
{
|
|
dprintf(" Field:\n");
|
|
dprintf(" fName : %s\n", pField->fName);
|
|
dprintf(" printName : %s\n", pField->printName);
|
|
dprintf(" size : %d\n", pField->size);
|
|
dprintf(" fOptions : %#x\n", pField->fOptions);
|
|
dprintf(" address : %#I64x\n", pField->address);
|
|
dprintf(" fieldCallBack: %lx\n", pField->fieldCallBack);
|
|
}
|
|
if (UserContext)
|
|
{
|
|
dprintf(" UserContext: ???\n");
|
|
}
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* PrintName
|
|
*
|
|
* Prints the field name or print name if callbacks are supposed to.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PrintName(PFIELD_INFO pField)
|
|
{
|
|
if (pField)
|
|
{
|
|
if (gCallbacksPrintNameWidth >= 0)
|
|
{
|
|
if (pField->printName)
|
|
{
|
|
dprintf("%*s", gCallbacksPrintNameWidth, pField->printName);
|
|
}
|
|
else if (pField->fName)
|
|
{
|
|
dprintf("%*s", gCallbacksPrintNameWidth, pField->fName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pField->fOptions & DBG_DUMP_FIELD_NO_PRINT)
|
|
{
|
|
if (pField->printName)
|
|
{
|
|
dprintf(" +0x___ %s ", pField->printName);
|
|
}
|
|
else if (pField->fName)
|
|
{
|
|
dprintf(" +0x___ %s ", pField->fName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* NextItemCallbackInit
|
|
*
|
|
* Specify printing and validation info to NextItemCallbacks.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL PrintItemHeader = FALSE;
|
|
char szItemHeader[512] = "";
|
|
ULONG64 LastItemExpected = 0;
|
|
BOOL FoundLastItemExpected = FALSE;
|
|
|
|
void NextItemCallbackInit(
|
|
const char *pszPrintHeader,
|
|
ULONG64 LastItemAddr
|
|
)
|
|
{
|
|
if (pszPrintHeader != NULL)
|
|
{
|
|
strncpy(szItemHeader, pszPrintHeader, sizeof(szItemHeader));
|
|
szItemHeader[sizeof(szItemHeader)-1] = 0;
|
|
PrintItemHeader = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PrintItemHeader = FALSE;
|
|
}
|
|
|
|
LastItemExpected = LastItemAddr;
|
|
FoundLastItemExpected = (LastItemExpected == 0);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* LastCallbackItemFound
|
|
*
|
|
* Returns TRUE if address specified in NextItemCallbackInit was found.
|
|
* Note: Always returns TRUE if 0 was specified for address.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL LastCallbackItemFound()
|
|
{
|
|
return FoundLastItemExpected;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* NextItemCallback
|
|
*
|
|
* Use with linked list dumping when initial address is the first item's.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG NextItemCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
ULONG64 NextAddr = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
dprintf("Error: NextItemCallback was given NULL pField.\n");
|
|
}
|
|
else
|
|
{
|
|
if (pField->address == 0)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
if (LastItemExpected != 0)
|
|
{
|
|
if (FoundLastItemExpected)
|
|
{
|
|
dprintf(" * Error: Next item is beyond last expected @ %#p\n", LastItemExpected);
|
|
}
|
|
else if (LastItemExpected == pField->address)
|
|
{
|
|
FoundLastItemExpected = TRUE;
|
|
}
|
|
}
|
|
|
|
if (PrintItemHeader)
|
|
{
|
|
dprintf(szItemHeader);
|
|
dprintf("%#p\n", pField->address);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* PointerToNextItemCallback
|
|
*
|
|
* Use with linked list dumping when initial address is a pointer to type.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG PointerToNextItemCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
ULONG64 NextAddr = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
dprintf("Error: PointerToNextItemCallback was given NULL pField.\n");
|
|
}
|
|
else
|
|
{
|
|
if (pField->address == 0)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
if (!ReadPointer(pField->address, &NextAddr) || NextAddr == 0)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
if (LastItemExpected != 0)
|
|
{
|
|
if (FoundLastItemExpected)
|
|
{
|
|
dprintf(" * Error: Next item is beyond last expected @ %#p\n", LastItemExpected);
|
|
}
|
|
else if (LastItemExpected == NextAddr)
|
|
{
|
|
FoundLastItemExpected = TRUE;
|
|
}
|
|
}
|
|
|
|
if (PrintItemHeader)
|
|
{
|
|
dprintf(szItemHeader);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* ArrayCallback
|
|
*
|
|
* Use with array dumping.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG ArrayCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
static PFIELD_INFO ArrayField = NULL;
|
|
static ULONG ArrayIndex = 0;
|
|
static ULONG ArrayIndexWidth;
|
|
|
|
if (pField != ArrayField || pField->size <= ArrayIndex)
|
|
{
|
|
ArrayField = pField;
|
|
|
|
if (ArrayIndex != 0 && gbVerbose)
|
|
{
|
|
dprintf("Warning: Beginning new array w/o completing last.\n");
|
|
}
|
|
ArrayIndex = 0;
|
|
}
|
|
|
|
if (ArrayIndex == 0)
|
|
{
|
|
ULONG i = pField->size-1;
|
|
ArrayIndexWidth = 1;
|
|
dprintf("Idx");
|
|
while (i /= 10)
|
|
{
|
|
dprintf(" ");
|
|
ArrayIndexWidth++;
|
|
}
|
|
|
|
PrintName(pField);
|
|
}
|
|
|
|
dprintf("\n[%*u]", ArrayIndexWidth, ArrayIndex++);
|
|
|
|
// If we hit the end of an array,
|
|
// prepare for a new array.
|
|
if (pField->size == ArrayIndex)
|
|
{
|
|
ArrayField = NULL;
|
|
ArrayIndex = 0;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* NewlineCallback
|
|
*
|
|
* To be used with DBG_DUMP_COMPACT_OUT as default callback.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG NewlineCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
dprintf("\n");
|
|
|
|
if (!gbCallbacksPrintNewline && gbVerbose)
|
|
{
|
|
dprintf(" Note: NewlineCallback called, but gbCallbacksPrintNewline is FALSE.\n");
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* AddressPrintCallback
|
|
*
|
|
* Useful with DBG_DUMP_FIELD_RETURN_ADDRESS when the field is
|
|
* a large embedded structure you don't want to print.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG AddressPrintCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: AddressPrintCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose) dprintf(" (pField->size = %d) ", pField->size);
|
|
dprintf("%#p", pField->address);
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Basic Type Callbacks:
|
|
* BOOL, BYTE, CHAR, DecimalCHAR, DecimalUCHAR,
|
|
* DWORD, LONG, SHORT, WORD, ULONG, USHORT
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG BOOLCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%s", ((BOOL)pField->address) ? "TRUE" : "FALSE");
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG BYTECallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("0x%2.2X", (BYTE)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG CHARCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("'%c'", (CHAR)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG DecimalCHARCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%d", (CHAR)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG DecimalUCHARCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%u", (UCHAR)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG DWORDCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("0x%8.8lX", (DWORD)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG LONGCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%ld", (LONG)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG WORDCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("0x%4.4X", (WORD)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG SHORTCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%d", (SHORT)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG ULONGCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%lu", (ULONG)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
ULONG USHORTCallback(PFIELD_INFO pField, PVOID UserContext)
|
|
{
|
|
PrintName(pField);
|
|
dprintf("%u", (USHORT)pField->address);
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* EnumCallback
|
|
*
|
|
* Specify ENUMDEF * in SYM_DUMP_PARAM.Context field
|
|
*
|
|
* Note: Only one Enum/FlagCallback can be specified per FIELD_INFO array.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG EnumCallback(
|
|
PFIELD_INFO pField,
|
|
ENUMDEF *pEnumDef
|
|
)
|
|
{
|
|
if (pField == NULL || pEnumDef == NULL)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
dprintf("Error: EnumCallback had NULL parameter.\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
PrintName(pField);
|
|
|
|
if (!gbCallbacksPrintNewline &&
|
|
!(pField->fOptions & DBG_DUMP_FIELD_NO_PRINT))
|
|
{
|
|
dprintf(" ");
|
|
}
|
|
|
|
dprintf(" ");
|
|
if (! bPrintEnum(pEnumDef, (ULONG)pField->address))
|
|
{
|
|
dprintf("Unknown Value");
|
|
if (pField->fOptions & DBG_DUMP_FIELD_NO_PRINT)
|
|
{
|
|
dprintf(": %lu", (ULONG)pField->address);
|
|
}
|
|
}
|
|
dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* FlagCallback
|
|
*
|
|
* Specify FLAGDEF * in SYM_DUMP_PARAM.Context field
|
|
*
|
|
* Note: Only one Enum/FlagCallback can be specified per FIELD_INFO array.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG FlagCallback(
|
|
PFIELD_INFO pField,
|
|
FLAGDEF *pFlagDef
|
|
)
|
|
{
|
|
ULONG64 UnknownFlags;
|
|
|
|
PrintName(pField);
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
if (pField == NULL || pFlagDef == NULL)
|
|
{
|
|
dprintf("Error: FlagCallback had NULL parameter.\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
UnknownFlags = flPrintFlags(pFlagDef, pField->address);
|
|
if (UnknownFlags)
|
|
{
|
|
if (UnknownFlags != pField->address) dprintf("\n");
|
|
dprintf(" Uknown flags: 0x%lx", UnknownFlags);
|
|
}
|
|
dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* POINTLCallback
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG POINTLCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
NTSTATUS RetVal = gCallbackReturnValue;
|
|
ULONG error;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: POINTLCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (!pField->address)
|
|
{
|
|
dprintf("\nError: POINTLCallback: pField->address = NULL");
|
|
|
|
RetVal = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (error = (ULONG)InitTypeRead(pField->address, win32k!_POINTL))
|
|
{
|
|
dprintf("\n InitTypeRead returned %s", pszWinDbgError(error));
|
|
|
|
RetVal = error;
|
|
}
|
|
else
|
|
{
|
|
dprintf("(%d,%d)",
|
|
(LONG)ReadField(x),
|
|
(LONG)ReadField(y));
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* RECTLCallback
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG RECTLCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
NTSTATUS RetVal = gCallbackReturnValue;
|
|
ULONG error;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: RECTLCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (!pField->address)
|
|
{
|
|
dprintf("\nError: RECTLCallback: pField->address = NULL");
|
|
|
|
RetVal = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (error = (ULONG)InitTypeRead(pField->address, win32k!_RECTL))
|
|
{
|
|
dprintf("\n InitTypeRead returned %s", pszWinDbgError(error));
|
|
|
|
RetVal = error;
|
|
}
|
|
else
|
|
{
|
|
dprintf("(%d,%d) - (%d,%d)",
|
|
(LONG)ReadField(left),
|
|
(LONG)ReadField(top),
|
|
(LONG)ReadField(right),
|
|
(LONG)ReadField(bottom));
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* SIZECallback
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG SIZECallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
NTSTATUS RetVal = gCallbackReturnValue;
|
|
ULONG error;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: SIZECallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (!pField->address)
|
|
{
|
|
dprintf("\nError: SIZECallback: pField->address = NULL");
|
|
|
|
RetVal = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (error = (ULONG)InitTypeRead(pField->address, win32k!tagSIZE))
|
|
{
|
|
dprintf("\n InitTypeRead returned %s", pszWinDbgError(error));
|
|
|
|
RetVal = error;
|
|
}
|
|
else
|
|
{
|
|
dprintf("%d x %d",
|
|
(LONG)ReadField(cx),
|
|
(LONG)ReadField(cy));
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* SIZELCallback
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG SIZELCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
return SIZECallback(pField, UserContext);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* PrintDEVMODEList
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG PrintDEVMODEList(
|
|
ULONG64 DevModeListAddr,
|
|
ULONG DevModeListSize
|
|
)
|
|
{
|
|
ULONG64 DevModeEnd;
|
|
ULONG error = 0;
|
|
|
|
#define DEVMODE_DMDRIVEREXTRA 0
|
|
#define DEVMODE_DMSIZE 1
|
|
#define DEVMODE_DMPELSWIDTH 2
|
|
#define DEVMODE_DMPELSHEIGHT 3
|
|
#define DEVMODE_DMBITSPERPEL 4
|
|
#define DEVMODE_DMDISPLAYFREQUENCY 5
|
|
|
|
FIELD_INFO DevModeFields[] = {
|
|
{ DbgStr("dmDriverExtra"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
{ DbgStr("dmSize"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
{ DbgStr("dmPelsWidth"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
{ DbgStr("dmPelsHeight"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
{ DbgStr("dmBitsPerPel"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
{ DbgStr("dmDisplayFrequency"), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
|
|
};
|
|
SYM_DUMP_PARAM DevModeSym = {
|
|
sizeof(SYM_DUMP_PARAM), DbgStr(GDIType(_devicemodeW)), DBG_DUMP_NO_PRINT, DevModeListAddr,
|
|
NULL, NULL, NULL, sizeof(DevModeFields)/sizeof(DevModeFields[0]), DevModeFields
|
|
};
|
|
|
|
DevModeEnd = DevModeSym.addr + DevModeListSize;
|
|
while ((DevModeSym.addr < DevModeEnd) &&
|
|
!(error = Ioctl( IG_DUMP_SYMBOL_INFO, &DevModeSym, DevModeSym.size )))
|
|
{
|
|
dprintf("\t %4d x %4d %2d %3d\n",
|
|
(DWORD)DevModeFields[DEVMODE_DMPELSWIDTH].address,
|
|
(DWORD)DevModeFields[DEVMODE_DMPELSHEIGHT].address,
|
|
(DWORD)DevModeFields[DEVMODE_DMBITSPERPEL].address,
|
|
(DWORD)DevModeFields[DEVMODE_DMDISPLAYFREQUENCY].address);
|
|
|
|
DevModeSym.addr += DevModeFields[DEVMODE_DMDRIVEREXTRA].address + DevModeFields[DEVMODE_DMSIZE].address;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* DEVMODECallback
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG DEVMODECallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (pField == NULL)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
dprintf(" Error: DEVMODEListCallback was given NULL pField.\n");
|
|
}
|
|
else if (pField->address)
|
|
{
|
|
ULONG error;
|
|
|
|
if (error = PrintDEVMODEList(pField->address, 1))
|
|
{
|
|
dprintf(" PrintDEVMODEList returned %s in DEVMODECallback\n", pszWinDbgError(error));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf(" DEVMODE address is NULL\n");
|
|
}
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* DEVMODEListCallback and SizeDEVMODEListCallback
|
|
*
|
|
* Make sure these are always called in conjuction with
|
|
* SizeDEVMODEListCallback before DEVMODEListCallback.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG cbDevModeList = -1;
|
|
|
|
ULONG SizeDEVMODEListCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("Error: SizeDEVMODEListCallback was given NULL pField.\n");
|
|
}
|
|
else
|
|
{
|
|
if (cbDevModeList != -1)
|
|
{
|
|
dprintf(" Warning: cbDevModeList (%d) was not clear before call to SizeDEVMODEListCallback\n", cbDevModeList);
|
|
}
|
|
|
|
cbDevModeList = (ULONG)pField->address;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG DEVMODEListCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf(" Error: DEVMODEListCallback was given NULL pField.\n");
|
|
}
|
|
else if (cbDevModeList == -1)
|
|
{
|
|
dprintf(" Error: cbDevModeList has not been set properly.\n");
|
|
}
|
|
else if (pField->address)
|
|
{
|
|
ULONG error;
|
|
|
|
if (error = PrintDEVMODEList(pField->address, cbDevModeList))
|
|
{
|
|
dprintf(" PrintDEVMODEList returned %s in DEVMODEListCallback\n", pszWinDbgError(error));
|
|
}
|
|
}
|
|
else if (cbDevModeList != 0)
|
|
{
|
|
dprintf(" DEVMODE list size (%d) is non-zero, but DEVMODE list address is NULL.\n", cbDevModeList);
|
|
}
|
|
|
|
cbDevModeList = -1;
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* PrintAString
|
|
*
|
|
* Reads and prints a char string at given target address.
|
|
*
|
|
* Returns address just past end of string or address of read failure.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG64 PrintAString(
|
|
ULONG64 StringAddr
|
|
)
|
|
{
|
|
CHAR Char;
|
|
ULONG cbRead;
|
|
|
|
if (StringAddr != 0)
|
|
{
|
|
while (ReadMemory(StringAddr, &Char, sizeof(Char), &cbRead) &&
|
|
cbRead == sizeof(Char) &&
|
|
(StringAddr+=sizeof(Char)) &&
|
|
Char != 0)
|
|
{
|
|
dprintf("%hc", Char);
|
|
}
|
|
}
|
|
|
|
return StringAddr;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* PrintWString
|
|
*
|
|
* Reads and prints a two-byte char string at given target address.
|
|
*
|
|
* Returns address just past end of string or address of read failure.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG64 PrintWString(
|
|
ULONG64 StringAddr
|
|
)
|
|
{
|
|
WCHAR Char;
|
|
ULONG cbRead;
|
|
|
|
if (StringAddr != 0)
|
|
{
|
|
while (ReadMemory(StringAddr, &Char, sizeof(Char), &cbRead) &&
|
|
cbRead == sizeof(Char) &&
|
|
(StringAddr+=sizeof(Char)) &&
|
|
Char != 0)
|
|
{
|
|
dprintf("%lc", Char);
|
|
}
|
|
}
|
|
|
|
return StringAddr;
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* String printing callbacks
|
|
*
|
|
* To be used when DBG_DUMP_FIELD_xxx_STRING flags can't be used.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* ACharArrayCallback callback for an array of chars
|
|
*
|
|
* Use DBG_DUMP_FIELD_RETURN_ADDRESS flag
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG ACharArrayCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
CHAR szBuffer[128];
|
|
ULONG cbRead = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: ACharArrayCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose && pField->size == 0)
|
|
dprintf("\n Note: ACharArrayCallback was given zero length array.\n");
|
|
|
|
if (pField->address)
|
|
{
|
|
if (pField->size < sizeof(szBuffer))
|
|
{
|
|
if (!ReadMemory(pField->address, szBuffer, pField->size, &cbRead) || cbRead == 0)
|
|
{
|
|
dprintf(" Memory read failed @ %#p", pField->address);
|
|
}
|
|
else
|
|
{
|
|
szBuffer[min(cbRead,sizeof(szBuffer)-sizeof(CHAR))/sizeof(CHAR)] = (CHAR) 0;
|
|
dprintf(" \"%hs\"", szBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PCHAR pszBuffer = (PCHAR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pField->size+sizeof(CHAR));
|
|
|
|
if (pszBuffer == NULL)
|
|
{
|
|
dprintf(" Buffer allocation failed - single-byte string @ %#p", pField->address);
|
|
}
|
|
else if (!ReadMemory(pField->address, szBuffer, pField->size, &cbRead) || cbRead == 0)
|
|
{
|
|
dprintf(" Memory read failed @ %#p", pField->address);
|
|
}
|
|
else
|
|
{
|
|
dprintf(" \"%hs\"", szBuffer);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* WCharArrayCallback callback for an array of two-byte chars
|
|
*
|
|
* Use DBG_DUMP_FIELD_RETURN_ADDRESS flag
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG WCharArrayCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
WCHAR wszBuffer[128];
|
|
ULONG cbRead = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: WStringCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose && pField->size == 0)
|
|
dprintf("\n Note: WCharArrayCallback was given zero length array.\n");
|
|
|
|
if (pField->address)
|
|
{
|
|
if (pField->size < sizeof(wszBuffer))
|
|
{
|
|
if (!ReadMemory(pField->address, wszBuffer, pField->size, &cbRead) || cbRead == 0)
|
|
{
|
|
dprintf(" Memory read failed @ %#p", pField->address);
|
|
}
|
|
else
|
|
{
|
|
wszBuffer[min(cbRead,sizeof(wszBuffer)-sizeof(WCHAR))/sizeof(WCHAR)] = (WCHAR) 0;
|
|
dprintf(" \"%ls\"", wszBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PWCHAR pwszBuffer = (PWCHAR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pField->size+sizeof(WCHAR));
|
|
|
|
if (pwszBuffer == NULL)
|
|
{
|
|
dprintf(" Buffer allocation failed - wide string @ %#p", pField->address);
|
|
}
|
|
else if (!ReadMemory(pField->address, wszBuffer, pField->size, &cbRead) || cbRead == 0)
|
|
{
|
|
dprintf(" Memory read failed @ %#p", pField->address);
|
|
}
|
|
else
|
|
{
|
|
dprintf(" \"%ls\"", wszBuffer);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* AStringCallback callback for a pointer to char string
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG AStringCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
CHAR szBuffer[128];
|
|
ULONG cbRead = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: AStringCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose)
|
|
{
|
|
if (pField->size == 0)
|
|
dprintf("\n Note: AStringCallback was given zero length type.\n");
|
|
else if (pField->size != GetTypeSize("PVOID"))
|
|
dprintf("\n Note: AStringCallback: String length is not the size of a pointer.\n"
|
|
" Should you be using ACharArrayCallback?\n");
|
|
}
|
|
|
|
if (pField->address)
|
|
{
|
|
dprintf(" \"");
|
|
PrintAString(pField->address);
|
|
dprintf("\"");
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* WStringCallback callback for a pointer to two-byte char string
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG WStringCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
CHAR szBuffer[128];
|
|
ULONG cbRead = 0;
|
|
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: WStringCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose)
|
|
{
|
|
if (pField->size == 0)
|
|
dprintf("\n Note: WStringCallback was given zero length type.\n");
|
|
else if (pField->size != GetTypeSize("PVOID"))
|
|
dprintf("\n Note: WStringCallback: String length is not the size of a pointer.\n"
|
|
" Should you be using WCharArrayCallback?\n");
|
|
}
|
|
|
|
if (pField->address)
|
|
{
|
|
dprintf(" \"");
|
|
PrintWString(pField->address);
|
|
dprintf("\"");
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* AMultiStringCallback callback for a pointer to several char
|
|
* strings one after another.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG AMultiStringCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: AMultiStringCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose)
|
|
{
|
|
if (pField->size == 0)
|
|
dprintf("\n Note: AMultiStringCallback was given zero length type.\n");
|
|
else if (pField->size != GetTypeSize("PVOID"))
|
|
dprintf("\n Note: AMulitStringCallback: String length is not the size of a pointer.\n"
|
|
" Should you be using ACharArrayCallback?\n");
|
|
}
|
|
|
|
if (pField->address)
|
|
{
|
|
ULONG64 PrevAddr = NULL;
|
|
ULONG64 CurAddr = pField->address;
|
|
CHAR Char;
|
|
ULONG cbRead;
|
|
|
|
while (CurAddr != PrevAddr &&
|
|
ReadMemory(CurAddr, &Char, sizeof(Char), &cbRead) &&
|
|
cbRead == sizeof(Char) &&
|
|
Char != 0)
|
|
{
|
|
PrevAddr = CurAddr;
|
|
|
|
dprintf("\n\t\"");
|
|
CurAddr = PrintAString(CurAddr);
|
|
dprintf("\"");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* WMultiStringCallback callback for a pointer to several two-byte char
|
|
* strings one after another.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG WMultiStringCallback(
|
|
PFIELD_INFO pField,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
if (pField == NULL)
|
|
{
|
|
dprintf("\nError: WMultiStringCallback was given NULL pField.");
|
|
}
|
|
else
|
|
{
|
|
PrintName(pField);
|
|
|
|
if (gbVerbose)
|
|
{
|
|
if (pField->size == 0)
|
|
dprintf("\n Note: WMultiStringCallback was given zero length type.\n");
|
|
else if (pField->size != GetTypeSize("PVOID"))
|
|
dprintf("\n Note: WMulitStringCallback: String length is not the size of a pointer.\n"
|
|
" Should you be using WCharArrayCallback?\n");
|
|
}
|
|
|
|
if (pField->address)
|
|
{
|
|
ULONG64 PrevAddr = NULL;
|
|
ULONG64 CurAddr = pField->address;
|
|
WCHAR Char;
|
|
ULONG cbRead;
|
|
|
|
while (CurAddr != PrevAddr &&
|
|
ReadMemory(CurAddr, &Char, sizeof(Char), &cbRead) &&
|
|
cbRead == sizeof(Char) &&
|
|
Char != 0)
|
|
{
|
|
PrevAddr = CurAddr;
|
|
|
|
dprintf("\n\t\"");
|
|
CurAddr = PrintWString(CurAddr);
|
|
dprintf("\"");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf(" (null)");
|
|
}
|
|
}
|
|
|
|
if (gbCallbacksPrintNewline) dprintf("\n");
|
|
|
|
return gCallbackReturnValue;
|
|
}
|
|
|