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.

743 lines
18 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. uwdump.c
  5. Abstract:
  6. This module implements a program which dumps the function table and
  7. unwind data for a specified executable file. It is an AMD64 specific
  8. program.
  9. Author:
  10. David N. Cutler (davec) 6-Feb-2001
  11. Environment:
  12. User mode.
  13. Revision History:
  14. None.
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. //
  23. // Define AMD64 exception handling structures and function prototypes.
  24. //
  25. // Define unwind operation codes.
  26. //
  27. typedef enum _UNWIND_OP_CODES {
  28. UWOP_PUSH_NONVOL = 0,
  29. UWOP_ALLOC_LARGE,
  30. UWOP_ALLOC_SMALL,
  31. UWOP_SET_FPREG,
  32. UWOP_SAVE_NONVOL,
  33. UWOP_SAVE_NONVOL_FAR,
  34. UWOP_SAVE_XMM,
  35. UWOP_SAVE_XMM_FAR,
  36. UWOP_SAVE_XMM128,
  37. UWOP_SAVE_XMM128_FAR,
  38. UWOP_PUSH_MACHFRAME
  39. } UNWIND_OP_CODES, *PUNWIND_OP_CODES;
  40. //
  41. // Define unwind code structure.
  42. //
  43. typedef union _UNWIND_CODE {
  44. struct {
  45. UCHAR CodeOffset;
  46. UCHAR UnwindOp : 4;
  47. UCHAR OpInfo : 4;
  48. };
  49. USHORT FrameOffset;
  50. } UNWIND_CODE, *PUNWIND_CODE;
  51. //
  52. // Define unwind information flags.
  53. //
  54. #define UNW_FLAG_NHANDLER 0x0
  55. #define UNW_FLAG_EHANDLER 0x1
  56. #define UNW_FLAG_UHANDLER 0x2
  57. #define UNW_FLAG_CHAININFO 0x4
  58. //
  59. // Define unwind information structure.
  60. //
  61. typedef struct _UNWIND_INFO {
  62. UCHAR Version : 3;
  63. UCHAR Flags : 5;
  64. UCHAR SizeOfProlog;
  65. UCHAR CountOfCodes;
  66. UCHAR FrameRegister : 4;
  67. UCHAR FrameOffset : 4;
  68. UNWIND_CODE UnwindCode[1];
  69. //
  70. // The unwind codes are followed by an optional DWORD aligned field that
  71. // contains the exception handler address or the address of chained unwind
  72. // information. If an exception handler address is specified, then it is
  73. // followed by the language specified exception handler data.
  74. //
  75. // union {
  76. // ULONG ExceptionHandler;
  77. // ULONG FunctionEntry;
  78. // };
  79. //
  80. // ULONG ExceptionData[];
  81. //
  82. } UNWIND_INFO, *PUNWIND_INFO;
  83. //
  84. // Define function table entry - a function table entry is generated for
  85. // each frame function.
  86. //
  87. typedef struct _RUNTIME_FUNCTION {
  88. ULONG BeginAddress;
  89. ULONG EndAddress;
  90. ULONG UnwindData;
  91. } RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
  92. //
  93. // Scope table structure definition.
  94. //
  95. typedef struct _SCOPE_ENTRY {
  96. ULONG BeginAddress;
  97. ULONG EndAddress;
  98. ULONG HandlerAddress;
  99. ULONG JumpTarget;
  100. } SCOPE_ENTRY;
  101. typedef struct _SCOPE_TABLE {
  102. ULONG Count;
  103. struct
  104. {
  105. ULONG BeginAddress;
  106. ULONG EndAddress;
  107. ULONG HandlerAddress;
  108. ULONG JumpTarget;
  109. } ScopeRecord[1];
  110. } SCOPE_TABLE, *PSCOPE_TABLE;
  111. //
  112. // Define register names.
  113. //
  114. PCHAR Register[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
  115. "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
  116. "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xxm6",
  117. "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
  118. "xmm13", "xxm14", "xmm15"};
  119. //
  120. // Define the sector size and header buffer.
  121. //
  122. #define SECTOR_SIZE 512
  123. CHAR LocalBuffer[SECTOR_SIZE * 2];
  124. //
  125. // Define input file stream.
  126. //
  127. FILE * InputFile;
  128. //
  129. // This gobal indicates whether we are processing an executable or an obj.
  130. //
  131. BOOLEAN IsObj;
  132. //
  133. // Define forward referenced prototypes.
  134. //
  135. VOID
  136. DumpPdata (
  137. IN ULONG NumberOfSections,
  138. IN PIMAGE_SECTION_HEADER SectionHeaders,
  139. IN PIMAGE_SECTION_HEADER PdataHeader
  140. );
  141. VOID
  142. DumpUData (
  143. IN ULONG NumberOfSections,
  144. IN PIMAGE_SECTION_HEADER SectionHeaders,
  145. IN ULONG Virtual
  146. );
  147. PIMAGE_SECTION_HEADER
  148. FindSectionHeader (
  149. IN ULONG NumberOfSections,
  150. IN PIMAGE_SECTION_HEADER SectionHeaders,
  151. IN PCHAR SectionName
  152. );
  153. VOID
  154. ReadData (
  155. IN ULONG Position,
  156. OUT PVOID Buffer,
  157. IN ULONG Count
  158. );
  159. USHORT
  160. ReadWord (
  161. IN ULONG Position
  162. );
  163. ULONG
  164. ReadDword (
  165. IN ULONG Position
  166. );
  167. //
  168. // Main program.
  169. //
  170. int
  171. __cdecl
  172. main(
  173. int argc,
  174. char **argv
  175. )
  176. {
  177. PIMAGE_FILE_HEADER FileHeader;
  178. PCHAR FileName;
  179. ULONG Index;
  180. PIMAGE_NT_HEADERS NtHeaders;
  181. ULONG NumberOfSections;
  182. PIMAGE_SECTION_HEADER PDataHeader;
  183. PIMAGE_SECTION_HEADER SectionHeaders;
  184. if (argc < 2) {
  185. printf("no executable file specified\n");
  186. } else {
  187. //
  188. // Open the input file.
  189. //
  190. FileName = argv[1];
  191. InputFile = fopen(FileName, "rb");
  192. if (InputFile != NULL) {
  193. //
  194. // Read the file header.
  195. //
  196. if (fread(&LocalBuffer[0],
  197. sizeof(CHAR),
  198. SECTOR_SIZE * 2,
  199. InputFile) == (SECTOR_SIZE * 2)) {
  200. //
  201. // Get the NT header address.
  202. //
  203. NtHeaders = RtlImageNtHeader(&LocalBuffer[0]);
  204. if (NtHeaders != NULL) {
  205. IsObj = FALSE;
  206. FileHeader = &NtHeaders->FileHeader;
  207. } else {
  208. IsObj = TRUE;
  209. FileHeader = (PIMAGE_FILE_HEADER)LocalBuffer;
  210. }
  211. printf("FileHeader->Machine %d\n",FileHeader->Machine);
  212. if (FileHeader->Machine == IMAGE_FILE_MACHINE_AMD64) {
  213. //
  214. // Look up the .pdata section.
  215. //
  216. NumberOfSections = FileHeader->NumberOfSections;
  217. SectionHeaders =
  218. (PIMAGE_SECTION_HEADER)((PUCHAR)(FileHeader + 1) +
  219. FileHeader->SizeOfOptionalHeader);
  220. PDataHeader = FindSectionHeader(NumberOfSections,
  221. SectionHeaders,
  222. ".pdata");
  223. if (PDataHeader != NULL) {
  224. printf("Dumping Unwind Information for file %s\n\n", FileName);
  225. DumpPdata(NumberOfSections,
  226. &SectionHeaders[0],
  227. PDataHeader);
  228. return 0;
  229. }
  230. printf("no .pdata section in image\n");
  231. } else {
  232. printf("the specified file is not an amd64 executable\n");
  233. }
  234. } else {
  235. printf("premature end of file encountered on input file\n");
  236. }
  237. fclose(InputFile);
  238. } else {
  239. printf("can't open input file %s\n", FileName);
  240. }
  241. }
  242. return 0;
  243. }
  244. VOID
  245. DumpPdata (
  246. IN ULONG NumberOfSections,
  247. IN PIMAGE_SECTION_HEADER SectionHeaders,
  248. IN PIMAGE_SECTION_HEADER PdataHeader
  249. )
  250. {
  251. RUNTIME_FUNCTION Entry;
  252. ULONG Number;
  253. ULONG Offset;
  254. ULONG SectionSize;
  255. //
  256. // Dump a .pdata function table entry and then dump the associated
  257. // unwind data.
  258. //
  259. if (IsObj == FALSE) {
  260. SectionSize = PdataHeader->Misc.VirtualSize;
  261. } else {
  262. SectionSize = PdataHeader->SizeOfRawData;
  263. }
  264. Number = 1;
  265. Offset = 0;
  266. do {
  267. //
  268. // Read and dump the next function table entry.
  269. //
  270. ReadData(PdataHeader->PointerToRawData + Offset,
  271. &Entry,
  272. sizeof(RUNTIME_FUNCTION));
  273. printf(".pdata entry %d 0x%08lX 0x%08lX\n",
  274. Number,
  275. Entry.BeginAddress,
  276. Entry.EndAddress);
  277. //
  278. // Dump the unwind data assoicated with the function table entry.
  279. //
  280. DumpUData(NumberOfSections, SectionHeaders, Entry.UnwindData);
  281. //
  282. // Increment the entry number and update the offset to the next
  283. // function table entry.
  284. //
  285. Number += 1;
  286. Offset += sizeof(RUNTIME_FUNCTION);
  287. } while (Offset < SectionSize);
  288. //
  289. // Function offset and size of raw data should be equal if there is
  290. // the correct amount of data in the .pdata section.
  291. //
  292. if (Offset != SectionSize) {
  293. printf("incorrect size of raw data in .pdata, 0x%lx\n",
  294. PdataHeader->SizeOfRawData);
  295. }
  296. return;
  297. }
  298. VOID
  299. DumpUData (
  300. IN ULONG NumberOfSections,
  301. IN PIMAGE_SECTION_HEADER SectionHeaders,
  302. IN ULONG Virtual
  303. )
  304. {
  305. ULONG Allocation;
  306. ULONG Count;
  307. ULONG Displacement;
  308. ULONG FrameOffset = 0;
  309. ULONG FrameRegister = 0;
  310. ULONG Handler;
  311. ULONG Index;
  312. ULONG Offset;
  313. SCOPE_ENTRY ScopeEntry;
  314. UNWIND_CODE UnwindCode;
  315. UNWIND_INFO UnwindInfo;
  316. PIMAGE_SECTION_HEADER XdataHeader;
  317. //
  318. // Locate the section that contains the unwind data.
  319. //
  320. printf("\n");
  321. printf(" Unwind data: 0x%08lX\n\n", Virtual);
  322. if (IsObj == FALSE) {
  323. XdataHeader = SectionHeaders;
  324. for (Index = 0; Index < NumberOfSections; Index += 1) {
  325. if ((XdataHeader->VirtualAddress <= Virtual) &&
  326. (Virtual < (XdataHeader->VirtualAddress + XdataHeader->Misc.VirtualSize))) {
  327. break;
  328. }
  329. XdataHeader += 1;
  330. }
  331. if (Index == NumberOfSections) {
  332. printf(" unwind data address outside of image\n\n");
  333. return;
  334. }
  335. Offset = Virtual -
  336. XdataHeader->VirtualAddress +
  337. XdataHeader->PointerToRawData;
  338. } else {
  339. //
  340. // This is an .obj, so there is only one Xdata header
  341. //
  342. XdataHeader = FindSectionHeader(NumberOfSections,
  343. SectionHeaders,
  344. ".xdata");
  345. Offset = Virtual + XdataHeader->PointerToRawData;
  346. }
  347. //
  348. // Read unwind information.
  349. //
  350. ReadData(Offset,
  351. &UnwindInfo,
  352. sizeof(UNWIND_INFO) - sizeof(UNWIND_CODE));
  353. //
  354. // Dump unwind version.
  355. //
  356. printf(" Unwind version: %d\n", UnwindInfo.Version);
  357. //
  358. // Dump unwind flags.
  359. //
  360. printf(" Unwind Flags: ");
  361. if ((UnwindInfo.Flags & UNW_FLAG_EHANDLER) != 0) {
  362. printf("EHANDLER ");
  363. }
  364. if ((UnwindInfo.Flags & UNW_FLAG_UHANDLER) != 0) {
  365. printf("UHANDLER ");
  366. }
  367. if ((UnwindInfo.Flags & UNW_FLAG_CHAININFO) != 0) {
  368. printf("CHAININFO");
  369. }
  370. if (UnwindInfo.Flags == 0) {
  371. printf("None");
  372. }
  373. printf("\n");
  374. //
  375. // Dump size of prologue.
  376. //
  377. printf(" Size of prologue: 0x%02lX\n", UnwindInfo.SizeOfProlog);
  378. //
  379. // Dump number of unwind codes.
  380. //
  381. printf(" Count of codes: %d\n", UnwindInfo.CountOfCodes);
  382. //
  383. // Dump frame register if specified.
  384. //
  385. if (UnwindInfo.FrameRegister != 0) {
  386. FrameOffset = UnwindInfo.FrameOffset * 16;
  387. FrameRegister = UnwindInfo.FrameRegister;
  388. printf(" Frame register: %s\n", Register[FrameRegister]);
  389. printf(" Frame offset: 0x%lx\n", FrameOffset);
  390. }
  391. //
  392. // Dump the unwind codes.
  393. //
  394. Offset += sizeof(UNWIND_INFO) - sizeof(UNWIND_CODE);
  395. if (UnwindInfo.CountOfCodes != 0) {
  396. printf(" Unwind codes:\n\n");
  397. Count = UnwindInfo.CountOfCodes;
  398. do {
  399. Count -= 1;
  400. UnwindCode.FrameOffset = ReadWord(Offset);
  401. Offset += sizeof(USHORT);
  402. printf(" Code offset: 0x%02lX, ", UnwindCode.CodeOffset);
  403. switch (UnwindCode.UnwindOp) {
  404. case UWOP_PUSH_NONVOL:
  405. printf("PUSH_NONVOL, register=%s\n", Register[UnwindCode.OpInfo]);
  406. break;
  407. case UWOP_ALLOC_LARGE:
  408. Count -= 1;
  409. Allocation = ReadWord(Offset);
  410. Offset += sizeof(USHORT);
  411. if (UnwindCode.OpInfo == 0) {
  412. Allocation *= 8;
  413. } else {
  414. Count -= 1;
  415. Allocation = (Allocation << 16) + ReadWord(Offset);
  416. Offset += sizeof(USHORT);
  417. }
  418. printf("ALLOC_LARGE, size=0x%lX\n", Allocation);
  419. break;
  420. case UWOP_ALLOC_SMALL:
  421. Allocation = (UnwindCode.OpInfo * 8) + 8;
  422. printf("ALLOC_SMALL, size=0x%lX\n", Allocation);
  423. break;
  424. case UWOP_SET_FPREG:
  425. printf("SET_FPREG, register=%s, offset=0x%02lX\n",
  426. Register[FrameRegister], FrameOffset);
  427. break;
  428. case UWOP_SAVE_NONVOL:
  429. Count -= 1;
  430. Displacement = ReadWord(Offset) * 8;
  431. Offset += sizeof(USHORT);
  432. printf("SAVE_NONVOL, register=%s offset=0x%lX\n",
  433. Register[UnwindCode.OpInfo],
  434. Displacement);
  435. break;
  436. case UWOP_SAVE_NONVOL_FAR:
  437. Count -= 2;
  438. Displacement = ReadWord(Offset) << 16;
  439. Offset += sizeof(USHORT);
  440. Displacement = Displacement + ReadWord(Offset);
  441. Offset += sizeof(USHORT);
  442. printf("SAVE_NONVOL_FAR, register=%s offset=0x%lX\n",
  443. Register[UnwindCode.OpInfo],
  444. Displacement);
  445. break;
  446. case UWOP_SAVE_XMM:
  447. Count -= 1;
  448. Displacement = ReadWord(Offset) * 8;
  449. Offset += sizeof(USHORT);
  450. printf("SAVE_XMM, register=%s offset=0x%lX\n",
  451. Register[UnwindCode.OpInfo + 16],
  452. Displacement);
  453. break;
  454. case UWOP_SAVE_XMM_FAR:
  455. Count -= 2;
  456. Displacement = ReadWord(Offset) << 16;
  457. Offset += sizeof(USHORT);
  458. Displacement = Displacement + ReadWord(Offset);
  459. Offset += sizeof(USHORT);
  460. printf("SAVE_XMM_FAR, register=%s offset=0x%lX\n",
  461. Register[UnwindCode.OpInfo + 16],
  462. Displacement);
  463. break;
  464. case UWOP_SAVE_XMM128:
  465. Count -= 1;
  466. Displacement = ReadWord(Offset) * 16;
  467. Offset += sizeof(USHORT);
  468. printf("SAVE_XMM128, register=%s offset=0x%lX\n",
  469. Register[UnwindCode.OpInfo + 16],
  470. Displacement);
  471. break;
  472. case UWOP_SAVE_XMM128_FAR:
  473. Count -= 2;
  474. Displacement = ReadWord(Offset) << 16;
  475. Offset += sizeof(USHORT);
  476. Displacement = Displacement + ReadWord(Offset);
  477. Offset += sizeof(USHORT);
  478. printf("SAVE_XMM128_FAR, register=%s offset=0x%lX\n",
  479. Register[UnwindCode.OpInfo + 16],
  480. Displacement);
  481. break;
  482. case UWOP_PUSH_MACHFRAME:
  483. if (UnwindCode.OpInfo == 0) {
  484. printf("PUSH_MACHFRAME without error code\n");
  485. } else {
  486. printf("PUSH_MACHFRAME with error code\n");
  487. }
  488. break;
  489. }
  490. } while (Count != 0);
  491. }
  492. //
  493. // Dump exception data if there is an excpetion or termination
  494. // handler.
  495. //
  496. if (((UnwindInfo.Flags & UNW_FLAG_EHANDLER) != 0) ||
  497. ((UnwindInfo.Flags & UNW_FLAG_UHANDLER) != 0)) {
  498. if ((UnwindInfo.CountOfCodes & 1) != 0) {
  499. Offset += sizeof(USHORT);
  500. }
  501. Handler = ReadDword(Offset);
  502. Offset += sizeof(ULONG);
  503. Count = ReadDword(Offset);
  504. Offset += sizeof(ULONG);
  505. printf("\n");
  506. printf(" Language specific handler: 0x%08lX\n", Handler);
  507. printf(" Count of scope table entries: %d\n\n", Count);
  508. if (Count != 0) {
  509. printf(" Begin End Handler Target\n");
  510. do {
  511. ReadData(Offset, &ScopeEntry, sizeof(SCOPE_ENTRY));
  512. printf(" 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n",
  513. ScopeEntry.BeginAddress,
  514. ScopeEntry.EndAddress,
  515. ScopeEntry.HandlerAddress,
  516. ScopeEntry.JumpTarget);
  517. Count -= 1;
  518. Offset += sizeof(SCOPE_ENTRY);
  519. } while (Count != 0);
  520. }
  521. }
  522. printf("\n");
  523. return;
  524. }
  525. PIMAGE_SECTION_HEADER
  526. FindSectionHeader (
  527. IN ULONG NumberOfSections,
  528. IN PIMAGE_SECTION_HEADER SectionHeaders,
  529. IN PCHAR SectionName
  530. )
  531. {
  532. ULONG RemainingSections;
  533. PIMAGE_SECTION_HEADER SectionHeader;
  534. SectionHeader = SectionHeaders;
  535. RemainingSections = NumberOfSections;
  536. while (RemainingSections > 0) {
  537. if (strncmp(SectionHeader->Name,
  538. SectionName,
  539. IMAGE_SIZEOF_SHORT_NAME) == 0) {
  540. return SectionHeader;
  541. }
  542. RemainingSections -= 1;
  543. SectionHeader += 1;
  544. }
  545. return NULL;
  546. }
  547. VOID
  548. ReadData (
  549. IN ULONG Position,
  550. OUT PVOID Buffer,
  551. IN ULONG Count
  552. )
  553. {
  554. if (fseek(InputFile,
  555. Position,
  556. SEEK_SET) == 0) {
  557. if (fread((PCHAR)Buffer,
  558. 1,
  559. Count,
  560. InputFile) == Count) {
  561. return;
  562. }
  563. }
  564. printf("premature end of file encounterd on inpout file\n");
  565. exit(0);
  566. }
  567. USHORT
  568. ReadWord (
  569. IN ULONG Position
  570. )
  571. {
  572. USHORT Buffer;
  573. ReadData(Position, &Buffer, sizeof(USHORT));
  574. return Buffer;
  575. }
  576. ULONG
  577. ReadDword (
  578. IN ULONG Position
  579. )
  580. {
  581. ULONG Buffer;
  582. ReadData(Position, &Buffer, sizeof(ULONG));
  583. return Buffer;
  584. }