windows-nt/Source/XPSP1/NT/drivers/storage/kdext/scsikd/util.c
2020-09-26 16:20:57 +08:00

759 lines
17 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1992 - 1999
Module Name:
util.c
Abstract:
Utility library used for the various debugger extensions in this library.
Author:
Peter Wieland (peterwie) 16-Oct-1995
Environment:
User Mode.
Revision History:
--*/
#include "pch.h"
#include "classkd.h" // routines that are useful for all class drivers
PUCHAR devicePowerStateNames[] = {
"PowerDeviceUnspecified",
"PowerDeviceD0",
"PowerDeviceD1",
"PowerDeviceD2",
"PowerDeviceD3",
"PowerDeviceMaximum",
"Invalid"
};
FLAG_NAME SrbFlags[] = {
FLAG_NAME(SRB_FLAGS_QUEUE_ACTION_ENABLE),
FLAG_NAME(SRB_FLAGS_DISABLE_DISCONNECT),
FLAG_NAME(SRB_FLAGS_DISABLE_SYNCH_TRANSFER),
FLAG_NAME(SRB_FLAGS_BYPASS_FROZEN_QUEUE),
FLAG_NAME(SRB_FLAGS_DISABLE_AUTOSENSE),
FLAG_NAME(SRB_FLAGS_DATA_IN),
FLAG_NAME(SRB_FLAGS_DATA_OUT),
FLAG_NAME(SRB_FLAGS_NO_DATA_TRANSFER),
FLAG_NAME(SRB_FLAGS_UNSPECIFIED_DIRECTION),
FLAG_NAME(SRB_FLAGS_NO_QUEUE_FREEZE),
FLAG_NAME(SRB_FLAGS_ADAPTER_CACHE_ENABLE),
FLAG_NAME(SRB_FLAGS_IS_ACTIVE),
FLAG_NAME(SRB_FLAGS_ALLOCATED_FROM_ZONE),
FLAG_NAME(SRB_FLAGS_SGLIST_FROM_POOL),
FLAG_NAME(SRB_FLAGS_BYPASS_LOCKED_QUEUE),
FLAG_NAME(SRB_FLAGS_NO_KEEP_AWAKE),
{0,0}
};
char *g_genericErrorHelpStr = "\n" \
"**************************************************************** \n" \
" Make sure you have _private_ symbols for classpnp.sys loaded.\n" \
" The FDO parameter should be the upper AttachedDevice of the disk/cdrom/etc PDO\n" \
" as returned by '!devnode 0 1 {disk|cdrom|4mmdat|etc}'.\n" \
"**************************************************************** \n\n" \
;
VOID
GetAddress(
IN PCSTR Args,
OUT PULONG64 Address
)
{
UCHAR addressBuffer[256];
addressBuffer[0] = '\0';
sscanf(Args, "%s", addressBuffer);
addressBuffer[255] = '\0';
*Address = 0;
if (addressBuffer[0] != '\0') {
//
// they provided an address
//
*Address = GetExpression(addressBuffer);
//
// if that still doesn't parse, print an error
//
if (*Address==0) {
dprintf("An error occured trying to evaluate the address\n");
*Address = 0;
return;
}
}
return;
}
VOID
GetAddressAndDetailLevel(
IN PCSTR Args,
OUT PULONG64 Address,
OUT PLONG Detail
)
{
UCHAR addressBuffer[256];
UCHAR detailBuffer[256];
addressBuffer[0] = '\0';
detailBuffer[0] = '\0';
sscanf(Args, "%s %s", addressBuffer, detailBuffer);
addressBuffer[255] = '\0';
detailBuffer[255] = '\0';
*Address = 0;
*Detail = 0;
if (addressBuffer[0] != '\0') {
//
// they provided an address
//
*Address = GetExpression(addressBuffer);
//
// if that still doesn't parse, print an error
//
if (*Address==0) {
dprintf("An error occured trying to evaluate the address\n");
*Address = 0;
*Detail = 0;
return;
}
//
// if they provided a detail level get it.
//
if (detailBuffer[0] == '\0') {
*Detail = 0;
} else {
*Detail = (ULONG)GetExpression(detailBuffer);
}
}
return;
}
VOID
GetAddressAndDetailLevel64(
IN PCSTR Args,
OUT PULONG64 Address,
OUT PLONG Detail
)
{
UCHAR addressBuffer[256];
UCHAR detailBuffer[256];
addressBuffer[0] = '\0';
detailBuffer[0] = '\0';
sscanf(Args, "%s %s", addressBuffer, detailBuffer);
addressBuffer[255] = '\0';
detailBuffer[255] = '\0';
*Address = 0;
*Detail = 0;
if (addressBuffer[0] != '\0') {
//
// they provided an address
//
*Address = GetExpression(addressBuffer);
//
// if that still doesn't parse, print an error
//
if (*Address==0) {
dprintf("An error occured trying to evaluate the address\n");
*Address = 0;
*Detail = 0;
return;
}
//
// if they provided a detail level get it.
//
if (detailBuffer[0] == '\0') {
*Detail = 0;
} else {
*Detail = (ULONG)GetExpression(detailBuffer);
}
}
return;
}
PUCHAR
DevicePowerStateToString(
IN DEVICE_POWER_STATE State
)
{
if(State > PowerDeviceMaximum) {
return devicePowerStateNames[PowerDeviceMaximum + 1];
} else {
return devicePowerStateNames[(UCHAR) State];
}
}
//
// Translates various printf formats to account for the target platform.
//
// This looks for %p type format and truncates the top 4 bytes of the ULONG64
// address argument if the debugee is a 32 bit machine.
// The %p is replaced by %I64x in format string.
//
BOOL
TranslateFormat(
LPSTR formatOut,
LPCSTR format,
va_list args,
ULONG formatOutSize
)
{
#define Duplicate(j,i) (formatOut[j++] = format[i++])
ULONG minSize = strlen(format), i = 0, j = 0;
CHAR c;
BOOL TypeFormat = FALSE;
BOOL FormatChanged = FALSE;
do
{
c = format[i];
if (c=='%')
{
TypeFormat = !TypeFormat;
}
if (TypeFormat)
{
switch (c)
{
case 'c': case 'C': case 'i': case 'd':
case 'o': case 'u': case 'x': case 'X':
Duplicate(j,i);
va_arg(args, int);
TypeFormat = FALSE;
break;
case 'e': case 'E': case 'f': case 'g':
case 'G':
Duplicate(j,i);
va_arg(args, double);
TypeFormat = FALSE;
break;
case 'n':
Duplicate(j,i);
va_arg(args, int*);
TypeFormat = FALSE;
break;
case 'N':
// Native pointer, turns into %p.
formatOut[j++] = 'p';
FormatChanged = TRUE;
i++;
va_arg(args, void*);
TypeFormat = FALSE;
break;
case 's': case 'S':
Duplicate(j,i);
va_arg(args, char*);
TypeFormat = FALSE;
break;
case 'I':
if ((format[i+1] == '6') && (format[i+2] == '4'))
{
Duplicate(j,i);
Duplicate(j,i);
va_arg(args, ULONG64);
TypeFormat = FALSE;
}
// dprintf("I64 a0 %lx, off %lx\n", args.a0, args.offset);
Duplicate(j,i);
break;
case 'z': case 'Z':
// unicode string
Duplicate(j,i);
va_arg(args, void*);
TypeFormat = FALSE;
break;
case 'p':
case 'P':
minSize +=3;
if (format[i-1] == '%')
{
minSize++;
if (IsPtr64())
{
minSize += 2;
if (minSize > formatOutSize)
{
return FALSE;
}
formatOut[j++] = '0';
formatOut[j++] = '1';
formatOut[j++] = '6';
}
else
{
if (minSize > formatOutSize)
{
return FALSE;
}
formatOut[j++] = '0';
formatOut[j++] = '8';
}
}
if (minSize > formatOutSize)
{
return FALSE;
}
formatOut[j++] = 'I';
formatOut[j++] = '6';
formatOut[j++] = '4';
formatOut[j++] = (c == 'p') ? 'x' : 'X'; ++i;
FormatChanged = TRUE;
if (!IsPtr64())
{
PULONG64 Arg;
#ifdef _M_ALPHA
Arg = (PULONG64) ((args.a0)+args.offset);
//dprintf("a0 %lx, off %lx\n", args.a0, args.offset);
#else
Arg = (PULONG64) (args);
#endif
//
// Truncate signextended addresses
//
*Arg = (ULONG64) (ULONG) *Arg;
}
va_arg(args, ULONG64);
TypeFormat = FALSE;
break;
default:
Duplicate(j,i);
} /* switch */
}
else
{
Duplicate(j,i);
}
}
while (format[i] != '\0');
formatOut[j] = '\0';
return FormatChanged;
#undef Duplicate
}
/*
* xdprintf
*
* Prints formatted text with leading spaces.
*
* WARNING: DOES NOT HANDLE ULONG64 PROPERLY.
*/
VOID
xdprintf(
ULONG Depth,
PCCHAR Format,
...
)
{
va_list args;
ULONG i;
CCHAR DebugBuffer[256];
for (i=0; i<Depth; i++) {
dprintf (" ");
}
va_start(args, Format);
_vsnprintf(DebugBuffer, 255, Format, args);
dprintf (DebugBuffer);
va_end(args);
}
VOID
DumpFlags(
ULONG Depth,
PUCHAR Name,
ULONG Flags,
PFLAG_NAME FlagTable
)
{
ULONG i;
ULONG mask = 0;
ULONG count = 0;
UCHAR prolog[64];
sprintf(prolog, "%s (0x%08x): ", Name, Flags);
xdprintf(Depth, "%s", prolog);
if(Flags == 0) {
dprintf("\n");
return;
}
memset(prolog, ' ', strlen(prolog));
for(i = 0; FlagTable[i].Name != 0; i++) {
PFLAG_NAME flag = &(FlagTable[i]);
mask |= flag->Flag;
if((Flags & flag->Flag) == flag->Flag) {
//
// print trailing comma
//
if(count != 0) {
dprintf(", ");
//
// Only print two flags per line.
//
if((count % 2) == 0) {
dprintf("\n");
xdprintf(Depth, "%s", prolog);
}
}
dprintf("%s", flag->Name);
count++;
}
}
dprintf("\n");
if((Flags & (~mask)) != 0) {
xdprintf(Depth, "%sUnknown flags %#010lx\n", prolog, (Flags & (~mask)));
}
return;
}
BOOLEAN
GetAnsiString(
IN ULONG64 Address,
IN PUCHAR Buffer,
IN OUT PULONG Length
)
{
ULONG i = 0;
//
// Grab the string in 64 character chunks until we find a NULL or the
// read fails.
//
while((i < *Length) && (!CheckControlC())) {
ULONG transferSize;
ULONG result;
if(*Length - i < 128) {
transferSize = *Length - i;
} else {
transferSize = 128;
}
if(!ReadMemory(Address + i,
Buffer + i,
transferSize,
&result)) {
//
// read failed and we didn't find the NUL the last time. Don't
// expect to find it this time.
//
*Length = i;
return FALSE;
} else {
ULONG j;
//
// Scan from where we left off looking for that NUL character.
//
for(j = 0; j < transferSize; j++) {
if(Buffer[i + j] == '\0') {
*Length = i + j;
return TRUE;
}
}
}
i += transferSize;
}
//
// We never found the NUL. Don't need to update Length since it's currently
// equal to i.
//
return FALSE;
}
PCHAR
GuidToString(
GUID* Guid
)
{
static CHAR Buffer [64];
sprintf (Buffer,
"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
Guid->Data1,
Guid->Data2,
Guid->Data3,
Guid->Data4[0],
Guid->Data4[1],
Guid->Data4[2],
Guid->Data4[3],
Guid->Data4[4],
Guid->Data4[5],
Guid->Data4[6],
Guid->Data4[7]
);
return Buffer;
}
ULONG64
GetDeviceExtension(
ULONG64 address
)
/*++
Routine Description:
The function accepts the address of either a device object or a device
extension. If the supplied address is that of a device object, the
device extension is retrieved and returned. If the address is that of
a device extension, the address is returned unmodified.
Arguments:
Address - address of a device extension or a device object
Return Value:
The address of the device extension or 0 if an error occurs.
--*/
{
ULONG result;
CSHORT Type;
ULONG64 Address = address;
//
// The supplied address may be either the address of a device object or the
// address of a device extension. To distinguish which, we treat the
// address as a device object and read what would be its type field. If
// the
//
result = GetFieldData(Address,
"scsiport!_DEVICE_OBJECT",
"Type",
sizeof(CSHORT),
&Type
);
if (result) {
SCSIKD_PRINT_ERROR(result);
return 0;
}
//
// See if the supplied address holds a device object. If it does, read the
// address of the device extension. Otherwise, we assume the supplied
// addres holds a device extension and we use it directly.
//
if (Type == IO_TYPE_DEVICE) {
result = GetFieldData(Address,
"scsiport!_DEVICE_OBJECT",
"DeviceExtension",
sizeof(ULONG64),
&Address
);
if (result) {
SCSIKD_PRINT_ERROR(result);
return 0;
}
}
return Address;
}
/*
* GetULONGField
*
* Return the field or -1 in case of error.
* Yes, it screws up if the field is actually -1.
*/
ULONG64 GetULONGField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
{
ULONG64 result;
ULONG dbgStat;
dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(ULONG64), &result);
if (dbgStat != 0){
dprintf("\n GetULONGField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
dprintf(g_genericErrorHelpStr);
result = BAD_VALUE;
}
return result;
}
/*
* GetUSHORTField
*
* Return the field or -1 in case of error.
* Yes, it screws up if the field is actually -1.
*/
USHORT GetUSHORTField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
{
USHORT result;
ULONG dbgStat;
dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(USHORT), &result);
if (dbgStat != 0){
dprintf("\n GetUSHORTField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
dprintf(g_genericErrorHelpStr);
result = (USHORT)BAD_VALUE;
}
return result;
}
/*
* GetUCHARField
*
* Return the field or -1 in case of error.
* Yes, it screws up if the field is actually -1.
*/
UCHAR GetUCHARField(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
{
UCHAR result;
ULONG dbgStat;
dbgStat = GetFieldData(StructAddr, StructType, FieldName, sizeof(UCHAR), &result);
if (dbgStat != 0){
dprintf("\n GetUCHARField: GetFieldData failed with %xh retrieving field '%s' of struct '%s', returning bogus field value %08xh.\n", dbgStat, FieldName, StructType, BAD_VALUE);
dprintf(g_genericErrorHelpStr);
result = (UCHAR)BAD_VALUE;
}
return result;
}
ULONG64 GetFieldAddr(ULONG64 StructAddr, LPCSTR StructType, LPCSTR FieldName)
{
ULONG64 result;
ULONG offset;
ULONG dbgStat;
dbgStat = GetFieldOffset(StructType, FieldName, &offset);
if (dbgStat == 0){
result = StructAddr+offset;
}
else {
dprintf("\n GetFieldAddr: GetFieldOffset failed with %xh retrieving offset of struct '%s' field '%s'.\n", dbgStat, StructType, FieldName);
dprintf(g_genericErrorHelpStr);
result = BAD_VALUE;
}
return result;
}
ULONG64 GetContainingRecord(ULONG64 FieldAddr, LPCSTR StructType, LPCSTR FieldName)
{
ULONG64 result;
ULONG offset;
ULONG dbgStat;
dbgStat = GetFieldOffset(StructType, FieldName, &offset);
if (dbgStat == 0){
result = FieldAddr-offset;
}
else {
dprintf("\n GetContainingRecord: GetFieldOffset failed with %xh retrieving offset of struct '%s' field '%s', returning bogus address %08xh.\n", dbgStat, StructType, FieldName, BAD_VALUE);
dprintf(g_genericErrorHelpStr);
result = BAD_VALUE;
}
return result;
}