/*++ Copyright (c) 2012 Minoca Corp. All Rights Reserved Module Name: reslist.c Abstract: This module implements resource list debugger extensions. Author: Evan Green 12-Dec-2012 Environment: Debug Client --*/ // // ------------------------------------------------------------------- Includes // #include #include #include "../../kernel/io/arb.h" #include #include #include #include #include // // ---------------------------------------------------------------- Definitions // #define MALLOC(_x) malloc(_x) #define FREE(_x) free(_x) // // ------------------------------------------------------ Data Type Definitions // // // ----------------------------------------------- Internal Function Prototypes // BOOL ExtpPrintDeviceResources ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceConfigurationList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceRequirementList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceRequirement ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceAllocationList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceAllocation ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintDeviceArbiters ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintResourceArbiter ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); BOOL ExtpPrintArbiterEntry ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ); PSTR ExtpGetResourceTypeString ( RESOURCE_TYPE Type ); // // -------------------------------------------------------------------- Globals // // // ------------------------------------------------------------------ Functions // INT ExtResource ( PDEBUGGER_CONTEXT Context, PSTR Command, ULONG ArgumentCount, PSTR *ArgumentValues ) /*++ Routine Description: This routine implements the resource related debugger extension. Arguments: Context - Supplies a pointer to the debugger applicaton context, which is an argument to most of the API functions. Command - Supplies a pointer to the subcommand string. ArgumentCount - Supplies the number of arguments in the ArgumentValues array. ArgumentValues - Supplies the values of each argument. This memory will be reused when the function returns, so extensions must not touch this memory after returning from this call. Return Value: 0 if the debugger extension command was successful. Returns an error code if a failure occurred along the way. --*/ { ULONGLONG Address; ULONG ArgumentIndex; INT Result; Address = 0; if (Command == NULL) { DbgOut("Error: Supply a subcommand. Valid subcommands are:\n" " !res.dev\n !res.req\n !res.reqlist\n " "!res.conflist\n !res.alloc\n !res.alloclist\n " "!res.arb\n !res.devarbs\n !res.arbentry\n"); return EINVAL; } // // At least one parameter is required. // if (ArgumentCount < 2) { DbgOut("Error: Supply an address to dump.\n"); } else { // // Loop through each argument, evaluate the address, and print the // namespace tree at that object. // for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) { Result = DbgEvaluate(Context, ArgumentValues[ArgumentIndex], &Address); if (Result != 0) { DbgOut("Failed to evaluate address at \"%s\".\n", ArgumentValues[ArgumentIndex]); return Result; } if (strcmp(Command, "dev") == 0) { ExtpPrintDeviceResources(Context, Address, 0); } else if (strcmp(Command, "req") == 0) { ExtpPrintResourceRequirement(Context, Address, 0); } else if (strcmp(Command, "reqlist") == 0) { ExtpPrintResourceRequirementList(Context, Address, 0); } else if (strcmp(Command, "conflist") == 0) { ExtpPrintResourceConfigurationList(Context, Address, 0); } else if (strcmp(Command, "alloc") == 0) { ExtpPrintResourceAllocation(Context, Address, 0); } else if (strcmp(Command, "alloclist") == 0) { ExtpPrintResourceAllocationList(Context, Address, 0); } else if (strcmp(Command, "arbentry") == 0) { ExtpPrintArbiterEntry(Context, Address, 0); } else if (strcmp(Command, "arb") == 0) { ExtpPrintResourceArbiter(Context, Address, 0); } else if (strcmp(Command, "devarbs") == 0) { ExtpPrintDeviceArbiters(Context, Address, 0); } else { DbgOut("Error: Invalid subcommand. Run !res for detailed" "usage.\n"); } if (ArgumentIndex != ArgumentCount - 1) { DbgOut("\n----\n"); } } } return 0; } // // --------------------------------------------------------- Internal Functions // BOOL ExtpPrintDeviceResources ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a device's resources. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the devices whose resources should be dumped. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONGLONG BootResources; ULONGLONG BusLocalResources; PVOID Data; ULONG DataSize; ULONGLONG DeviceAddress; PTYPE_SYMBOL DeviceType; ULONGLONG HeaderType; ULONGLONG ProcessorLocalResources; ULONGLONG ResourceRequirements; BOOL Result; ULONGLONG SelectedConfiguration; INT Status; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); DeviceAddress = Address; DbgOut("Device %I64x:\n", DeviceAddress); Status = DbgReadTypeByName(Context, Address, "_DEVICE", &DeviceType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read _DEVICE at 0x%I64x\n", Address); goto PrintDeviceResourcesEnd; } Status = DbgReadIntegerMember(Context, DeviceType, "Header.Type", Address, Data, DataSize, &HeaderType); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (HeaderType != ObjectDevice) { DbgOut("Object header type %I64d, probably not a device!\n", HeaderType); Status = EINVAL; goto PrintDeviceResourcesEnd; } IndentationLevel += 1; // // Print the processor resources. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadIntegerMember(Context, DeviceType, "ProcessorLocalResources", Address, Data, DataSize, &ProcessorLocalResources); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (ProcessorLocalResources == 0) { DbgOut("No Processor Local Resources.\n"); } else { DbgOut("Processor Local Resources @ %x\n", ProcessorLocalResources); ExtpPrintResourceAllocationList(Context, ProcessorLocalResources, IndentationLevel); } // // Print the bus local resources. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadIntegerMember(Context, DeviceType, "BusLocalResources", Address, Data, DataSize, &BusLocalResources); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (BusLocalResources == 0) { DbgOut("No Bus Local Resources.\n"); } else { DbgOut("Bus Local Resources @ %x\n", BusLocalResources); ExtpPrintResourceAllocationList(Context, BusLocalResources, IndentationLevel); } // // Print the boot resources. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadIntegerMember(Context, DeviceType, "BootResources", Address, Data, DataSize, &BootResources); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (BootResources == 0) { DbgOut("No Boot Resources.\n"); } else { DbgOut("Boot Resources @ %x\n", BootResources); ExtpPrintResourceAllocationList(Context, BootResources, IndentationLevel); } // // Print the selected configuration. // Status = DbgReadIntegerMember(Context, DeviceType, "SelectedConfiguration", Address, Data, DataSize, &SelectedConfiguration); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (SelectedConfiguration != 0) { DbgOut("%*s", IndentationLevel, ""); DbgOut("Selected Configuration %x\n", SelectedConfiguration); } // // Print the resource requirements. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadIntegerMember(Context, DeviceType, "ResourceRequirements", Address, Data, DataSize, &ResourceRequirements); if (Status != 0) { goto PrintDeviceResourcesEnd; } if (ResourceRequirements == 0) { DbgOut("No Resource Requirements.\n"); } else { DbgOut("Resource Requirements @ %x\n", ResourceRequirements); ExtpPrintResourceConfigurationList(Context, ResourceRequirements, IndentationLevel); } Status = 0; PrintDeviceResourcesEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceConfigurationList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource configuration list. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the resource configuration list to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; PTYPE_SYMBOL ConfigurationListType; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; PTYPE_SYMBOL ListEntryType; ULONG RequirementHeadOffset; ULONG RequirementListEntryOffset; PTYPE_SYMBOL RequirementListType; BOOL Result; INT Status; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); DbgOut("Resource Configuration List @ %08I64x\n", Address); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_CONFIGURATION_LIST", &ConfigurationListType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read configuration list at 0x%I64x.\n", Address); goto PrintResourceConfigurationListEnd; } Status = DbgGetMemberOffset(ConfigurationListType, "RequirementListListHead", &RequirementHeadOffset, NULL); if (Status != 0) { goto PrintResourceConfigurationListEnd; } RequirementHeadOffset /= BITS_PER_BYTE; Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintResourceConfigurationListEnd; } Status = DbgGetTypeByName(Context, "_RESOURCE_REQUIREMENT_LIST", &RequirementListType); if (Status != 0) { goto PrintResourceConfigurationListEnd; } Status = DbgGetMemberOffset(RequirementListType, "ListEntry", &RequirementListEntryOffset, NULL); if (Status != 0) { goto PrintResourceConfigurationListEnd; } RequirementListEntryOffset /= BITS_PER_BYTE; // // Print out all children. // IndentationLevel += 1; ChildListHead = Address + RequirementHeadOffset; Status = DbgReadIntegerMember(Context, ConfigurationListType, "RequirementListListHead.Next", Address, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceConfigurationListEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(Data == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &Data, &DataSize); if (Status != 0) { goto PrintResourceConfigurationListEnd; } // // Print the resource requirement list. // ChildObjectAddress = CurrentEntryAddress - RequirementListEntryOffset; Status = ExtpPrintResourceRequirementList(Context, ChildObjectAddress, IndentationLevel); if (Status == FALSE) { Status = EINVAL; goto PrintResourceConfigurationListEnd; } // // Move to the next child. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceConfigurationListEnd; } free(Data); Data = NULL; } PrintResourceConfigurationListEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceRequirementList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource requirement list. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the resource requirement list to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; PTYPE_SYMBOL ListEntryType; ULONG RequirementEntryOffset; ULONG RequirementListHeadOffset; PTYPE_SYMBOL RequirementListType; PTYPE_SYMBOL RequirementType; BOOL Result; INT Status; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); DbgOut("Resource Requirement List @ %08I64x\n", Address); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_REQUIREMENT_LIST", &RequirementListType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read requirement list at 0x%I64x.\n", Address); goto PrintResourceRequirementListEnd; } Status = DbgGetMemberOffset(RequirementListType, "RequirementListHead", &RequirementListHeadOffset, NULL); if (Status != 0) { goto PrintResourceRequirementListEnd; } RequirementListHeadOffset /= BITS_PER_BYTE; Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintResourceRequirementListEnd; } Status = DbgGetTypeByName(Context, "_RESOURCE_REQUIREMENT", &RequirementType); if (Status != 0) { goto PrintResourceRequirementListEnd; } Status = DbgGetMemberOffset(RequirementType, "ListEntry", &RequirementEntryOffset, NULL); if (Status != 0) { goto PrintResourceRequirementListEnd; } RequirementEntryOffset /= BITS_PER_BYTE; // // Print out all children. // IndentationLevel += 1; ChildListHead = Address + RequirementListHeadOffset; Status = DbgReadIntegerMember(Context, RequirementListType, "RequirementListHead.Next", Address, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceRequirementListEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(Data == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &Data, &DataSize); if (Status != 0) { goto PrintResourceRequirementListEnd; } // // Print the resource requirement list. // ChildObjectAddress = CurrentEntryAddress - RequirementEntryOffset; Result = ExtpPrintResourceRequirement(Context, ChildObjectAddress, IndentationLevel); if (Result == FALSE) { Status = EINVAL; goto PrintResourceRequirementListEnd; } // // Move to the next child. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceRequirementListEnd; } free(Data); Data = NULL; } PrintResourceRequirementListEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceRequirement ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource requirement. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the resource requirement to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONG AlternativeListEntryOffset; ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; ULONGLONG Flags; PTYPE_SYMBOL ListEntryType; ULONGLONG RequirementDataSize; PTYPE_SYMBOL RequirementType; PSTR ResourceType; BOOL Result; INT Status; ULONGLONG Value; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_REQUIREMENT", &RequirementType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read requirement at 0x%I64x.\n", Address); goto PrintResourceRequirementEnd; } Status = DbgReadIntegerMember(Context, RequirementType, "Type", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } ResourceType = ExtpGetResourceTypeString(Value); DbgOut("%08I64x %16s: Range ", Address, ResourceType); Status = DbgReadIntegerMember(Context, RequirementType, "Minimum", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%08I64x - ", Value); Status = DbgReadIntegerMember(Context, RequirementType, "Maximum", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%08I64x, Len ", Value); Status = DbgReadIntegerMember(Context, RequirementType, "Length", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%08I64x, Align ", Value); Status = DbgReadIntegerMember(Context, RequirementType, "Alignment", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%I64x, Char ", Value); Status = DbgReadIntegerMember(Context, RequirementType, "Characteristics", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%I64x, Flags ", Value); Status = DbgReadIntegerMember(Context, RequirementType, "Flags", Address, Data, DataSize, &Flags); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut("%I64x", Flags); Status = DbgReadIntegerMember(Context, RequirementType, "OwningRequirement", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } if (Value != 0) { DbgOut(", Owner %I64x", Value); } if ((Flags & RESOURCE_FLAG_NOT_SHAREABLE) != 0) { DbgOut(" NotShared"); } Status = DbgReadIntegerMember(Context, RequirementType, "Provider", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } if (Value != 0) { DbgOut(", Provider %x", Value); } Status = DbgReadIntegerMember(Context, RequirementType, "DataSize", Address, Data, DataSize, &RequirementDataSize); if (Status != 0) { goto PrintResourceRequirementEnd; } if (RequirementDataSize != 0) { Status = DbgReadIntegerMember(Context, RequirementType, "Data", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } DbgOut(", Data 0x%I64x Size 0x%I64x", Value, RequirementDataSize); } DbgOut("\n"); // // If the requirement is not linked in, assume it is an alternative and // don't try to traverse alternatives. // Status = DbgReadIntegerMember(Context, RequirementType, "ListEntry.Next", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceRequirementEnd; } if (Value == 0) { Status = 0; goto PrintResourceRequirementEnd; } Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintResourceRequirementEnd; } Status = DbgGetMemberOffset(RequirementType, "AlternativeListEntry", &AlternativeListEntryOffset, NULL); if (Status != 0) { goto PrintResourceRequirementEnd; } AlternativeListEntryOffset /= BITS_PER_BYTE; // // Print out all children. // IndentationLevel += 1; ChildListHead = Address + AlternativeListEntryOffset; Status = DbgReadIntegerMember(Context, RequirementType, "AlternativeListEntry.Next", Address, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceRequirementEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(Data == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &Data, &DataSize); if (Status != 0) { goto PrintResourceRequirementEnd; } // // Print the resource requirement alternative. // ChildObjectAddress = CurrentEntryAddress - AlternativeListEntryOffset; Result = ExtpPrintResourceRequirement(Context, ChildObjectAddress, IndentationLevel); if (Result == FALSE) { Status = EINVAL; goto PrintResourceRequirementEnd; } // // Move to the next child. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceRequirementEnd; } free(Data); Data = NULL; } Status = 0; PrintResourceRequirementEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceAllocationList ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource allocation list. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the resource allocation list to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONG AllocationEntryOffset; ULONG AllocationListHeadOffset; PTYPE_SYMBOL AllocationListType; PTYPE_SYMBOL AllocationType; ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; PTYPE_SYMBOL ListEntryType; BOOL Result; INT Status; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); DbgOut("Resource Allocation List @ %08I64x\n", Address); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_ALLOCATION_LIST", &AllocationListType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read allocation list at 0x%I64x.\n", Address); goto PrintResourceAllocationListEnd; } Status = DbgGetMemberOffset(AllocationListType, "AllocationListHead", &AllocationListHeadOffset, NULL); if (Status != 0) { goto PrintResourceAllocationListEnd; } AllocationListHeadOffset /= BITS_PER_BYTE; Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintResourceAllocationListEnd; } Status = DbgGetTypeByName(Context, "_RESOURCE_ALLOCATION", &AllocationType); if (Status != 0) { goto PrintResourceAllocationListEnd; } Status = DbgGetMemberOffset(AllocationType, "ListEntry", &AllocationEntryOffset, NULL); if (Status != 0) { goto PrintResourceAllocationListEnd; } // // Print out all children. // IndentationLevel += 1; ChildListHead = Address + AllocationListHeadOffset; Status = DbgReadIntegerMember(Context, AllocationListType, "AllocationListHead.Next", Address, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceAllocationListEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(Data == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &Data, &DataSize); if (Status != 0) { goto PrintResourceAllocationListEnd; } // // Print the resource requirement list. // ChildObjectAddress = CurrentEntryAddress - AllocationEntryOffset; Result = ExtpPrintResourceAllocation(Context, ChildObjectAddress, IndentationLevel); if (Result == FALSE) { Status = EINVAL; goto PrintResourceAllocationListEnd; } // // Move to the next child. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceAllocationListEnd; } free(Data); Data = NULL; } Status = 0; PrintResourceAllocationListEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceAllocation ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource allocation. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the resource allocation to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONGLONG AllocationDataSize; PTYPE_SYMBOL AllocationType; PVOID Data; ULONG DataSize; PSTR ResourceType; BOOL Result; INT Status; ULONGLONG Value; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_ALLOCATION", &AllocationType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read allocation at 0x%I64x.\n", Address); goto PrintResourceAllocationEnd; } Status = DbgReadIntegerMember(Context, AllocationType, "Type", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } ResourceType = ExtpGetResourceTypeString(Value); DbgOut("%08I64x %16s: ", Address, ResourceType); Status = DbgReadIntegerMember(Context, AllocationType, "Allocation", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } DbgOut("%08I64x, Len ", Value); Status = DbgReadIntegerMember(Context, AllocationType, "Length", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } DbgOut("%08I64x, Char ", Value); Status = DbgReadIntegerMember(Context, AllocationType, "Characteristics", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } DbgOut("%I64x", Value); Status = DbgReadIntegerMember(Context, AllocationType, "OwningAllocation", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } if (Value != 0) { DbgOut(", Owner %I64x", Value); } Status = DbgReadIntegerMember(Context, AllocationType, "Flags", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } if ((Value & RESOURCE_FLAG_NOT_SHAREABLE) != 0) { DbgOut(" NotShared"); } Status = DbgReadIntegerMember(Context, AllocationType, "Provider", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } if (Value != 0) { DbgOut(", Provider %I64x", Value); } Status = DbgReadIntegerMember(Context, AllocationType, "DataSize", Address, Data, DataSize, &AllocationDataSize); if (Status != 0) { goto PrintResourceAllocationEnd; } if (AllocationDataSize != 0) { Status = DbgReadIntegerMember(Context, AllocationType, "Data", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceAllocationEnd; } DbgOut(", Data %I64x Size 0x%I64x", Value, AllocationDataSize); } Status = 0; PrintResourceAllocationEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } DbgOut("\n"); return Result; } BOOL ExtpPrintDeviceArbiters ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out the resource arbiters associated with a device. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the device whose arbiters should be dumped. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONG ArbiterIndex; ULONG ArbiterListEntryOffset; ULONG ArbiterListHeadOffset; PTYPE_SYMBOL ArbiterType; ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; ULONGLONG DeviceAddress; ULONGLONG DeviceParentAddress; PTYPE_SYMBOL DeviceType; ULONGLONG HeaderType; PVOID ListEntryData; ULONG ListEntryDataSize; PTYPE_SYMBOL ListEntryType; ULONGLONG NextParent; ULONGLONG OriginalDeviceAddress; ULONGLONG ResourceType; BOOL Result; INT Status; ChildObjectAddress = 0; Data = NULL; ListEntryData = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); // // Get the parent of the current device. // OriginalDeviceAddress = Address; Status = DbgReadTypeByName(Context, Address, "_DEVICE", &DeviceType, &Data, &DataSize); if (Status != 0) { DbgOut("Failed to read device at %I64x.\n", Address); goto PrintDeviceArbitersEnd; } Status = DbgGetMemberOffset(DeviceType, "ArbiterListHead", &ArbiterListHeadOffset, NULL); if (Status != 0) { goto PrintDeviceArbitersEnd; } ArbiterListHeadOffset /= BITS_PER_BYTE; Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintDeviceArbitersEnd; } Status = DbgGetTypeByName(Context, "_RESOURCE_ARBITER", &ArbiterType); if (Status != 0) { goto PrintDeviceArbitersEnd; } Status = DbgGetMemberOffset(ArbiterType, "ListEntry", &ArbiterListEntryOffset, NULL); if (Status != 0) { goto PrintDeviceArbitersEnd; } Status = DbgReadIntegerMember(Context, DeviceType, "Header.Type", Address, Data, DataSize, &HeaderType); if (Status != 0) { goto PrintDeviceArbitersEnd; } if (HeaderType != ObjectDevice) { DbgOut("Object header type %I64d, probably not a device!\n", HeaderType); return FALSE; } Status = DbgReadIntegerMember(Context, DeviceType, "ParentDevice", Address, Data, DataSize, &DeviceParentAddress); if (Status != 0) { goto PrintDeviceArbitersEnd; } DbgOut("Arbiters for device %I64x (parent %I64x):\n", OriginalDeviceAddress, DeviceParentAddress); free(Data); Data = NULL; // // Attempt to find each arbiter. // IndentationLevel += 1; for (ArbiterIndex = 1; ArbiterIndex < ArbiterTypeCount; ArbiterIndex += 1) { // // Start at the original device address and look through all its // arbiters. // DeviceAddress = DeviceParentAddress; while (TRUE) { assert(Data == NULL); Status = DbgReadType(Context, DeviceAddress, DeviceType, &Data, &DataSize); if (Status != 0) { DbgOut("Failed to read device at %I64x.\n", DeviceAddress); goto PrintDeviceArbitersEnd; } Status = DbgReadIntegerMember(Context, DeviceType, "Header.Type", DeviceAddress, Data, DataSize, &HeaderType); if (Status != 0) { goto PrintDeviceArbitersEnd; } if (HeaderType != ObjectDevice) { DbgOut("Object header type %I64d, probably not a device!\n", HeaderType); Status = EINVAL; goto PrintDeviceArbitersEnd; } Status = DbgReadIntegerMember(Context, DeviceType, "ParentDevice", Address, Data, DataSize, &NextParent); if (Status != 0) { goto PrintDeviceArbitersEnd; } // // Loop through every arbiter in the device. // ChildListHead = DeviceAddress + ArbiterListHeadOffset; Status = DbgReadIntegerMember(Context, DeviceType, "ArbiterListHead.Next", DeviceAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintDeviceArbitersEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(ListEntryData == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &ListEntryData, &ListEntryDataSize); if (Status != 0) { goto PrintDeviceArbitersEnd; } // // Read in the arbiter. // ChildObjectAddress = CurrentEntryAddress - ArbiterListEntryOffset; assert(Data == NULL); Status = DbgReadType(Context, ChildObjectAddress, ArbiterType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read arbiter at 0x%I64x.\n", ChildObjectAddress); goto PrintDeviceArbitersEnd; } Status = DbgReadIntegerMember(Context, ArbiterType, "ResourceType", ChildObjectAddress, Data, DataSize, &ResourceType); if (Status != 0) { goto PrintDeviceArbitersEnd; } free(Data); Data = NULL; // // Stop looking if this arbiter is the right type. // if (ResourceType == ArbiterIndex) { free(ListEntryData); ListEntryData = NULL; break; } // // Move to the next entry. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, ListEntryData, ListEntryDataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintDeviceArbitersEnd; } free(ListEntryData); ListEntryData = NULL; } // // If an arbiter was found, print it out and stop looking for this // arbiter type. // if (CurrentEntryAddress != ChildListHead) { ExtpPrintResourceArbiter(Context, ChildObjectAddress, IndentationLevel); break; } // // No arbiter was found in this device, so move to the parent // device. // DeviceAddress = NextParent; if (DeviceAddress == 0) { DbgOut("Could not find %s arbiter.\n", ExtpGetResourceTypeString(ArbiterIndex)); break; } } } PrintDeviceArbitersEnd: if (Data != NULL) { free(Data); } if (ListEntryData != NULL) { free(ListEntryData); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintResourceArbiter ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out a resource arbiter. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the arbiter to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { ULONG ArbiterEntryListHeadOffset; ULONG ArbiterEntryOffset; PTYPE_SYMBOL ArbiterType; ULONGLONG ChildListHead; ULONGLONG ChildObjectAddress; ULONGLONG CurrentEntryAddress; PVOID Data; ULONG DataSize; PTYPE_SYMBOL ListEntryType; PSTR ResourceType; BOOL Result; INT Status; ULONGLONG Value; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadTypeByName(Context, Address, "_RESOURCE_ARBITER", &ArbiterType, &Data, &DataSize); if (Status != 0) { DbgOut("Failed to read _RESOURCE_ARBITER at %I64x.\n", Address); goto PrintResourceArbiterEnd; } Status = DbgReadIntegerMember(Context, ArbiterType, "ResourceType", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceArbiterEnd; } ResourceType = ExtpGetResourceTypeString(Value); DbgOut("%s Arbiter @ 0x%I64x owned by device ", ResourceType, Address); Status = DbgReadIntegerMember(Context, ArbiterType, "OwningDevice", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintResourceArbiterEnd; } DbgOut("0x%I64x\n", Value); Status = DbgGetMemberOffset(ArbiterType, "EntryListHead", &ArbiterEntryListHeadOffset, NULL); if (Status != 0) { goto PrintResourceArbiterEnd; } ArbiterEntryListHeadOffset /= BITS_PER_BYTE; Status = DbgGetMemberOffset(ArbiterType, "ListEntry", &ArbiterEntryOffset, NULL); if (Status != 0) { goto PrintResourceArbiterEnd; } ArbiterEntryOffset /= BITS_PER_BYTE; Status = DbgGetTypeByName(Context, "LIST_ENTRY", &ListEntryType); if (Status != 0) { goto PrintResourceArbiterEnd; } // // Print out all entries. // IndentationLevel += 1; ChildListHead = Address + ArbiterEntryListHeadOffset; Status = DbgReadIntegerMember(Context, ArbiterType, "EntryListHead.Next", Address, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceArbiterEnd; } free(Data); Data = NULL; while (CurrentEntryAddress != ChildListHead) { // // Read the list entry. // assert(Data == NULL); Status = DbgReadType(Context, CurrentEntryAddress, ListEntryType, &Data, &DataSize); if (Status != 0) { goto PrintResourceArbiterEnd; } // // Print the arbiter entry. // ChildObjectAddress = CurrentEntryAddress - ArbiterEntryOffset; Result = ExtpPrintArbiterEntry(Context, ChildObjectAddress, IndentationLevel); if (Result == FALSE) { Status = EINVAL; goto PrintResourceArbiterEnd; } // // Move to the next entry. // Status = DbgReadIntegerMember(Context, ListEntryType, "Next", CurrentEntryAddress, Data, DataSize, &CurrentEntryAddress); if (Status != 0) { goto PrintResourceArbiterEnd; } free(Data); Data = NULL; } Status = 0; PrintResourceArbiterEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } BOOL ExtpPrintArbiterEntry ( PDEBUGGER_CONTEXT Context, ULONGLONG Address, ULONG IndentationLevel ) /*++ Routine Description: This routine prints out an arbiter entry. Arguments: Context - Supplies a pointer to the application context. Address - Supplies the address of the arbiter entry to print. IndentationLevel - Supplies the indentation level to print the object at. Return Value: TRUE on success. FALSE on failure. --*/ { PVOID Data; ULONG DataSize; PTYPE_SYMBOL EntryType; BOOL Result; PSTR SpaceType; INT Status; ULONGLONG Value; Data = NULL; // // Bail out if the indentation seems too deep. // if (IndentationLevel > 50) { return FALSE; } // // Print out the indentation. // DbgOut("%*s", IndentationLevel, ""); Status = DbgReadTypeByName(Context, Address, "_ARBITER_ENTRY", &EntryType, &Data, &DataSize); if (Status != 0) { DbgOut("Error: Could not read entry at 0x%I64x.\n", Address); goto PrintArbiterEntryEnd; } Status = DbgReadIntegerMember(Context, EntryType, "Type", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } switch (Value) { case ArbiterSpaceInvalid: SpaceType = "Invalid"; break; case ArbiterSpaceFree: SpaceType = "Free"; break; case ArbiterSpaceReserved: SpaceType = "Reserved"; break; case ArbiterSpaceAllocated: SpaceType = "Allocated"; break; default: SpaceType = "INVALID"; break; } DbgOut("%08I64x %9s: ", Address, SpaceType); Status = DbgReadIntegerMember(Context, EntryType, "Allocation", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } DbgOut("%08I64x, Len ", Value); Status = DbgReadIntegerMember(Context, EntryType, "Length", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } DbgOut("%08I64x, Char ", Value); Status = DbgReadIntegerMember(Context, EntryType, "Characteristics", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } DbgOut("%I64x, Requirement ", Value); Status = DbgReadIntegerMember(Context, EntryType, "CorrespondingRequirement", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } DbgOut("0x%I64x, Device ", Value); Status = DbgReadIntegerMember(Context, EntryType, "Device", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } DbgOut("0x%I64x", Value); Status = DbgReadIntegerMember(Context, EntryType, "DependentEntry", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } if (Value != 0) { DbgOut(", Dependent %I64x", Value); } Status = DbgReadIntegerMember(Context, EntryType, "Flags", Address, Data, DataSize, &Value); if (Status != 0) { goto PrintArbiterEntryEnd; } if ((Value & RESOURCE_FLAG_NOT_SHAREABLE) != 0) { DbgOut(" NotShared"); } if ((Value & RESOURCE_FLAG_BOOT) != 0) { DbgOut(" Boot"); } DbgOut("\n"); PrintArbiterEntryEnd: if (Data != NULL) { free(Data); } Result = TRUE; if (Status != 0) { Result = FALSE; } return Result; } PSTR ExtpGetResourceTypeString ( RESOURCE_TYPE Type ) /*++ Routine Description: This routine returns a string representing the given resource type. Arguments: Type - Supplies the resource type. Return Value: Returns a pointer to a constant read-only string representing the given resource type. --*/ { PSTR ResourceType; switch (Type) { case ResourceTypeInvalid: ResourceType = "Invalid"; break; case ResourceTypePhysicalAddressSpace: ResourceType = "Physical Address"; break; case ResourceTypeIoPort: ResourceType = "I/O Port"; break; case ResourceTypeInterruptLine: ResourceType = "Interrupt Line"; break; case ResourceTypeInterruptVector: ResourceType = "Interrupt Vector"; break; case ResourceTypeBusNumber: ResourceType = "Bus Number"; break; case ResourceTypeDmaChannel: ResourceType = "DMA Channel"; break; case ResourceTypeVendorSpecific: ResourceType = "Vendor Specific"; break; case ResourceTypeGpio: ResourceType = "GPIO"; break; case ResourceTypeSimpleBus: ResourceType = "SPB"; break; default: ResourceType = "INVALID RESOURCE TYPE"; break; } return ResourceType; }