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.

1301 lines
37 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. kdextlib.c
  5. Abstract:
  6. Library routines for dumping data structures given a meta level descrioption
  7. Author:
  8. Balan Sethu Raman (SethuR) 11-May-1994
  9. Notes:
  10. The implementation tends to avoid memory allocation and deallocation as much as possible.
  11. Therefore We have choosen an arbitrary length as the default buffer size. A mechanism will
  12. be provided to modify this buffer length through the debugger extension commands.
  13. Revision History:
  14. 11-Nov-1994 SethuR Created
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include "ntverp.h"
  19. #define KDEXTMODE
  20. #include <windef.h>
  21. #include <ntkdexts.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <kdextlib.h>
  26. #include <..\..\inc\types.h>
  27. PNTKD_OUTPUT_ROUTINE lpOutputRoutine;
  28. PNTKD_GET_EXPRESSION lpGetExpressionRoutine;
  29. PNTKD_GET_SYMBOL lpGetSymbolRoutine;
  30. PNTKD_READ_VIRTUAL_MEMORY lpReadMemoryRoutine;
  31. #define PRINTF lpOutputRoutine
  32. #define ERROR lpOutputRoutine
  33. #define NL 1
  34. #define NONL 0
  35. #define MAX_LIST_ELEMENTS 4096
  36. BYTE DataBuffer[4096];
  37. #define SETCALLBACKS() \
  38. lpOutputRoutine = lpExtensionApis->lpOutputRoutine; \
  39. lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine; \
  40. lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \
  41. lpReadMemoryRoutine = lpExtensionApis->lpReadVirtualMemRoutine;
  42. #define DEFAULT_UNICODE_DATA_LENGTH 4096
  43. USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH;
  44. WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH];
  45. WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
  46. #define DEFAULT_ANSI_DATA_LENGTH 4096
  47. USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH;
  48. CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH];
  49. CHAR *s_pAnsiStringData = s_AnsiStringData;
  50. //
  51. // No. of columns used to display struct fields;
  52. //
  53. ULONG s_MaxNoOfColumns = 3;
  54. ULONG s_NoOfColumns = 1;
  55. /*
  56. * Fetches the data at the given address
  57. */
  58. BOOLEAN
  59. GetData(PVOID dwAddress, PVOID ptr, ULONG size)
  60. {
  61. BOOL b;
  62. ULONG BytesRead;
  63. b = (lpReadMemoryRoutine)(dwAddress, ptr, size, &BytesRead );
  64. if (!b || BytesRead != size )
  65. {
  66. return FALSE;
  67. }
  68. return TRUE;
  69. }
  70. /*
  71. * Fetch the null terminated ASCII string at dwAddress into buf
  72. */
  73. BOOL
  74. GetString(PUCHAR dwAddress, PSZ buf )
  75. {
  76. do
  77. {
  78. if (!GetData (dwAddress, buf, 1))
  79. {
  80. return FALSE;
  81. }
  82. dwAddress++;
  83. buf++;
  84. } while( *buf != '\0' );
  85. return TRUE;
  86. }
  87. /*
  88. * Displays a byte in hexadecimal
  89. */
  90. VOID
  91. PrintHexChar( UCHAR c )
  92. {
  93. PRINTF( "%c%c", "0123456789abcdef"[ (c>>4)&7 ], "0123456789abcdef"[ c&7 ] );
  94. }
  95. /*
  96. * Displays a buffer of data in hexadecimal
  97. */
  98. VOID
  99. PrintHexBuf( PUCHAR buf, ULONG cbuf )
  100. {
  101. while( cbuf-- ) {
  102. PrintHexChar( *buf++ );
  103. PRINTF( " " );
  104. }
  105. }
  106. /*
  107. * Displays a unicode string
  108. */
  109. BOOL
  110. PrintStringW(LPSTR msg, PUNICODE_STRING puStr, BOOL nl )
  111. {
  112. UNICODE_STRING UnicodeString;
  113. ANSI_STRING AnsiString;
  114. BOOL b;
  115. if( msg )
  116. PRINTF( msg );
  117. if( puStr->Length == 0 ) {
  118. if( nl )
  119. PRINTF( "\n" );
  120. return TRUE;
  121. }
  122. UnicodeString.Buffer = s_pUnicodeStringData;
  123. UnicodeString.MaximumLength = s_UnicodeStringDataLength;
  124. UnicodeString.Length = (puStr->Length > s_UnicodeStringDataLength)
  125. ? s_UnicodeStringDataLength
  126. : puStr->Length;
  127. b = (lpReadMemoryRoutine)(
  128. (LPVOID) puStr->Buffer,
  129. UnicodeString.Buffer,
  130. UnicodeString.Length,
  131. NULL);
  132. if (b) {
  133. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
  134. PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
  135. RtlFreeAnsiString(&AnsiString);
  136. }
  137. return b;
  138. }
  139. /*
  140. * Displays a ANSI string
  141. */
  142. BOOL
  143. PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl )
  144. {
  145. ANSI_STRING AnsiString;
  146. BOOL b;
  147. if( msg )
  148. PRINTF( msg );
  149. if( pStr->Length == 0 ) {
  150. if( nl )
  151. PRINTF( "\n" );
  152. return TRUE;
  153. }
  154. AnsiString.Buffer = s_pAnsiStringData;
  155. AnsiString.MaximumLength = s_AnsiStringDataLength;
  156. AnsiString.Length = (pStr->Length > (s_AnsiStringDataLength - 1))
  157. ? (s_AnsiStringDataLength - 1)
  158. : pStr->Length;
  159. b = (lpReadMemoryRoutine)(
  160. (LPVOID) pStr->Buffer,
  161. AnsiString.Buffer,
  162. AnsiString.Length,
  163. NULL);
  164. if (b) {
  165. AnsiString.Buffer[ AnsiString.Length ] = '\0';
  166. PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
  167. }
  168. return b;
  169. }
  170. /*
  171. * Get the ULONG value referenced by the pointer given to us
  172. */
  173. VOID
  174. Next3(
  175. PVOID Ptr,
  176. PVOID *pFLink,
  177. PVOID *pBLink,
  178. PULONG_PTR pVerify
  179. )
  180. {
  181. PVOID Buffer[4];
  182. GetData(Ptr, (PVOID) Buffer, sizeof(PVOID)*3);
  183. if (pFLink)
  184. {
  185. *pFLink = Buffer[0];
  186. }
  187. if (pBLink)
  188. {
  189. *pBLink = Buffer[1];
  190. }
  191. if (pVerify)
  192. {
  193. *pVerify = (ULONG_PTR) Buffer[2];
  194. }
  195. }
  196. /*
  197. * Displays all the fields of a given struct. This is the driver routine that is called
  198. * with the appropriate descriptor array to display all the fields in a given struct.
  199. */
  200. char *NewLine = "\n";
  201. char *FieldSeparator = " ";
  202. char *DotSeparator = ".";
  203. #define NewLineForFields(FieldNo) \
  204. ((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator)
  205. #define FIELD_NAME_LENGTH 30
  206. VOID
  207. PrintStructFields(PVOID dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors )
  208. {
  209. int i;
  210. int j;
  211. BYTE ch;
  212. // Display the fields in the struct.
  213. for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) {
  214. // Indentation to begin the struct display.
  215. PRINTF( " " );
  216. if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) {
  217. PRINTF( "%-17s...%s ", pFieldDescriptors->Name, pFieldDescriptors->Name+strlen(pFieldDescriptors->Name)-10 );
  218. } else {
  219. PRINTF( "%-30s ", pFieldDescriptors->Name );
  220. }
  221. PRINTF( "(0x%-2X) ", pFieldDescriptors->Offset );
  222. switch( pFieldDescriptors->FieldType ) {
  223. case FieldTypeByte:
  224. case FieldTypeChar:
  225. PRINTF( "%-16d%s",
  226. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
  227. NewLineForFields(i) );
  228. break;
  229. case FieldTypeBoolean:
  230. PRINTF( "%-16s%s",
  231. *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  232. NewLineForFields(i));
  233. break;
  234. case FieldTypeBool:
  235. PRINTF( "%-16s%s",
  236. *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  237. NewLineForFields(i));
  238. break;
  239. case FieldTypePointer:
  240. PRINTF( "%-16X%s",
  241. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  242. NewLineForFields(i) );
  243. break;
  244. case FieldTypeULongULong:
  245. PRINTF( "%d%s",
  246. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)),
  247. FieldSeparator );
  248. PRINTF( "%d%s",
  249. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  250. NewLineForFields(i) );
  251. break;
  252. case FieldTypeListEntry:
  253. if ( (PVOID)((PUCHAR)dwAddress + pFieldDescriptors->Offset) ==
  254. *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset ))
  255. {
  256. PRINTF( "%s", "List Empty\n" );
  257. }
  258. else
  259. {
  260. PVOID Address, StartAddress;
  261. ULONG Count = 0;
  262. UCHAR Greater = ' ';
  263. StartAddress = (PVOID) (((PUCHAR)dwAddress) + pFieldDescriptors->Offset);
  264. Address = *(PVOID *) (((PUCHAR)ptr) + pFieldDescriptors->Offset);
  265. while ((Address != StartAddress) &&
  266. (++Count < MAX_LIST_ELEMENTS))
  267. {
  268. Next3 (Address, &Address, NULL, NULL);
  269. }
  270. if (Address != StartAddress)
  271. {
  272. Greater = '>';
  273. }
  274. PRINTF( "%-8X%s",
  275. *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset ),
  276. FieldSeparator );
  277. PRINTF( "%-8X, (%c %d Elements)%s",
  278. *(PVOID *)(((PUCHAR)ptr) + pFieldDescriptors->Offset + sizeof(PVOID)),
  279. Greater, Count,
  280. NewLineForFields(i) );
  281. }
  282. break;
  283. // Ip address: 4 bytes long
  284. case FieldTypeIpAddr:
  285. PRINTF( "%X%s",
  286. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  287. FieldSeparator );
  288. PRINTF( "(%d%s",
  289. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 3),
  290. DotSeparator );
  291. PRINTF( "%d%s",
  292. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 2 ),
  293. DotSeparator );
  294. PRINTF( "%d%s",
  295. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 1 ),
  296. DotSeparator );
  297. PRINTF( "%d)%s",
  298. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
  299. NewLineForFields(i) );
  300. break;
  301. // Mac address: 6 bytes long
  302. case FieldTypeMacAddr:
  303. for (j=0; j<5; j++)
  304. {
  305. PRINTF( "%X%s",
  306. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j),
  307. FieldSeparator );
  308. }
  309. PRINTF( "%X%s",
  310. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 5),
  311. NewLineForFields(i) );
  312. break;
  313. // Netbios name: 16 bytes long
  314. case FieldTypeNBName:
  315. //
  316. // if first byte is printable, print the first 15 bytes as characters
  317. // and 16th byte as a hex value. otherwise, print all the 16 bytes
  318. // as hex values
  319. //
  320. ch = *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset);
  321. if (ch >= 0x20 && ch <= 0x7e)
  322. {
  323. for (j=0; j<15; j++)
  324. {
  325. PRINTF( "%c", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j));
  326. }
  327. PRINTF( "<%X>%s",
  328. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 15),
  329. NewLineForFields(i) );
  330. }
  331. else
  332. {
  333. for (j=0; j<16; j++)
  334. {
  335. PRINTF( "%.2X",
  336. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j));
  337. }
  338. PRINTF( "%s", NewLineForFields(i) );
  339. }
  340. break;
  341. case FieldTypeULong:
  342. case FieldTypeLong:
  343. PRINTF( "%-16d%s",
  344. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  345. NewLineForFields(i) );
  346. break;
  347. case FieldTypeShort:
  348. PRINTF( "%-16X%s",
  349. *(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  350. NewLineForFields(i) );
  351. break;
  352. case FieldTypeUShort:
  353. PRINTF( "%-16X%s",
  354. *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  355. NewLineForFields(i) );
  356. break;
  357. case FieldTypeUnicodeString:
  358. PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
  359. PRINTF( NewLine );
  360. break;
  361. case FieldTypeAnsiString:
  362. PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
  363. PRINTF( NewLine );
  364. break;
  365. case FieldTypeSymbol:
  366. {
  367. UCHAR SymbolName[ 200 ];
  368. ULONG Displacement;
  369. PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ));
  370. lpGetSymbolRoutine( sym, SymbolName, &Displacement );
  371. PRINTF( "%-16s%s",
  372. SymbolName,
  373. NewLineForFields(i) );
  374. }
  375. break;
  376. case FieldTypeEnum:
  377. {
  378. ULONG EnumValue;
  379. ENUM_VALUE_DESCRIPTOR *pEnumValueDescr;
  380. // Get the associated numericla value.
  381. EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset));
  382. if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor)
  383. != NULL) {
  384. //
  385. // An auxilary textual description of the value is
  386. // available. Display it instead of the numerical value.
  387. //
  388. LPSTR pEnumName = NULL;
  389. while (pEnumValueDescr->EnumName != NULL) {
  390. if (EnumValue == pEnumValueDescr->EnumValue) {
  391. pEnumName = pEnumValueDescr->EnumName;
  392. break;
  393. }
  394. }
  395. if (pEnumName != NULL) {
  396. PRINTF( "%-16s ", pEnumName );
  397. } else {
  398. PRINTF( "%-4d (%-10s) ", EnumValue,"@$#%^&*");
  399. }
  400. } else {
  401. //
  402. // No auxilary information is associated with the ehumerated type
  403. // print the numerical value.
  404. //
  405. PRINTF( "%-16d",EnumValue);
  406. }
  407. }
  408. break;
  409. case FieldTypeStruct:
  410. PRINTF( "@%-15X%s",
  411. ((PUCHAR)dwAddress + pFieldDescriptors->Offset ),
  412. NewLineForFields(i) );
  413. break;
  414. case FieldTypeLargeInteger:
  415. case FieldTypeFileTime:
  416. default:
  417. ERROR( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name );
  418. break;
  419. }
  420. }
  421. }
  422. LPSTR LibCommands[] = {
  423. "columns <d> -- controls the number of columns in the display ",
  424. "logdump <Log Address>\n",
  425. "dump <Struct Type Name>@<address expr>, for eg: !netbtkd.dump tNBTCONFIG@xxxxxx ",
  426. "devices <netbt!NbtConfig>",
  427. "connections <netbt!NbtConfig>",
  428. "verifyll <ListHead> [<Verify>]",
  429. "cache [Local|Remote]",
  430. 0
  431. };
  432. BOOL
  433. help(
  434. DWORD dwCurrentPC,
  435. PNTKD_EXTENSION_APIS lpExtensionApis,
  436. LPSTR lpArgumentString
  437. )
  438. {
  439. int i;
  440. SETCALLBACKS();
  441. for( i=0; Extensions[i]; i++ )
  442. PRINTF( " %s\n", Extensions[i] );
  443. for( i=0; LibCommands[i]; i++ )
  444. PRINTF( " %s\n", LibCommands[i] );
  445. return TRUE;
  446. }
  447. BOOL
  448. columns(
  449. DWORD dwCurrentPC,
  450. PNTKD_EXTENSION_APIS lpExtensionApis,
  451. LPSTR lpArgumentString
  452. )
  453. {
  454. ULONG NoOfColumns;
  455. int i;
  456. SETCALLBACKS();
  457. sscanf(lpArgumentString,"%ld",&NoOfColumns);
  458. if (NoOfColumns > s_MaxNoOfColumns) {
  459. // PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns );
  460. } else {
  461. s_NoOfColumns = NoOfColumns;
  462. }
  463. PRINTF("Not Yet Implemented\n");
  464. return TRUE;
  465. }
  466. BOOL
  467. globals(
  468. DWORD dwCurrentPC,
  469. PNTKD_EXTENSION_APIS lpExtensionApis,
  470. LPSTR lpArgumentString
  471. )
  472. {
  473. PVOID dwAddress;
  474. CHAR buf[ 100 ];
  475. int i;
  476. int c=0;
  477. SETCALLBACKS();
  478. strcpy( buf, "srv!" );
  479. for( i=0; GlobalBool[i]; i++, c++ ) {
  480. BOOL b;
  481. strcpy( &buf[4], GlobalBool[i] );
  482. dwAddress = (PVOID) (lpGetExpressionRoutine) (buf);
  483. if( dwAddress == 0 ) {
  484. ERROR( "Unable to get address of %s\n", GlobalBool[i] );
  485. continue;
  486. }
  487. if( !GetData( dwAddress,&b, sizeof(b)) )
  488. return FALSE;
  489. PRINTF( "%s%-30s %10s%s",
  490. c&1 ? " " : "",
  491. GlobalBool[i],
  492. b ? " TRUE" : "FALSE",
  493. c&1 ? "\n" : "" );
  494. }
  495. for( i=0; GlobalShort[i]; i++, c++ ) {
  496. SHORT s;
  497. strcpy( &buf[4], GlobalShort[i] );
  498. dwAddress = (PVOID) (lpGetExpressionRoutine) ( buf );
  499. if( dwAddress == 0 ) {
  500. ERROR( "Unable to get address of %s\n", GlobalShort[i] );
  501. continue;
  502. }
  503. if( !GetData( dwAddress,&s,sizeof(s)) )
  504. return FALSE;
  505. PRINTF( "%s%-30s %10d%s",
  506. c&1 ? " " : "",
  507. GlobalShort[i],
  508. s,
  509. c&1 ? "\n" : "" );
  510. }
  511. for( i=0; GlobalLong[i]; i++, c++ ) {
  512. LONG l;
  513. strcpy( &buf[4], GlobalLong[i] );
  514. dwAddress = (PVOID) (lpGetExpressionRoutine) ( buf );
  515. if( dwAddress == 0 ) {
  516. ERROR( "Unable to get address of %s\n", GlobalLong[i] );
  517. continue;
  518. }
  519. if( !GetData(dwAddress,&l, sizeof(l)) )
  520. return FALSE;
  521. PRINTF( "%s%-30s %10d%s",
  522. c&1 ? " " : "",
  523. GlobalLong[i],
  524. l,
  525. c&1 ? "\n" : "" );
  526. }
  527. PRINTF( "\n" );
  528. return TRUE;
  529. }
  530. BOOL
  531. version
  532. (
  533. DWORD dwCurrentPC,
  534. PNTKD_EXTENSION_APIS lpExtensionApis,
  535. LPSTR lpArgumentString
  536. )
  537. {
  538. #if VER_DEBUG
  539. char *kind = "checked";
  540. #else
  541. char *kind = "free";
  542. #endif
  543. SETCALLBACKS();
  544. PRINTF( "Redirector debugger Extension dll for %s build %u\n", kind, VER_PRODUCTBUILD );
  545. return TRUE;
  546. }
  547. #define NAME_DELIMITER '@'
  548. #define NAME_DELIMITERS "@ "
  549. #define INVALID_INDEX 0xffffffff
  550. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  551. ULONG SearchStructs(LPSTR lpArgument)
  552. {
  553. ULONG i = 0;
  554. STRUCT_DESCRIPTOR *pStructs = Structs;
  555. ULONG NameIndex = INVALID_INDEX;
  556. ULONG ArgumentLength = strlen(lpArgument);
  557. BOOLEAN fAmbigous = FALSE;
  558. while ((pStructs->StructName != 0)) {
  559. int Result = _strnicmp(lpArgument,
  560. pStructs->StructName,
  561. MIN(strlen(pStructs->StructName),ArgumentLength));
  562. if (Result == 0) {
  563. if (NameIndex != INVALID_INDEX) {
  564. // We have encountered duplicate matches. Print out the
  565. // matching strings and let the user disambiguate.
  566. fAmbigous = TRUE;
  567. break;
  568. } else {
  569. NameIndex = i;
  570. }
  571. }
  572. pStructs++;i++;
  573. }
  574. if (fAmbigous) {
  575. PRINTF("Ambigous Name Specification -- The following structs match\n");
  576. PRINTF("%s\n",Structs[NameIndex].StructName);
  577. PRINTF("%s\n",Structs[i].StructName);
  578. while (pStructs->StructName != 0) {
  579. if (_strnicmp(lpArgument,
  580. pStructs->StructName,
  581. MIN(strlen(pStructs->StructName),ArgumentLength)) == 0) {
  582. PRINTF("%s\n",pStructs->StructName);
  583. }
  584. pStructs++;
  585. }
  586. PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName);
  587. }
  588. return(NameIndex);
  589. }
  590. VOID DisplayStructs()
  591. {
  592. STRUCT_DESCRIPTOR *pStructs = Structs;
  593. PRINTF("The following structs are handled .... \n");
  594. while (pStructs->StructName != 0) {
  595. PRINTF("\t%s\n",pStructs->StructName);
  596. pStructs++;
  597. }
  598. }
  599. BOOL
  600. dump(
  601. DWORD dwCurrentPC,
  602. PNTKD_EXTENSION_APIS lpExtensionApis,
  603. LPSTR lpArgumentString
  604. )
  605. {
  606. PVOID dwAddress;
  607. SETCALLBACKS();
  608. if( lpArgumentString && *lpArgumentString ) {
  609. // Parse the argument string to determine the structure to be displayed.
  610. // Scan for the NAME_DELIMITER ( '@' ).
  611. LPSTR lpName = lpArgumentString;
  612. LPSTR lpArgs = strpbrk(lpArgumentString, NAME_DELIMITERS);
  613. ULONG Index;
  614. if (lpArgs) {
  615. //
  616. // The specified command is of the form
  617. // dump <name>@<address expr.>
  618. //
  619. // Locate the matching struct for the given name. In the case
  620. // of ambiguity we seek user intervention for disambiguation.
  621. //
  622. // We do an inplace modification of the argument string to
  623. // facilitate matching.
  624. //
  625. *lpArgs = '\0';
  626. Index = SearchStructs(lpName);
  627. //
  628. // Let us restore the original value back.
  629. //
  630. *lpArgs = NAME_DELIMITER;
  631. if (INVALID_INDEX != Index) {
  632. dwAddress = (PVOID) (lpGetExpressionRoutine)( ++lpArgs );
  633. if (GetData(dwAddress,DataBuffer,Structs[Index].StructSize)) {
  634. PRINTF(
  635. "++++++++++++++++ %s@%lx ++++++++++++++++\n",
  636. Structs[Index].StructName,
  637. dwAddress);
  638. PrintStructFields(
  639. dwAddress,
  640. &DataBuffer,
  641. Structs[Index].FieldDescriptors);
  642. PRINTF(
  643. "---------------- %s@%lx ----------------\n",
  644. Structs[Index].StructName,
  645. dwAddress);
  646. } else {
  647. PRINTF("Error reading Memory @ %lx\n",dwAddress);
  648. }
  649. } else {
  650. // No matching struct was found. Display the list of
  651. // structs currently handled.
  652. DisplayStructs();
  653. }
  654. } else {
  655. //
  656. // The command is of the form
  657. // dump <name>
  658. //
  659. // Currently we do not handle this. In future we will map it to
  660. // the name of a global variable and display it if required.
  661. //
  662. DisplayStructs();
  663. }
  664. } else {
  665. //
  666. // display the list of structs currently handled.
  667. //
  668. DisplayStructs();
  669. }
  670. return TRUE;
  671. }
  672. BOOL
  673. devices(
  674. DWORD dwCurrentPC,
  675. PNTKD_EXTENSION_APIS lpExtensionApis,
  676. LPSTR lpArgumentString
  677. )
  678. {
  679. PLIST_ENTRY pEntry;
  680. PLIST_ENTRY pHead;
  681. tDEVICECONTEXT *pDeviceContext;
  682. STRUCT_DESCRIPTOR *pStructs = Structs;
  683. ULONG Index = 0;
  684. tNBTCONFIG *ConfigPtr = (tNBTCONFIG *) lpArgumentString;
  685. tDEVICECONTEXT **ppNbtSmbDevice;
  686. PVOID dwAddress;
  687. SETCALLBACKS();
  688. if (!lpArgumentString || !(*lpArgumentString ))
  689. {
  690. ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig");
  691. }
  692. else
  693. {
  694. ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine (lpArgumentString);
  695. }
  696. ppNbtSmbDevice = (tDEVICECONTEXT **) lpGetExpressionRoutine ("netbt!pNbtSmbDevice");
  697. while (pStructs->StructName != 0)
  698. {
  699. if (!(_strnicmp("tDEVICECONTEXT", pStructs->StructName, 10)))
  700. {
  701. break;
  702. }
  703. Index++;
  704. pStructs++;
  705. }
  706. if (pStructs->StructName == 0)
  707. {
  708. PRINTF ("ERROR: Could not find structure definition for <tDEVICECONTEXT>\n");
  709. return FALSE;
  710. }
  711. if (!GetData(ppNbtSmbDevice, DataBuffer, sizeof (tDEVICECONTEXT *)))
  712. {
  713. PRINTF ("ERROR: Could not read pNbtSmbDevice ptr\n");
  714. }
  715. else if (!(pDeviceContext = *((tDEVICECONTEXT **) DataBuffer)))
  716. {
  717. PRINTF ("pNbtSmbDevice is NULL\n");
  718. }
  719. else if (!GetData(pDeviceContext, DataBuffer, Structs[Index].StructSize))
  720. {
  721. PRINTF ("ERROR: Could not read pNbtSmbDevice data@ <%p>\n", pDeviceContext);
  722. }
  723. else
  724. {
  725. //
  726. // Dump this Device's Info
  727. //
  728. PRINTF("pNbtSmbDevice @ <%p>\n", pDeviceContext);
  729. PRINTF( "++++++++++++++++ %s @%lx ++++++++++++++++\n", Structs[Index].StructName, pDeviceContext);
  730. PrintStructFields( pDeviceContext, &DataBuffer, Structs[Index].FieldDescriptors);
  731. PRINTF("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  732. }
  733. pHead = &ConfigPtr->DeviceContexts;
  734. if (!GetData(ConfigPtr, DataBuffer, sizeof(tNBTCONFIG)))
  735. {
  736. PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", ConfigPtr);
  737. return FALSE;
  738. }
  739. //
  740. // Get the number of Devices attached
  741. //
  742. {
  743. PVOID StartAddress;
  744. PVOID Address;
  745. ULONG Count = 0;
  746. PVOID Buffer[4];
  747. UCHAR Greater = ' ';
  748. StartAddress = pHead;
  749. GetData( StartAddress, Buffer, sizeof(ULONG)*4 );
  750. Address = Buffer[0];
  751. while ((Address != StartAddress) &&
  752. (++Count < MAX_LIST_ELEMENTS))
  753. {
  754. GetData( Address, Buffer, sizeof(ULONG)*4 );
  755. Address = Buffer[0];
  756. }
  757. PRINTF( "Dumping <%d> Devices attached to NbtConfig@<%x>\n", Count, ConfigPtr);
  758. }
  759. ConfigPtr = (tNBTCONFIG *) DataBuffer;
  760. pEntry = ConfigPtr->DeviceContexts.Flink;
  761. while (pEntry != pHead)
  762. {
  763. pDeviceContext = (tDEVICECONTEXT *) CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  764. if (!GetData(pDeviceContext, DataBuffer, Structs[Index].StructSize))
  765. {
  766. PRINTF ("ERROR: Could not read DeviceContext data @<%x>\n", pDeviceContext);
  767. return FALSE;
  768. }
  769. //
  770. // Dump this Device's Info
  771. //
  772. PRINTF( "++++++++++++++++ %s @%lx ++++++++++++++++\n", Structs[Index].StructName, pDeviceContext);
  773. PrintStructFields( pDeviceContext, &DataBuffer, Structs[Index].FieldDescriptors);
  774. //
  775. // Go to next device
  776. //
  777. pDeviceContext = (tDEVICECONTEXT *) DataBuffer;
  778. pEntry = pDeviceContext->Linkage.Flink;
  779. }
  780. return (TRUE);
  781. }
  782. BOOL
  783. connections(
  784. DWORD dwCurrentPC,
  785. PNTKD_EXTENSION_APIS lpExtensionApis,
  786. LPSTR lpArgumentString
  787. )
  788. {
  789. PLIST_ENTRY pEntry, pHead, pClientHead, pClientEntry, pConnHead, pConnEntry;
  790. tNBTCONFIG *ConfigPtr;
  791. tADDRESSELE *pAddressEle;
  792. tCLIENTELE *pClient;
  793. tCONNECTELE *pConnEle, *pSavConnEle;
  794. tNAMEADDR *pNameAddr;
  795. tLISTENREQUESTS *pListen;
  796. SETCALLBACKS();
  797. PRINTF ("Dumping information on all NetBT conections ...\n");
  798. if (!lpArgumentString || !(*lpArgumentString ))
  799. {
  800. ConfigPtr = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig");
  801. }
  802. else
  803. {
  804. ConfigPtr = (tNBTCONFIG *) (lpGetExpressionRoutine) (lpArgumentString);
  805. }
  806. pHead = &ConfigPtr->AddressHead;
  807. if (!GetData(ConfigPtr, DataBuffer, sizeof(tNBTCONFIG)))
  808. {
  809. PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", ConfigPtr);
  810. return FALSE;
  811. }
  812. ConfigPtr = (tNBTCONFIG *) DataBuffer;
  813. Next3 (pHead, &pEntry, NULL, NULL);
  814. while (pEntry != pHead)
  815. {
  816. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  817. Next3 (&pAddressEle->pNameAddr, &pNameAddr, NULL, NULL);
  818. if (!GetData(pNameAddr, DataBuffer, sizeof(tNAMEADDR)))
  819. {
  820. PRINTF ("[1] Error reading pNameAddr data @<%x>", pNameAddr);
  821. return FALSE;
  822. }
  823. pNameAddr = (tNAMEADDR *) DataBuffer;
  824. PRINTF ("Address@<%x> ==> <%-16.16s:%x>\n", pAddressEle, pNameAddr->Name, pNameAddr->Name[15]);
  825. pClientHead = &pAddressEle->ClientHead;
  826. Next3 (pClientHead, &pClientEntry, NULL, NULL);
  827. while (pClientEntry != pClientHead)
  828. {
  829. pClient = CONTAINING_RECORD(pClientEntry,tCLIENTELE,Linkage);
  830. if (!GetData(pClient, DataBuffer, sizeof(tCLIENTELE)))
  831. {
  832. PRINTF ("Error reading pClientEle data @<%p>", pClient);
  833. continue;
  834. }
  835. PRINTF ("\tClient@<%p> ==> pDevice=<%p>\n", pClient, ((tCLIENTELE *)DataBuffer)->pDeviceContext);
  836. PRINTF ("\t\t(ConnectHead):\n");
  837. pConnHead = &pClient->ConnectHead;
  838. Next3 (pConnHead, &pConnEntry, NULL, NULL);
  839. while (pConnEntry != pConnHead)
  840. {
  841. pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage);
  842. if (!GetData(pConnEle, DataBuffer, sizeof(tCONNECTELE)))
  843. {
  844. PRINTF ("[2] Error reading pConnEle data @<%x>", pConnEle);
  845. return FALSE;
  846. }
  847. pConnEle = (tCONNECTELE *) DataBuffer;
  848. PRINTF ("\t\t ** Connection@<%x> ==> <%-16.16s:%x>:\n",
  849. pSavConnEle, pConnEle->RemoteName, pConnEle->RemoteName[15]);
  850. Next3 (pConnEntry, &pConnEntry, NULL, NULL);
  851. }
  852. PRINTF ("\t\t(ConnectActive):\n");
  853. pConnHead = &pClient->ConnectActive;
  854. Next3 (pConnHead, &pConnEntry, NULL, NULL);
  855. while (pConnEntry != pConnHead)
  856. {
  857. pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage);
  858. if (!GetData(pConnEle, DataBuffer, sizeof(tCONNECTELE)))
  859. {
  860. PRINTF ("[3] Error reading pConnEle data @<%x>", pConnEle);
  861. return FALSE;
  862. }
  863. pConnEle = (tCONNECTELE *) DataBuffer;
  864. PRINTF ("\t\t ** Connection@<%x> ==> <%-16.16s:%x>:\n",
  865. pSavConnEle, pConnEle->RemoteName, pConnEle->RemoteName[15]);
  866. Next3 (pConnEntry, &pConnEntry, NULL, NULL);
  867. }
  868. PRINTF ("\t\t(ListenHead):\n");
  869. pConnHead = &pClient->ListenHead;
  870. Next3 (pConnHead, &pConnEntry, NULL, NULL);
  871. while (pConnEntry != pConnHead)
  872. {
  873. pSavConnEle = pConnEle = CONTAINING_RECORD(pConnEntry,tCONNECTELE,Linkage);
  874. if (!GetData(pConnEle, DataBuffer, sizeof(tLISTENREQUESTS)))
  875. {
  876. PRINTF ("[4] Error reading pListen data @<%x>", pSavConnEle);
  877. return FALSE;
  878. }
  879. pListen = (tLISTENREQUESTS *) DataBuffer;
  880. PRINTF ("\t\t ** pListen@<%p> ==> pIrp=<%p>\n", pSavConnEle, pListen->pIrp);
  881. Next3 (pConnEntry, &pConnEntry, NULL, NULL);
  882. }
  883. Next3 (pClientEntry, &pClientEntry, NULL, NULL);
  884. }
  885. Next3 (pEntry, &pEntry, NULL, NULL);
  886. PRINTF ("\n");
  887. }
  888. PRINTF( "---------------- Connections ----------------\n");
  889. return (TRUE);
  890. }
  891. BOOL
  892. verifyll(
  893. DWORD dwCurrentPC,
  894. PNTKD_EXTENSION_APIS lpExtensionApis,
  895. LPSTR lpArgumentString
  896. )
  897. {
  898. PLIST_ENTRY pHead, pCurrentEntry, pNextEntry, pPreviousEntry;
  899. ULONG_PTR VerifyRead, VerifyIn = 0;
  900. ULONG Count = 0;
  901. BOOL fVerifyIn = FALSE;
  902. BOOL fListCorrupt = FALSE;
  903. SETCALLBACKS();
  904. PRINTF ("Verifying Linked list ...\n");
  905. if (!lpArgumentString || !(*lpArgumentString ))
  906. {
  907. PRINTF ("Usage: !NetbtKd.VerifyLL <ListHead> [<Verify]>\n");
  908. return FALSE;
  909. }
  910. else
  911. {
  912. //
  913. // lpArgumentString = "<pHead> [<Verify>]"
  914. //
  915. LPSTR lpVerify;
  916. while (*lpArgumentString == ' ')
  917. {
  918. lpArgumentString++;
  919. }
  920. lpVerify = strpbrk(lpArgumentString, NAME_DELIMITERS);
  921. pHead = (PVOID) (lpGetExpressionRoutine) (lpArgumentString);
  922. if (lpVerify)
  923. {
  924. VerifyIn = (lpGetExpressionRoutine) (lpVerify);
  925. fVerifyIn = TRUE;
  926. }
  927. }
  928. PRINTF ("** ListHead@<%x>, fVerifyIn=<%x>, VerifyIn=<%x>:\n\n", pHead, fVerifyIn, VerifyIn);
  929. PRINTF ("Verifying Flinks ...");
  930. // Read in the data for the first FLink in the list!
  931. pPreviousEntry = pHead;
  932. Next3 (pHead, &pCurrentEntry, NULL, NULL);
  933. Next3 (pCurrentEntry, &pNextEntry, NULL, &VerifyRead);
  934. while ((pCurrentEntry != pHead) &&
  935. (++Count < MAX_LIST_ELEMENTS))
  936. {
  937. if ((fVerifyIn) &&
  938. (VerifyRead != VerifyIn))
  939. {
  940. PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far, Previous=<%x>, Current=<%x>, Next=<%x>\n",
  941. Count, pPreviousEntry, pCurrentEntry, pNextEntry);
  942. fListCorrupt = TRUE;
  943. break;
  944. }
  945. pPreviousEntry = pCurrentEntry;
  946. pCurrentEntry = pNextEntry;
  947. Next3 (pCurrentEntry, &pNextEntry, NULL, &VerifyRead);
  948. }
  949. if (!fListCorrupt)
  950. {
  951. PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count);
  952. }
  953. PRINTF ("Verifying Blinks ...");
  954. Count = 0;
  955. fListCorrupt = FALSE;
  956. // Read in the data for the first BLink in the list!
  957. pPreviousEntry = pHead;
  958. Next3 (pHead, NULL, &pCurrentEntry, NULL);
  959. Next3 (pCurrentEntry, NULL, &pNextEntry, &VerifyRead);
  960. while ((pCurrentEntry != pHead) &&
  961. (++Count < MAX_LIST_ELEMENTS))
  962. {
  963. if ((fVerifyIn) &&
  964. (VerifyRead != VerifyIn))
  965. {
  966. PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far, Previous=<%x>, Current=<%x>, Next=<%x>\n",
  967. Count, pPreviousEntry, pCurrentEntry, pNextEntry);
  968. fListCorrupt = TRUE;
  969. break;
  970. }
  971. pPreviousEntry = pCurrentEntry;
  972. pCurrentEntry = pNextEntry;
  973. Next3 (pCurrentEntry, NULL, &pNextEntry, &VerifyRead);
  974. }
  975. if (!fListCorrupt)
  976. {
  977. PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count);
  978. }
  979. PRINTF( "---------------- Verify LinkedList ----------------\n");
  980. return (TRUE);
  981. }
  982. BOOL
  983. DumpCache(
  984. tHASHTABLE *pHashTable,
  985. enum eNbtLocation CacheType
  986. )
  987. {
  988. LONG i, NumBuckets;
  989. PLIST_ENTRY pHead;
  990. PLIST_ENTRY pEntry;
  991. tHASHTABLE HashTbl;
  992. tNAMEADDR NameAddr, *pNameAddr;
  993. if (!GetData(pHashTable, &HashTbl, sizeof(tHASHTABLE)))
  994. {
  995. PRINTF ("ERROR: Could not read %s HashTable data @<%x>\n",
  996. (CacheType == NBT_LOCAL ? "Local":"Remote"), pHashTable);
  997. return FALSE;
  998. }
  999. NumBuckets = HashTbl.lNumBuckets;
  1000. PRINTF ("\nDumping %s Cache = <%d> buckets:\n",
  1001. (CacheType == NBT_LOCAL ? "Local":"Remote"), NumBuckets);
  1002. PRINTF ("[Bkt#]\t<Address> => <Name > | IpAddr | RefC | State | Ttl\n");
  1003. PRINTF ("-----------------------------------------------------------------------------------\n");
  1004. for (i=0; i < NumBuckets; i++)
  1005. {
  1006. pHead = &pHashTable->Bucket[i];
  1007. Next3 (pHead, &pEntry, NULL, NULL);
  1008. //
  1009. // Go through each name in each bucket of the hashtable
  1010. //
  1011. while (pEntry != pHead)
  1012. {
  1013. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1014. if (!GetData(pNameAddr, &NameAddr, sizeof(tNAMEADDR)))
  1015. {
  1016. PRINTF ("ERROR: Could not read NameAddr data @<%x>\n", pNameAddr);
  1017. return FALSE;
  1018. }
  1019. if ((NameAddr.Verify == LOCAL_NAME) || (NameAddr.Verify == REMOTE_NAME))
  1020. {
  1021. PRINTF ("[%d]\t<%x> => <%-15.15s:%2x> | %8x | %d | %8x | %9d\n",
  1022. i, pNameAddr, NameAddr.Name, (NameAddr.Name[15]&0x000000ff), NameAddr.IpAddress, NameAddr.RefCount, NameAddr.NameTypeState, NameAddr.Ttl);
  1023. }
  1024. else
  1025. {
  1026. PRINTF ("ERROR: Bad Name cache entry @ <%x>!\n", pNameAddr);
  1027. return FALSE;
  1028. }
  1029. Next3 (pEntry, &pEntry, NULL, NULL); // next hash table entry
  1030. }
  1031. } // for ( .. pHashTable .. )
  1032. return TRUE;
  1033. }
  1034. BOOL
  1035. cache(
  1036. DWORD dwCurrentPC,
  1037. PNTKD_EXTENSION_APIS lpExtensionApis,
  1038. LPSTR lpArgumentString
  1039. )
  1040. {
  1041. tNBTCONFIG NbtConfig, *pConfig;
  1042. BOOL fDumpLocal = TRUE; // Dump both local and remote cache by default
  1043. BOOL fDumpRemote = TRUE;
  1044. SETCALLBACKS();
  1045. if (lpArgumentString && (*lpArgumentString ))
  1046. {
  1047. //
  1048. // lpArgumentString = "[Local|Remote]"
  1049. //
  1050. while (*lpArgumentString == ' ')
  1051. {
  1052. lpArgumentString++;
  1053. }
  1054. if ((*lpArgumentString == 'l') || (*lpArgumentString == 'L'))
  1055. {
  1056. fDumpRemote = FALSE;
  1057. }
  1058. else if ((*lpArgumentString == 'r') || (*lpArgumentString == 'R'))
  1059. {
  1060. fDumpLocal = FALSE;
  1061. }
  1062. }
  1063. pConfig = (tNBTCONFIG *) lpGetExpressionRoutine ("netbt!NbtConfig");
  1064. if (!GetData(pConfig, &NbtConfig, sizeof(tNBTCONFIG)))
  1065. {
  1066. PRINTF ("ERROR: Could not read NbtConfig data @<%x>\n", pConfig);
  1067. return FALSE;
  1068. }
  1069. if (fDumpLocal)
  1070. {
  1071. DumpCache (NbtConfig.pLocalHashTbl, NBT_LOCAL);
  1072. }
  1073. if (fDumpRemote)
  1074. {
  1075. DumpCache (NbtConfig.pRemoteHashTbl, NBT_REMOTE);
  1076. }
  1077. PRINTF( "---------------- Cache ----------------\n");
  1078. return (TRUE);
  1079. }