631 lines
13 KiB
C
631 lines
13 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
util.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
WinDbg Extension Api
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Wesley Witt (wesw) 15-Aug-1993
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
ULONG
|
||
|
GetBitFieldOffset (
|
||
|
IN LPSTR Type,
|
||
|
IN LPSTR Field,
|
||
|
OUT PULONG pOffset,
|
||
|
OUT PULONG pSize
|
||
|
)
|
||
|
{
|
||
|
FIELD_INFO flds = {
|
||
|
Field, "", 0,
|
||
|
DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_SIZE_IN_BITS,
|
||
|
0, NULL};
|
||
|
SYM_DUMP_PARAM Sym = {
|
||
|
sizeof (SYM_DUMP_PARAM), Type, DBG_DUMP_NO_PRINT, 0,
|
||
|
NULL, NULL, NULL, 1, &flds
|
||
|
};
|
||
|
ULONG Err, i=0;
|
||
|
LPSTR dot, last=Field;
|
||
|
|
||
|
Sym.nFields = 1;
|
||
|
Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
|
||
|
*pOffset = (ULONG) (flds.address - Sym.addr);
|
||
|
*pSize = flds.size;
|
||
|
return Err;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
GetFieldOffsetEx (
|
||
|
IN LPSTR Type,
|
||
|
IN LPSTR Field,
|
||
|
OUT PULONG pOffset,
|
||
|
OUT PULONG pSize
|
||
|
)
|
||
|
{
|
||
|
FIELD_INFO flds = {
|
||
|
Field, "", 0,
|
||
|
DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS,
|
||
|
0, NULL};
|
||
|
SYM_DUMP_PARAM Sym = {
|
||
|
sizeof (SYM_DUMP_PARAM), Type, DBG_DUMP_NO_PRINT, 0,
|
||
|
NULL, NULL, NULL, 1, &flds
|
||
|
};
|
||
|
ULONG Err, i=0;
|
||
|
LPSTR dot, last=Field;
|
||
|
|
||
|
Sym.nFields = 1;
|
||
|
Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
|
||
|
*pOffset = (ULONG) (flds.address - Sym.addr);
|
||
|
*pSize = flds.size;
|
||
|
return Err;
|
||
|
} // GetFieldOffsetEx()
|
||
|
|
||
|
ULONG
|
||
|
GetUlongFromAddress (
|
||
|
ULONG64 Location
|
||
|
)
|
||
|
{
|
||
|
ULONG Value;
|
||
|
ULONG result;
|
||
|
|
||
|
if ((!ReadMemory(Location,&Value,sizeof(ULONG),&result)) ||
|
||
|
(result < sizeof(ULONG))) {
|
||
|
dprintf("GetUlongFromAddress: unable to read from %p\n", Location);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return Value;
|
||
|
}
|
||
|
|
||
|
ULONG64
|
||
|
GetPointerFromAddress (
|
||
|
ULONG64 Location
|
||
|
)
|
||
|
{
|
||
|
ULONG64 Value;
|
||
|
ULONG result;
|
||
|
|
||
|
if (!ReadPointer( Location, &Value )) {
|
||
|
dprintf( "GetPointerFromAddress: unable to read from %p\n", Location );
|
||
|
return 0;
|
||
|
}
|
||
|
return Value;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
GetUlongValue (
|
||
|
PCHAR String
|
||
|
)
|
||
|
{
|
||
|
ULONG64 Location;
|
||
|
ULONG Value;
|
||
|
ULONG result;
|
||
|
|
||
|
|
||
|
Location = GetExpression( String );
|
||
|
if (!Location) {
|
||
|
dprintf("unable to get %s\n",String);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return GetUlongFromAddress( Location );
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG64
|
||
|
GetPointerValue (
|
||
|
PCHAR String
|
||
|
)
|
||
|
{
|
||
|
ULONG64 Location, Val=0;
|
||
|
|
||
|
|
||
|
Location = GetExpression( String );
|
||
|
if (!Location) {
|
||
|
dprintf("unable to get %s\n",String);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
ReadPointer(Location, &Val);
|
||
|
|
||
|
return Val;
|
||
|
}
|
||
|
|
||
|
ULONG64
|
||
|
GetGlobalFromAddress (
|
||
|
ULONG64 Location,
|
||
|
ULONG Size
|
||
|
)
|
||
|
{
|
||
|
ULONG64 value;
|
||
|
ULONG result;
|
||
|
|
||
|
value = 0;
|
||
|
if ((!ReadMemory(Location,&value,Size,&result)) || (result < Size)) {
|
||
|
dprintf("GetGlobalFromAddress: unable to read from %p\n", Location);
|
||
|
return 0;
|
||
|
}
|
||
|
return value;
|
||
|
} // GetGlobalFromAddress()
|
||
|
|
||
|
ULONG64
|
||
|
GetGlobalValue (
|
||
|
PCHAR String
|
||
|
)
|
||
|
{
|
||
|
ULONG64 location;
|
||
|
ULONG size;
|
||
|
|
||
|
location = GetExpression( String );
|
||
|
if (!location) {
|
||
|
dprintf("GetGlobalValue: unable to get %s\n",String);
|
||
|
return 0;
|
||
|
}
|
||
|
size = GetTypeSize( String );
|
||
|
if (!size) {
|
||
|
dprintf("GetGlobalValue: unable to get %s type size\n",String);
|
||
|
return 0;
|
||
|
}
|
||
|
return GetGlobalFromAddress( location, size );
|
||
|
} // GetGlobalValue()
|
||
|
|
||
|
HRESULT
|
||
|
GetGlobalEx(
|
||
|
PCHAR String,
|
||
|
PVOID OutValue,
|
||
|
ULONG OutSize
|
||
|
)
|
||
|
{
|
||
|
ULONG64 location;
|
||
|
ULONG size;
|
||
|
ULONG result;
|
||
|
|
||
|
ZeroMemory( OutValue, OutSize );
|
||
|
location = GetExpression( String );
|
||
|
if (!location) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
size = GetTypeSize( String );
|
||
|
if (!size) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
if ( size > OutSize ) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
if ((!ReadMemory(location,OutValue,size,&result)) || (result < size)) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
return S_OK;
|
||
|
} // GetGlobalEx()
|
||
|
|
||
|
#if 0
|
||
|
VOID
|
||
|
DumpImageName(
|
||
|
IN ULONG64 Process
|
||
|
)
|
||
|
{
|
||
|
ULONG64 ImageFileName;
|
||
|
STRING String;
|
||
|
ULONG Result;
|
||
|
IN WCHAR Buf[512];
|
||
|
|
||
|
|
||
|
if ( !GetFieldValue(Process, "EPROCESS", "ImageFileName.Buffer", ImageFileName ) ){
|
||
|
|
||
|
wcscpy(Buf,L"*** image name unavailable ***");
|
||
|
if ( ReadMemory( ImageFileName,
|
||
|
&String,
|
||
|
sizeof(STRING),
|
||
|
&Result) ) {
|
||
|
if ( ReadMemory( (DWORD)String.Buffer,
|
||
|
&Buf[0],
|
||
|
String.Length,
|
||
|
&Result) ) {
|
||
|
Buf[String.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
wcscpy(Buf,L"System Process");
|
||
|
}
|
||
|
dprintf("%ws",Buf);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
BOOLEAN
|
||
|
DbgRtlIsRightChild(
|
||
|
ULONG64 pLinks,
|
||
|
ULONG64 Parent
|
||
|
)
|
||
|
{
|
||
|
ULONG64 RightChild;
|
||
|
if (Parent == pLinks) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (GetFieldValue(Parent, "RTL_SPLAY_LINKS", "RightChild", RightChild)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (RightChild == pLinks) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
DbgRtlIsLeftChild(
|
||
|
ULONG64 pLinks,
|
||
|
ULONG64 Parent
|
||
|
)
|
||
|
{
|
||
|
ULONG64 LeftChild;
|
||
|
if (Parent == pLinks) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (GetFieldValue(Parent, "RTL_SPLAY_LINKS", "LeftChild", LeftChild)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (LeftChild == pLinks) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
DumpSplayTree(
|
||
|
IN ULONG64 pSplayLinks,
|
||
|
IN PDUMP_SPLAY_NODE_FN DumpNodeFn
|
||
|
)
|
||
|
/*++
|
||
|
Purpose:
|
||
|
|
||
|
Perform an in-order iteration across a splay tree, calling a
|
||
|
user supplied function with a pointer to each RTL_SPLAY_LINKS
|
||
|
structure encountered in the tree, and the level in the tree
|
||
|
at which it was encountered (zero based).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pSplayLinks - pointer to root of a splay tree
|
||
|
|
||
|
DumpNodeFn - user supplied dumping function
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Count of nodes encountered in the tree.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Errors reading memory do not terminate the iteration if more
|
||
|
work is possible.
|
||
|
|
||
|
Consumes the Control-C flag to terminate possible loops in
|
||
|
corrupt structures.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG Level = 0;
|
||
|
ULONG NodeCount = 0;
|
||
|
|
||
|
if (pSplayLinks) {
|
||
|
ULONG64 LeftChild, RightChild, Parent, Current;
|
||
|
|
||
|
//
|
||
|
// Retrieve the root links, find the leftmost node in the tree
|
||
|
//
|
||
|
|
||
|
if (GetFieldValue(Current = pSplayLinks,
|
||
|
"RTL_SPLAY_LINKS",
|
||
|
"LeftChild",
|
||
|
LeftChild)) {
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
while (LeftChild != 0) {
|
||
|
|
||
|
if ( CheckControlC() ) {
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
if (GetFieldValue(Current = LeftChild,
|
||
|
"RTL_SPLAY_LINKS",
|
||
|
"LeftChild",
|
||
|
LeftChild)) {
|
||
|
|
||
|
//
|
||
|
// We can try to continue from this
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Level++;
|
||
|
}
|
||
|
|
||
|
while (TRUE) {
|
||
|
|
||
|
if ( CheckControlC() ) {
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
NodeCount++;
|
||
|
pSplayLinks = Current;
|
||
|
(*DumpNodeFn)(pSplayLinks, Level);
|
||
|
|
||
|
/*
|
||
|
first check to see if there is a right subtree to the input link
|
||
|
if there is then the real successor is the left most node in
|
||
|
the right subtree. That is find and return P in the following diagram
|
||
|
|
||
|
Links
|
||
|
\
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
/
|
||
|
P
|
||
|
\
|
||
|
*/
|
||
|
|
||
|
GetFieldValue(Current, "RTL_SPLAY_LINKS", "RightChild", RightChild);
|
||
|
if (RightChild != 0) {
|
||
|
|
||
|
if (GetFieldValue(Current = RightChild,
|
||
|
"RTL_SPLAY_LINKS",
|
||
|
"RightChild",
|
||
|
RightChild)) {
|
||
|
|
||
|
//
|
||
|
// We've failed to step through to a successor, so
|
||
|
// there is no more to do
|
||
|
//
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
Level++;
|
||
|
|
||
|
GetFieldValue(Current,"RTL_SPLAY_LINKS","LeftChild",LeftChild);
|
||
|
while (LeftChild != 0) {
|
||
|
|
||
|
if ( CheckControlC() ) {
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
if (GetFieldValue(Current = LeftChild,
|
||
|
"RTL_SPLAY_LINKS",
|
||
|
"LeftChild",
|
||
|
LeftChild)) {
|
||
|
|
||
|
//
|
||
|
// We can continue from this
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Level++;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
/*
|
||
|
we do not have a right child so check to see if have a parent and if
|
||
|
so find the first ancestor that we are a left decendent of. That
|
||
|
is find and return P in the following diagram
|
||
|
|
||
|
P
|
||
|
/
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
Links
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// If the IsLeft or IsRight functions fail to read through a parent
|
||
|
// pointer, then we will quickly exit through the break below
|
||
|
//
|
||
|
|
||
|
GetFieldValue(Current, "RTL_SPLAY_LINKS", "Parent", Parent);
|
||
|
while (DbgRtlIsRightChild(Current, Parent)) {
|
||
|
|
||
|
if ( CheckControlC() ) {
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
Level--;
|
||
|
pSplayLinks = (Current = Parent);
|
||
|
}
|
||
|
|
||
|
GetFieldValue(Current, "RTL_SPLAY_LINKS", "Parent", Parent);
|
||
|
if (!DbgRtlIsLeftChild(Current, Parent)) {
|
||
|
|
||
|
//
|
||
|
// we do not have a real successor so we break out
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Level--;
|
||
|
pSplayLinks = (Current = Parent);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NodeCount;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DumpUnicode64(
|
||
|
UNICODE_STRING64 u
|
||
|
)
|
||
|
{
|
||
|
UNICODE_STRING v;
|
||
|
DWORD BytesRead;
|
||
|
|
||
|
// dprintf("L %x, M %x, B %p ", u.Length, u.MaximumLength, u.Buffer);
|
||
|
if ((u.Length <= u.MaximumLength) &&
|
||
|
(u.Buffer) &&
|
||
|
(u.Length > 0)) {
|
||
|
|
||
|
v.Buffer = LocalAlloc(LPTR, u.MaximumLength);
|
||
|
if (v.Buffer != NULL) {
|
||
|
v.MaximumLength = u.MaximumLength;
|
||
|
v.Length = u.Length;
|
||
|
if (ReadMemory(u.Buffer,
|
||
|
v.Buffer,
|
||
|
u.Length,
|
||
|
(PULONG) &u.Buffer)) {
|
||
|
dprintf("%wZ", &v);
|
||
|
} else {
|
||
|
dprintf("<???>");
|
||
|
}
|
||
|
LocalFree(v.Buffer);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
IsHexNumber(
|
||
|
const char *szExpression
|
||
|
)
|
||
|
{
|
||
|
if (!szExpression[0]) {
|
||
|
return FALSE ;
|
||
|
}
|
||
|
|
||
|
for(;*szExpression; szExpression++) {
|
||
|
|
||
|
if ((*szExpression)< '0') { return FALSE ; }
|
||
|
else if ((*szExpression)> 'f') { return FALSE ; }
|
||
|
else if ((*szExpression)>='a') { continue ; }
|
||
|
else if ((*szExpression)> 'F') { return FALSE ; }
|
||
|
else if ((*szExpression)<='9') { continue ; }
|
||
|
else if ((*szExpression)>='A') { continue ; }
|
||
|
else { return FALSE ; }
|
||
|
}
|
||
|
return TRUE ;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
IsDecNumber(
|
||
|
const char *szExpression
|
||
|
)
|
||
|
{
|
||
|
if (!szExpression[0]) {
|
||
|
return FALSE ;
|
||
|
}
|
||
|
|
||
|
while(*szExpression) {
|
||
|
|
||
|
if ((*szExpression)<'0') { return FALSE ; }
|
||
|
else if ((*szExpression)>'9') { return FALSE ; }
|
||
|
szExpression ++ ;
|
||
|
}
|
||
|
return TRUE ;
|
||
|
}
|
||
|
|
||
|
ULONG64
|
||
|
UtilStringToUlong64 (
|
||
|
UCHAR *String
|
||
|
)
|
||
|
{
|
||
|
UCHAR LowDword[9], HighDword[9];
|
||
|
|
||
|
ZeroMemory (&HighDword, sizeof (HighDword));
|
||
|
ZeroMemory (&LowDword, sizeof (LowDword));
|
||
|
|
||
|
if (strlen (String) > 8) {
|
||
|
|
||
|
memcpy (&LowDword, (void *) &String[strlen (String) - 8], 8);
|
||
|
memcpy (&HighDword, (void *) &String[0], strlen (String) - 8);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return strtoul (String, 0, 16);
|
||
|
}
|
||
|
|
||
|
return ((ULONG64) strtoul (HighDword, 0, 16) << 32) + strtoul (LowDword, 0, 16);
|
||
|
}
|
||
|
|
||
|
const char *
|
||
|
getEnumName(
|
||
|
ULONG EnumVal,
|
||
|
PENUM_NAME EnumTable
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Gets the supplied enum value's name in string format
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
EnumVal - Enum to be retrieved
|
||
|
EnumTable - Table in which the enum is looked up to find
|
||
|
the string to be retrieved (since we can't rely on the debugger)
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
for (i=0; EnumTable[i].Name != NULL; i++) {
|
||
|
if (EnumTable[i].EnumVal == EnumVal) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (EnumTable[i].Name != NULL) {
|
||
|
return EnumTable[i].Name;
|
||
|
} else {
|
||
|
return "Unknown ";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|