windows-nt/Source/XPSP1/NT/base/tools/kdexts2/device.c
2020-09-26 16:20:57 +08:00

441 lines
13 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
device.c
Abstract:
WinDbg Extension Api
Author:
Wesley Witt (wesw) 15-Aug-1993
Environment:
User Mode.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#define FLAG_NAME(flag) {flag, #flag}
FLAG_NAME DeviceObjectExtensionFlags[] = {
FLAG_NAME(DOE_UNLOAD_PENDING), // 00000001
FLAG_NAME(DOE_DELETE_PENDING), // 00000002
FLAG_NAME(DOE_REMOVE_PENDING), // 00000004
FLAG_NAME(DOE_REMOVE_PROCESSED), // 00000008
FLAG_NAME(DOE_START_PENDING), // 00000010
FLAG_NAME(DOE_RAW_FDO), // 20000000
FLAG_NAME(DOE_BOTTOM_OF_FDO_STACK), // 40000000
FLAG_NAME(DOE_DESIGNATED_FDO), // 80000000
{ 0, 0 }
};
DECLARE_API( devobj )
/*++
Routine Description:
Dump a device object.
Arguments:
args - the location of the device object to dump.
Return Value:
None
--*/
{
ULONG64 deviceToDump ;
char deviceExprBuf[256] ;
char *deviceExpr ;
//
// !devobj DeviceAddress DumpLevel
// where DeviceAddress can be an expression or device name
// and DumpLevel is a hex mask
//
strcpy(deviceExprBuf, "\\Device\\") ;
deviceExpr = deviceExprBuf+strlen(deviceExprBuf) ;
deviceToDump = 0 ;
strcpy(deviceExpr, args) ;
//
// The debugger will treat C0000000 as a symbol first, then a number if
// no match comes up. We sanely reverse this ordering.
//
if (IsHexNumber(deviceExpr)) {
deviceToDump = GetExpression(deviceExpr) ;
} else if (deviceExpr[0] == '\\') {
deviceToDump = FindObjectByName( deviceExpr, 0);
} else if (isalpha(deviceExpr[0])) {
//
// Perhaps it's an object. Try with \\Device\\ prepended...
//
deviceToDump = FindObjectByName((PUCHAR) deviceExprBuf, 0);
}
if (deviceToDump == 0) {
//
// Last try, is it an expression to evaluate?
//
deviceToDump = GetExpression( deviceExpr ) ;
}
if(deviceToDump == 0) {
dprintf("Device object %s not found\n", args);
return E_INVALIDARG;
}
DumpDevice( deviceToDump, 0, TRUE);
return S_OK;
}
VOID
DumpDevice(
ULONG64 DeviceAddress,
ULONG FieldLength,
BOOLEAN FullDetail
)
/*++
Routine Description:
Displays the driver name for the device object if FullDetail == FALSE.
Otherwise displays more information about the device and the device queue.
Arguments:
DeviceAddress - address of device object to dump.
FieldLength - Width of printf field for driver name (eg %11s).
FullDetail - TRUE means the device object name, driver name, and
information about Irps queued to the device.
Return Value:
None
--*/
{
ULONG result;
ULONG i;
ULONG64 nextEntry;
ULONG64 queueAddress;
ULONG64 irp;
BOOLEAN devObjExtRead;
ULONG Type=0, ReferenceCount=0, DeviceType=0, Flags=0, DeviceObjEx_ExtensionFlags=0,
DeviceQueue_Busy=0;
ULONG64 DriverObject=0, CurrentIrp=0, Vpb=0, DeviceObjectExtension=0,
DeviceExtension=0, DeviceObjEx_Dope=0, DeviceObjEx_DeviceNode=0,
DeviceObjEx_AttachedTo=0, AttachedDevice=0, DeviceQueue_Dev_Flink=0,
DeviceQueue_Dev_Blink=0;
#define RECUR DBG_DUMP_FIELD_RECUR_ON_THIS
#define F_ADDR DBG_DUMP_FIELD_RETURN_ADDRESS
#define COPY DBG_DUMP_FIELD_COPY_FIELD_DATA
FIELD_INFO deviceFields[] = {
{"DriverObject", NULL, 0, COPY, 0, (PVOID) &DriverObject},
{"Type", NULL, 0, COPY, 0, (PVOID) &Type},
{"CurrentIrp", NULL, 0, COPY, 0, (PVOID) &CurrentIrp},
{"ReferenceCount", NULL, 0, COPY, 0, (PVOID) &ReferenceCount},
{"DeviceType", NULL, 0, COPY, 0, (PVOID) &DeviceType},
{"Flags", NULL, 0, COPY, 0, (PVOID) &Flags},
{"Vpb", NULL, 0, COPY, 0, (PVOID) &Vpb},
{"DeviceObjectExtension", NULL, 0, COPY | RECUR, 0, (PVOID) &DeviceObjectExtension},
{"DeviceObjectExtension->Dope", NULL, 0, COPY, 0, (PVOID) &DeviceObjEx_Dope},
{"DeviceObjectExtension->DeviceNode", NULL, 0, COPY, 0, (PVOID) &DeviceObjEx_DeviceNode},
{"DeviceObjectExtension->ExtensionFlags", NULL, 0, COPY, 0, (PVOID) &DeviceObjEx_ExtensionFlags},
{"DeviceObjectExtension->AttachedTo", NULL, 0, COPY, 0, (PVOID) &DeviceObjEx_AttachedTo},
{"DeviceExtension",NULL, 0, COPY, 0, (PVOID) &DeviceExtension},
{"AttachedDevice", NULL, 0, COPY, 0, (PVOID) &AttachedDevice},
{"DeviceQueue", NULL, 0, RECUR,0, NULL},
{"DeviceQueue.Busy", NULL, 0, COPY, 0, (PVOID) &DeviceQueue_Busy},
{"DeviceQueue.DeviceListHead", NULL, 0, RECUR | F_ADDR, 0, NULL},
{"DeviceQueue.DeviceListHead.Flink", NULL, 0, COPY | F_ADDR, 0, (PVOID) &DeviceQueue_Dev_Flink},
{"DeviceQueue.DeviceListHead.Blink", NULL, 0, COPY | F_ADDR, 0, (PVOID) &DeviceQueue_Dev_Blink},
};
SYM_DUMP_PARAM DevSym = {
sizeof (SYM_DUMP_PARAM), "nt!_DEVICE_OBJECT", DBG_DUMP_NO_PRINT, DeviceAddress,
NULL, NULL, NULL, sizeof (deviceFields) / sizeof (FIELD_INFO), &deviceFields[0]
};
if ((Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size))) {
dprintf("%08p: Could not read device object or _DEVICE_OBJECT not found\n", DeviceAddress);
return;
}
if (Type != IO_TYPE_DEVICE) {
dprintf("%08p: is not a device object\n", DeviceAddress);
return;
}
if (FullDetail == TRUE) {
//
// Dump the device name if present.
//
dprintf("Device object (%08p) is for:\n ", DeviceAddress);
DumpObjectName(DeviceAddress) ;
}
DumpDriver( DriverObject, FieldLength, 0);
if (FullDetail == TRUE) {
//
// Dump Irps related to driver.
//
dprintf(" DriverObject %08p\n", DriverObject);
dprintf("Current Irp %08p RefCount %d Type %08lx Flags %08lx\n",
CurrentIrp,
ReferenceCount,
DeviceType,
Flags);
if (Vpb) {
dprintf("Vpb %08p ", Vpb);
}
dprintf("DevExt %08p DevObjExt %08p ",
DeviceExtension,
DeviceObjectExtension);
devObjExtRead = FALSE ;
if (DeviceObjectExtension) {
devObjExtRead = TRUE ;
if (DeviceObjEx_Dope) {
dprintf("Dope %08p ", DeviceObjEx_Dope);
}
if(DeviceObjEx_DeviceNode) {
dprintf("DevNode %08p ",
DeviceObjEx_DeviceNode);
}
dprintf("\n");
DumpFlags(0,
"ExtensionFlags",
DeviceObjEx_ExtensionFlags,
DeviceObjectExtensionFlags);
} else {
dprintf("\n");
}
if (AttachedDevice) {
dprintf("AttachedDevice (Upper) %08p", AttachedDevice);
DumpDevice(AttachedDevice, 0, FALSE) ;
dprintf("\n") ;
}
if (devObjExtRead && DeviceObjEx_AttachedTo) {
dprintf("AttachedTo (Lower) %08p", DeviceObjEx_AttachedTo);
DumpDevice(DeviceObjEx_AttachedTo, 0, FALSE) ;
dprintf("\n") ;
}
if (DeviceQueue_Busy) {
ULONG64 listHead = DeviceAddress, DevFlinkAddress;
for (i=0; i<DevSym.nFields; i++) {
if (!strcmp(deviceFields[i].fName, "DeviceQueue.DeviceListHead")) {
listHead = deviceFields[i].address;
}
if (!strcmp(deviceFields[i].fName, "DeviceQueue.DeviceListHead.Flink")) {
DevFlinkAddress = deviceFields[i].address;
}
}
// listHead += FIELD_OFFSET(DEVICE_OBJECT, DeviceQueue.DeviceListHead);
if (DeviceQueue_Dev_Flink == listHead) {
dprintf("Device queue is busy -- Queue empty.\n");
// } else if (IsListEmpty(& DeviceQueue.DeviceListHead)) {
// dprintf("Device queue is busy -- Queue empty\n");
} else if(DeviceQueue_Dev_Flink == DeviceQueue_Dev_Blink) {
dprintf("Device queue is busy - Queue flink = blink\n");
} else {
ULONG64 DevListOffset=0, DevQEntryOffset=0;
FIELD_INFO getOffset = {0};
//
// Get offsets required for list
//
DevSym.addr = 0; DevSym.nFields =1; DevSym.Fields = &getOffset;
DevSym.sName = "nt!_KDEVICE_QUEUE_ENTRY"; getOffset.fName = "DeviceListEntry";
Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
DevListOffset = getOffset.address;
DevSym.sName = "nt!_IRP"; getOffset.fName = "Tail.Overlay.DeviceQueueEntry";
Ioctl(IG_DUMP_SYMBOL_INFO, &DevSym, DevSym.size);
DevQEntryOffset = getOffset.address;
dprintf("DeviceQueue: ");
nextEntry = DeviceQueue_Dev_Flink;
i = 0;
/*
while ((PCH) nextEntry != (PCH)
((PCH) DeviceAddress +
((PCH) &deviceObject.DeviceQueue.DeviceListHead.Flink -
(PCH) &deviceObject))) {
*/
while (nextEntry != (DevFlinkAddress)) {
ULONG64 DevList_Flink=0;
queueAddress = nextEntry - DevListOffset;
/*CONTAINING_RECORD(nextEntry,KDEVICE_QUEUE_ENTRY,
DeviceListEntry);*/
GetFieldValue(queueAddress, "_KDEVICE_QUEUE_ENTRY", "DeviceListEntry.Flink", DevList_Flink);
nextEntry = DevList_Flink;
irp = queueAddress - DevQEntryOffset;
/*CONTAINING_RECORD(queueAddress,
IRP,
Tail.Overlay.DeviceQueueEntry);*/
dprintf("%08p%s",
irp,
(i & 0x03) == 0x03 ? "\n\t " : " ");
if (CheckControlC()) {
break;
}
++i;
}
dprintf("\n");
}
} else {
dprintf("Device queue is not busy.\n");
}
}
}
VOID
DumpObjectName(
ULONG64 ObjectAddress
)
{
ULONG64 pObjectHeader;
ULONG64 pNameInfo;
PUCHAR buffer;
UNICODE_STRING unicodeString;
ULONG result, NameInfoOffset=0;
ULONG off=0;
if (GetFieldOffset("_OBJECT_HEADER", "Body", &off)) {
// Type not found
return;
}
pObjectHeader = ObjectAddress - off;
if (!GetFieldValue(pObjectHeader, "_OBJECT_HEADER", "NameInfoOffset", NameInfoOffset)) {
ULONG64 bufferAddr=0;
ULONG Len=0, MaxLen=0;
//
// Get Name info's address
//
pNameInfo = (NameInfoOffset ? (pObjectHeader - NameInfoOffset) : 0);
if (!InitTypeRead(pNameInfo, _OBJECT_HEADER_NAME_INFO)) {
Len = (ULONG) ReadField(Name.Length);
MaxLen = (ULONG) ReadField(Name.MaximumLength);
bufferAddr = ReadField(Name.Buffer);
buffer = LocalAlloc(LPTR, MaxLen);
if (buffer != NULL) {
unicodeString.MaximumLength = (USHORT) MaxLen;
unicodeString.Length = (USHORT) Len;
unicodeString.Buffer = (PWSTR)buffer;
if (ReadMemory(bufferAddr,
buffer,
unicodeString.Length,
&result) && (result == unicodeString.Length)) {
dprintf("%wZ", &unicodeString);
}
LocalFree(buffer);
}
}
}
}
HRESULT
GetDevObjInfo(
IN ULONG64 DeviceObject,
OUT PDEBUG_DEVICE_OBJECT_INFO pDevObjInfo)
{
ZeroMemory(pDevObjInfo, sizeof(DEBUG_DEVICE_OBJECT_INFO));
pDevObjInfo->SizeOfStruct = sizeof(DEBUG_DEVICE_OBJECT_INFO);
pDevObjInfo->DevObjAddress = DeviceObject;
if (InitTypeRead(DeviceObject, nt!_DEVICE_OBJECT)) {
return E_INVALIDARG;
}
pDevObjInfo->CurrentIrp = ReadField(CurrentIrp);
pDevObjInfo->DevExtension = ReadField(DevExtension);
pDevObjInfo->DevObjExtension = ReadField(DevObjExtension);
pDevObjInfo->DriverObject = ReadField(DriverObject);
pDevObjInfo->QBusy = (BOOL) ReadField(DeviceQueue.Busy);
pDevObjInfo->ReferenceCount = (ULONG) ReadField(ReferenceCount);
return S_OK;
}
EXTENSION_API( GetDevObjInfo )(
IN PDEBUG_CLIENT Client,
IN ULONG64 DeviceObject,
OUT PDEBUG_DEVICE_OBJECT_INFO pDevObjInfo)
{
HRESULT Hr = E_FAIL;
INIT_API();
if (pDevObjInfo && (pDevObjInfo->SizeOfStruct == sizeof(DEBUG_DEVICE_OBJECT_INFO))) {
Hr = GetDevObjInfo(DeviceObject, pDevObjInfo);
}
EXIT_API();
return Hr;
}