Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

627 lines
18 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
strucsup.c
Abstract:
Library routines for dumping data structures given a meta level descrioption
Author:
Balan Sethu Raman (SethuR) 11-May-1994
Notes:
Revision History:
11-Nov-1994 SethuR Created
--*/
#include "rxovride.h" //common compile flags
#include <ntos.h>
#include <nturtl.h>
#include "ntverp.h"
#include <windows.h>
#include <wdbgexts.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <kdextlib.h>
#include <rdr2kd.h>
#include <ntrxdef.h>
#include <rxtypes.h>
#include <rxlog.h>
//need this for unaligned smbget macros
#include <smbgtpt.h>
extern WINDBG_EXTENSION_APIS ExtensionApis;
//EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
#define ERRPRT dprintf
#define PRINTF dprintf
#define NL 1
#define NONL 0
BOOLEAN
wGetData( ULONG_PTR dwAddress, PVOID ptr, ULONG size, IN PSZ type);
//
// No. of columns used to display struct fields;
//
ULONG s_MaxNoOfColumns = 3;
#ifndef RXKD_2col
ULONG s_NoOfColumns = 1;
#else
ULONG s_NoOfColumns = 2;
#endif
/*
* Displays all the fields of a given struct. This is the driver routine that is called
* with the appropriate descriptor array to display all the fields in a given struct.
*/
char *NewLine = "\n";
char *FieldSeparator = " ";
#define NewLineForFields(FieldNo) \
((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator)
#define FIELD_NAME_LENGTH 30
/*
* Print out an optional message, a UNICODE_STRING, and maybe a new-line
*/
BOOL
wPrintStringU( IN LPSTR PrefixMsg OPTIONAL, IN PUNICODE_STRING puStr, IN LPSTR SuffixMsg OPTIONAL )
{
PWCHAR StringData;
UNICODE_STRING UnicodeString;
ULONG BytesRead;
if (PrefixMsg == NULL) {
PrefixMsg = "";
}
if (SuffixMsg == NULL) {
SuffixMsg = "";
}
StringData = (PWCHAR)LocalAlloc( LPTR, puStr->Length + sizeof(UNICODE_NULL));
if( StringData == NULL ) {
dprintf( "Out of memory!\n" );
return FALSE;
}
UnicodeString.Buffer = StringData; //puStr->Buffer;
UnicodeString.Length = puStr->Length;
UnicodeString.MaximumLength = puStr->MaximumLength;
ReadMemory( (ULONG_PTR)puStr->Buffer,
StringData,
puStr->Length,
&BytesRead);
if (BytesRead) {
dprintf("%s%wZ%s", PrefixMsg, &UnicodeString, SuffixMsg );
} else {
dprintf("MEMORYREAD FAILED %s%s",PrefixMsg,SuffixMsg);
}
LocalFree( (HLOCAL)StringData );
return BytesRead;
}
VOID
SetFlagString(
ULONG Value,
PCHAR FlagString
)
{
ULONG i,t,mask;
*FlagString = '('; FlagString++;
for (i=t=0,mask=1;i<32;i++,mask<<=1) {
//PRINTF("hithere %08lx %08lx %08lx\n",Value,mask,i);
if (i==t+10) {
*FlagString = ':'; FlagString++;
t=t+10;
}
if (Value&mask) {
*FlagString = '0'+(UCHAR)(i-t); FlagString++;
}
}
*FlagString = ')'; FlagString++;
*FlagString = 0;
}
VOID
PrintStructFields( ULONG_PTR dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors )
{
int i;
// Display the fields in the struct.
for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) {
// Indentation to begin the struct display.
PRINTF( " " );
if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) {
PRINTF( "%-17s...%s ", pFieldDescriptors->Name, pFieldDescriptors->Name+strlen(pFieldDescriptors->Name)-10 );
} else {
PRINTF( "%-30s ", pFieldDescriptors->Name );
}
switch( pFieldDescriptors->FieldType ) {
case FieldTypeByte:
case FieldTypeChar:
PRINTF( "%-16X%s",
*(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeBoolean:
PRINTF( "%-16s%s",
*(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
NewLineForFields(i));
break;
case FieldTypeBool:
PRINTF( "%-16s%s",
*(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
NewLineForFields(i));
break;
case FieldTypePointer:
PRINTF( "%-16X%s",
*(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeULong:
case FieldTypeLong:
PRINTF( "%-16X%s",
*(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeULongUnaligned:
case FieldTypeLongUnaligned:
PRINTF( "%-16X%s",
SmbGetUlong( (BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ) ),
NewLineForFields(i) );
break;
case FieldTypeShort:
PRINTF( "%-16X%s",
*(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeUShort:
PRINTF( "%-16X%s",
*(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeUShortUnaligned:
PRINTF( "%-16X%s",
SmbGetUshort( (BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ) ),
NewLineForFields(i) );
break;
case FieldTypeULongFlags:{ULONG Value; char FlagString[60];
Value = *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset );
SetFlagString(Value,FlagString);
PRINTF( "%-16X%s%s", Value, FlagString,
NewLineForFields(i) );
break;}
case FieldTypeUShortFlags:{USHORT Value; char FlagString[60];
Value = *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
SetFlagString(Value,FlagString);
PRINTF( "%-16X%s%s", Value, FlagString,
NewLineForFields(i) );
break;}
case FieldTypeUnicodeString:
wPrintStringU( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NULL );
PRINTF( NewLine );
break;
//case FieldTypeAnsiString:
// //PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
// //PRINTF( NewLine );
// PRINTF( NewLine );
// break;
case FieldTypeSymbol:
{
UCHAR SymbolName[ 200 ];
ULONG_PTR Displacement;
PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ));
GetSymbol( sym, SymbolName, &Displacement );
PRINTF( "%-16s%s",
SymbolName,
NewLineForFields(i) );
}
break;
case FieldTypeEnum:
{
ULONG EnumValue;
ENUM_VALUE_DESCRIPTOR *pEnumValueDescr;
// Get the associated numericla value.
EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset));
if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor)
!= NULL) {
//
// An auxilary textual description of the value is
// available. Display it instead of the numerical value.
//
LPSTR pEnumName = NULL;
while (pEnumValueDescr->EnumName != NULL) {
if (EnumValue == pEnumValueDescr->EnumValue) {
pEnumName = pEnumValueDescr->EnumName;
break;
}
}
if (pEnumName != NULL) {
PRINTF( "%-16s ", pEnumName );
} else {
PRINTF( "%-4d (%-10s) ", EnumValue,"@$#%^&*");
}
} else {
//
// No auxilary information is associated with the ehumerated type
// print the numerical value.
//
PRINTF( "%-16d",EnumValue);
}
}
break;
case FieldTypeStruct:
PRINTF( "@%-15X%s",
(dwAddress + pFieldDescriptors->Offset ),
NewLineForFields(i) );
break;
case FieldTypeLargeInteger:
case FieldTypeFileTime:
default:
ERRPRT( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name );
break;
}
}
}
DECLARE_API( columns )
{
ULONG NoOfColumns;
int i;
//SETCALLBACKS();
//sscanf(lpArgumentString,"%ld",&NoOfColumns);
sscanf(args,"%ld",&NoOfColumns);
if (NoOfColumns > s_MaxNoOfColumns) {
// PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns );
} else {
s_NoOfColumns = NoOfColumns;
}
PRINTF("Not Yet Implemented\n");
return;
}
#define NAME_DELIMITER '@'
#define NAME_DELIMITERS "@"
#define INVALID_INDEX 0xffffffff
#define MIN(x,y) ((x) < (y) ? (x) : (y))
ULONG SearchStructs(LPSTR lpArgument)
{
ULONG i = 0;
STRUCT_DESCRIPTOR *pStructs = Structs;
ULONG NameIndex = INVALID_INDEX;
ULONG ArgumentLength = strlen(lpArgument);
BOOLEAN fAmbigous = FALSE;
while ((pStructs->StructName != 0)) {
int Result = _strnicmp(lpArgument,
pStructs->StructName,
MIN(strlen(pStructs->StructName),ArgumentLength));
if (Result == 0) {
if (NameIndex != INVALID_INDEX) {
// We have encountered duplicate matches. Print out the
// matching strings and let the user disambiguate.
fAmbigous = TRUE;
break;
} else {
NameIndex = i;
}
}
pStructs++;i++;
}
if (fAmbigous) {
PRINTF("Ambigous Name Specification -- The following structs match\n");
PRINTF("%s\n",Structs[NameIndex].StructName);
PRINTF("%s\n",Structs[i].StructName);
while (pStructs->StructName != 0) {
if (_strnicmp(lpArgument,
pStructs->StructName,
MIN(strlen(pStructs->StructName),ArgumentLength)) == 0) {
PRINTF("%s\n",pStructs->StructName);
}
pStructs++;
}
PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName);
}
return(NameIndex);
}
VOID DisplayStructs()
{
STRUCT_DESCRIPTOR *pStructs = Structs;
PRINTF("The following structs are handled .... \n");
while (pStructs->StructName != 0) {
PRINTF("\t%s\n",pStructs->StructName);
pStructs++;
}
}
PPERSISTENT_RDR2KD_INFO
LocatePersistentInfoFromView()
/*
the purpose of this routine is to allocate or find the named section that holds the
data we expect to find across calls. the way that we make this persitent is that we
do not close the handle used to create the view. it will go away when the process does.
*/
{
BYTE SectionName[128];
DWORD SectionSize;
DWORD ProcessId;
HANDLE h;
BOOLEAN CreatedSection = FALSE;
PPERSISTENT_RDR2KD_INFO p;
ProcessId = GetCurrentProcessId();
SectionSize = sizeof(PERSISTENT_RDR2KD_INFO);
sprintf(SectionName,"Rdr2KdSection_%08lx",ProcessId);
//PRINTF("sectionname=%s, size=%x\n",SectionName,SectionSize);
h = OpenFileMappingA(
FILE_MAP_WRITE, //DWORD dwDesiredAccess, // access mode
FALSE, //BOOL bInheritHandle, // inherit flag
SectionName //LPCTSTR lpName // address of name of file-mapping object
);
if (h==NULL) {
h = CreateFileMappingA(
(HANDLE)IntToPtr(0xFFFFFFFF), // HANDLE hFile, // handle of file to map
NULL, //LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
PAGE_READWRITE, //DWORD flProtect, // protection for mapping object
0, //DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
SectionSize, //DWORD dwMaximumSizeLow, // low-order 32 bits of object size
SectionName //LPCTSTR lpName // name of file-mapping object
);
if (h==NULL) {
return(FALSE);
}
CreatedSection = TRUE;
}
//now we have a filemapping....get a view.....
p = MapViewOfFile(h,FILE_MAP_WRITE,0,0,0);
if (p==NULL) {
CloseHandle(h);
return(NULL);
}
if (CreatedSection) {
//zero the stuff that needs to be zeroed....
ULONG i;
p->IdOfLastDump = 0;
for (i=0;i<100;i++) {
p->LastAddressDumped[i] = 0;
}
p->OpenCount = 100;
} else {
CloseHandle(h);
p->OpenCount++;
}
//PRINTF("Opencount for persistent section = %08lx\n",p->OpenCount);
return(p);
}
VOID
FreePersistentInfoView (
PPERSISTENT_RDR2KD_INFO p
)
{
UnmapViewOfFile(p);
}
VOID
DumpAStruct (
ULONG_PTR dwAddress,
STRUCT_DESCRIPTOR *pStruct
)
{
DWORD Index = (DWORD)(pStruct - Structs);
DWORD SizeToRead = min(pStruct->StructSize,2048);
PPERSISTENT_RDR2KD_INFO p;
p = LocatePersistentInfoFromView();
PRINTF("top @ %lx and %lx for %s(%d,%d)\n",dwAddress,p,pStruct->StructName,Index,p->IdOfLastDump);
if (!p) {
PRINTF("Couldn't allocate perstistent info buffer...sorry...\n");
return;
}
if ((dwAddress==0) &&(Index<100)) {
dwAddress = p->LastAddressDumped[Index];
PRINTF("setting @ %lx and %lx for %s\n",dwAddress,p->LastAddressDumped[Index],pStruct->StructName);
}
if (wGetData(dwAddress,&p->StructDumpBuffer[0],SizeToRead,pStruct->StructName)) {
p->LastAddressDumped[Index] = dwAddress;
p->IdOfLastDump = pStruct->EnumManifest;
p->IndexOfLastDump = Index;
PRINTF("++++++++++++++++ %s(%d/%d)@%lx ---+++++++++++++\n",
pStruct->StructName,
p->IdOfLastDump,p->IndexOfLastDump,
dwAddress);
PrintStructFields(
dwAddress,
&p->StructDumpBuffer[0],
pStruct->FieldDescriptors);
PRINTF("---------------- %s@%lx ----------------\n",
pStruct->StructName,
dwAddress);
}
if (p!= NULL) FreePersistentInfoView(p);
return;
}
DECLARE_API( dump )
{
ULONG_PTR dwAddress;
//SETCALLBACKS();
if( args && *args ) {
// Parse the argument string to determine the structure to be displayed.
// Scan for the NAME_DELIMITER ( '@' ).
LPSTR lpName = (PSTR)args;
LPSTR lpArgs = strpbrk(args, NAME_DELIMITERS);
ULONG Index;
if (lpArgs) {
//
// The specified command is of the form
// dump <name>@<address expr.>
//
// Locate the matching struct for the given name. In the case
// of ambiguity we seek user intervention for disambiguation.
//
// We do an inplace modification of the argument string to
// facilitate matching.
//
*lpArgs = '\0';
for (;*lpName==' ';) { lpName++; } //skip leading blanks
Index = SearchStructs(lpName);
//
// Let us restore the original value back.
//
*lpArgs = NAME_DELIMITER;
if (INVALID_INDEX != Index) {
BYTE DataBuffer[512];
dwAddress = GetExpression( ++lpArgs );
DumpAStruct(dwAddress,&Structs[Index]);
//if (wGetData(dwAddress,DataBuffer,Structs[Index].StructSize,"..structure")) {
//
// PRINTF(
// "++++++++++++++++ %s@%lx ++++++++++++++++\n",
// Structs[Index].StructName,
// dwAddress);
// PrintStructFields(
// dwAddress,
// &DataBuffer,
// Structs[Index].FieldDescriptors);
// PRINTF(
// "---------------- %s@%lx ----------------\n",
// Structs[Index].StructName,
// dwAddress);
//} else {
// PRINTF("Error reading Memory @ %lx\n",dwAddress);
//}
} else {
// No matching struct was found. Display the list of
// structs currently handled.
DisplayStructs();
}
} else {
#if 0
//
// The command is of the form
// dump <name>
//
// Currently we do not handle this. In future we will map it to
// the name of a global variable and display it if required.
//
DisplayStructs();
#endif
//
// here we try to figure out what to display based on the context....whoa, nellie!
//
USHORT Tag;
STRUCT_DESCRIPTOR *pStructs = Structs;
ULONG NameIndex = INVALID_INDEX;
BYTE DataBuffer[512];
//ULONG ArgumentLength = strlen(lpArgument);
//BOOLEAN fAmbigous = FALSE;
dwAddress = GetExpression( args );
if (!wGetData(dwAddress,&Tag,sizeof(Tag),"..structure TAG")) return;
PRINTF("here's the tag: %04lx\n",Tag);
//look thru the table for matching structs
while ((pStructs->StructName != 0)) {
int Result = (Tag&pStructs->MatchMask)==pStructs->MatchValue;
if (Result != 0) {
DumpAStruct(dwAddress,pStructs);
break;
}
pStructs++;
}
}
} else {
DisplayStructs();
}
return;
}
DECLARE_API( ddd )
{
dump( hCurrentProcess,
hCurrentThread,
dwCurrentPc,
dwProcessor,
args
);
}