Leaked source code of windows server 2003
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.

999 lines
29 KiB

  1. /*++
  2. Copyright (c) 1990, 1998 Microsoft Corporation
  3. Module Name:
  4. dbgdumpx.c
  5. *WAS* kdextlib.c
  6. Abstract:
  7. Library routines for dumping data structures given a meta level descrioption
  8. Author:
  9. Balan Sethu Raman (SethuR) 11-May-1994
  10. Notes:
  11. The implementation tends to avoid memory allocation and deallocation as much as possible.
  12. Therefore We have choosen an arbitrary length as the default buffer size. A mechanism will
  13. be provided to modify this buffer length through the debugger extension commands.
  14. Revision History:
  15. 11-Nov-1994 SethuR Created
  16. 19-April-1998 Mikeswa Modify for Exchange Platinum
  17. 22-Sept-1998 Mikeswa moved to IIS
  18. 22-July-1999 Mikeswa and back to platinum
  19. 24-March-2000 Mikeswa and back to IIS
  20. --*/
  21. #include <windows.h>
  22. #include <imagehlp.h>
  23. #include <transdbg.h>
  24. #include <dbgdumpx.h>
  25. #include <stdlib.h>
  26. char *s_rgszMonth[ 12 ] =
  27. {
  28. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  29. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  30. };
  31. char *s_rgszWeekDays[7] =
  32. {
  33. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  34. };
  35. char *NewLine = "\n";
  36. #define FIELD_NAME_LENGTH 30
  37. char FieldIndent[5 + 2*FIELD_NAME_LENGTH] = " ";
  38. #define GET_STRUCT_VALUE(Type, pvStruct, Offset) \
  39. (*(Type *)(((char *)pvStruct) + Offset))
  40. #define FIELD_BUFFER_SIZE 100
  41. BOOL
  42. kdextAtoi(
  43. LPSTR lpArg,
  44. int *pRet
  45. );
  46. int
  47. kdextStrlen(
  48. LPSTR lpsz
  49. );
  50. int
  51. kdextStrnicmp(
  52. LPSTR lpsz1,
  53. LPSTR lpsz2,
  54. int cLen
  55. );
  56. PWINDBG_OUTPUT_ROUTINE g_lpOutputRoutine;
  57. PWINDBG_GET_EXPRESSION g_lpGetExpressionRoutine;
  58. PWINDBG_GET_SYMBOL g_lpGetSymbolRoutine;
  59. PWINDBG_READ_PROCESS_MEMORY_ROUTINE g_lpReadMemoryRoutine;
  60. HANDLE g_hCurrentProcess;
  61. #define NL 1
  62. #define NONL 0
  63. #define DEFAULT_UNICODE_DATA_LENGTH 512
  64. USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH;
  65. WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH];
  66. WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
  67. #define DEFAULT_ANSI_DATA_LENGTH 512
  68. USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH;
  69. CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH];
  70. CHAR *s_pAnsiStringData = s_AnsiStringData;
  71. /*
  72. * Fetches the data at the given address
  73. */
  74. BOOLEAN
  75. GetDataEx( DWORD_PTR dwAddress, PVOID ptr, ULONG size, PULONG pBytesRead)
  76. {
  77. BOOL b;
  78. SIZE_T BytesRead;
  79. if (pBytesRead)
  80. *pBytesRead = 0;
  81. b = KdExtReadMemory((LPVOID) dwAddress, ptr, size, &BytesRead );
  82. if (!pBytesRead && (BytesRead != size)) {
  83. return FALSE;
  84. }
  85. if (!b) {
  86. /* If we have an out param... try reading less */
  87. if (!pBytesRead || !size)
  88. return FALSE;
  89. /* maybe our buffer size is too big... try to read 1 byte */
  90. b = KdExtReadMemory((LPVOID) dwAddress, ptr, 1, &BytesRead );
  91. if (!b)
  92. return FALSE;
  93. /* Try to find the best size... this is useful for strings */
  94. while (!b && (--size > 0)) {
  95. b = KdExtReadMemory((LPVOID) dwAddress, ptr, size, &BytesRead );
  96. }
  97. }
  98. if (pBytesRead)
  99. *pBytesRead = (ULONG)BytesRead;
  100. return TRUE;
  101. }
  102. BOOLEAN
  103. GetData( DWORD_PTR dwAddress, PVOID ptr, ULONG size)
  104. {
  105. return GetDataEx(dwAddress, ptr, size, NULL);
  106. }
  107. /*
  108. * Displays a byte in hexadecimal
  109. */
  110. VOID
  111. PrintHexChar( UCHAR c )
  112. {
  113. PRINTF( "%c%c", "0123456789abcdef"[ (c>>4)&7 ], "0123456789abcdef"[ c&7 ] );
  114. }
  115. /*
  116. * Displays a buffer of data in hexadecimal
  117. */
  118. VOID
  119. PrintHexBuf( PUCHAR buf, ULONG cbuf )
  120. {
  121. while( cbuf-- ) {
  122. PrintHexChar( *buf++ );
  123. PRINTF( " " );
  124. }
  125. }
  126. /*
  127. * Displays a unicode string
  128. */
  129. BOOL
  130. PrintStringW(LPSTR msg, PUNICODE_STRING puStr, BOOL nl )
  131. {
  132. UNICODE_STRING UnicodeString;
  133. BOOLEAN b;
  134. if( msg )
  135. PRINTF( msg );
  136. if( puStr->Length == 0 ) {
  137. if( nl )
  138. PRINTF( "\n" );
  139. return TRUE;
  140. }
  141. UnicodeString.Buffer = s_pUnicodeStringData;
  142. UnicodeString.MaximumLength = s_UnicodeStringDataLength;
  143. UnicodeString.Length = (puStr->Length > s_UnicodeStringDataLength)
  144. ? s_UnicodeStringDataLength
  145. : puStr->Length;
  146. b = GetData((DWORD_PTR) puStr->Buffer, UnicodeString.Buffer, (ULONG) UnicodeString.Length);
  147. if (b) {
  148. PRINTF("%wZ%s", &UnicodeString, nl ? "\n" : "" );
  149. }
  150. return b;
  151. }
  152. /*
  153. * Displays a ANSI string
  154. */
  155. BOOL
  156. PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl )
  157. {
  158. ANSI_STRING AnsiString;
  159. BOOL b;
  160. if( msg )
  161. PRINTF( msg );
  162. if( pStr->Length == 0 ) {
  163. if( nl )
  164. PRINTF( "\n" );
  165. return TRUE;
  166. }
  167. AnsiString.Buffer = s_pAnsiStringData;
  168. AnsiString.MaximumLength = s_AnsiStringDataLength;
  169. AnsiString.Length = (pStr->Length > (s_AnsiStringDataLength - 1))
  170. ? (s_AnsiStringDataLength - 1)
  171. : pStr->Length;
  172. b = KdExtReadMemory(
  173. (LPVOID) pStr->Buffer,
  174. AnsiString.Buffer,
  175. AnsiString.Length,
  176. NULL);
  177. if (b) {
  178. AnsiString.Buffer[ AnsiString.Length ] = '\0';
  179. PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
  180. }
  181. return b;
  182. }
  183. /*
  184. * Displays a GUID
  185. */
  186. BOOL
  187. PrintGuid(
  188. GUID *pguid)
  189. {
  190. ULONG i;
  191. PRINTF( "%08x-%04x-%04x", pguid->Data1, pguid->Data2, pguid->Data3 );
  192. for (i = 0; i < 8; i++) {
  193. PRINTF("%02x",pguid->Data4[i]);
  194. }
  195. return( TRUE );
  196. }
  197. /*
  198. * Displays a LARGE_INTEGER
  199. */
  200. BOOL
  201. PrintLargeInt(
  202. LARGE_INTEGER *bigint)
  203. {
  204. PRINTF( "%08x:%08x", bigint->HighPart, bigint->LowPart);
  205. return( TRUE );
  206. }
  207. /*
  208. * Displays a DWORD size class signature
  209. */
  210. BOOL
  211. PrintClassSignature(
  212. CHAR * pch)
  213. {
  214. PRINTF("0x%08X (%c%c%c%c)", *((DWORD *)pch), *(pch), *(pch+1), *(pch+2), *(pch+3));
  215. return( TRUE );
  216. }
  217. /*
  218. * Displays a standard LIST_ENTRY structure
  219. */
  220. BOOL
  221. PrintListEntry(DWORD_PTR dwAddress, CHAR * pch)
  222. {
  223. PLIST_ENTRY pli = (PLIST_ENTRY) pch;
  224. LIST_ENTRY liCurrent;
  225. PLIST_ENTRY pliCurrent = pli->Flink;
  226. DWORD cEntries= 0;
  227. BOOL fListOK = TRUE;
  228. //figure out how many entries there are
  229. while (pliCurrent != (PLIST_ENTRY) dwAddress)
  230. {
  231. cEntries++;
  232. if ((cEntries > 1000) ||
  233. !GetData((DWORD_PTR) pliCurrent, &liCurrent, sizeof(LIST_ENTRY)))
  234. {
  235. fListOK = FALSE;
  236. break;
  237. }
  238. pliCurrent = liCurrent.Flink;
  239. }
  240. PRINTF("0x%p ", dwAddress);
  241. if (fListOK)
  242. PRINTF("(%d entries)", cEntries);
  243. else
  244. PRINTF("(Unable to determine how many entries)");
  245. PRINTF(NewLine);
  246. PRINTF("%s FLINK: 0x%p%s", FieldIndent, pli->Flink, NewLine);
  247. PRINTF("%s BLINK: 0x%p", FieldIndent, pli->Blink);
  248. return( TRUE );
  249. }
  250. /*
  251. * Displays a human readable FILETIME
  252. */
  253. BOOL PrintFileTime(FILETIME *pft, BOOL fLocalize)
  254. {
  255. SYSTEMTIME st;
  256. FILETIME ftDisplay = *pft;
  257. BOOL fInit = TRUE;
  258. ZeroMemory(&st, sizeof(SYSTEMTIME));
  259. //Translate to local timezone if requested
  260. if (fLocalize)
  261. FileTimeToLocalFileTime(pft, &ftDisplay);
  262. //Only convert if non-zero
  263. if (!pft->dwLowDateTime && !pft->dwHighDateTime)
  264. {
  265. fInit = FALSE;
  266. }
  267. else if (!FileTimeToSystemTime(&ftDisplay, &st))
  268. {
  269. PRINTF("Unable to convert %08X %08X to a SYSTEMTIME - error %d",
  270. ftDisplay.dwLowDateTime,ftDisplay.dwHighDateTime, GetLastError());
  271. return FALSE;
  272. }
  273. if (fInit)
  274. {
  275. PRINTF("%s, %d %s %04d %02d:%02d:%02d %s",
  276. s_rgszWeekDays[st.wDayOfWeek],
  277. st.wDay, s_rgszMonth[ st.wMonth - 1 ],
  278. st.wYear, st.wHour, st.wMinute, st.wSecond,
  279. fLocalize ? "(localized)" : "");
  280. }
  281. else
  282. {
  283. PRINTF("FILETIME is zero");
  284. }
  285. return TRUE;
  286. }
  287. /*
  288. * Displays a the values of a bitmask
  289. */
  290. BOOL
  291. PrintBitMaskValues(
  292. DWORD BitMaskValue,
  293. FIELD_DESCRIPTOR *pFieldDescriptor)
  294. {
  295. BOOL fFirstFlag;
  296. BIT_MASK_DESCRIPTOR *pBitMaskDescr;
  297. pBitMaskDescr = pFieldDescriptor->AuxillaryInfo.pBitMaskDescriptor;
  298. fFirstFlag = TRUE;
  299. if (pBitMaskDescr != NULL)
  300. {
  301. while (pBitMaskDescr->BitmaskName != NULL)
  302. {
  303. if (((BitMaskValue & pBitMaskDescr->BitmaskValue) ==
  304. pBitMaskDescr->BitmaskValue) && //need to check all bits of bit mask
  305. //If descriptor value is 0.. it will always match any bit mask
  306. //it should only when the actual BitMaskValue is 0 as well
  307. (pBitMaskDescr->BitmaskValue || !BitMaskValue))
  308. {
  309. if (fFirstFlag)
  310. {
  311. fFirstFlag = FALSE;
  312. PRINTF("%s ( %-s", FieldIndent, pBitMaskDescr->BitmaskName);
  313. }
  314. else
  315. {
  316. PRINTF( " |\n" );
  317. PRINTF("%s %-s", FieldIndent, pBitMaskDescr->BitmaskName);
  318. }
  319. }
  320. pBitMaskDescr++;
  321. }
  322. PRINTF(" )");
  323. return TRUE;
  324. }
  325. return FALSE;
  326. }
  327. /*
  328. * Displays all the fields of a given struct. This is the driver routine that is called
  329. * with the appropriate descriptor array to display all the fields in a given struct.
  330. */
  331. VOID
  332. PrintStructFields( DWORD_PTR dwAddress, BYTE *ptr, FIELD_DESCRIPTOR *pFieldDescriptors, DWORD cIndentLevel)
  333. {
  334. DWORD i,j;
  335. BYTE pbBuffer[FIELD_BUFFER_SIZE];
  336. DWORD BitMaskValue = 0;
  337. DWORD cbGetData = 0;
  338. CHAR szTmpName[FIELD_NAME_LENGTH];
  339. //Make sure FieldIndent is correct
  340. for (j = 0; j < cIndentLevel%(FIELD_NAME_LENGTH/2); j++)
  341. lstrcat(FieldIndent, " ");
  342. // Display the fields in the struct.
  343. for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) {
  344. // Indentation to begin the struct display.
  345. PRINTF( " " );
  346. for (j = 0; j < cIndentLevel%(FIELD_NAME_LENGTH/2); j++)
  347. PRINTF(" "); //print 2 spaces for every indent level
  348. if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) {
  349. memcpy(szTmpName, pFieldDescriptors->Name, FIELD_NAME_LENGTH-3);
  350. szTmpName[FIELD_NAME_LENGTH-3] = '\0';
  351. PRINTF( "%s... ", szTmpName);
  352. } else {
  353. PRINTF( "%-30s ", pFieldDescriptors->Name );
  354. }
  355. switch( pFieldDescriptors->FieldType ) {
  356. case FieldTypeByte:
  357. case FieldTypeChar:
  358. PRINTF( "%-16d%s",
  359. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
  360. NewLine );
  361. break;
  362. case FieldTypeBoolean:
  363. PRINTF( "%-16s%s",
  364. *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  365. NewLine);
  366. break;
  367. case FieldTypeBool:
  368. PRINTF( "%-16s%s",
  369. *(BOOL *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  370. NewLine);
  371. break;
  372. case FieldTypePointer:
  373. PRINTF( "@0x%p%s",
  374. *(DWORD_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ),
  375. NewLine );
  376. break;
  377. case FieldTypeLong:
  378. PRINTF( "%-16d%s",
  379. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  380. NewLine );
  381. break;
  382. case FieldTypeULong:
  383. case FieldTypeDword:
  384. PRINTF( "%-16u%s",
  385. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  386. NewLine );
  387. break;
  388. case FieldTypeShort:
  389. PRINTF( "%-16X%s",
  390. *(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  391. NewLine );
  392. break;
  393. case FieldTypeUShort:
  394. PRINTF( "%-16X%s",
  395. *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  396. NewLine );
  397. break;
  398. case FieldTypeGuid:
  399. PrintGuid( (GUID *)(((char *)ptr) + pFieldDescriptors->Offset) );
  400. PRINTF( NewLine );
  401. break;
  402. case FieldTypePStr: //pointer to a string
  403. if (GetDataEx(GET_STRUCT_VALUE(DWORD_PTR, ptr,
  404. pFieldDescriptors->Offset), pbBuffer, FIELD_BUFFER_SIZE, &cbGetData))
  405. {
  406. //make sure the string is terminated
  407. pbBuffer[FIELD_BUFFER_SIZE - 1] = '\0';
  408. PRINTF( "%s", (LPSTR) pbBuffer );
  409. }
  410. else if (!GET_STRUCT_VALUE(DWORD_PTR, ptr, pFieldDescriptors->Offset))
  411. {
  412. PRINTF( "<Null String>");
  413. }
  414. else
  415. {
  416. PRINTF("ERROR: Unable to read string a 0x%p",
  417. GET_STRUCT_VALUE(DWORD_PTR, ptr, pFieldDescriptors->Offset));
  418. }
  419. PRINTF( NewLine );
  420. break;
  421. case FieldTypePWStr:
  422. if (GetDataEx(GET_STRUCT_VALUE(DWORD_PTR, ptr, pFieldDescriptors->Offset),
  423. pbBuffer, FIELD_BUFFER_SIZE, &cbGetData))
  424. {
  425. //make sure the string is terminated
  426. pbBuffer[FIELD_BUFFER_SIZE - 1] = '\0';
  427. pbBuffer[FIELD_BUFFER_SIZE - 2] = '\0';
  428. PRINTF( "%ws", (LPWSTR) pbBuffer );
  429. }
  430. else
  431. {
  432. PRINTF("ERROR: Unable to read string a 0x%p",
  433. GET_STRUCT_VALUE(DWORD_PTR, ptr, pFieldDescriptors->Offset));
  434. }
  435. PRINTF( NewLine );
  436. break;
  437. case FieldTypeStrBuffer: //member is a character array
  438. PRINTF( "%.100s%s", (CHAR *)(((char *)ptr) + pFieldDescriptors->Offset), NewLine);
  439. break;
  440. case FieldTypeWStrBuffer:
  441. PRINTF( "%.100ws%s", (WCHAR *)(((char *)ptr) + pFieldDescriptors->Offset), NewLine);
  442. break;
  443. case FieldTypeUnicodeString:
  444. PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
  445. PRINTF( NewLine );
  446. break;
  447. case FieldTypeAnsiString:
  448. PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
  449. PRINTF( NewLine );
  450. break;
  451. case FieldTypeSymbol:
  452. {
  453. UCHAR SymbolName[ 200 ];
  454. ULONG_PTR Displacement;
  455. PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ));
  456. g_lpGetSymbolRoutine( sym, SymbolName, &Displacement );
  457. PRINTF( "%-16s%s",
  458. SymbolName,
  459. NewLine );
  460. }
  461. break;
  462. case FieldTypeEnum:
  463. {
  464. ULONG EnumValue;
  465. ENUM_VALUE_DESCRIPTOR *pEnumValueDescr;
  466. // Get the associated numerical value.
  467. EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset));
  468. if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor)
  469. != NULL) {
  470. //
  471. // An auxilary textual description of the value is
  472. // available. Display it instead of the numerical value.
  473. //
  474. LPSTR pEnumName = NULL;
  475. while (pEnumValueDescr->EnumName != NULL) {
  476. if (EnumValue == pEnumValueDescr->EnumValue) {
  477. pEnumName = pEnumValueDescr->EnumName;
  478. break;
  479. }
  480. pEnumValueDescr++;
  481. }
  482. if (pEnumName != NULL) {
  483. PRINTF( "%-16s ", pEnumName );
  484. } else {
  485. PRINTF( "%-4d (%-10s) ", EnumValue,"Unknown!");
  486. }
  487. } else {
  488. //
  489. // No auxilary information is associated with the ehumerated type
  490. // print the numerical value.
  491. //
  492. PRINTF( "%-16d",EnumValue);
  493. }
  494. PRINTF( NewLine );
  495. }
  496. break;
  497. case FieldTypeByteBitMask:
  498. BitMaskValue = GET_STRUCT_VALUE(BYTE, ptr, pFieldDescriptors->Offset);
  499. PRINTF("0x%02X ", (BYTE) BitMaskValue);
  500. PRINTF( NewLine );
  501. if (PrintBitMaskValues(BitMaskValue, pFieldDescriptors))
  502. PRINTF( NewLine );
  503. break;
  504. case FieldTypeWordBitMask:
  505. BitMaskValue = GET_STRUCT_VALUE(WORD, ptr, pFieldDescriptors->Offset);
  506. PRINTF("0x%04X ", (WORD) BitMaskValue);
  507. PRINTF( NewLine );
  508. if (PrintBitMaskValues(BitMaskValue, pFieldDescriptors))
  509. PRINTF( NewLine );
  510. break;
  511. case FieldTypeDWordBitMask:
  512. BitMaskValue = GET_STRUCT_VALUE(DWORD, ptr, pFieldDescriptors->Offset);
  513. PRINTF("0x%08X ", (DWORD) BitMaskValue);
  514. PRINTF( NewLine );
  515. if (PrintBitMaskValues(BitMaskValue, pFieldDescriptors))
  516. PRINTF( NewLine );
  517. break;
  518. case FieldTypeStruct:
  519. PRINTF( "@0x%p%s",
  520. (dwAddress + pFieldDescriptors->Offset ),
  521. NewLine );
  522. break;
  523. case FieldTypeLargeInteger:
  524. PrintLargeInt( (LARGE_INTEGER *)(((char *)ptr) + pFieldDescriptors->Offset) );
  525. PRINTF( NewLine );
  526. break;
  527. case FieldTypeClassSignature:
  528. PrintClassSignature(((char *)ptr) + pFieldDescriptors->Offset);
  529. PRINTF( NewLine );
  530. break;
  531. case FieldTypeListEntry:
  532. PrintListEntry(dwAddress + pFieldDescriptors->Offset,
  533. ((char *)ptr) + pFieldDescriptors->Offset);
  534. PRINTF( NewLine );
  535. break;
  536. case FieldTypeLocalizedFiletime:
  537. PrintFileTime((FILETIME *) (((char *)ptr) + pFieldDescriptors->Offset), TRUE);
  538. PRINTF( NewLine );
  539. break;
  540. case FieldTypeFiletime:
  541. PrintFileTime((FILETIME *) (((char *)ptr) + pFieldDescriptors->Offset), FALSE);
  542. PRINTF( NewLine );
  543. break;
  544. case FieldTypeEmbeddedStruct:
  545. PRINTF( "Dumping %s@0x%p%s",
  546. ((STRUCT_DESCRIPTOR *) (pFieldDescriptors->AuxillaryInfo.pStructDescriptor))->StructName,
  547. dwAddress+ pFieldDescriptors->Offset, NewLine );
  548. PrintStructFields(dwAddress+pFieldDescriptors->Offset,
  549. ((char *)ptr) + pFieldDescriptors->Offset,
  550. ((STRUCT_DESCRIPTOR *) (pFieldDescriptors->AuxillaryInfo.pStructDescriptor))->FieldDescriptors,
  551. cIndentLevel+1);
  552. break;
  553. default:
  554. PRINTF( "Unrecognized field type %d for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name );
  555. break;
  556. }
  557. }
  558. //Make sure FieldIndent is correct when we leave
  559. FieldIndent[lstrlen(FieldIndent)-(cIndentLevel%(FIELD_NAME_LENGTH/2))] = '\0';
  560. }
  561. LPSTR LibCommands[] = {
  562. "help -- This command ",
  563. "dump <Struct Type Name>@<address expr> ",
  564. 0
  565. };
  566. PT_DEBUG_EXTENSION(_help)
  567. {
  568. int i;
  569. SETCALLBACKS();
  570. PRINTF("\n");
  571. for( i=0; ExtensionNames[i]; i++ )
  572. PRINTF( "%s\n", ExtensionNames[i] );
  573. for( i=0; LibCommands[i]; i++ )
  574. PRINTF( " %s\n", LibCommands[i] );
  575. for( i=0; Extensions[i]; i++) {
  576. PRINTF( " %s\n", Extensions[i] );
  577. }
  578. return;
  579. }
  580. #define NAME_DELIMITER '@'
  581. #define INVALID_INDEX 0xffffffff
  582. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  583. ULONG SearchStructs(LPSTR lpArgument)
  584. {
  585. ULONG i = 0;
  586. STRUCT_DESCRIPTOR *pStructs = Structs;
  587. ULONG NameIndex = INVALID_INDEX;
  588. int ArgumentLength = kdextStrlen(lpArgument);
  589. BOOLEAN fAmbiguous = FALSE;
  590. while ((pStructs->StructName != 0)) {
  591. int StructLength;
  592. StructLength = kdextStrlen(pStructs->StructName);
  593. if (StructLength >= ArgumentLength) {
  594. int Result = kdextStrnicmp(
  595. lpArgument,
  596. pStructs->StructName,
  597. ArgumentLength);
  598. if (Result == 0) {
  599. if (StructLength == ArgumentLength) {
  600. // Exact match. They must mean this struct!
  601. fAmbiguous = FALSE;
  602. NameIndex = i;
  603. break;
  604. } else if (NameIndex != INVALID_INDEX) {
  605. // We have encountered duplicate matches. Print out the
  606. // matching strings and let the user disambiguate.
  607. fAmbiguous = TRUE;
  608. break;
  609. } else {
  610. NameIndex = i;
  611. }
  612. }
  613. }
  614. pStructs++;i++;
  615. }
  616. if (fAmbiguous) {
  617. PRINTF("Ambigous Name Specification -- The following structs match\n");
  618. PRINTF("%s\n",Structs[NameIndex].StructName);
  619. PRINTF("%s\n",Structs[i].StructName);
  620. while (pStructs->StructName != 0) {
  621. if (kdextStrnicmp(lpArgument,
  622. pStructs->StructName,
  623. MIN(kdextStrlen(pStructs->StructName),ArgumentLength)) == 0) {
  624. PRINTF("%s\n",pStructs->StructName);
  625. }
  626. pStructs++;
  627. }
  628. PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName);
  629. }
  630. return(NameIndex);
  631. }
  632. VOID DisplayStructs()
  633. {
  634. STRUCT_DESCRIPTOR *pStructs = Structs;
  635. PRINTF("The following structs are handled .... \n");
  636. while (pStructs->StructName != 0) {
  637. PRINTF("\t%s\n",pStructs->StructName);
  638. pStructs++;
  639. }
  640. }
  641. PT_DEBUG_EXTENSION(_dump)
  642. {
  643. DWORD_PTR dwAddress;
  644. BYTE *pDataBuffer = NULL;
  645. SETCALLBACKS();
  646. if( szArg && *szArg ) {
  647. // Parse the argument string to determine the structure to be displayed.
  648. // Scan for the NAME_DELIMITER ( '@' ).
  649. LPSTR lpName = (LPSTR) szArg;
  650. LPSTR lpArgs;
  651. ULONG Index;
  652. for (lpArgs = (LPSTR) szArg;
  653. *lpArgs != NAME_DELIMITER && *lpArgs != 0; lpArgs++) {
  654. ;
  655. }
  656. if (*lpArgs == NAME_DELIMITER) {
  657. //
  658. // The specified command is of the form
  659. // dump <name>@<address expr.>
  660. //
  661. // Locate the matching struct for the given name. In the case
  662. // of ambiguity we seek user intervention for disambiguation.
  663. //
  664. // We do an inplace modification of the argument string to
  665. // facilitate matching.
  666. //
  667. *lpArgs = '\0';
  668. Index = SearchStructs(lpName);
  669. //
  670. // Let us restore the original value back.
  671. //
  672. *lpArgs = NAME_DELIMITER;
  673. if (INVALID_INDEX != Index) {
  674. pDataBuffer = (BYTE *) LocalAlloc(0, Structs[Index].StructSize);
  675. if (!pDataBuffer)
  676. return;
  677. //Eat up any extra @'s
  678. do {lpArgs++;} while ('@' == *lpArgs);
  679. dwAddress = (g_lpGetExpressionRoutine)( lpArgs );
  680. if (pDataBuffer &&
  681. GetData(dwAddress,pDataBuffer,Structs[Index].StructSize)) {
  682. PRINTF(
  683. "++++++++++++++++ %s@0x%p ++++++++++++++++\n",
  684. Structs[Index].StructName,
  685. dwAddress);
  686. PrintStructFields(
  687. dwAddress,
  688. pDataBuffer,
  689. Structs[Index].FieldDescriptors, 0);
  690. PRINTF(
  691. "++++++++++++++++ size is %.10d bytes +++++++++++++++\n",
  692. Structs[Index].StructSize);
  693. PRINTF(
  694. "---------------- %s@0x%p ----------------\n",
  695. Structs[Index].StructName,
  696. dwAddress);
  697. } else {
  698. PRINTF("Error reading Memory @ %lx\n",dwAddress);
  699. }
  700. } else {
  701. // No matching struct was found. Display the list of
  702. // structs currently handled.
  703. DisplayStructs();
  704. }
  705. } else {
  706. //
  707. // The command is of the form
  708. // dump <name>
  709. //
  710. // Currently we do not handle this. In future we will map it to
  711. // the name of a global variable and display it if required.
  712. //
  713. DisplayStructs();
  714. }
  715. } else {
  716. //
  717. // display the list of structs currently handled.
  718. //
  719. DisplayStructs();
  720. }
  721. if (pDataBuffer)
  722. LocalFree(pDataBuffer);
  723. return;
  724. }
  725. PT_DEBUG_EXTENSION(_dumpoffsets)
  726. {
  727. if( szArg && *szArg ) {
  728. LPSTR lpName = (LPSTR) szArg;
  729. LPSTR lpArgs = NULL;
  730. CHAR chSave = '\0';
  731. FIELD_DESCRIPTOR *pFieldDescriptors = NULL;
  732. ULONG Index;
  733. for (lpArgs = (LPSTR) szArg;
  734. !isspace((UCHAR)*lpArgs) && *lpArgs != 0; lpArgs++) {
  735. ;
  736. }
  737. if (TRUE) {
  738. chSave = *lpArgs;
  739. *lpArgs = '\0';
  740. Index = SearchStructs(lpName);
  741. //
  742. // Let us restore the original value back.
  743. //
  744. *lpArgs = chSave;
  745. if (INVALID_INDEX != Index) {
  746. PRINTF(
  747. "++++++++++++++++ %s ++++++++++++++++\n",
  748. Structs[Index].StructName);
  749. for (pFieldDescriptors = Structs[Index].FieldDescriptors;
  750. pFieldDescriptors && pFieldDescriptors->Name;
  751. pFieldDescriptors++)
  752. {
  753. PRINTF("\t0x%08X\t%s\n",
  754. pFieldDescriptors->Offset, pFieldDescriptors->Name);
  755. }
  756. PRINTF(
  757. "++++++++++++++++ size is %.10d bytes +++++++++++++++\n",
  758. Structs[Index].StructSize);
  759. PRINTF(
  760. "---------------- %s ----------------\n",
  761. Structs[Index].StructName);
  762. } else {
  763. // No matching struct was found. Display the list of
  764. // structs currently handled.
  765. DisplayStructs();
  766. }
  767. } else {
  768. //
  769. // The command is of the form
  770. // dump <name>
  771. //
  772. // Currently we do not handle this. In future we will map it to
  773. // the name of a global variable and display it if required.
  774. //
  775. DisplayStructs();
  776. }
  777. } else {
  778. //
  779. // display the list of structs currently handled.
  780. //
  781. DisplayStructs();
  782. }
  783. return;
  784. }
  785. /*
  786. * KD Extensions should not link with the C-Runtime library routines. So,
  787. * we implement a few of the needed ones here.
  788. */
  789. BOOL
  790. kdextAtoi(
  791. LPSTR lpArg,
  792. int *pRet
  793. )
  794. {
  795. int n, cbArg, val = 0;
  796. BOOL fNegative = FALSE;
  797. cbArg = kdextStrlen( lpArg );
  798. if (cbArg > 0) {
  799. for (n = 0; lpArg[n] == ' '; n++) {
  800. ;
  801. }
  802. if (lpArg[n] == '-') {
  803. n++;
  804. fNegative = TRUE;
  805. }
  806. for (; lpArg[n] >= '0' && lpArg[n] <= '9'; n++) {
  807. val *= 10;
  808. val += (int) (lpArg[n] - '0');
  809. }
  810. if (lpArg[n] == 0) {
  811. *pRet = (fNegative ? -val : val);
  812. return( TRUE );
  813. } else {
  814. return( FALSE );
  815. }
  816. } else {
  817. return( FALSE );
  818. }
  819. }
  820. int
  821. kdextStrlen(
  822. LPSTR lpsz
  823. )
  824. {
  825. int c;
  826. if (lpsz == NULL) {
  827. c = 0;
  828. } else {
  829. for (c = 0; lpsz[c] != 0; c++) {
  830. ;
  831. }
  832. }
  833. return( c );
  834. }
  835. #define UPCASE_CHAR(c) \
  836. ( (((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c) )
  837. int
  838. kdextStrnicmp(
  839. LPSTR lpsz1,
  840. LPSTR lpsz2,
  841. int cLen
  842. )
  843. {
  844. int nDif, i;
  845. for (i = nDif = 0; nDif == 0 && i < cLen; i++) {
  846. nDif = UPCASE_CHAR(lpsz1[i]) - UPCASE_CHAR(lpsz2[i]);
  847. }
  848. return( nDif );
  849. }