863 lines
15 KiB
C
863 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1998-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dbgutil.c
|
||
|
||
Abstract:
|
||
|
||
Utility functions for dealing with the kernel debugger.
|
||
|
||
Author:
|
||
|
||
Keith Moore (keithmo) 17-Jun-1998
|
||
|
||
Environment:
|
||
|
||
User Mode.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
|
||
|
||
//
|
||
// Private constants.
|
||
//
|
||
|
||
#define EXT_DLL "kdexts.dll"
|
||
|
||
|
||
//
|
||
// Private globals.
|
||
//
|
||
|
||
PSTR WeekdayNames[] =
|
||
{
|
||
"Sunday",
|
||
"Monday",
|
||
"Tuesday",
|
||
"Wednesday",
|
||
"Thursday",
|
||
"Friday",
|
||
"Saturday"
|
||
};
|
||
|
||
PSTR MonthNames[] =
|
||
{
|
||
"",
|
||
"January",
|
||
"February",
|
||
"March",
|
||
"April",
|
||
"May",
|
||
"June",
|
||
"July",
|
||
"August",
|
||
"September",
|
||
"October",
|
||
"November",
|
||
"December"
|
||
};
|
||
|
||
HMODULE ExtensionDll = NULL;
|
||
|
||
|
||
//
|
||
// Public functions.
|
||
//
|
||
|
||
|
||
VOID
|
||
SystemTimeToString(
|
||
IN LONGLONG Value,
|
||
OUT PSTR Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Maps a LONGLONG representing system time to a displayable string.
|
||
|
||
Arguments:
|
||
|
||
Value - The LONGLONG time to map.
|
||
|
||
Buffer - Receives the mapped time.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS status;
|
||
LARGE_INTEGER systemTime;
|
||
LARGE_INTEGER localTime;
|
||
TIME_FIELDS timeFields;
|
||
|
||
systemTime.QuadPart = Value;
|
||
|
||
status = RtlSystemTimeToLocalTime( &systemTime, &localTime );
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
sprintf( Buffer, "%I64d", Value );
|
||
return;
|
||
}
|
||
|
||
RtlTimeToTimeFields( &localTime, &timeFields );
|
||
|
||
sprintf(
|
||
Buffer,
|
||
"%s %s %2d %4d %02d:%02d:%02d.%03d",
|
||
WeekdayNames[timeFields.Weekday],
|
||
MonthNames[timeFields.Month],
|
||
timeFields.Day,
|
||
timeFields.Year,
|
||
timeFields.Hour,
|
||
timeFields.Minute,
|
||
timeFields.Second,
|
||
timeFields.Milliseconds
|
||
);
|
||
|
||
} // SystemTimeToString
|
||
|
||
PSTR
|
||
SignatureToString(
|
||
IN ULONG CurrentSignature,
|
||
IN ULONG ValidSignature,
|
||
IN ULONG FreedSignature,
|
||
OUT PSTR Buffer
|
||
)
|
||
{
|
||
PSTR pstr = Buffer;
|
||
int i;
|
||
UCHAR ch;
|
||
|
||
*pstr++ = '\'';
|
||
|
||
for (i = 0; i < 4; ++i)
|
||
{
|
||
ch = (UCHAR)((CurrentSignature >> (8 * i)) & 0xFF);
|
||
*pstr++ = isprint(ch) ? (ch) : '?';
|
||
}
|
||
|
||
*pstr++ = '\'';
|
||
*pstr++ = ' ';
|
||
*pstr = '\0';
|
||
|
||
if (CurrentSignature == ValidSignature)
|
||
{
|
||
strcat(pstr, "OK");
|
||
}
|
||
else if (CurrentSignature == FreedSignature)
|
||
{
|
||
strcat(pstr, "FREED");
|
||
}
|
||
else
|
||
{
|
||
strcat(pstr, "INVALID");
|
||
}
|
||
|
||
return Buffer;
|
||
} // SignatureToString
|
||
|
||
|
||
PSTR
|
||
ParseStateToString(
|
||
IN PARSE_STATE State
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
switch (State)
|
||
{
|
||
case ParseVerbState:
|
||
result = "ParseVerbState";
|
||
break;
|
||
|
||
case ParseUrlState:
|
||
result = "ParseUrlState";
|
||
break;
|
||
|
||
case ParseVersionState:
|
||
result = "ParseVersionState";
|
||
break;
|
||
|
||
case ParseHeadersState:
|
||
result = "ParseHeadersState";
|
||
break;
|
||
|
||
case ParseCookState:
|
||
result = "ParseCookState";
|
||
break;
|
||
|
||
case ParseEntityBodyState:
|
||
result = "ParseEntityBodyState";
|
||
break;
|
||
|
||
case ParseTrailerState:
|
||
result = "ParseTrailerState";
|
||
break;
|
||
|
||
case ParseDoneState:
|
||
result = "ParseDoneState";
|
||
break;
|
||
|
||
case ParseErrorState:
|
||
result = "ParseErrorState";
|
||
break;
|
||
|
||
default:
|
||
result = "INVALID";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
|
||
} // ParseStateToString
|
||
|
||
|
||
PSTR
|
||
UlEnabledStateToString(
|
||
IN HTTP_ENABLED_STATE State
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
switch (State)
|
||
{
|
||
case HttpEnabledStateActive:
|
||
result = "HttpEnabledStateActive";
|
||
break;
|
||
|
||
case HttpEnabledStateInactive:
|
||
result = "HttpEnabledStateInactive";
|
||
break;
|
||
|
||
default:
|
||
result = "INVALID";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
PSTR
|
||
CachePolicyToString(
|
||
IN HTTP_CACHE_POLICY_TYPE PolicyType
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
switch (PolicyType)
|
||
{
|
||
case HttpCachePolicyNocache:
|
||
result = "HttpCachePolicyNocache";
|
||
break;
|
||
|
||
case HttpCachePolicyUserInvalidates:
|
||
result = "HttpCachePolicyUserInvalidates";
|
||
break;
|
||
|
||
case HttpCachePolicyTimeToLive:
|
||
result = "HttpCachePolicyTimeToLive";
|
||
break;
|
||
|
||
default:
|
||
result = "INVALID";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
PSTR
|
||
VerbToString(
|
||
IN HTTP_VERB Verb
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
switch (Verb)
|
||
{
|
||
case HttpVerbUnparsed:
|
||
result = "UnparsedVerb";
|
||
break;
|
||
|
||
case HttpVerbGET:
|
||
result = "GET";
|
||
break;
|
||
|
||
case HttpVerbPUT:
|
||
result = "PUT";
|
||
break;
|
||
|
||
case HttpVerbHEAD:
|
||
result = "HEAD";
|
||
break;
|
||
|
||
case HttpVerbPOST:
|
||
result = "POST";
|
||
break;
|
||
|
||
case HttpVerbDELETE:
|
||
result = "DELETE";
|
||
break;
|
||
|
||
case HttpVerbTRACE:
|
||
result = "TRACE";
|
||
break;
|
||
|
||
case HttpVerbOPTIONS:
|
||
result = "OPTIONS";
|
||
break;
|
||
|
||
case HttpVerbCONNECT:
|
||
result = "CONNECT";
|
||
break;
|
||
|
||
case HttpVerbMOVE:
|
||
result = "MOVE";
|
||
break;
|
||
|
||
case HttpVerbCOPY:
|
||
result = "COPY";
|
||
break;
|
||
|
||
case HttpVerbPROPFIND:
|
||
result = "PROPFIND";
|
||
break;
|
||
|
||
case HttpVerbPROPPATCH:
|
||
result = "PROPPATCH";
|
||
break;
|
||
|
||
case HttpVerbMKCOL:
|
||
result = "MKCOL";
|
||
break;
|
||
|
||
case HttpVerbLOCK:
|
||
result = "LOCK";
|
||
break;
|
||
|
||
case HttpVerbUNLOCK:
|
||
result = "LOCK";
|
||
break;
|
||
|
||
case HttpVerbSEARCH:
|
||
result = "SEARCH";
|
||
break;
|
||
|
||
case HttpVerbUnknown:
|
||
result = "UnknownVerb";
|
||
break;
|
||
|
||
case HttpVerbInvalid:
|
||
result = "InvalidVerb";
|
||
break;
|
||
|
||
default:
|
||
result = "INVALID";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
|
||
} // VerbToString
|
||
|
||
|
||
PSTR
|
||
VersionToString(
|
||
IN HTTP_VERSION Version
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
if (HTTP_EQUAL_VERSION(Version, 0, 9))
|
||
{
|
||
result = "Version09";
|
||
}
|
||
else
|
||
if (HTTP_EQUAL_VERSION(Version, 1, 0))
|
||
{
|
||
result = "Version10";
|
||
}
|
||
else
|
||
if (HTTP_EQUAL_VERSION(Version, 1, 1))
|
||
{
|
||
result = "Version11";
|
||
}
|
||
else
|
||
{
|
||
result = "INVALID";
|
||
}
|
||
|
||
return result;
|
||
|
||
} // VersionToString
|
||
|
||
PSTR
|
||
QueueStateToString(
|
||
IN QUEUE_STATE QueueState
|
||
)
|
||
{
|
||
PSTR result;
|
||
|
||
switch (QueueState)
|
||
{
|
||
case QueueUnroutedState:
|
||
result = "QueueUnroutedState";
|
||
break;
|
||
|
||
case QueueDeliveredState:
|
||
result = "QueueDeliveredState";
|
||
break;
|
||
|
||
case QueueCopiedState:
|
||
result = "QueueCopiedState";
|
||
break;
|
||
|
||
case QueueUnlinkedState:
|
||
result = "QueueUnlinkedState";
|
||
break;
|
||
|
||
default:
|
||
result = "INVALID";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
VOID
|
||
BuildSymbol(
|
||
IN PVOID RemoteAddress,
|
||
OUT PSTR Symbol
|
||
)
|
||
{
|
||
ULONG_PTR offset;
|
||
CHAR tmpSymbol[MAX_SYMBOL_LENGTH];
|
||
|
||
tmpSymbol[0] = '\0';
|
||
GetSymbol( RemoteAddress, tmpSymbol, &offset );
|
||
|
||
if (tmpSymbol[0] == '\0')
|
||
{
|
||
Symbol[0] = '\0';
|
||
}
|
||
else
|
||
if (offset == 0)
|
||
{
|
||
strcpy( Symbol, (PCHAR)tmpSymbol );
|
||
}
|
||
else
|
||
{
|
||
sprintf( Symbol, "%s+0x%p", tmpSymbol, offset );
|
||
}
|
||
|
||
} // BuildSymbol
|
||
|
||
PSTR
|
||
GetSpinlockState(
|
||
IN PUL_SPIN_LOCK SpinLock
|
||
)
|
||
{
|
||
if (*((PULONG_PTR)SpinLock) == 0)
|
||
{
|
||
return "FREE";
|
||
}
|
||
else
|
||
{
|
||
return "ACQUIRED";
|
||
}
|
||
|
||
} // GetSpinlockState
|
||
|
||
BOOLEAN
|
||
EnumLinkedList(
|
||
IN PLIST_ENTRY RemoteListHead,
|
||
IN PENUM_LINKED_LIST_CALLBACK Callback,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
LIST_ENTRY localListEntry;
|
||
PLIST_ENTRY nextRemoteListEntry;
|
||
ULONG result;
|
||
|
||
//
|
||
// Try to read the list head.
|
||
//
|
||
|
||
if (!ReadMemory(
|
||
(ULONG_PTR)RemoteListHead,
|
||
&localListEntry,
|
||
sizeof(localListEntry),
|
||
&result
|
||
))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Loop through the entries.
|
||
//
|
||
|
||
nextRemoteListEntry = localListEntry.Flink;
|
||
|
||
while (nextRemoteListEntry != RemoteListHead)
|
||
{
|
||
if (CheckControlC())
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (!(Callback)( nextRemoteListEntry, Context ))
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (!ReadMemory(
|
||
(ULONG_PTR)nextRemoteListEntry,
|
||
&localListEntry,
|
||
sizeof(localListEntry),
|
||
&result
|
||
))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
nextRemoteListEntry = localListEntry.Flink;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // EnumLinkedList
|
||
|
||
|
||
|
||
BOOLEAN
|
||
EnumSList(
|
||
IN PSLIST_HEADER RemoteSListHead,
|
||
IN PENUM_SLIST_CALLBACK Callback,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
SLIST_HEADER localSListHead;
|
||
SINGLE_LIST_ENTRY localSListEntry;
|
||
PSINGLE_LIST_ENTRY nextRemoteSListEntry;
|
||
ULONG result;
|
||
|
||
//
|
||
// Try to read the list head.
|
||
//
|
||
|
||
if (!ReadMemory(
|
||
(ULONG_PTR)RemoteSListHead,
|
||
&localSListHead,
|
||
sizeof(localSListHead),
|
||
&result
|
||
))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Loop through the entries.
|
||
//
|
||
|
||
nextRemoteSListEntry = SLIST_HEADER_NEXT(&localSListHead);
|
||
|
||
while (nextRemoteSListEntry != NULL)
|
||
{
|
||
if (CheckControlC())
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (!(Callback)( nextRemoteSListEntry, Context ))
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (!ReadMemory(
|
||
(ULONG_PTR)nextRemoteSListEntry,
|
||
&localSListEntry,
|
||
sizeof(localSListEntry),
|
||
&result
|
||
))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
nextRemoteSListEntry = localSListEntry.Next;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // EnumSList
|
||
|
||
|
||
|
||
PSTR
|
||
BuildResourceState(
|
||
IN PUL_ERESOURCE LocalAddress,
|
||
OUT PSTR Buffer
|
||
)
|
||
{
|
||
PERESOURCE pResource;
|
||
|
||
pResource = (PERESOURCE)LocalAddress;
|
||
|
||
if (pResource->ActiveCount == 0)
|
||
{
|
||
sprintf(
|
||
Buffer,
|
||
"UNOWNED"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
if ((pResource->Flag & ResourceOwnedExclusive) != 0)
|
||
{
|
||
sprintf(
|
||
Buffer,
|
||
"OWNED EXCLUSIVE BY %p [%ld]",
|
||
pResource->OwnerThreads[0].OwnerThread,
|
||
pResource->OwnerThreads[0].OwnerCount
|
||
);
|
||
}
|
||
else
|
||
{
|
||
sprintf(
|
||
Buffer,
|
||
"OWNED SHARED"
|
||
);
|
||
}
|
||
}
|
||
|
||
return Buffer;
|
||
|
||
} // BuildResourceState
|
||
|
||
BOOLEAN
|
||
IsThisACheckedBuild(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG_PTR address;
|
||
ULONG value = 0;
|
||
ULONG result;
|
||
BOOLEAN isChecked = FALSE;
|
||
|
||
address = GetExpression( "&http!g_UlCheckedBuild" );
|
||
|
||
if (address != 0)
|
||
{
|
||
if (ReadMemory(
|
||
address,
|
||
&value,
|
||
sizeof(value),
|
||
&result
|
||
))
|
||
{
|
||
isChecked = (value != 0);
|
||
}
|
||
}
|
||
|
||
return isChecked;
|
||
|
||
} // IsThisACheckedBuild
|
||
|
||
VOID
|
||
DumpBitVector(
|
||
IN PSTR Prefix1,
|
||
IN PSTR Prefix2,
|
||
IN ULONG Vector,
|
||
IN PVECTORMAP VectorMap
|
||
)
|
||
{
|
||
while ((Vector != 0) && (VectorMap->Vector != 0))
|
||
{
|
||
if (Vector & VectorMap->Vector)
|
||
{
|
||
dprintf(
|
||
"%s%s%s\n",
|
||
Prefix1,
|
||
Prefix2,
|
||
VectorMap->Name
|
||
);
|
||
|
||
Vector &= ~(VectorMap->Vector);
|
||
}
|
||
|
||
VectorMap++;
|
||
}
|
||
|
||
if (Vector != 0)
|
||
{
|
||
dprintf(
|
||
"%s%sExtra Bits = %08lx\n",
|
||
Prefix1,
|
||
Prefix2,
|
||
Vector
|
||
);
|
||
}
|
||
|
||
} // DumpBitVector
|
||
|
||
VOID
|
||
DumpRawData(
|
||
IN PSTR Prefix,
|
||
IN ULONG_PTR RemoteAddress,
|
||
IN ULONG BufferLength
|
||
)
|
||
{
|
||
PSTR lineScan;
|
||
ULONG lineLength;
|
||
ULONG i;
|
||
ULONG result;
|
||
UCHAR ch;
|
||
UCHAR rawData[16];
|
||
CHAR formattedData[sizeof("1234567812345678 11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00 123456789abcdef0")];
|
||
|
||
while (BufferLength > 0)
|
||
{
|
||
lineLength = (BufferLength > 16) ? 16 : BufferLength;
|
||
|
||
if (!ReadMemory(
|
||
RemoteAddress,
|
||
rawData,
|
||
lineLength,
|
||
&result
|
||
))
|
||
{
|
||
dprintf( "%sCannot read memory @ %p\n", Prefix, RemoteAddress );
|
||
break;
|
||
}
|
||
|
||
lineScan = formattedData;
|
||
|
||
lineScan += sprintf( lineScan, "%p ", RemoteAddress );
|
||
|
||
for (i = 0 ; i < 16 ; i++)
|
||
{
|
||
if (i < lineLength)
|
||
{
|
||
lineScan += sprintf(
|
||
lineScan,
|
||
"%02X%c",
|
||
rawData[i],
|
||
(i == 7)
|
||
? '-'
|
||
: ' '
|
||
);
|
||
}
|
||
else
|
||
{
|
||
*lineScan++ = ' ';
|
||
*lineScan++ = ' ';
|
||
*lineScan++ = ' ';
|
||
}
|
||
}
|
||
|
||
*lineScan++ = ' ';
|
||
*lineScan++ = ' ';
|
||
|
||
for (i = 0 ; i < 16 ; i++)
|
||
{
|
||
if (i < lineLength)
|
||
{
|
||
ch = rawData[i];
|
||
|
||
if ((ch < ' ') || (ch > '~'))
|
||
{
|
||
ch = '.';
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ch = ' ';
|
||
}
|
||
|
||
*lineScan++ = ch;
|
||
}
|
||
|
||
*lineScan = '\0';
|
||
|
||
dprintf(
|
||
"%s%s\n",
|
||
Prefix,
|
||
formattedData
|
||
);
|
||
|
||
BufferLength -= lineLength;
|
||
RemoteAddress += (ULONG_PTR)lineLength;
|
||
}
|
||
|
||
} // DumpRawData
|
||
|
||
|
||
BOOLEAN
|
||
CallExtensionRoutine(
|
||
IN PSTR RoutineName,
|
||
IN PSTR ArgumentString
|
||
)
|
||
{
|
||
#if _WIN64
|
||
PWINDBG_EXTENSION_ROUTINE64 ExtRoutine;
|
||
#else
|
||
PWINDBG_EXTENSION_ROUTINE ExtRoutine;
|
||
#endif
|
||
|
||
BOOLEAN result = FALSE;
|
||
|
||
#ifdef EXT_DLL
|
||
if (ExtensionDll == NULL)
|
||
{
|
||
ExtensionDll = LoadLibraryA( EXT_DLL );
|
||
}
|
||
#endif
|
||
|
||
if (ExtensionDll != NULL)
|
||
{
|
||
#if _WIN64
|
||
ExtRoutine = (PWINDBG_EXTENSION_ROUTINE64)GetProcAddress(
|
||
ExtensionDll,
|
||
RoutineName
|
||
);
|
||
#else
|
||
ExtRoutine = (PWINDBG_EXTENSION_ROUTINE)GetProcAddress(
|
||
ExtensionDll,
|
||
RoutineName
|
||
);
|
||
#endif
|
||
if (ExtRoutine != NULL)
|
||
{
|
||
(ExtRoutine)(
|
||
g_hCurrentProcess,
|
||
g_hCurrentThread,
|
||
g_dwCurrentPc,
|
||
g_dwProcessor,
|
||
ArgumentString
|
||
);
|
||
|
||
result = TRUE;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
|
||
} // CallExtensionRoutine
|
||
|