/*++ 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 #include #include "ntverp.h" #define KDEXTMODE #include #include #include #include #include #include #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 -- controls the number of columns in the display ", "logdump \n", "dump @
, for eg: !netbtkd.dump tNBTCONFIG@xxxxxx ", "devices ", "connections ", "verifyll []", "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 @
// // 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 // // 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 \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 [\n"); return FALSE; } else { // // lpArgumentString = " []" // 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
=> | 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); }