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.

1830 lines
45 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. dumpoff.cxx
  5. Abstract:
  6. Structure dumper
  7. Author:
  8. Bilal Alam (balam) Oct-17-1998 Initial Revision
  9. --*/
  10. #include "inetdbgp.h"
  11. #include "oemdbi.h"
  12. #include "cvinfo.h"
  13. #include "imagehlp.h"
  14. #define INVALID_LENGTH ((DWORD)-1)
  15. #define MAX_MEMBERNAME_LENGTH 256
  16. #define MAX_TYPENAME_LENGTH 256
  17. #define MAX_ARG_SIZE 256
  18. typedef DWORD (*PFN_READ_MEMORY) (
  19. VOID * address,
  20. DWORD cbBytes,
  21. VOID *pBuffer
  22. );
  23. typedef DWORD (*PFN_PRINTF) (
  24. CHAR * pszBuffer,
  25. DWORD cbBytes
  26. );
  27. typedef struct _STRUCTURE_MEMBER {
  28. CHAR achMemberName[ MAX_MEMBERNAME_LENGTH + 1 ];
  29. DWORD cbOffset;
  30. DWORD cbMaxSize;
  31. } STRUCTURE_MEMBER, *PSTRUCTURE_MEMBER;
  32. typedef struct _STRUCTURE_TEMPLATE {
  33. CHAR achName[ MAX_TYPENAME_LENGTH + 1 ];
  34. PSTRUCTURE_MEMBER pMembers;
  35. DWORD cMembers;
  36. DWORD cUseful;
  37. DWORD cbTotalSize;
  38. DWORD Type;
  39. } STRUCTURE_TEMPLATE, *PSTRUCTURE_TEMPLATE;
  40. DWORD
  41. GetOffset(
  42. BYTE * pBuffer,
  43. DWORD * pcbOffset
  44. );
  45. DWORD
  46. ReadFieldList(
  47. TPI * pTypeInterface,
  48. STRUCTURE_TEMPLATE* pStructure,
  49. lfFieldList * pFieldList,
  50. DWORD cbLen,
  51. DWORD dwFlags
  52. );
  53. DWORD
  54. ReadBClass(
  55. TPI * pTypeInterface,
  56. lfBClass * pBClass,
  57. DWORD * pcbReturnSize,
  58. DWORD * pcbOffset,
  59. CHAR * pszBuffer,
  60. DWORD cbBuffer
  61. );
  62. DWORD
  63. ReadMember(
  64. lfMember* pMember,
  65. DWORD * pcbReturnSize,
  66. DWORD * pcbOffset,
  67. CHAR * pszBuffer,
  68. DWORD cbBuffer
  69. );
  70. DWORD
  71. ReadNestType(
  72. lfNestType* pNestType,
  73. DWORD * pcbReturnSize,
  74. DWORD * pcbOffset,
  75. CHAR * pszBuffer,
  76. DWORD cbBuffer
  77. );
  78. DWORD
  79. ReadOneMethod(
  80. lfOneMethod* pOneMethod,
  81. DWORD * pcbReturnSize,
  82. DWORD * pcbOffset,
  83. CHAR * pszBuffer,
  84. DWORD cbBuffer
  85. );
  86. DWORD
  87. ReadMethod(
  88. lfMethod* pMethod,
  89. DWORD * pcbReturnSize,
  90. DWORD * pcbOffset,
  91. CHAR * pszBuffer,
  92. DWORD cbBuffer
  93. );
  94. DWORD
  95. ReadVTable(
  96. lfVFuncTab* pVTable,
  97. DWORD * pcbReturnSize,
  98. DWORD * pcbOffset,
  99. CHAR * pszBuffer,
  100. DWORD cbBuffer
  101. );
  102. DWORD
  103. ReadStaticMember(
  104. lfSTMember* pStaticMember,
  105. DWORD * pcbReturnSize,
  106. DWORD * pcbOffset,
  107. CHAR * pszBuffer,
  108. DWORD cbBuffer
  109. );
  110. DWORD
  111. InitializeStructureTemplate(
  112. PSTRUCTURE_TEMPLATE pTemplate
  113. );
  114. DWORD
  115. TerminateStructureTemplate(
  116. PSTRUCTURE_TEMPLATE pTemplate
  117. );
  118. VOID
  119. DumpoffUsage(
  120. VOID
  121. );
  122. DWORD
  123. OutputTemplate(
  124. STRUCTURE_TEMPLATE * pTemplate,
  125. CHAR * pszMemberName,
  126. DWORD dwFlags,
  127. PVOID pvAddress,
  128. PFN_READ_MEMORY pfnReadMemory,
  129. PFN_PRINTF pfnPrintf
  130. );
  131. DWORD
  132. BuildMemberList(
  133. IN PSTRUCTURE_TEMPLATE pTemplate,
  134. IN TPI * pTypeInterface,
  135. IN TI tiType,
  136. IN BOOL fTypeSizeOnly
  137. );
  138. DWORD
  139. BuildMemberListForTypeName(
  140. IN PSTRUCTURE_TEMPLATE pTemplate,
  141. IN PDB * pPDB,
  142. IN LPSTR pszTypeName
  143. );
  144. DWORD
  145. FindMembersOfTypeSize(
  146. IN PDB * pPDB,
  147. IN DWORD cbSize,
  148. IN PFN_PRINTF pfnPrintf
  149. );
  150. DWORD
  151. OutputTemplate(
  152. STRUCTURE_TEMPLATE * pTemplate,
  153. CHAR * pszMemberName,
  154. DWORD dwFlags,
  155. PVOID pvAddress,
  156. PFN_READ_MEMORY pfnReadMemory,
  157. PFN_PRINTF pfnPrintf
  158. )
  159. /*++
  160. Routine Description:
  161. Output a structure template.
  162. If pvAddress is NULL, then this function will output a general template
  163. of the structure, listing each member along with its offset from the
  164. start of the structure.
  165. If pvAddress is non-NULL, then this function will output the structure
  166. with the memory at pvAddress cast as this type.
  167. If pszMemberName is NULL, then the above two statements apply to all
  168. members of the structure. If pszMember is not NULL, then the statements
  169. apply only the member whose name is pszMember.
  170. Arguments:
  171. pTemplate - Template to dump
  172. pszMemberName - Optional member name filter
  173. dwFlags - Flags describing Output() details. Currently not supported
  174. pvAddress - Optional address of memory to cast as type
  175. pfnReadMemory - Provides read memory functionality
  176. pfnPrintf - Provides printf functionality
  177. Return Value:
  178. If successful ERROR_SUCCESS, else Win32 Error Code
  179. --*/
  180. {
  181. DWORD cCounter;
  182. BOOL fDidSomething = FALSE;
  183. PBYTE pBuffer = NULL;
  184. DWORD dwError = ERROR_SUCCESS;
  185. CHAR achFormat[ 256 ];
  186. DWORD cbRunningLength;
  187. BOOL fLastBitField = FALSE;
  188. DWORD cBitField = 0;
  189. DWORD dwTotalMask;
  190. DWORD cbSize;
  191. INT i;
  192. pBuffer = (PBYTE) LocalAlloc( LPTR, pTemplate->cbTotalSize );
  193. if ( pBuffer == NULL )
  194. {
  195. dwError = GetLastError();
  196. goto Finished;
  197. }
  198. //
  199. // If address is specified, then read the amount required for this
  200. // structure. Otherwise, we are simply dumping the template and thus
  201. // output the size of the type
  202. //
  203. if ( pvAddress )
  204. {
  205. dwError = pfnReadMemory( pvAddress, pTemplate->cbTotalSize, pBuffer );
  206. if ( dwError != ERROR_SUCCESS )
  207. {
  208. goto Finished;
  209. }
  210. }
  211. else
  212. {
  213. _snprintf( achFormat,
  214. sizeof( achFormat ),
  215. "sizeof( %s %s ) = 0x%X bytes (%d bytes)\n",
  216. pTemplate->Type == LF_CLASS ? "class" : "struct",
  217. pTemplate->achName,
  218. pTemplate->cbTotalSize,
  219. pTemplate->cbTotalSize );
  220. pfnPrintf( achFormat, -1 );
  221. }
  222. //
  223. // Iterate through consequential members of type
  224. //
  225. for( cCounter = 0;
  226. cCounter < pTemplate->cUseful;
  227. cCounter++ )
  228. {
  229. //
  230. // Do filtering on member name if specified
  231. //
  232. if ( pszMemberName )
  233. {
  234. if ( fDidSomething )
  235. {
  236. break;
  237. }
  238. if ( strcmp( pTemplate->pMembers[ cCounter ].achMemberName,
  239. pszMemberName ) )
  240. {
  241. continue;
  242. }
  243. }
  244. //
  245. // Dump member name
  246. //
  247. cbRunningLength = pfnPrintf( pTemplate->pMembers[ cCounter ].achMemberName,
  248. -1 );
  249. //
  250. // Formatting junk
  251. //
  252. for ( i = cbRunningLength;
  253. i < 25;
  254. i++ )
  255. {
  256. cbRunningLength += pfnPrintf( " ", -1 );
  257. }
  258. cbRunningLength += pfnPrintf( " = ", -1 );
  259. achFormat[ 0 ] = '\0';
  260. cbSize = pTemplate->pMembers[ cCounter ].cbMaxSize;
  261. if ( !pvAddress )
  262. {
  263. //
  264. // Just dumping template. Output the offset from the start of
  265. // the type
  266. //
  267. _snprintf( achFormat,
  268. sizeof( achFormat ),
  269. "+%8X",
  270. pTemplate->pMembers[ cCounter ].cbOffset );
  271. }
  272. else if ( !cbSize ||
  273. ( ( cbSize == sizeof( DWORD ) ) && fLastBitField ) )
  274. {
  275. //
  276. // If the maxsize is 0, then this must be a bitfield
  277. // If the maxsize is 4, and the last item was a bit field, then
  278. // this must be the last bit of the bit field.
  279. //
  280. // TODO: Need to make this work for bit fields larger than 32
  281. //
  282. if ( !fLastBitField )
  283. {
  284. fLastBitField = TRUE;
  285. }
  286. cBitField++;
  287. dwTotalMask = (DWORD) *(DWORD*) ((PBYTE)pBuffer+
  288. pTemplate->pMembers[ cCounter ].cbOffset);
  289. _snprintf( achFormat,
  290. sizeof( achFormat ),
  291. "%s",
  292. (dwTotalMask & (1 << ( cBitField - 1 ))) ? "TRUE" : "FALSE" );
  293. if ( cbSize == sizeof( DWORD ) )
  294. {
  295. fLastBitField = FALSE;
  296. cBitField = 0;
  297. }
  298. }
  299. else if ( cbSize != sizeof( DWORD ) )
  300. {
  301. //
  302. // If this structure is not a DWORD in size, then assume we don't
  303. // know how to dump it affectly. In this case, we will simply
  304. // dump out the address at which the member data starts
  305. //
  306. _snprintf( achFormat,
  307. sizeof( achFormat ),
  308. "%016p..",
  309. (PBYTE) pvAddress +
  310. pTemplate->pMembers[ cCounter ].cbOffset );
  311. }
  312. else
  313. {
  314. //
  315. // This is a DWORD sized member. We can dump out the value
  316. // effectively -> so we do it
  317. //
  318. _snprintf( achFormat,
  319. sizeof( achFormat ),
  320. "%08X",
  321. (DWORD) *(DWORD*) ((PBYTE)pBuffer+
  322. pTemplate->pMembers[ cCounter ].cbOffset ) );
  323. }
  324. cbRunningLength += pfnPrintf( achFormat, -1 );
  325. //
  326. // Two column display. Given 80 columns, seems like the only
  327. // reasonable setting (maybe 1 column is useful?)
  328. //
  329. if ( pszMemberName ||
  330. ( cCounter % 2 ) )
  331. {
  332. pfnPrintf( "\n", -1 );
  333. }
  334. else
  335. {
  336. for ( i = cbRunningLength;
  337. i < 40;
  338. i++ )
  339. {
  340. pfnPrintf( " ", -1 );
  341. }
  342. }
  343. //
  344. // Keep tabs on whether we actually dumped something
  345. //
  346. fDidSomething = TRUE;
  347. }
  348. if ( !fDidSomething )
  349. {
  350. dwError = ERROR_FILE_NOT_FOUND;
  351. }
  352. pfnPrintf( "\n", -1 );
  353. Finished:
  354. if ( pBuffer != NULL )
  355. {
  356. LocalFree( pBuffer );
  357. }
  358. return dwError;
  359. }
  360. DWORD
  361. BuildMemberListForTypeName(
  362. IN PSTRUCTURE_TEMPLATE pTemplate,
  363. IN PDB * pPDB,
  364. IN LPSTR pszTypeName
  365. )
  366. /*++
  367. Routine Description:
  368. Build the structure template for a given type
  369. Arguments:
  370. pTemplate - Template to populate (must have been previously inited)
  371. pPDB - PDB structure opened using MSDBI!PDBOpen
  372. pszTypeName - Name of type
  373. Return Value:
  374. If successful ERROR_SUCCESS, else Win32 Error Code
  375. --*/
  376. {
  377. TPI * pTypeInterface = NULL;
  378. TI RootTI;
  379. DWORD dwError = ERROR_SUCCESS;
  380. PB pb;
  381. if ( !pTemplate || !pPDB || !pszTypeName )
  382. {
  383. dwError = ERROR_INVALID_PARAMETER;
  384. goto Finished;
  385. }
  386. //
  387. // Get the type interface
  388. //
  389. if ( !PDBOpenTpi( pPDB,
  390. pdbRead,
  391. &pTypeInterface ) )
  392. {
  393. dwError = GetLastError();
  394. goto Finished;
  395. }
  396. //
  397. // Does this PDB have the necessary type information?
  398. //
  399. if ( TypesQueryTiMinEx( pTypeInterface ) ==
  400. TypesQueryTiMacEx( pTypeInterface ) )
  401. {
  402. dwError = ERROR_NOT_SUPPORTED;
  403. goto Finished;
  404. }
  405. //
  406. // Lookup with specified type
  407. //
  408. if ( !TypesQueryTiForUDTEx( pTypeInterface,
  409. pszTypeName,
  410. TRUE,
  411. &RootTI) )
  412. {
  413. dwError = ERROR_FILE_NOT_FOUND;
  414. goto Finished;
  415. }
  416. strncpy( pTemplate->achName,
  417. pszTypeName,
  418. sizeof( pTemplate->achName ) - 1 );
  419. dwError = BuildMemberList( pTemplate,
  420. pTypeInterface,
  421. RootTI,
  422. FALSE );
  423. Finished:
  424. if ( pTypeInterface != NULL )
  425. {
  426. TypesClose( pTypeInterface );
  427. }
  428. return dwError;
  429. }
  430. DWORD
  431. FindMembersOfTypeSize(
  432. IN PDB * pPDB,
  433. IN DWORD cbSize,
  434. IN PFN_PRINTF pfnPrintf
  435. )
  436. /*++
  437. Routine Description:
  438. Find members of a certain size. Output these types
  439. Arguments:
  440. pPDB - PDB structure opened using MSDBI!PDBOpen
  441. cbSize - Size in question
  442. pfnPrintf - Output routine
  443. Return Value:
  444. If successful ERROR_SUCCESS, else Win32 Error Code
  445. --*/
  446. {
  447. STRUCTURE_TEMPLATE Template;
  448. TPI * pTypeInterface = NULL;
  449. DWORD dwError = ERROR_SUCCESS;
  450. TI tiMin;
  451. TI tiMax;
  452. TI tiCursor;
  453. CHAR achLast[ MAX_TYPENAME_LENGTH ];
  454. CHAR achBuffer[ 256 ];
  455. if ( !pPDB || !pfnPrintf || !cbSize )
  456. {
  457. dwError = ERROR_INVALID_PARAMETER;
  458. goto Finished;
  459. }
  460. //
  461. // Get the type interface
  462. //
  463. if ( !PDBOpenTpi( pPDB,
  464. pdbRead,
  465. &pTypeInterface ) )
  466. {
  467. dwError = GetLastError();
  468. goto Finished;
  469. }
  470. //
  471. // Get min/max type indices
  472. //
  473. tiMin = TypesQueryTiMinEx( pTypeInterface );
  474. tiMax = TypesQueryTiMacEx( pTypeInterface );
  475. if ( tiMin == tiMax )
  476. {
  477. //
  478. // Probably no type info available in PDB
  479. //
  480. dwError = ERROR_NOT_SUPPORTED;
  481. goto Finished;
  482. }
  483. //
  484. // Cursor thru
  485. //
  486. achLast[ 0 ] = '\0';
  487. for ( tiCursor = tiMin;
  488. tiCursor < tiMax;
  489. tiCursor++ )
  490. {
  491. dwError = BuildMemberList( &Template,
  492. pTypeInterface,
  493. tiCursor,
  494. TRUE );
  495. if ( dwError != ERROR_SUCCESS )
  496. {
  497. if ( dwError == ERROR_NOT_SUPPORTED )
  498. {
  499. //
  500. // Not a struct/class. Ignore
  501. //
  502. dwError = ERROR_SUCCESS;
  503. continue;
  504. }
  505. else
  506. {
  507. break;
  508. }
  509. }
  510. if ( Template.cbTotalSize == cbSize &&
  511. strcmp( Template.achName, achLast ) )
  512. {
  513. pfnPrintf( Template.Type == LF_CLASS ? "class " : "struct ", -1 );
  514. pfnPrintf( Template.achName, -1 );
  515. pfnPrintf( "\n", -1 );
  516. strncpy( achLast,
  517. Template.achName,
  518. sizeof( achLast ) );
  519. }
  520. }
  521. Finished:
  522. if ( pTypeInterface != NULL )
  523. {
  524. TypesClose( pTypeInterface );
  525. }
  526. return dwError;
  527. }
  528. DWORD
  529. BuildMemberList(
  530. IN PSTRUCTURE_TEMPLATE pTemplate,
  531. IN TPI * pTypeInterface,
  532. IN TI tiType,
  533. IN BOOL fTypeSizeOnly
  534. )
  535. /*++
  536. Routine Description:
  537. Build a template describing the given type. This template contains
  538. an array of members representing the member of the type.
  539. Arguments:
  540. pTemplate - Template to populate (must have been previously inited)
  541. pTypeInterface - Type interface
  542. tiType - Type ID to retrieve
  543. fStructSizeOnly - TRUE if we only need type size (and not the members)
  544. Return Value:
  545. If successful ERROR_SUCCESS, else Win32 Error Code
  546. --*/
  547. {
  548. TYPTYPE * pType = NULL;
  549. lfStructure * pStructure;
  550. lfFieldList * pFieldList;
  551. PB pb;
  552. DWORD dwError = ERROR_SUCCESS;
  553. DWORD cbTotalSize = 0;
  554. DWORD cbStructSize = 0;
  555. DWORD cUseful;
  556. DWORD cbNameOffset;
  557. TI RootTI;
  558. if ( !pTypeInterface || !pTemplate )
  559. {
  560. dwError = ERROR_INVALID_PARAMETER;
  561. goto Finished;
  562. }
  563. RootTI = tiType;
  564. //
  565. // Parse root record of the type, verifying that it is of type
  566. // STRUCTURE or CLASS
  567. //
  568. if ( !TypesQueryPbCVRecordForTiEx( pTypeInterface,
  569. RootTI,
  570. &pb ) )
  571. {
  572. dwError = ERROR_FILE_NOT_FOUND;
  573. goto Finished;
  574. }
  575. pType = (TYPTYPE*) pb;
  576. if ( ( pType->leaf != LF_CLASS ) &&
  577. ( pType->leaf != LF_STRUCTURE ) )
  578. {
  579. dwError = ERROR_NOT_SUPPORTED;
  580. goto Finished;
  581. }
  582. pTemplate->Type = pType->leaf;
  583. pStructure = (lfStructure*) &(pType->leaf);
  584. cbNameOffset = GetOffset( pStructure->data, &cbStructSize );
  585. //
  586. // If we only need the overall structure size, then we can exit out now
  587. //
  588. if ( fTypeSizeOnly )
  589. {
  590. pTemplate->cbTotalSize = cbStructSize;
  591. memset( pTemplate->achName,
  592. 0,
  593. sizeof( pTemplate->achName ) );
  594. strncpy( pTemplate->achName,
  595. (LPSTR) pStructure->data + cbNameOffset + 1,
  596. min( (DWORD) *(CHAR*)(pStructure->data + cbNameOffset),
  597. sizeof( pTemplate->achName ) ) );
  598. goto Finished;
  599. }
  600. //
  601. // In allocating # of members for the structure, get upper bound by
  602. // taking structure member count.
  603. //
  604. // OPTIMIZATION: Dynamically grow the list to avoid gross overestimation.
  605. //
  606. if ( pTemplate->cMembers < pStructure->count )
  607. {
  608. pTemplate->pMembers = (PSTRUCTURE_MEMBER) LocalAlloc( LPTR,
  609. sizeof( STRUCTURE_MEMBER ) *
  610. pStructure->count );
  611. if ( pTemplate->pMembers == NULL )
  612. {
  613. dwError = ERROR_NOT_ENOUGH_MEMORY;
  614. goto Finished;
  615. }
  616. pTemplate->cMembers = pStructure->count;
  617. }
  618. if ( !TypesQueryPbCVRecordForTi( pTypeInterface,
  619. pStructure->field,
  620. &pb ) )
  621. {
  622. dwError = ERROR_FILE_NOT_FOUND;
  623. goto Finished;
  624. }
  625. pType = (TYPTYPE*)pb;
  626. pFieldList = (lfFieldList*) &(pType->leaf);
  627. //
  628. // Read the list of the fields in the type
  629. //
  630. dwError = ReadFieldList( pTypeInterface,
  631. pTemplate,
  632. pFieldList,
  633. pType->len,
  634. 0 );
  635. cUseful = pTemplate->cUseful;
  636. if ( cUseful && ( dwError == ERROR_SUCCESS ) )
  637. {
  638. pTemplate->pMembers[ cUseful - 1 ].cbMaxSize =
  639. cbStructSize - pTemplate->pMembers[ cUseful - 1 ].cbOffset;
  640. pTemplate->cbTotalSize = cbStructSize;
  641. }
  642. Finished:
  643. return dwError;
  644. }
  645. DWORD
  646. ReadFieldList(
  647. IN TPI * pTypeInterface,
  648. IN STRUCTURE_TEMPLATE * pTemplate,
  649. IN lfFieldList * pFieldList,
  650. IN DWORD cbLen,
  651. IN DWORD dwFlags
  652. )
  653. /*++
  654. Routine Description:
  655. Read the elements of the field list which represents the class/struct
  656. Arguments:
  657. Return Value:
  658. If successful ERROR_SUCCESS, else Win32 Error Code
  659. --*/
  660. {
  661. DWORD cbBytes = 0;
  662. PBYTE pBuffer;
  663. DWORD cbReturnSize = 0;
  664. BOOL fExit = FALSE;
  665. CHAR achMemberBuffer[ 256 ];
  666. DWORD cbMemberBuffer;
  667. DWORD dwError = ERROR_SUCCESS;
  668. DWORD cFields = 0;
  669. DWORD cbLastOffset = 0;
  670. while ( cbBytes < cbLen )
  671. {
  672. //
  673. // Account for padding the field list blob
  674. //
  675. for ( ; ; )
  676. {
  677. pBuffer = (PBYTE) pFieldList->data + cbBytes;
  678. if ( *(BYTE*)pBuffer < LF_PAD0 )
  679. {
  680. break;
  681. }
  682. cbBytes++;
  683. }
  684. //
  685. // After each padding block (if any), the first SHORT will contain
  686. // the field type of the next field in the struct/class. Handle
  687. // each type accordingly. If the handle function (Read*) returns
  688. // a cbReturnSize of -1 then this type will not contribute to the
  689. // offsets in the struct/class. For example, member functions.
  690. //
  691. achMemberBuffer[ 0 ] = '\0';
  692. cbReturnSize = 0;
  693. cbMemberBuffer = sizeof( achMemberBuffer );
  694. switch ( *(USHORT*) pBuffer )
  695. {
  696. case LF_BCLASS:
  697. dwError = ReadBClass( pTypeInterface,
  698. (lfBClass*) pBuffer,
  699. &cbReturnSize,
  700. &cbBytes,
  701. achMemberBuffer,
  702. cbMemberBuffer );
  703. break;
  704. case LF_MEMBER:
  705. dwError = ReadMember( (lfMember*) pBuffer,
  706. &cbReturnSize,
  707. &cbBytes,
  708. achMemberBuffer,
  709. cbMemberBuffer );
  710. break;
  711. case LF_NESTTYPE:
  712. dwError = ReadNestType( (lfNestType*) pBuffer,
  713. &cbReturnSize,
  714. &cbBytes,
  715. achMemberBuffer,
  716. cbMemberBuffer );
  717. break;
  718. case LF_ONEMETHOD:
  719. dwError = ReadOneMethod( (lfOneMethod*) pBuffer,
  720. &cbReturnSize,
  721. &cbBytes,
  722. achMemberBuffer,
  723. cbMemberBuffer );
  724. break;
  725. case LF_METHOD:
  726. dwError = ReadMethod( (lfMethod*) pBuffer,
  727. &cbReturnSize,
  728. &cbBytes,
  729. achMemberBuffer,
  730. cbMemberBuffer );
  731. break;
  732. case LF_STMEMBER:
  733. dwError = ReadStaticMember( (lfSTMember*) pBuffer,
  734. &cbReturnSize,
  735. &cbBytes,
  736. achMemberBuffer,
  737. cbMemberBuffer );
  738. break;
  739. case LF_VFUNCTAB:
  740. dwError = ReadVTable( (lfVFuncTab*) pBuffer,
  741. &cbReturnSize,
  742. &cbBytes,
  743. achMemberBuffer,
  744. cbMemberBuffer );
  745. break;
  746. default:
  747. fExit = TRUE;
  748. break;
  749. }
  750. if ( fExit )
  751. {
  752. break;
  753. }
  754. if ( dwError != ERROR_SUCCESS ||
  755. cbReturnSize == INVALID_LENGTH )
  756. {
  757. continue;
  758. }
  759. //
  760. // We got a useful member of the struct/class. Add it to the
  761. // template.
  762. //
  763. pTemplate->cUseful++;
  764. strncpy( pTemplate->pMembers[ cFields ].achMemberName,
  765. achMemberBuffer,
  766. sizeof( pTemplate->pMembers[ cFields ].achMemberName ) - 1 );
  767. pTemplate->pMembers[ cFields ].cbOffset = cbReturnSize;
  768. //
  769. // Calculate the maximum size of the previous member by taking the
  770. // difference between the start offset of the member and the start
  771. // offset of the previous member. Note that this is not necessarily
  772. // the exact size because of potential alignment padding. It is only
  773. // an upper bound on the size of the previous member.
  774. //
  775. if ( cFields )
  776. {
  777. pTemplate->pMembers[ cFields - 1 ].cbMaxSize =
  778. cbReturnSize - cbLastOffset;
  779. }
  780. cbLastOffset = cbReturnSize;
  781. cFields++;
  782. }
  783. return dwError;
  784. }
  785. DWORD
  786. ReadBClass(
  787. IN TPI * pTypeInterface,
  788. IN lfBClass* pBClass,
  789. OUT DWORD * pcbReturnSize,
  790. OUT DWORD * pcbOffset,
  791. OUT CHAR * pszBuffer,
  792. IN DWORD cbBuffer
  793. )
  794. /*++
  795. Routine Description:
  796. Read the type info of base class field
  797. Arguments:
  798. pTypeInterface - MSDBI type interface
  799. pBClass - Points to a base class descriptor
  800. pcbReturnSize - Filled with offset from start of original type
  801. pcbOffset - Filled with new offset to result field traversal in
  802. field list handler
  803. pszBuffer - Filled with name of base class
  804. cbBuffer - Size of pszBuffer
  805. Return Value:
  806. If successful ERROR_SUCCESS, else Win32 Error Code
  807. --*/
  808. {
  809. PB pb;
  810. DWORD Offset;
  811. TYPTYPE* pType;
  812. lfStructure * pStructure;
  813. DWORD cbUnused;
  814. Offset = GetOffset( pBClass->offset, pcbReturnSize );
  815. *pcbOffset += sizeof( lfBClass ) + Offset;
  816. //
  817. // We have to lookup the name of the base class explicitly by using the
  818. // index type in the base class descriptor
  819. //
  820. if ( !TypesQueryPbCVRecordForTiEx( pTypeInterface,
  821. pBClass->index,
  822. &pb ) )
  823. {
  824. return ERROR_FILE_NOT_FOUND;
  825. }
  826. //
  827. // Process/munge/extract
  828. //
  829. pType = (TYPTYPE*)pb;
  830. pStructure = (lfStructure*) &(pType->leaf );
  831. Offset = GetOffset( pStructure->data, &cbUnused );
  832. memset( pszBuffer, 0, cbBuffer );
  833. memcpy( pszBuffer,
  834. (CHAR*) pStructure->data + Offset + 1,
  835. min( (DWORD) *(CHAR*) ( pStructure->data + Offset ), cbBuffer ) );
  836. return ERROR_SUCCESS;
  837. }
  838. DWORD
  839. ReadMember(
  840. IN lfMember * pMember,
  841. OUT DWORD * pcbReturnSize,
  842. OUT DWORD * pcbOffset,
  843. IN CHAR * pszBuffer,
  844. IN DWORD cbBuffer
  845. )
  846. /*++
  847. Routine Description:
  848. Read the type info of a member
  849. Arguments:
  850. pMember - Points to a member descriptor
  851. pcbReturnSize - Filled with offset from start of original type
  852. pcbOffset - Filled with new offset to result field traversal in
  853. field list handler
  854. pszBuffer - Filled with name of base class
  855. cbBuffer - Size of pszBuffer
  856. Return Value:
  857. If successful ERROR_SUCCESS, else Win32 Error Code
  858. --*/
  859. {
  860. DWORD Offset = GetOffset( pMember->offset, pcbReturnSize );
  861. memset( pszBuffer, 0, cbBuffer );
  862. memcpy( pszBuffer,
  863. (CHAR*) pMember->offset + Offset + 1,
  864. min( (DWORD) *(CHAR*) ( pMember->offset + Offset ), cbBuffer ) );
  865. *pcbOffset += sizeof( lfMember ) + Offset + pMember->offset[Offset] + 1;
  866. return ERROR_SUCCESS;
  867. }
  868. DWORD
  869. ReadOneMethod(
  870. IN lfOneMethod * pOneMethod,
  871. OUT DWORD * pcbReturnSize,
  872. OUT DWORD * pcbOffset,
  873. IN CHAR * pszBuffer,
  874. IN DWORD cbBuffer
  875. )
  876. /*++
  877. Routine Description:
  878. Read the type info of a non-overloaded member function.
  879. We process this only to up the offset within the field list for
  880. traversal purposes. Member methods themselves have no affect on
  881. the offsets/size of the data structure
  882. Arguments:
  883. pOneMethod - Method type descriptor
  884. pcbReturnSize - Filled with offset from start of original type
  885. pcbOffset - Filled with new offset to result field traversal in
  886. field list handler
  887. pszBuffer - Filled with name of base class
  888. cbBuffer - Size of pszBuffer
  889. Return Value:
  890. If successful ERROR_SUCCESS, else Win32 Error Code
  891. --*/
  892. {
  893. CHAR * pszSource = NULL;
  894. pszSource = (CHAR*) pOneMethod + sizeof( lfOneMethod );
  895. *pcbOffset += sizeof( lfOneMethod );
  896. if ( ( pOneMethod->attr.mprop == CV_MTintro ) ||
  897. ( pOneMethod->attr.mprop == CV_MTpureintro ) )
  898. {
  899. *pcbOffset += sizeof( LONG );
  900. pszSource += sizeof( LONG );
  901. }
  902. *pcbOffset += *(CHAR*)pszSource + 1;
  903. *pcbReturnSize = INVALID_LENGTH;
  904. return ERROR_SUCCESS;
  905. }
  906. DWORD
  907. ReadMethod(
  908. IN lfMethod * pMethod,
  909. OUT DWORD * pcbReturnSize,
  910. OUT DWORD * pcbOffset,
  911. IN CHAR * pszBuffer,
  912. IN DWORD cbBuffer
  913. )
  914. /*++
  915. Routine Description:
  916. Read the type info of a member function. We process this only to
  917. up the offset within the field list for traversal purposes. Member
  918. methods themselves have no affect on the offsets/size of the data
  919. structure
  920. Arguments:
  921. pMethod - Method type descriptor
  922. pcbReturnSize - Filled with offset from start of original type
  923. pcbOffset - Filled with new offset to result field traversal in
  924. field list handler
  925. pszBuffer - Filled with name of base class
  926. cbBuffer - Size of pszBuffer
  927. Return Value:
  928. If successful ERROR_SUCCESS, else Win32 Error Code
  929. --*/
  930. {
  931. *pcbOffset += sizeof( lfMethod ) + pMethod->Name[ 0 ];
  932. *pcbReturnSize = INVALID_LENGTH;
  933. return ERROR_SUCCESS;
  934. }
  935. DWORD
  936. ReadVTable(
  937. IN lfVFuncTab * pVTable,
  938. OUT DWORD * pcbReturnSize,
  939. OUT DWORD * pcbOffset,
  940. IN CHAR * pszBuffer,
  941. IN DWORD cbBuffer
  942. )
  943. /*++
  944. Routine Description:
  945. Read the vtable of the structure.
  946. Arguments:
  947. pVTable - Vtable type descriptor
  948. pcbReturnSize - Filled with offset from start of original type
  949. pcbOffset - Filled with new offset to result field traversal in
  950. field list handler
  951. pszBuffer - Filled with name of base class
  952. cbBuffer - Size of pszBuffer
  953. Return Value:
  954. If successful ERROR_SUCCESS, else Win32 Error Code
  955. --*/
  956. {
  957. *pcbOffset += sizeof( lfVFuncTab );
  958. strncpy( pszBuffer,
  959. "'vftable'",
  960. cbBuffer - 1 );
  961. //
  962. // Assume at the beginning of the data structure.
  963. //
  964. *pcbReturnSize = 0;
  965. return ERROR_SUCCESS;
  966. }
  967. DWORD
  968. ReadStaticMember(
  969. IN lfSTMember * pStaticMember,
  970. OUT DWORD * pcbReturnSize,
  971. OUT DWORD * pcbOffset,
  972. IN CHAR * pszBuffer,
  973. IN DWORD cbBuffer
  974. )
  975. {
  976. *pcbOffset += sizeof( lfSTMember ) + pStaticMember->Name[ 0 ];
  977. *pcbReturnSize = INVALID_LENGTH;
  978. return ERROR_SUCCESS;
  979. }
  980. DWORD
  981. ReadNestType(
  982. IN lfNestType * pNestType,
  983. OUT DWORD * pcbReturnSize,
  984. OUT DWORD * pcbOffset,
  985. IN CHAR * pszBuffer,
  986. IN DWORD cbBuffer
  987. )
  988. {
  989. *pcbOffset += sizeof( lfNestType ) + pNestType->Name[ 0 ];
  990. *pcbReturnSize = INVALID_LENGTH;
  991. return ERROR_SUCCESS;
  992. }
  993. DWORD
  994. GetOffset(
  995. BYTE * pBuffer,
  996. DWORD * pcbOffset
  997. )
  998. /*++
  999. Routine Description:
  1000. Read the offset for the type record. Then advance the cursor.
  1001. Arguments:
  1002. pBuffer - Points to current position in field list buffer
  1003. pcbOffset - Filled with offset of field member
  1004. Return Value:
  1005. Amount to advance cursor to next field member
  1006. --*/
  1007. {
  1008. USHORT leaf = *(USHORT*)pBuffer;
  1009. if ( leaf < LF_NUMERIC )
  1010. {
  1011. *pcbOffset = leaf;
  1012. return sizeof( leaf );
  1013. }
  1014. else
  1015. {
  1016. switch( leaf )
  1017. {
  1018. case LF_CHAR:
  1019. *pcbOffset = *((char*)pBuffer);
  1020. return sizeof(leaf) + sizeof(char);
  1021. case LF_SHORT:
  1022. *pcbOffset = *(short*)pBuffer;
  1023. return sizeof(leaf) + sizeof(short);
  1024. case LF_USHORT:
  1025. *pcbOffset = *(USHORT*)pBuffer;
  1026. return sizeof(leaf) + sizeof(USHORT);
  1027. case LF_LONG:
  1028. *pcbOffset = *(long*)pBuffer;
  1029. return sizeof(leaf) + sizeof(long);
  1030. case LF_ULONG:
  1031. *pcbOffset = *(ULONG*)pBuffer;
  1032. return sizeof(leaf) + sizeof(ULONG);
  1033. }
  1034. }
  1035. return 0;
  1036. }
  1037. DWORD
  1038. InitializeStructureTemplate(
  1039. IN PSTRUCTURE_TEMPLATE pTemplate
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Initialize structure template
  1044. Arguments:
  1045. pTemplate - Template buffer to be initialized
  1046. Return Value:
  1047. If successful ERROR_SUCCESS, else Win32 Error Code
  1048. --*/
  1049. {
  1050. if ( pTemplate == NULL )
  1051. {
  1052. return ERROR_INVALID_PARAMETER;
  1053. }
  1054. pTemplate->pMembers = NULL;
  1055. pTemplate->cMembers = 0;
  1056. pTemplate->achName[ 0 ] = '\0';
  1057. pTemplate->cUseful = 0;
  1058. pTemplate->cbTotalSize = 0;
  1059. pTemplate->Type = 0xFFFFFFFF;
  1060. return ERROR_SUCCESS;
  1061. }
  1062. DWORD
  1063. TerminateStructureTemplate(
  1064. IN PSTRUCTURE_TEMPLATE pTemplate
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Terminate structure template
  1069. Arguments:
  1070. pTemplate - Template buffer to be terminated
  1071. Return Value:
  1072. If successful ERROR_SUCCESS, else Win32 Error Code
  1073. --*/
  1074. {
  1075. if ( pTemplate == NULL )
  1076. {
  1077. return ERROR_INVALID_PARAMETER;
  1078. }
  1079. if ( pTemplate->pMembers )
  1080. {
  1081. LocalFree( pTemplate->pMembers );
  1082. pTemplate->pMembers = NULL;
  1083. pTemplate->cMembers = 0;
  1084. }
  1085. return ERROR_SUCCESS;
  1086. }
  1087. DWORD
  1088. OutputStructure(
  1089. IN PDB * pDebug,
  1090. IN CHAR * pszStructureType,
  1091. IN CHAR * pszMemberName,
  1092. IN DWORD dwFlags,
  1093. IN VOID * pvAddress,
  1094. IN PFN_READ_MEMORY pfnReadMemory,
  1095. IN PFN_PRINTF pfnPrintf
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Top level call to output a structure
  1100. Arguments:
  1101. pDebug - PDB handle
  1102. pszStructureType - Name of structure/class to dump
  1103. pszMemberName - (optional) Name of particular member of structure to dump
  1104. dwFlags - (not supported)
  1105. pvAddress - (optional) Address of start of structure
  1106. pfnReadMemory - (optional) Function to read memory. Not needed if
  1107. pvAddress==NULL
  1108. pfnPrintf - Output function
  1109. Return Value:
  1110. If successful ERROR_SUCCESS, else Win32 Error Code
  1111. --*/
  1112. {
  1113. STRUCTURE_TEMPLATE Template;
  1114. DWORD dwError;
  1115. if ( !pDebug ||
  1116. !pszStructureType ||
  1117. !pfnReadMemory ||
  1118. !pfnPrintf )
  1119. {
  1120. return ERROR_INVALID_PARAMETER;
  1121. }
  1122. dwError = InitializeStructureTemplate( &Template );
  1123. if ( dwError != ERROR_SUCCESS )
  1124. {
  1125. return dwError;
  1126. }
  1127. dwError = BuildMemberListForTypeName( &Template,
  1128. pDebug,
  1129. pszStructureType );
  1130. if ( dwError != ERROR_SUCCESS )
  1131. {
  1132. return dwError;
  1133. }
  1134. dwError = OutputTemplate( &Template,
  1135. pszMemberName,
  1136. dwFlags,
  1137. pvAddress,
  1138. pfnReadMemory,
  1139. pfnPrintf );
  1140. //
  1141. // CODEWORK: Cache the templates
  1142. //
  1143. TerminateStructureTemplate( &Template );
  1144. return dwError;
  1145. }
  1146. DWORD
  1147. DoPrintf(
  1148. CHAR * pszBuffer,
  1149. DWORD cbBytes
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Print out buffer
  1154. Arguments:
  1155. pszBuffer - buffer to print
  1156. cbBytes - Bytes to print
  1157. Return Value:
  1158. Number of bytes printed
  1159. --*/
  1160. {
  1161. dprintf( "%s", pszBuffer );
  1162. return strlen( pszBuffer );
  1163. }
  1164. DWORD
  1165. DoReadMemory(
  1166. VOID * pvAddress,
  1167. DWORD cbBytes,
  1168. VOID * pBuffer
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Read debuggee memory into buffer
  1173. Arguments:
  1174. pvAddress - Address to read
  1175. cbBytes - # of bytes to read
  1176. pBuffer - Buffer to be filled
  1177. Return Value:
  1178. If successful ERROR_SUCCESS, else Win32 Error Code
  1179. --*/
  1180. {
  1181. if ( ReadMemory( pvAddress, pBuffer, cbBytes, NULL ) )
  1182. {
  1183. return ERROR_SUCCESS;
  1184. }
  1185. else
  1186. {
  1187. return GetLastError();
  1188. }
  1189. }
  1190. VOID
  1191. DumpoffUsage(
  1192. VOID
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. !dumpoff usage message
  1197. Arguments:
  1198. None
  1199. Return Value:
  1200. None
  1201. --*/
  1202. {
  1203. dprintf(
  1204. "Usage: !dumpoff <pdb_file>!<type_name>[.<member_name>] [expression]\n"
  1205. " !dumpoff -s [<pdb_search_path>]\n"
  1206. "\n"
  1207. "pdb_file Un-qualified name of PDB file (eg. KERNEL32, NTDLL)\n"
  1208. "type_name Name of type (struct/class) to dump, OR \n"
  1209. " ==<cbHexSize> to dump struct/classes of size cbHexSize\n"
  1210. "member_name (optional) Name of member in type_name to dump\n"
  1211. "expression (optional) Address of memory to dump as type_name\n"
  1212. " if not present, offset(s) are dumped\n"
  1213. "pdb_search_path Set the search path for PDBs\n"
  1214. "\n"
  1215. "Examples: !dumpoff ntdll!_RTL_CRITICAL_SECTION 14d4d0\n"
  1216. " !dumpoff w3svc!HTTP_REQUEST._dwSignature w3svc!g_GlobalObj\n"
  1217. " !dumpoff ntdll!_RTL_CRITICAL_SECTION\n"
  1218. " !dumpoff w3svc!==840\n"
  1219. " !dumpoff -s \\\\mydrive\\pdbs;c:\\local\\pdbs\n"
  1220. );
  1221. }
  1222. #if defined( _X86_ )
  1223. CHAR g_achPDBSearchPath[ 1024 ] = "\\\\x86fre\\symbols.pri\\retail\\dll";
  1224. #else
  1225. CHAR g_achPDBSearchPath[ 1024 ] = "\\\\alphafre\\symbols.pri\\retail\\dll";
  1226. #endif
  1227. DECLARE_API( dumpoff )
  1228. /*++
  1229. Routine Description:
  1230. This function is called as an NTSD extension to dump a structure
  1231. based on debug info in PDB
  1232. Arguments:
  1233. hCurrentProcess - Supplies a handle to the current process (at the
  1234. time the extension was called).
  1235. hCurrentThread - Supplies a handle to the current thread (at the
  1236. time the extension was called).
  1237. CurrentPc - Supplies the current pc at the time the extension is
  1238. called.
  1239. lpExtensionApis - Supplies the address of the functions callable
  1240. by this extension.
  1241. lpArgumentString - Supplies the asciiz string that describes the
  1242. ansi string to be dumped.
  1243. Return Value:
  1244. None.
  1245. --*/
  1246. {
  1247. CHAR * pszPdb = NULL;
  1248. CHAR * pszType = NULL;
  1249. CHAR * pszAddress = NULL;
  1250. CHAR * pszMember = NULL;
  1251. CHAR * pszCursor = NULL;
  1252. CHAR * pszNext = NULL;
  1253. CHAR achArg1[ MAX_ARG_SIZE ];
  1254. CHAR achArg2[ MAX_ARG_SIZE ];
  1255. CHAR achBuffer[ MAX_ARG_SIZE ] = "";
  1256. CHAR achFileName[ MAX_PATH + 1 ];
  1257. CHAR achFullPath[ MAX_PATH + 1 ];
  1258. CHAR achSymPath[ MAX_PATH + 1 ];
  1259. BOOL fRet;
  1260. EC ec;
  1261. PDB * pDebug = NULL;
  1262. DWORD dwError;
  1263. CHAR * pszError = NULL;
  1264. DWORD cArguments;
  1265. DWORD cbSize;
  1266. BOOL fRetry = TRUE;
  1267. INIT_API();
  1268. //
  1269. // get the debugger symbol path
  1270. //
  1271. fRet = SymGetSearchPath( hCurrentProcess,
  1272. achSymPath,
  1273. sizeof( achSymPath ) );
  1274. if (!fRet )
  1275. {
  1276. //
  1277. // If we couldn't get the default sym path, just use the SYSTEMROOT
  1278. //
  1279. dwError = GetEnvironmentVariable( "SYSTEMROOT",
  1280. achSymPath,
  1281. sizeof( achSymPath ) );
  1282. if ( dwError == 0 )
  1283. {
  1284. _snprintf( achBuffer,
  1285. sizeof( achBuffer ),
  1286. "Unable to determine symbol path. Error = %d\n",
  1287. GetLastError() );
  1288. goto Finished;
  1289. }
  1290. }
  1291. //
  1292. // parse out the argument style
  1293. // <pdbfile>!<type>[.member] [address]
  1294. //
  1295. cArguments = sscanf( (CHAR*) lpArgumentString,
  1296. "%256s%256s",
  1297. achArg1,
  1298. achArg2 );
  1299. if ( cArguments == EOF || cArguments == 0 )
  1300. {
  1301. DumpoffUsage();
  1302. goto Finished;
  1303. }
  1304. //
  1305. // Handle the !dumpoff -s [sympath] case
  1306. //
  1307. if ( ( achArg1[ 0 ] == '-' || achArg1[ 0 ] == '/' ) &&
  1308. ( achArg1[ 1 ] == 's' || achArg1[ 1 ] == 'S' ) )
  1309. {
  1310. if ( cArguments == 2 )
  1311. {
  1312. strncpy( g_achPDBSearchPath,
  1313. achArg2,
  1314. sizeof( g_achPDBSearchPath ) );
  1315. }
  1316. dprintf( "PDB search path set to\n%s%s%s\n",
  1317. g_achPDBSearchPath,
  1318. *g_achPDBSearchPath ? "\n" : "",
  1319. achSymPath );
  1320. goto Finished;
  1321. }
  1322. //
  1323. // Parse the regular !dumpoff command
  1324. //
  1325. pszPdb = achArg1;
  1326. pszCursor = strchr( achArg1, '!' );
  1327. if ( pszCursor == NULL )
  1328. {
  1329. DumpoffUsage();
  1330. goto Finished;
  1331. }
  1332. *pszCursor = '\0';
  1333. pszType = pszCursor + 1;
  1334. pszCursor = strchr( pszType, '.' );
  1335. if ( pszCursor != NULL )
  1336. {
  1337. *pszCursor = '\0';
  1338. pszMember = pszCursor + 1;
  1339. }
  1340. if ( cArguments > 1 )
  1341. {
  1342. pszAddress = achArg2;
  1343. }
  1344. //
  1345. // done parsing, now get the PDB
  1346. //
  1347. strncpy( achFileName,
  1348. pszPdb,
  1349. MAX_ARG_SIZE );
  1350. strcat( achFileName,
  1351. ".pdb");
  1352. //
  1353. // Look for the PDB file. First in the PDB search path, then sympath
  1354. //
  1355. pszCursor = g_achPDBSearchPath;
  1356. Retry:
  1357. while ( pszCursor )
  1358. {
  1359. pszNext = strchr( pszCursor, ';' );
  1360. if ( pszNext != NULL )
  1361. {
  1362. *pszNext = '\0';
  1363. }
  1364. fRet = SearchTreeForFile( pszCursor,
  1365. achFileName,
  1366. achFullPath );
  1367. if ( fRet )
  1368. {
  1369. break;
  1370. }
  1371. if ( pszNext )
  1372. {
  1373. pszCursor = pszNext + 1;
  1374. }
  1375. else
  1376. {
  1377. pszCursor = NULL;
  1378. }
  1379. }
  1380. if ( !pszCursor && fRetry )
  1381. {
  1382. fRetry = FALSE;
  1383. // now try the debugger sympath
  1384. pszCursor = achSymPath;
  1385. goto Retry;
  1386. }
  1387. if ( !pszCursor )
  1388. {
  1389. _snprintf( achBuffer,
  1390. sizeof( achBuffer ),
  1391. "Couldn't find PDB file %s\n",
  1392. achFileName );
  1393. goto Finished;
  1394. }
  1395. //
  1396. // Open the PDB file
  1397. //
  1398. if ( !PDBOpen( achFullPath,
  1399. pdbRead,
  1400. 0,
  1401. &ec,
  1402. achBuffer,
  1403. &pDebug ) )
  1404. {
  1405. _snprintf( achBuffer,
  1406. sizeof( achBuffer ),
  1407. "Error opening PDB file. Error = %d\n",
  1408. ec );
  1409. goto Finished;
  1410. }
  1411. if ( pszType[ 0 ] == '=' && pszType[ 1 ] == '=' )
  1412. {
  1413. //
  1414. // Find all types of size after ==
  1415. //
  1416. cbSize = strtoul( pszType + 2,
  1417. NULL,
  1418. 16 );
  1419. dwError = FindMembersOfTypeSize( pDebug,
  1420. cbSize,
  1421. DoPrintf );
  1422. }
  1423. else
  1424. {
  1425. dwError = OutputStructure( pDebug,
  1426. pszType,
  1427. pszMember,
  1428. 0,
  1429. pszAddress ? (VOID*) GetExpression( pszAddress ) : NULL,
  1430. DoReadMemory,
  1431. DoPrintf );
  1432. }
  1433. if ( dwError != ERROR_SUCCESS )
  1434. {
  1435. switch ( dwError )
  1436. {
  1437. case ERROR_FILE_NOT_FOUND:
  1438. _snprintf( achBuffer,
  1439. sizeof( achBuffer ),
  1440. "Could not find type '%s' in PDB file '%s'\n",
  1441. pszType,
  1442. achFullPath );
  1443. break;
  1444. case ERROR_NOT_SUPPORTED:
  1445. _snprintf( achBuffer,
  1446. sizeof( achBuffer ),
  1447. "PDB file '%s' does not contain necessary type info\n",
  1448. achFullPath );
  1449. break;
  1450. default:
  1451. _snprintf( achBuffer,
  1452. sizeof( achBuffer ),
  1453. "Error dumping structure. Error = %d\n",
  1454. dwError );
  1455. }
  1456. goto Finished;
  1457. }
  1458. Finished:
  1459. if ( achBuffer[ 0 ] )
  1460. {
  1461. dprintf( "%s", achBuffer );
  1462. }
  1463. if ( pDebug )
  1464. {
  1465. PDBClose( pDebug );
  1466. }
  1467. } // DECLARE_API( dumpoff )