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

627 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. strucsup.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. Revision History:
  11. 11-Nov-1994 SethuR Created
  12. --*/
  13. #include "rxovride.h" //common compile flags
  14. #include <ntos.h>
  15. #include <nturtl.h>
  16. #include "ntverp.h"
  17. #include <windows.h>
  18. #include <wdbgexts.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <kdextlib.h>
  23. #include <rdr2kd.h>
  24. #include <ntrxdef.h>
  25. #include <rxtypes.h>
  26. #include <rxlog.h>
  27. //need this for unaligned smbget macros
  28. #include <smbgtpt.h>
  29. extern WINDBG_EXTENSION_APIS ExtensionApis;
  30. //EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
  31. #define ERRPRT dprintf
  32. #define PRINTF dprintf
  33. #define NL 1
  34. #define NONL 0
  35. BOOLEAN
  36. wGetData( ULONG_PTR dwAddress, PVOID ptr, ULONG size, IN PSZ type);
  37. //
  38. // No. of columns used to display struct fields;
  39. //
  40. ULONG s_MaxNoOfColumns = 3;
  41. #ifndef RXKD_2col
  42. ULONG s_NoOfColumns = 1;
  43. #else
  44. ULONG s_NoOfColumns = 2;
  45. #endif
  46. /*
  47. * Displays all the fields of a given struct. This is the driver routine that is called
  48. * with the appropriate descriptor array to display all the fields in a given struct.
  49. */
  50. char *NewLine = "\n";
  51. char *FieldSeparator = " ";
  52. #define NewLineForFields(FieldNo) \
  53. ((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator)
  54. #define FIELD_NAME_LENGTH 30
  55. /*
  56. * Print out an optional message, a UNICODE_STRING, and maybe a new-line
  57. */
  58. BOOL
  59. wPrintStringU( IN LPSTR PrefixMsg OPTIONAL, IN PUNICODE_STRING puStr, IN LPSTR SuffixMsg OPTIONAL )
  60. {
  61. PWCHAR StringData;
  62. UNICODE_STRING UnicodeString;
  63. ULONG BytesRead;
  64. if (PrefixMsg == NULL) {
  65. PrefixMsg = "";
  66. }
  67. if (SuffixMsg == NULL) {
  68. SuffixMsg = "";
  69. }
  70. StringData = (PWCHAR)LocalAlloc( LPTR, puStr->Length + sizeof(UNICODE_NULL));
  71. if( StringData == NULL ) {
  72. dprintf( "Out of memory!\n" );
  73. return FALSE;
  74. }
  75. UnicodeString.Buffer = StringData; //puStr->Buffer;
  76. UnicodeString.Length = puStr->Length;
  77. UnicodeString.MaximumLength = puStr->MaximumLength;
  78. ReadMemory( (ULONG_PTR)puStr->Buffer,
  79. StringData,
  80. puStr->Length,
  81. &BytesRead);
  82. if (BytesRead) {
  83. dprintf("%s%wZ%s", PrefixMsg, &UnicodeString, SuffixMsg );
  84. } else {
  85. dprintf("MEMORYREAD FAILED %s%s",PrefixMsg,SuffixMsg);
  86. }
  87. LocalFree( (HLOCAL)StringData );
  88. return BytesRead;
  89. }
  90. VOID
  91. SetFlagString(
  92. ULONG Value,
  93. PCHAR FlagString
  94. )
  95. {
  96. ULONG i,t,mask;
  97. *FlagString = '('; FlagString++;
  98. for (i=t=0,mask=1;i<32;i++,mask<<=1) {
  99. //PRINTF("hithere %08lx %08lx %08lx\n",Value,mask,i);
  100. if (i==t+10) {
  101. *FlagString = ':'; FlagString++;
  102. t=t+10;
  103. }
  104. if (Value&mask) {
  105. *FlagString = '0'+(UCHAR)(i-t); FlagString++;
  106. }
  107. }
  108. *FlagString = ')'; FlagString++;
  109. *FlagString = 0;
  110. }
  111. VOID
  112. PrintStructFields( ULONG_PTR dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors )
  113. {
  114. int i;
  115. // Display the fields in the struct.
  116. for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) {
  117. // Indentation to begin the struct display.
  118. PRINTF( " " );
  119. if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) {
  120. PRINTF( "%-17s...%s ", pFieldDescriptors->Name, pFieldDescriptors->Name+strlen(pFieldDescriptors->Name)-10 );
  121. } else {
  122. PRINTF( "%-30s ", pFieldDescriptors->Name );
  123. }
  124. switch( pFieldDescriptors->FieldType ) {
  125. case FieldTypeByte:
  126. case FieldTypeChar:
  127. PRINTF( "%-16X%s",
  128. *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
  129. NewLineForFields(i) );
  130. break;
  131. case FieldTypeBoolean:
  132. PRINTF( "%-16s%s",
  133. *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  134. NewLineForFields(i));
  135. break;
  136. case FieldTypeBool:
  137. PRINTF( "%-16s%s",
  138. *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
  139. NewLineForFields(i));
  140. break;
  141. case FieldTypePointer:
  142. PRINTF( "%-16X%s",
  143. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  144. NewLineForFields(i) );
  145. break;
  146. case FieldTypeULong:
  147. case FieldTypeLong:
  148. PRINTF( "%-16X%s",
  149. *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
  150. NewLineForFields(i) );
  151. break;
  152. case FieldTypeULongUnaligned:
  153. case FieldTypeLongUnaligned:
  154. PRINTF( "%-16X%s",
  155. SmbGetUlong( (BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ) ),
  156. NewLineForFields(i) );
  157. break;
  158. case FieldTypeShort:
  159. PRINTF( "%-16X%s",
  160. *(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  161. NewLineForFields(i) );
  162. break;
  163. case FieldTypeUShort:
  164. PRINTF( "%-16X%s",
  165. *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  166. NewLineForFields(i) );
  167. break;
  168. case FieldTypeUShortUnaligned:
  169. PRINTF( "%-16X%s",
  170. SmbGetUshort( (BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ) ),
  171. NewLineForFields(i) );
  172. break;
  173. case FieldTypeULongFlags:{ULONG Value; char FlagString[60];
  174. Value = *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset );
  175. SetFlagString(Value,FlagString);
  176. PRINTF( "%-16X%s%s", Value, FlagString,
  177. NewLineForFields(i) );
  178. break;}
  179. case FieldTypeUShortFlags:{USHORT Value; char FlagString[60];
  180. Value = *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
  181. SetFlagString(Value,FlagString);
  182. PRINTF( "%-16X%s%s", Value, FlagString,
  183. NewLineForFields(i) );
  184. break;}
  185. case FieldTypeUnicodeString:
  186. wPrintStringU( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NULL );
  187. PRINTF( NewLine );
  188. break;
  189. //case FieldTypeAnsiString:
  190. // //PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
  191. // //PRINTF( NewLine );
  192. // PRINTF( NewLine );
  193. // break;
  194. case FieldTypeSymbol:
  195. {
  196. UCHAR SymbolName[ 200 ];
  197. ULONG_PTR Displacement;
  198. PVOID sym = (PVOID)(*(ULONG_PTR *)(((char *)ptr) + pFieldDescriptors->Offset ));
  199. GetSymbol( sym, SymbolName, &Displacement );
  200. PRINTF( "%-16s%s",
  201. SymbolName,
  202. NewLineForFields(i) );
  203. }
  204. break;
  205. case FieldTypeEnum:
  206. {
  207. ULONG EnumValue;
  208. ENUM_VALUE_DESCRIPTOR *pEnumValueDescr;
  209. // Get the associated numericla value.
  210. EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset));
  211. if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor)
  212. != NULL) {
  213. //
  214. // An auxilary textual description of the value is
  215. // available. Display it instead of the numerical value.
  216. //
  217. LPSTR pEnumName = NULL;
  218. while (pEnumValueDescr->EnumName != NULL) {
  219. if (EnumValue == pEnumValueDescr->EnumValue) {
  220. pEnumName = pEnumValueDescr->EnumName;
  221. break;
  222. }
  223. }
  224. if (pEnumName != NULL) {
  225. PRINTF( "%-16s ", pEnumName );
  226. } else {
  227. PRINTF( "%-4d (%-10s) ", EnumValue,"@$#%^&*");
  228. }
  229. } else {
  230. //
  231. // No auxilary information is associated with the ehumerated type
  232. // print the numerical value.
  233. //
  234. PRINTF( "%-16d",EnumValue);
  235. }
  236. }
  237. break;
  238. case FieldTypeStruct:
  239. PRINTF( "@%-15X%s",
  240. (dwAddress + pFieldDescriptors->Offset ),
  241. NewLineForFields(i) );
  242. break;
  243. case FieldTypeLargeInteger:
  244. case FieldTypeFileTime:
  245. default:
  246. ERRPRT( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name );
  247. break;
  248. }
  249. }
  250. }
  251. DECLARE_API( columns )
  252. {
  253. ULONG NoOfColumns;
  254. int i;
  255. //SETCALLBACKS();
  256. //sscanf(lpArgumentString,"%ld",&NoOfColumns);
  257. sscanf(args,"%ld",&NoOfColumns);
  258. if (NoOfColumns > s_MaxNoOfColumns) {
  259. // PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns );
  260. } else {
  261. s_NoOfColumns = NoOfColumns;
  262. }
  263. PRINTF("Not Yet Implemented\n");
  264. return;
  265. }
  266. #define NAME_DELIMITER '@'
  267. #define NAME_DELIMITERS "@"
  268. #define INVALID_INDEX 0xffffffff
  269. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  270. ULONG SearchStructs(LPSTR lpArgument)
  271. {
  272. ULONG i = 0;
  273. STRUCT_DESCRIPTOR *pStructs = Structs;
  274. ULONG NameIndex = INVALID_INDEX;
  275. ULONG ArgumentLength = strlen(lpArgument);
  276. BOOLEAN fAmbigous = FALSE;
  277. while ((pStructs->StructName != 0)) {
  278. int Result = _strnicmp(lpArgument,
  279. pStructs->StructName,
  280. MIN(strlen(pStructs->StructName),ArgumentLength));
  281. if (Result == 0) {
  282. if (NameIndex != INVALID_INDEX) {
  283. // We have encountered duplicate matches. Print out the
  284. // matching strings and let the user disambiguate.
  285. fAmbigous = TRUE;
  286. break;
  287. } else {
  288. NameIndex = i;
  289. }
  290. }
  291. pStructs++;i++;
  292. }
  293. if (fAmbigous) {
  294. PRINTF("Ambigous Name Specification -- The following structs match\n");
  295. PRINTF("%s\n",Structs[NameIndex].StructName);
  296. PRINTF("%s\n",Structs[i].StructName);
  297. while (pStructs->StructName != 0) {
  298. if (_strnicmp(lpArgument,
  299. pStructs->StructName,
  300. MIN(strlen(pStructs->StructName),ArgumentLength)) == 0) {
  301. PRINTF("%s\n",pStructs->StructName);
  302. }
  303. pStructs++;
  304. }
  305. PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName);
  306. }
  307. return(NameIndex);
  308. }
  309. VOID DisplayStructs()
  310. {
  311. STRUCT_DESCRIPTOR *pStructs = Structs;
  312. PRINTF("The following structs are handled .... \n");
  313. while (pStructs->StructName != 0) {
  314. PRINTF("\t%s\n",pStructs->StructName);
  315. pStructs++;
  316. }
  317. }
  318. PPERSISTENT_RDR2KD_INFO
  319. LocatePersistentInfoFromView()
  320. /*
  321. the purpose of this routine is to allocate or find the named section that holds the
  322. data we expect to find across calls. the way that we make this persitent is that we
  323. do not close the handle used to create the view. it will go away when the process does.
  324. */
  325. {
  326. BYTE SectionName[128];
  327. DWORD SectionSize;
  328. DWORD ProcessId;
  329. HANDLE h;
  330. BOOLEAN CreatedSection = FALSE;
  331. PPERSISTENT_RDR2KD_INFO p;
  332. ProcessId = GetCurrentProcessId();
  333. SectionSize = sizeof(PERSISTENT_RDR2KD_INFO);
  334. sprintf(SectionName,"Rdr2KdSection_%08lx",ProcessId);
  335. //PRINTF("sectionname=%s, size=%x\n",SectionName,SectionSize);
  336. h = OpenFileMappingA(
  337. FILE_MAP_WRITE, //DWORD dwDesiredAccess, // access mode
  338. FALSE, //BOOL bInheritHandle, // inherit flag
  339. SectionName //LPCTSTR lpName // address of name of file-mapping object
  340. );
  341. if (h==NULL) {
  342. h = CreateFileMappingA(
  343. (HANDLE)IntToPtr(0xFFFFFFFF), // HANDLE hFile, // handle of file to map
  344. NULL, //LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
  345. PAGE_READWRITE, //DWORD flProtect, // protection for mapping object
  346. 0, //DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
  347. SectionSize, //DWORD dwMaximumSizeLow, // low-order 32 bits of object size
  348. SectionName //LPCTSTR lpName // name of file-mapping object
  349. );
  350. if (h==NULL) {
  351. return(FALSE);
  352. }
  353. CreatedSection = TRUE;
  354. }
  355. //now we have a filemapping....get a view.....
  356. p = MapViewOfFile(h,FILE_MAP_WRITE,0,0,0);
  357. if (p==NULL) {
  358. CloseHandle(h);
  359. return(NULL);
  360. }
  361. if (CreatedSection) {
  362. //zero the stuff that needs to be zeroed....
  363. ULONG i;
  364. p->IdOfLastDump = 0;
  365. for (i=0;i<100;i++) {
  366. p->LastAddressDumped[i] = 0;
  367. }
  368. p->OpenCount = 100;
  369. } else {
  370. CloseHandle(h);
  371. p->OpenCount++;
  372. }
  373. //PRINTF("Opencount for persistent section = %08lx\n",p->OpenCount);
  374. return(p);
  375. }
  376. VOID
  377. FreePersistentInfoView (
  378. PPERSISTENT_RDR2KD_INFO p
  379. )
  380. {
  381. UnmapViewOfFile(p);
  382. }
  383. VOID
  384. DumpAStruct (
  385. ULONG_PTR dwAddress,
  386. STRUCT_DESCRIPTOR *pStruct
  387. )
  388. {
  389. DWORD Index = (DWORD)(pStruct - Structs);
  390. DWORD SizeToRead = min(pStruct->StructSize,2048);
  391. PPERSISTENT_RDR2KD_INFO p;
  392. p = LocatePersistentInfoFromView();
  393. PRINTF("top @ %lx and %lx for %s(%d,%d)\n",dwAddress,p,pStruct->StructName,Index,p->IdOfLastDump);
  394. if (!p) {
  395. PRINTF("Couldn't allocate perstistent info buffer...sorry...\n");
  396. return;
  397. }
  398. if ((dwAddress==0) &&(Index<100)) {
  399. dwAddress = p->LastAddressDumped[Index];
  400. PRINTF("setting @ %lx and %lx for %s\n",dwAddress,p->LastAddressDumped[Index],pStruct->StructName);
  401. }
  402. if (wGetData(dwAddress,&p->StructDumpBuffer[0],SizeToRead,pStruct->StructName)) {
  403. p->LastAddressDumped[Index] = dwAddress;
  404. p->IdOfLastDump = pStruct->EnumManifest;
  405. p->IndexOfLastDump = Index;
  406. PRINTF("++++++++++++++++ %s(%d/%d)@%lx ---+++++++++++++\n",
  407. pStruct->StructName,
  408. p->IdOfLastDump,p->IndexOfLastDump,
  409. dwAddress);
  410. PrintStructFields(
  411. dwAddress,
  412. &p->StructDumpBuffer[0],
  413. pStruct->FieldDescriptors);
  414. PRINTF("---------------- %s@%lx ----------------\n",
  415. pStruct->StructName,
  416. dwAddress);
  417. }
  418. if (p!= NULL) FreePersistentInfoView(p);
  419. return;
  420. }
  421. DECLARE_API( dump )
  422. {
  423. ULONG_PTR dwAddress;
  424. //SETCALLBACKS();
  425. if( args && *args ) {
  426. // Parse the argument string to determine the structure to be displayed.
  427. // Scan for the NAME_DELIMITER ( '@' ).
  428. LPSTR lpName = (PSTR)args;
  429. LPSTR lpArgs = strpbrk(args, NAME_DELIMITERS);
  430. ULONG Index;
  431. if (lpArgs) {
  432. //
  433. // The specified command is of the form
  434. // dump <name>@<address expr.>
  435. //
  436. // Locate the matching struct for the given name. In the case
  437. // of ambiguity we seek user intervention for disambiguation.
  438. //
  439. // We do an inplace modification of the argument string to
  440. // facilitate matching.
  441. //
  442. *lpArgs = '\0';
  443. for (;*lpName==' ';) { lpName++; } //skip leading blanks
  444. Index = SearchStructs(lpName);
  445. //
  446. // Let us restore the original value back.
  447. //
  448. *lpArgs = NAME_DELIMITER;
  449. if (INVALID_INDEX != Index) {
  450. BYTE DataBuffer[512];
  451. dwAddress = GetExpression( ++lpArgs );
  452. DumpAStruct(dwAddress,&Structs[Index]);
  453. //if (wGetData(dwAddress,DataBuffer,Structs[Index].StructSize,"..structure")) {
  454. //
  455. // PRINTF(
  456. // "++++++++++++++++ %s@%lx ++++++++++++++++\n",
  457. // Structs[Index].StructName,
  458. // dwAddress);
  459. // PrintStructFields(
  460. // dwAddress,
  461. // &DataBuffer,
  462. // Structs[Index].FieldDescriptors);
  463. // PRINTF(
  464. // "---------------- %s@%lx ----------------\n",
  465. // Structs[Index].StructName,
  466. // dwAddress);
  467. //} else {
  468. // PRINTF("Error reading Memory @ %lx\n",dwAddress);
  469. //}
  470. } else {
  471. // No matching struct was found. Display the list of
  472. // structs currently handled.
  473. DisplayStructs();
  474. }
  475. } else {
  476. #if 0
  477. //
  478. // The command is of the form
  479. // dump <name>
  480. //
  481. // Currently we do not handle this. In future we will map it to
  482. // the name of a global variable and display it if required.
  483. //
  484. DisplayStructs();
  485. #endif
  486. //
  487. // here we try to figure out what to display based on the context....whoa, nellie!
  488. //
  489. USHORT Tag;
  490. STRUCT_DESCRIPTOR *pStructs = Structs;
  491. ULONG NameIndex = INVALID_INDEX;
  492. BYTE DataBuffer[512];
  493. //ULONG ArgumentLength = strlen(lpArgument);
  494. //BOOLEAN fAmbigous = FALSE;
  495. dwAddress = GetExpression( args );
  496. if (!wGetData(dwAddress,&Tag,sizeof(Tag),"..structure TAG")) return;
  497. PRINTF("here's the tag: %04lx\n",Tag);
  498. //look thru the table for matching structs
  499. while ((pStructs->StructName != 0)) {
  500. int Result = (Tag&pStructs->MatchMask)==pStructs->MatchValue;
  501. if (Result != 0) {
  502. DumpAStruct(dwAddress,pStructs);
  503. break;
  504. }
  505. pStructs++;
  506. }
  507. }
  508. } else {
  509. DisplayStructs();
  510. }
  511. return;
  512. }
  513. DECLARE_API( ddd )
  514. {
  515. dump( hCurrentProcess,
  516. hCurrentThread,
  517. dwCurrentPc,
  518. dwProcessor,
  519. args
  520. );
  521. }