|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
kdextlib.c
Abstract:
Library routines for dumping data structures given a meta level descrioption
Author:
Balan Sethu Raman (SethuR) 11-May-1994
Notes: The implementation tends to avoid memory allocation and deallocation as much as possible. Therefore We have choosen an arbitrary length as the default buffer size. A mechanism will be provided to modify this buffer length through the debugger extension commands.
Revision History:
11-Nov-1994 SethuR Created
--*/
#include <nt.h>
#include <ntrtl.h>
#include "ntverp.h"
#define KDEXTMODE
#include <windef.h>
#include <ntkdexts.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <kdextlib.h>
#include <..\..\inc\types.h>
PNTKD_OUTPUT_ROUTINE lpOutputRoutine; PNTKD_GET_EXPRESSION lpGetExpressionRoutine; PNTKD_GET_SYMBOL lpGetSymbolRoutine; PNTKD_READ_VIRTUAL_MEMORY lpReadMemoryRoutine;
#define PRINTF lpOutputRoutine
#define ERROR lpOutputRoutine
#define NL 1
#define NONL 0
#define MAX_LIST_ELEMENTS 4096
BYTE DataBuffer[4096];
#define SETCALLBACKS() \
lpOutputRoutine = lpExtensionApis->lpOutputRoutine; \ lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine; \ lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \ lpReadMemoryRoutine = lpExtensionApis->lpReadVirtualMemRoutine;
#define DEFAULT_UNICODE_DATA_LENGTH 4096
USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH; WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH]; WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
#define DEFAULT_ANSI_DATA_LENGTH 4096
USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH; CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH]; CHAR *s_pAnsiStringData = s_AnsiStringData;
//
// No. of columns used to display struct fields;
//
ULONG s_MaxNoOfColumns = 3; ULONG s_NoOfColumns = 1;
/*
* Fetches the data at the given address */ BOOLEAN GetData(PVOID dwAddress, PVOID ptr, ULONG size) { BOOL b; ULONG BytesRead;
b = (lpReadMemoryRoutine)(dwAddress, ptr, size, &BytesRead );
if (!b || BytesRead != size ) { return FALSE; }
return TRUE; }
/*
* Fetch the null terminated ASCII string at dwAddress into buf */ BOOL GetString(PUCHAR dwAddress, PSZ buf ) { do { if (!GetData (dwAddress, buf, 1)) { return FALSE; }
dwAddress++; buf++;
} while( *buf != '\0' );
return TRUE; }
/*
* Displays a byte in hexadecimal */ VOID PrintHexChar( UCHAR c ) { PRINTF( "%c%c", "0123456789abcdef"[ (c>>4)&7 ], "0123456789abcdef"[ c&7 ] ); }
/*
* Displays a buffer of data in hexadecimal */ VOID PrintHexBuf( PUCHAR buf, ULONG cbuf ) { while( cbuf-- ) { PrintHexChar( *buf++ ); PRINTF( " " ); } }
/*
* Displays a unicode string */ BOOL PrintStringW(LPSTR msg, PUNICODE_STRING puStr, BOOL nl ) { UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; BOOL b;
if( msg ) PRINTF( msg );
if( puStr->Length == 0 ) { if( nl ) PRINTF( "\n" ); return TRUE; }
UnicodeString.Buffer = s_pUnicodeStringData; UnicodeString.MaximumLength = s_UnicodeStringDataLength; UnicodeString.Length = (puStr->Length > s_UnicodeStringDataLength) ? s_UnicodeStringDataLength : puStr->Length;
b = (lpReadMemoryRoutine)( (LPVOID) puStr->Buffer, UnicodeString.Buffer, UnicodeString.Length, NULL);
if (b) { RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE); PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" ); RtlFreeAnsiString(&AnsiString); }
return b; }
/*
* Displays a ANSI string */ BOOL PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl ) { ANSI_STRING AnsiString; BOOL b;
if( msg ) PRINTF( msg );
if( pStr->Length == 0 ) { if( nl ) PRINTF( "\n" ); return TRUE; }
AnsiString.Buffer = s_pAnsiStringData; AnsiString.MaximumLength = s_AnsiStringDataLength; AnsiString.Length = (pStr->Length > (s_AnsiStringDataLength - 1)) ? (s_AnsiStringDataLength - 1) : pStr->Length;
b = (lpReadMemoryRoutine)( (LPVOID) pStr->Buffer, AnsiString.Buffer, AnsiString.Length, NULL);
if (b) { AnsiString.Buffer[ AnsiString.Length ] = '\0'; PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" ); }
return b; }
/*
* Get the ULONG value referenced by the pointer given to us */ VOID Next3( PVOID Ptr, PVOID *pFLink, PVOID *pBLink, PULONG_PTR pVerify ) { PVOID Buffer[4];
GetData(Ptr, (PVOID) Buffer, sizeof(PVOID)*3);
if (pFLink) { *pFLink = Buffer[0]; }
if (pBLink) { *pBLink = Buffer[1]; }
if (pVerify) { *pVerify = (ULONG_PTR) Buffer[2]; } }
/*
* 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 = " "; char *DotSeparator = "."; #define NewLineForFields(FieldNo) \
((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator) #define FIELD_NAME_LENGTH 30
VOID PrintStructFields(PVOID dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors ) { int i; int j; BYTE ch;
// 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 ); }
PRINTF( "(0x%-2X) ", pFieldDescriptors->Offset );
switch( pFieldDescriptors->FieldType ) { case FieldTypeByte: case FieldTypeChar: PRINTF( "%-16d%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 FieldTypeULongULong: PRINTF( "%d%s", *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)), FieldSeparator ); PRINTF( "%d%s", *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), NewLineForFields(i) ); break;
case FieldTypeListEntry:
if ( (PVOID)((PUCHAR)dwAddress + pFieldDescriptors->Offset) == *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset )) { PRINTF( "%s", "List Empty\n" ); } else { PVOID Address, StartAddress; ULONG Count = 0; UCHAR Greater = ' ';
StartAddress = (PVOID) (((PUCHAR)dwAddress) + pFieldDescriptors->Offset); Address = *(PVOID *) (((PUCHAR)ptr) + pFieldDescriptors->Offset);
while ((Address != StartAddress) && (++Count < MAX_LIST_ELEMENTS)) { Next3 (Address, &Address, NULL, NULL); }
if (Address != StartAddress) { Greater = '>'; }
PRINTF( "%-8X%s", *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset ), FieldSeparator ); PRINTF( "%-8X, (%c %d Elements)%s", *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset + sizeof(PVOID)), Greater, Count, NewLineForFields(i) ); } break;
// Ip address: 4 bytes long
case FieldTypeIpAddr: PRINTF( "%X%s", *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), FieldSeparator ); PRINTF( "(%d%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 3), DotSeparator ); PRINTF( "%d%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 2 ), DotSeparator ); PRINTF( "%d%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 1 ), DotSeparator ); PRINTF( "%d)%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ), NewLineForFields(i) ); break;
// Mac address: 6 bytes long
case FieldTypeMacAddr: for (j=0; j<5; j++) { PRINTF( "%X%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j), FieldSeparator ); } PRINTF( "%X%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 5), NewLineForFields(i) ); break;
// Netbios name: 16 bytes long
case FieldTypeNBName: //
// if first byte is printable, print the first 15 bytes as characters
// and 16th byte as a hex value. otherwise, print all the 16 bytes
// as hex values
//
ch = *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset); if (ch >= 0x20 && ch <= 0x7e) { for (j=0; j<15; j++) { PRINTF( "%c", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j)); } PRINTF( "<%X>%s", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 15), NewLineForFields(i) ); } else { for (j=0; j<16; j++) { PRINTF( "%.2X", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j)); } PRINTF( "%s", NewLineForFields(i) ); } break;
case FieldTypeULong: case FieldTypeLong: PRINTF( "%-16d%s", *(ULONG *)(((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 FieldTypeUnicodeString: PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL ); PRINTF( NewLine ); break;
case FieldTypeAnsiString: PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL ); PRINTF( NewLine ); break;
case FieldTypeSymbol: { UCHAR SymbolName[ 200 ]; ULONG Displacement; PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ));
lpGetSymbolRoutine( 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", ((PUCHAR)dwAddress + pFieldDescriptors->Offset ), NewLineForFields(i) ); break;
case FieldTypeLargeInteger: case FieldTypeFileTime: default: ERROR( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name ); break; } } }
LPSTR LibCommands[] = { "columns <d> -- controls the number of columns in the display ", "logdump <Log Address>\n", "dump <Struct Type Name>@<address expr>, for eg: !netbtkd.dump tNBTCONFIG@xxxxxx ", "devices <netbt!NbtConfig>", "connections <netbt!NbtConfig>", "verifyll <ListHead> [<Verify>]", "cache [Local|Remote]", 0 };
BOOL help( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { int i;
SETCALLBACKS();
for( i=0; Extensions[i]; i++ ) PRINTF( " %s\n", Extensions[i] );
for( i=0; LibCommands[i]; i++ ) PRINTF( " %s\n", LibCommands[i] );
return TRUE; }
BOOL columns( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { ULONG NoOfColumns; int i;
SETCALLBACKS();
sscanf(lpArgumentString,"%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 TRUE; }
BOOL globals( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { PVOID dwAddress; CHAR buf[ 100 ]; int i; int c=0;
SETCALLBACKS();
strcpy( buf, "srv!" );
for( i=0; GlobalBool[i]; i++, c++ ) { BOOL b;
strcpy( &buf[4], GlobalBool[i] ); dwAddress = (PVOID) (lpGetExpressionRoutine) (buf); if( dwAddress == 0 ) { ERROR( "Unable to get address of %s\n", GlobalBool[i] ); continue; } if( !GetData( dwAddress,&b, sizeof(b)) ) return FALSE;
PRINTF( "%s%-30s %10s%s", c&1 ? " " : "", GlobalBool[i], b ? " TRUE" : "FALSE", c&1 ? "\n" : "" ); }
for( i=0; GlobalShort[i]; i++, c++ ) { SHORT s;
strcpy( &buf[4], GlobalShort[i] ); dwAddress = (PVOID) (lpGetExpressionRoutine) ( buf ); if( dwAddress == 0 ) { ERROR( "Unable to get address of %s\n", GlobalShort[i] ); continue; } if( !GetData( dwAddress,&s,sizeof(s)) ) return FALSE;
PRINTF( "%s%-30s %10d%s", c&1 ? " " : "", GlobalShort[i], s, c&1 ? "\n" : "" ); }
for( i=0; GlobalLong[i]; i++, c++ ) { LONG l;
strcpy( &buf[4], GlobalLong[i] ); dwAddress = (PVOID) (lpGetExpressionRoutine) ( buf ); if( dwAddress == 0 ) { ERROR( "Unable to get address of %s\n", GlobalLong[i] ); continue; } if( !GetData(dwAddress,&l, sizeof(l)) ) return FALSE;
PRINTF( "%s%-30s %10d%s", c&1 ? " " : "", GlobalLong[i], l, c&1 ? "\n" : "" ); }
PRINTF( "\n" );
return TRUE; }
BOOL version ( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { #if VER_DEBUG
char *kind = "checked"; #else
char *kind = "free"; #endif
SETCALLBACKS();
PRINTF( "Redirector debugger Extension dll for %s build %u\n", kind, VER_PRODUCTBUILD );
return TRUE; }
#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++; } }
BOOL dump( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { PVOID dwAddress;
SETCALLBACKS();
if( lpArgumentString && *lpArgumentString ) { // Parse the argument string to determine the structure to be displayed.
// Scan for the NAME_DELIMITER ( '@' ).
LPSTR lpName = lpArgumentString; LPSTR lpArgs = strpbrk(lpArgumentString, 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';
Index = SearchStructs(lpName);
//
// Let us restore the original value back.
//
*lpArgs = NAME_DELIMITER;
if (INVALID_INDEX != Index) {
dwAddress = (PVOID) (lpGetExpressionRoutine)( ++lpArgs ); if (GetData(dwAddress,DataBuffer,Structs[Index].StructSize)) {
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 { //
// 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(); } } else { //
// display the list of structs currently handled.
//
DisplayStructs(); }
return TRUE; }
BOOL devices( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { PLIST_ENTRY pEntry; PLIST_ENTRY pHead; tDEVICECONTEXT *pDeviceContext; STRUCT_DESCRIPTOR *pStructs = Structs; ULONG Index = 0; tNBTCONFIG *ConfigPtr = (tNBTCONFIG *) lpArgumentString; tDEVICECONTEXT **ppNbtSmbDevice;
PVOID dwAddress;
SETCALLBACKS();
if (!lpArgumentString || !(*lpArgumentString )) { ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig"); } else { ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine (lpArgumentString); } ppNbtSmbDevice = (tDEVICECONTEXT **) lpGetExpressionRoutine ("netbt!pNbtSmbDevice");
while (pStructs->StructName != 0) { if (!(_strnicmp("tDEVICECONTEXT", pStructs->StructName, 10))) { break; } Index++; pStructs++; }
if (pStructs->StructName == 0) { PRINTF ("ERROR: Could not find structure definition for <tDEVICECONTEXT>\n"); return FALSE; }
if (!GetData(ppNbtSmbDevice, DataBuffer, sizeof (tDEVICECONTEXT *))) { PRINTF ("ERROR: Could not read pNbtSmbDevice ptr\n"); } else if (!(pDeviceContext = *((tDEVICECONTEXT **) DataBuffer))) { PRINTF ("pNbtSmbDevice is NULL\n"); } else if (!GetData(pDeviceContext, DataBuffer, Structs[Index].StructSize)) { PRINTF ("ERROR: Could not read pNbtSmbDevice data@ <%p>\n", pDeviceContext); } else { //
// Dump this Device's Info
//
PRINTF("pNbtSmbDevice @ <%p>\n", pDeviceContext); PRINTF( "++++++++++++++++ %s @%lx ++++++++++++++++\n", Structs[Index].StructName, pDeviceContext); PrintStructFields( pDeviceContext, &DataBuffer, Structs[Index].FieldDescriptors); PRINTF("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); }
pHead = &ConfigPtr->DeviceContexts; if (!GetData(ConfigPtr, DataBuffer, sizeof(tNBTCONFIG))) { PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", ConfigPtr); return FALSE; }
//
// Get the number of Devices attached
//
{ PVOID StartAddress; PVOID Address; ULONG Count = 0; PVOID Buffer[4]; UCHAR Greater = ' ';
StartAddress = pHead; GetData( StartAddress, Buffer, sizeof(ULONG)*4 ); Address = Buffer[0];
while ((Address != StartAddress) && (++Count < MAX_LIST_ELEMENTS)) { GetData( Address, Buffer, sizeof(ULONG)*4 ); Address = Buffer[0]; }
PRINTF( "Dumping <%d> Devices attached to NbtConfig@<%x>\n", Count, ConfigPtr); }
ConfigPtr = (tNBTCONFIG *) DataBuffer; pEntry = ConfigPtr->DeviceContexts.Flink;
while (pEntry != pHead) { pDeviceContext = (tDEVICECONTEXT *) CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage); if (!GetData(pDeviceContext, DataBuffer, Structs[Index].StructSize)) { PRINTF ("ERROR: Could not read DeviceContext data @<%x>\n", pDeviceContext); return FALSE; }
//
// Dump this Device's Info
//
PRINTF( "++++++++++++++++ %s @%lx ++++++++++++++++\n", Structs[Index].StructName, pDeviceContext); PrintStructFields( pDeviceContext, &DataBuffer, Structs[Index].FieldDescriptors);
//
// Go to next device
//
pDeviceContext = (tDEVICECONTEXT *) DataBuffer; pEntry = pDeviceContext->Linkage.Flink; }
return (TRUE); }
BOOL connections( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { PLIST_ENTRY pEntry, pHead, pClientHead, pClientEntry, pConnHead, pConnEntry; tNBTCONFIG *ConfigPtr; tADDRESSELE *pAddressEle; tCLIENTELE *pClient; tCONNECTELE *pConnEle, *pSavConnEle; tNAMEADDR *pNameAddr; tLISTENREQUESTS *pListen;
SETCALLBACKS();
PRINTF ("Dumping information on all NetBT conections ...\n");
if (!lpArgumentString || !(*lpArgumentString )) { ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig"); } else { ConfigPtr = (tNBTCONFIG *) (lpGetExpressionRoutine) (lpArgumentString); }
pHead = &ConfigPtr->AddressHead; if (!GetData(ConfigPtr, DataBuffer, sizeof(tNBTCONFIG))) { PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", ConfigPtr); return FALSE; } ConfigPtr = (tNBTCONFIG *) DataBuffer; Next3 (pHead, &pEntry, NULL, NULL);
while (pEntry != pHead) { pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
Next3 (&pAddressEle->pNameAddr, &pNameAddr, NULL, NULL); if (!GetData(pNameAddr, DataBuffer, sizeof(tNAMEADDR))) { PRINTF ("[1] Error reading pNameAddr data @<%x>", pNameAddr); return FALSE; } pNameAddr = (tNAMEADDR *) DataBuffer; PRINTF ("Address@<%x> ==> <%-16.16s:%x>\n", pAddressEle, pNameAddr->Name, pNameAddr->Name[15]);
pClientHead = &pAddressEle->ClientHead; Next3 (pClientHead, &pClientEntry, NULL, NULL); while (pClientEntry != pClientHead) { pClient = CONTAINING_RECORD(pClientEntry,tCLIENTELE,Linkage); if (!GetData(pClient, DataBuffer, sizeof(tCLIENTELE))) { PRINTF ("Error reading pClientEle data @<%p>", pClient); continue; }
PRINTF ("\tClient@<%p> ==> pDevice=<%p>\n", pClient, ((tCLIENTELE *)DataBuffer)->pDeviceContext);
PRINTF ("\t\t(ConnectHead):\n"); pConnHead = &pClient->ConnectHead; Next3 (pConnHead, &pConnEntry, NULL, NULL); while (pConnEntry != pConnHead) { pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage); if (!GetData(pConnEle, DataBuffer, sizeof(tCONNECTELE))) { PRINTF ("[2] Error reading pConnEle data @<%x>", pConnEle); return FALSE; } pConnEle = (tCONNECTELE *) DataBuffer; PRINTF ("\t\t ** Connection@<%x> ==> <%-16.16s:%x>:\n", pSavConnEle, pConnEle->RemoteName, pConnEle->RemoteName[15]);
Next3 (pConnEntry, &pConnEntry, NULL, NULL); }
PRINTF ("\t\t(ConnectActive):\n"); pConnHead = &pClient->ConnectActive; Next3 (pConnHead, &pConnEntry, NULL, NULL); while (pConnEntry != pConnHead) { pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage); if (!GetData(pConnEle, DataBuffer, sizeof(tCONNECTELE))) { PRINTF ("[3] Error reading pConnEle data @<%x>", pConnEle); return FALSE; } pConnEle = (tCONNECTELE *) DataBuffer; PRINTF ("\t\t ** Connection@<%x> ==> <%-16.16s:%x>:\n", pSavConnEle, pConnEle->RemoteName, pConnEle->RemoteName[15]);
Next3 (pConnEntry, &pConnEntry, NULL, NULL); }
PRINTF ("\t\t(ListenHead):\n"); pConnHead = &pClient->ListenHead; Next3 (pConnHead, &pConnEntry, NULL, NULL); while (pConnEntry != pConnHead) { pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage); if (!GetData(pConnEle, DataBuffer, sizeof(tLISTENREQUESTS))) { PRINTF ("[4] Error reading pListen data @<%x>", pSavConnEle); return FALSE; } pListen = (tLISTENREQUESTS *) DataBuffer; PRINTF ("\t\t ** pListen@<%p> ==> pIrp=<%p>\n", pSavConnEle, pListen->pIrp);
Next3 (pConnEntry, &pConnEntry, NULL, NULL); }
Next3 (pClientEntry, &pClientEntry, NULL, NULL); } Next3 (pEntry, &pEntry, NULL, NULL); PRINTF ("\n"); }
PRINTF( "---------------- Connections ----------------\n");
return (TRUE); }
BOOL verifyll( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { PLIST_ENTRY pHead, pCurrentEntry, pNextEntry, pPreviousEntry; ULONG_PTR VerifyRead, VerifyIn = 0; ULONG Count = 0; BOOL fVerifyIn = FALSE; BOOL fListCorrupt = FALSE;
SETCALLBACKS();
PRINTF ("Verifying Linked list ...\n");
if (!lpArgumentString || !(*lpArgumentString )) { PRINTF ("Usage: !NetbtKd.VerifyLL <ListHead> [<Verify]>\n"); return FALSE; } else { //
// lpArgumentString = "<pHead> [<Verify>]"
//
LPSTR lpVerify;
while (*lpArgumentString == ' ') { lpArgumentString++; } lpVerify = strpbrk(lpArgumentString, NAME_DELIMITERS);
pHead = (PVOID) (lpGetExpressionRoutine) (lpArgumentString); if (lpVerify) { VerifyIn = (lpGetExpressionRoutine) (lpVerify); fVerifyIn = TRUE; } }
PRINTF ("** ListHead@<%x>, fVerifyIn=<%x>, VerifyIn=<%x>:\n\n", pHead, fVerifyIn, VerifyIn); PRINTF ("Verifying Flinks ...");
// Read in the data for the first FLink in the list!
pPreviousEntry = pHead; Next3 (pHead, &pCurrentEntry, NULL, NULL); Next3 (pCurrentEntry, &pNextEntry, NULL, &VerifyRead);
while ((pCurrentEntry != pHead) && (++Count < MAX_LIST_ELEMENTS)) { if ((fVerifyIn) && (VerifyRead != VerifyIn)) { PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far, Previous=<%x>, Current=<%x>, Next=<%x>\n", Count, pPreviousEntry, pCurrentEntry, pNextEntry); fListCorrupt = TRUE; break; } pPreviousEntry = pCurrentEntry; pCurrentEntry = pNextEntry; Next3 (pCurrentEntry, &pNextEntry, NULL, &VerifyRead); }
if (!fListCorrupt) { PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count); }
PRINTF ("Verifying Blinks ...");
Count = 0; fListCorrupt = FALSE; // Read in the data for the first BLink in the list!
pPreviousEntry = pHead; Next3 (pHead, NULL, &pCurrentEntry, NULL); Next3 (pCurrentEntry, NULL, &pNextEntry, &VerifyRead);
while ((pCurrentEntry != pHead) && (++Count < MAX_LIST_ELEMENTS)) { if ((fVerifyIn) && (VerifyRead != VerifyIn)) { PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far, Previous=<%x>, Current=<%x>, Next=<%x>\n", Count, pPreviousEntry, pCurrentEntry, pNextEntry); fListCorrupt = TRUE; break; } pPreviousEntry = pCurrentEntry; pCurrentEntry = pNextEntry; Next3 (pCurrentEntry, NULL, &pNextEntry, &VerifyRead); }
if (!fListCorrupt) { PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count); }
PRINTF( "---------------- Verify LinkedList ----------------\n");
return (TRUE); }
BOOL DumpCache( tHASHTABLE *pHashTable, enum eNbtLocation CacheType ) { LONG i, NumBuckets; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; tHASHTABLE HashTbl; tNAMEADDR NameAddr, *pNameAddr;
if (!GetData(pHashTable, &HashTbl, sizeof(tHASHTABLE))) { PRINTF ("ERROR: Could not read %s HashTable data @<%x>\n", (CacheType == NBT_LOCAL ? "Local":"Remote"), pHashTable); return FALSE; }
NumBuckets = HashTbl.lNumBuckets; PRINTF ("\nDumping %s Cache = <%d> buckets:\n", (CacheType == NBT_LOCAL ? "Local":"Remote"), NumBuckets); PRINTF ("[Bkt#]\t<Address> => <Name > | IpAddr | RefC | State | Ttl\n"); PRINTF ("-----------------------------------------------------------------------------------\n");
for (i=0; i < NumBuckets; i++) { pHead = &pHashTable->Bucket[i]; Next3 (pHead, &pEntry, NULL, NULL);
//
// Go through each name in each bucket of the hashtable
//
while (pEntry != pHead) { pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); if (!GetData(pNameAddr, &NameAddr, sizeof(tNAMEADDR))) { PRINTF ("ERROR: Could not read NameAddr data @<%x>\n", pNameAddr); return FALSE; }
if ((NameAddr.Verify == LOCAL_NAME) || (NameAddr.Verify == REMOTE_NAME)) { PRINTF ("[%d]\t<%x> => <%-15.15s:%2x> | %8x | %d | %8x | %9d\n", i, pNameAddr, NameAddr.Name, (NameAddr.Name[15]&0x000000ff), NameAddr.IpAddress, NameAddr.RefCount, NameAddr.NameTypeState, NameAddr.Ttl); } else { PRINTF ("ERROR: Bad Name cache entry @ <%x>!\n", pNameAddr); return FALSE; }
Next3 (pEntry, &pEntry, NULL, NULL); // next hash table entry
} } // for ( .. pHashTable .. )
return TRUE; }
BOOL cache( DWORD dwCurrentPC, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { tNBTCONFIG NbtConfig, *pConfig; BOOL fDumpLocal = TRUE; // Dump both local and remote cache by default
BOOL fDumpRemote = TRUE;
SETCALLBACKS();
if (lpArgumentString && (*lpArgumentString )) { //
// lpArgumentString = "[Local|Remote]"
//
while (*lpArgumentString == ' ') { lpArgumentString++; }
if ((*lpArgumentString == 'l') || (*lpArgumentString == 'L')) { fDumpRemote = FALSE; } else if ((*lpArgumentString == 'r') || (*lpArgumentString == 'R')) { fDumpLocal = FALSE; } }
pConfig = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig"); if (!GetData(pConfig, &NbtConfig, sizeof(tNBTCONFIG))) { PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", pConfig); return FALSE; }
if (fDumpLocal) { DumpCache (NbtConfig.pLocalHashTbl, NBT_LOCAL); } if (fDumpRemote) { DumpCache (NbtConfig.pRemoteHashTbl, NBT_REMOTE); }
PRINTF( "---------------- Cache ----------------\n");
return (TRUE); }
|