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.

1382 lines
43 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. walkamd64.c
  5. Abstract:
  6. This file implements the AMD64 stack walking api.
  7. Author:
  8. Environment:
  9. User Mode
  10. --*/
  11. #define _IMAGEHLP_SOURCE_
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include "private.h"
  16. #define NOEXTAPI
  17. #include "wdbgexts.h"
  18. #include "ntdbg.h"
  19. #include "symbols.h"
  20. #include <stdlib.h>
  21. #include <globals.h>
  22. #if 1
  23. #define WDB(Args) dbPrint Args
  24. #else
  25. #define WDB(Args)
  26. #endif
  27. //
  28. // Lookup table providing the number of slots used by each unwind code.
  29. //
  30. UCHAR RtlpUnwindOpSlotTableAmd64[] = {
  31. 1, // UWOP_PUSH_NONVOL
  32. 2, // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
  33. 1, // UWOP_ALLOC_SMALL
  34. 1, // UWOP_SET_FPREG
  35. 2, // UWOP_SAVE_NONVOL
  36. 3, // UWOP_SAVE_NONVOL_FAR
  37. 2, // UWOP_SAVE_XMM
  38. 3, // UWOP_SAVE_XMM_FAR
  39. 2, // UWOP_SAVE_XMM128
  40. 3, // UWOP_SAVE_XMM128_FAR
  41. 1 // UWOP_PUSH_MACHFRAME
  42. };
  43. BOOL
  44. WalkAmd64Init(
  45. HANDLE Process,
  46. LPSTACKFRAME64 StackFrame,
  47. PAMD64_CONTEXT Context,
  48. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  49. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  50. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  51. );
  52. BOOL
  53. WalkAmd64Next(
  54. HANDLE Process,
  55. LPSTACKFRAME64 StackFrame,
  56. PAMD64_CONTEXT Context,
  57. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  58. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  59. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  60. );
  61. BOOL
  62. UnwindStackFrameAmd64(
  63. HANDLE Process,
  64. PULONG64 ReturnAddress,
  65. PULONG64 StackPointer,
  66. PULONG64 FramePointer,
  67. PAMD64_CONTEXT Context,
  68. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  69. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  70. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  71. );
  72. PAMD64_UNWIND_INFO
  73. ReadUnwindInfoAmd64(ULONG64 Offset, BOOL ReadCodes, HANDLE Process,
  74. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  75. PVOID StaticBuffer, ULONG StaticBufferSize)
  76. {
  77. ULONG Done;
  78. ULONG UnwindInfoSize;
  79. PAMD64_UNWIND_INFO UnwindInfo;
  80. // Static buffer should at least be large enough to read the
  81. // basic structure.
  82. if (StaticBufferSize < sizeof(*UnwindInfo)) {
  83. return NULL;
  84. }
  85. UnwindInfo = (PAMD64_UNWIND_INFO)StaticBuffer;
  86. // First read just the basic structure since the information
  87. // is needed to compute the complete size.
  88. if (!ReadMemory(Process, Offset, UnwindInfo, sizeof(*UnwindInfo), &Done) ||
  89. Done != sizeof(*UnwindInfo)) {
  90. WDB(("Unable to read unwind info at %I64X\n", Offset));
  91. return FALSE;
  92. }
  93. if (!ReadCodes) {
  94. return UnwindInfo;
  95. }
  96. // Compute the size of all the data.
  97. UnwindInfoSize = sizeof(*UnwindInfo) +
  98. (UnwindInfo->CountOfCodes - 1) * sizeof(AMD64_UNWIND_CODE);
  99. // An extra alignment code and pointer may be added on to handle
  100. // the chained info case where the chain pointer is just
  101. // beyond the end of the normal code array.
  102. if ((UnwindInfo->Flags & AMD64_UNW_FLAG_CHAININFO) != 0) {
  103. if ((UnwindInfo->CountOfCodes & 1) != 0) {
  104. UnwindInfoSize += sizeof(AMD64_UNWIND_CODE);
  105. }
  106. UnwindInfoSize += sizeof(ULONG64);
  107. }
  108. if (UnwindInfoSize > StaticBufferSize) {
  109. if (UnwindInfoSize > 0xffff) {
  110. // Too large to be valid data, assume it's garbage.
  111. WDB(("Invalid unwind info at %I64X\n", Offset));
  112. return NULL;
  113. }
  114. UnwindInfo = (PAMD64_UNWIND_INFO)MemAlloc(UnwindInfoSize);
  115. if (UnwindInfo == NULL) {
  116. return NULL;
  117. }
  118. }
  119. // Now read all the data.
  120. if (!ReadMemory(Process, Offset, UnwindInfo, UnwindInfoSize, &Done) ||
  121. Done != UnwindInfoSize) {
  122. if ((PVOID)UnwindInfo != StaticBuffer) {
  123. MemFree(UnwindInfo);
  124. }
  125. WDB(("Unable to read unwind info at %I64X\n", Offset));
  126. return NULL;
  127. }
  128. return UnwindInfo;
  129. }
  130. //
  131. // ****** temp - defin elsewhere ******
  132. //
  133. #define SIZE64_PREFIX 0x48
  134. #define ADD_IMM8_OP 0x83
  135. #define ADD_IMM32_OP 0x81
  136. #define LEA_OP 0x8d
  137. #define POP_OP 0x58
  138. #define RET_OP 0xc3
  139. BOOLEAN
  140. RtlpUnwindPrologueAmd64 (
  141. IN ULONG64 ImageBase,
  142. IN ULONG64 ControlPc,
  143. IN ULONG64 FrameBase,
  144. IN _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
  145. IN OUT PAMD64_CONTEXT ContextRecord,
  146. IN HANDLE Process,
  147. IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  148. )
  149. /*++
  150. Routine Description:
  151. This function processes unwind codes and reverses the state change
  152. effects of a prologue. If the specified unwind information contains
  153. chained unwind information, then that prologue is unwound recursively.
  154. As the prologue is unwound state changes are recorded in the specified
  155. context structure and optionally in the specified context pointers
  156. structures.
  157. Arguments:
  158. ImageBase - Supplies the base address of the image that contains the
  159. function being unwound.
  160. ControlPc - Supplies the address where control left the specified
  161. function.
  162. FrameBase - Supplies the base of the stack frame subject function stack
  163. frame.
  164. FunctionEntry - Supplies the address of the function table entry for the
  165. specified function.
  166. ContextRecord - Supplies the address of a context record.
  167. --*/
  168. {
  169. ULONG64 FloatingAddress;
  170. PAMD64_M128 FloatingRegister;
  171. ULONG FrameOffset;
  172. ULONG Index;
  173. ULONG64 IntegerAddress;
  174. PULONG64 IntegerRegister;
  175. BOOLEAN MachineFrame;
  176. ULONG OpInfo;
  177. ULONG PrologOffset;
  178. PULONG64 RegisterAddress;
  179. ULONG64 ReturnAddress;
  180. ULONG64 StackAddress;
  181. PAMD64_UNWIND_CODE UnwindCode;
  182. ULONG64 UnwindInfoBuffer[32];
  183. PAMD64_UNWIND_INFO UnwindInfo;
  184. ULONG Done;
  185. ULONG UnwindOp;
  186. //
  187. // Process the unwind codes.
  188. //
  189. FloatingRegister = &ContextRecord->Xmm0;
  190. IntegerRegister = &ContextRecord->Rax;
  191. Index = 0;
  192. MachineFrame = FALSE;
  193. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  194. WDB(("Prol: RIP %I64X, 0x%X bytes in function at %I64X\n",
  195. ControlPc, PrologOffset, FunctionEntry->BeginAddress + ImageBase));
  196. WDB(("Prol: Read unwind info at %I64X\n",
  197. PrologOffset, FunctionEntry->UnwindInfoAddress + ImageBase));
  198. UnwindInfo =
  199. ReadUnwindInfoAmd64(FunctionEntry->UnwindInfoAddress + ImageBase,
  200. TRUE, Process, ReadMemory, UnwindInfoBuffer,
  201. sizeof(UnwindInfoBuffer));
  202. if (UnwindInfo == NULL) {
  203. WDB(("Prol: Unable to read unwind info\n"));
  204. return FALSE;
  205. }
  206. WDB((" Unwind info has 0x%X codes\n", UnwindInfo->CountOfCodes));
  207. while (Index < UnwindInfo->CountOfCodes) {
  208. WDB((" %02X: Code %X offs %03X, RSP %I64X\n",
  209. Index, UnwindInfo->UnwindCode[Index].UnwindOp,
  210. UnwindInfo->UnwindCode[Index].CodeOffset,
  211. ContextRecord->Rsp));
  212. //
  213. // If the prologue offset is greater than the next unwind code offset,
  214. // then simulate the effect of the unwind code.
  215. //
  216. UnwindOp = UnwindInfo->UnwindCode[Index].UnwindOp;
  217. OpInfo = UnwindInfo->UnwindCode[Index].OpInfo;
  218. if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
  219. switch (UnwindOp) {
  220. //
  221. // Push nonvolatile integer register.
  222. //
  223. // The operation information is the register number of the
  224. // register than was pushed.
  225. //
  226. case AMD64_UWOP_PUSH_NONVOL:
  227. IntegerAddress = ContextRecord->Rsp;
  228. if (!ReadMemory(Process, IntegerAddress,
  229. &IntegerRegister[OpInfo], sizeof(ULONG64),
  230. &Done) ||
  231. Done != sizeof(ULONG64)) {
  232. goto Fail;
  233. }
  234. ContextRecord->Rsp += 8;
  235. break;
  236. //
  237. // Allocate a large sized area on the stack.
  238. //
  239. // The operation information determines if the size is
  240. // 16- or 32-bits.
  241. //
  242. case AMD64_UWOP_ALLOC_LARGE:
  243. Index += 1;
  244. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset;
  245. if (OpInfo != 0) {
  246. Index += 1;
  247. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  248. } else {
  249. // The 16-bit form is scaled.
  250. FrameOffset *= 8;
  251. }
  252. ContextRecord->Rsp += FrameOffset;
  253. break;
  254. //
  255. // Allocate a small sized area on the stack.
  256. //
  257. // The operation information is the size of the unscaled
  258. // allocation size (8 is the scale factor) minus 8.
  259. //
  260. case AMD64_UWOP_ALLOC_SMALL:
  261. ContextRecord->Rsp += (OpInfo * 8) + 8;
  262. break;
  263. //
  264. // Establish the the frame pointer register.
  265. //
  266. // The operation information is not used.
  267. //
  268. case AMD64_UWOP_SET_FPREG:
  269. ContextRecord->Rsp = IntegerRegister[UnwindInfo->FrameRegister];
  270. ContextRecord->Rsp -= UnwindInfo->FrameOffset * 16;
  271. break;
  272. //
  273. // Save nonvolatile integer register on the stack using a
  274. // 16-bit displacment.
  275. //
  276. // The operation information is the register number.
  277. //
  278. case AMD64_UWOP_SAVE_NONVOL:
  279. Index += 1;
  280. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 8;
  281. IntegerAddress = FrameBase + FrameOffset;
  282. if (!ReadMemory(Process, IntegerAddress,
  283. &IntegerRegister[OpInfo], sizeof(ULONG64),
  284. &Done) ||
  285. Done != sizeof(ULONG64)) {
  286. goto Fail;
  287. }
  288. break;
  289. //
  290. // Save nonvolatile integer register on the stack using a
  291. // 32-bit displacment.
  292. //
  293. // The operation information is the register number.
  294. //
  295. case AMD64_UWOP_SAVE_NONVOL_FAR:
  296. Index += 2;
  297. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  298. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  299. IntegerAddress = FrameBase + FrameOffset;
  300. if (!ReadMemory(Process, IntegerAddress,
  301. &IntegerRegister[OpInfo], sizeof(ULONG64),
  302. &Done) ||
  303. Done != sizeof(ULONG64)) {
  304. goto Fail;
  305. }
  306. break;
  307. //
  308. // Save a nonvolatile XMM(64) register on the stack using a
  309. // 16-bit displacement.
  310. //
  311. // The operation information is the register number.
  312. //
  313. case AMD64_UWOP_SAVE_XMM:
  314. Index += 1;
  315. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 8;
  316. FloatingAddress = FrameBase + FrameOffset;
  317. FloatingRegister[OpInfo].High = 0;
  318. if (!ReadMemory(Process, FloatingAddress,
  319. &FloatingRegister[OpInfo].Low, sizeof(ULONG64),
  320. &Done) ||
  321. Done != sizeof(ULONG64)) {
  322. goto Fail;
  323. }
  324. break;
  325. //
  326. // Save a nonvolatile XMM(64) register on the stack using a
  327. // 32-bit displacement.
  328. //
  329. // The operation information is the register number.
  330. //
  331. case AMD64_UWOP_SAVE_XMM_FAR:
  332. Index += 2;
  333. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  334. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  335. FloatingAddress = FrameBase + FrameOffset;
  336. FloatingRegister[OpInfo].High = 0;
  337. if (!ReadMemory(Process, FloatingAddress,
  338. &FloatingRegister[OpInfo].Low, sizeof(ULONG64),
  339. &Done) ||
  340. Done != sizeof(ULONG64)) {
  341. goto Fail;
  342. }
  343. break;
  344. //
  345. // Save a nonvolatile XMM(128) register on the stack using a
  346. // 16-bit displacement.
  347. //
  348. // The operation information is the register number.
  349. //
  350. case AMD64_UWOP_SAVE_XMM128:
  351. Index += 1;
  352. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 16;
  353. FloatingAddress = FrameBase + FrameOffset;
  354. if (!ReadMemory(Process, FloatingAddress,
  355. &FloatingRegister[OpInfo], sizeof(AMD64_M128),
  356. &Done) ||
  357. Done != sizeof(AMD64_M128)) {
  358. goto Fail;
  359. }
  360. break;
  361. //
  362. // Save a nonvolatile XMM(128) register on the stack using a
  363. // 32-bit displacement.
  364. //
  365. // The operation information is the register number.
  366. //
  367. case AMD64_UWOP_SAVE_XMM128_FAR:
  368. Index += 2;
  369. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  370. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  371. FloatingAddress = FrameBase + FrameOffset;
  372. if (!ReadMemory(Process, FloatingAddress,
  373. &FloatingRegister[OpInfo], sizeof(AMD64_M128),
  374. &Done) ||
  375. Done != sizeof(AMD64_M128)) {
  376. goto Fail;
  377. }
  378. break;
  379. //
  380. // Push a machine frame on the stack.
  381. //
  382. // The operation information determines whether the machine
  383. // frame contains an error code or not.
  384. //
  385. case AMD64_UWOP_PUSH_MACHFRAME:
  386. MachineFrame = TRUE;
  387. ReturnAddress = ContextRecord->Rsp;
  388. StackAddress = ContextRecord->Rsp + (3 * 8);
  389. if (OpInfo != 0) {
  390. ReturnAddress += 8;
  391. StackAddress += 8;
  392. }
  393. if (!ReadMemory(Process, ReturnAddress,
  394. &ContextRecord->Rip, sizeof(ULONG64),
  395. &Done) ||
  396. Done != sizeof(ULONG64)) {
  397. goto Fail;
  398. }
  399. if (!ReadMemory(Process, StackAddress,
  400. &ContextRecord->Rsp, sizeof(ULONG64),
  401. &Done) ||
  402. Done != sizeof(ULONG64)) {
  403. goto Fail;
  404. }
  405. break;
  406. //
  407. // Unused codes.
  408. //
  409. default:
  410. break;
  411. }
  412. Index += 1;
  413. } else {
  414. //
  415. // Skip this unwind operation by advancing the slot index by the
  416. // number of slots consumed by this operation.
  417. //
  418. Index += RtlpUnwindOpSlotTableAmd64[UnwindOp];
  419. //
  420. // Special case any unwind operations that can consume a variable
  421. // number of slots.
  422. //
  423. switch (UnwindOp) {
  424. //
  425. // A non-zero operation information indicates that an
  426. // additional slot is consumed.
  427. //
  428. case AMD64_UWOP_ALLOC_LARGE:
  429. if (OpInfo != 0) {
  430. Index += 1;
  431. }
  432. break;
  433. //
  434. // No other special cases.
  435. //
  436. default:
  437. break;
  438. }
  439. }
  440. }
  441. //
  442. // If chained unwind information is specified, then recursively unwind
  443. // the chained information. Otherwise, determine the return address if
  444. // a machine frame was not encountered during the scan of the unwind
  445. // codes.
  446. //
  447. if ((UnwindInfo->Flags & AMD64_UNW_FLAG_CHAININFO) != 0) {
  448. Index = UnwindInfo->CountOfCodes;
  449. if ((Index & 1) != 0) {
  450. Index += 1;
  451. }
  452. ULONG64 ChainEntryAddr =
  453. *(PULONG64)(&UnwindInfo->UnwindCode[Index]) + ImageBase;
  454. if (UnwindInfo != (PAMD64_UNWIND_INFO)UnwindInfoBuffer) {
  455. MemFree(UnwindInfo);
  456. }
  457. _IMAGE_RUNTIME_FUNCTION_ENTRY ChainEntry;
  458. WDB((" Chain to entry at %I64X\n", ChainEntryAddr));
  459. if (!ReadMemory(Process, ChainEntryAddr,
  460. &ChainEntry, sizeof(ChainEntry), &Done) ||
  461. Done != sizeof(ChainEntry)) {
  462. WDB((" Unable to read entry\n"));
  463. return FALSE;
  464. }
  465. return RtlpUnwindPrologueAmd64(ImageBase,
  466. ControlPc,
  467. FrameBase,
  468. &ChainEntry,
  469. ContextRecord,
  470. Process,
  471. ReadMemory);
  472. } else {
  473. if (UnwindInfo != (PAMD64_UNWIND_INFO)UnwindInfoBuffer) {
  474. MemFree(UnwindInfo);
  475. }
  476. if (MachineFrame == FALSE) {
  477. if (!ReadMemory(Process, ContextRecord->Rsp,
  478. &ContextRecord->Rip, sizeof(ULONG64),
  479. &Done) ||
  480. Done != sizeof(ULONG64)) {
  481. return FALSE;
  482. }
  483. ContextRecord->Rsp += 8;
  484. }
  485. WDB(("Prol: Returning with RIP %I64X, RSP %I64X\n",
  486. ContextRecord->Rip, ContextRecord->Rsp));
  487. return TRUE;
  488. }
  489. Fail:
  490. if (UnwindInfo != (PAMD64_UNWIND_INFO)UnwindInfoBuffer) {
  491. MemFree(UnwindInfo);
  492. }
  493. WDB(("Prol: Unwind failed\n"));
  494. return FALSE;
  495. }
  496. BOOLEAN
  497. RtlVirtualUnwindAmd64 (
  498. IN ULONG64 ImageBase,
  499. IN ULONG64 ControlPc,
  500. IN _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
  501. IN OUT PAMD64_CONTEXT ContextRecord,
  502. OUT PULONG64 EstablisherFrame,
  503. IN HANDLE Process,
  504. IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  505. )
  506. /*++
  507. Routine Description:
  508. This function virtually unwinds the specified function by executing its
  509. prologue code backward or its epilogue code forward.
  510. If a context pointers record is specified, then the address where each
  511. nonvolatile registers is restored from is recorded in the appropriate
  512. element of the context pointers record.
  513. Arguments:
  514. ImageBase - Supplies the base address of the image that contains the
  515. function being unwound.
  516. ControlPc - Supplies the address where control left the specified
  517. function.
  518. FunctionEntry - Supplies the address of the function table entry for the
  519. specified function.
  520. ContextRecord - Supplies the address of a context record.
  521. EstablisherFrame - Supplies a pointer to a variable that receives the
  522. the establisher frame pointer value.
  523. --*/
  524. {
  525. LONG Displacement;
  526. ULONG FrameRegister;
  527. ULONG Index;
  528. PULONG64 IntegerRegister;
  529. PUCHAR NextByte;
  530. ULONG PrologOffset;
  531. ULONG RegisterNumber;
  532. PAMD64_UNWIND_INFO UnwindInfo;
  533. ULONG64 UnwindInfoBuffer[8];
  534. ULONG Done;
  535. UCHAR InstrBuffer[32];
  536. ULONG InstrBytes;
  537. ULONG Bytes;
  538. ULONG UnwindFrameReg;
  539. //
  540. // If the specified function does not use a frame pointer, then the
  541. // establisher frame is the contents of the stack pointer. This may
  542. // not actually be the real establisher frame if control left the
  543. // function from within the prologue. In this case the establisher
  544. // frame may be not required since control has not actually entered
  545. // the function and prologue entries cannot refer to the establisher
  546. // frame before it has been established, i.e., if it has not been
  547. // established, then no save unwind codes should be encountered during
  548. // the unwind operation.
  549. //
  550. // If the specified function uses a frame pointer and control left the
  551. // function outside of the prologue or the unwind information contains
  552. // a chained information structure, then the establisher frame is the
  553. // contents of the frame pointer.
  554. //
  555. // If the specified function uses a frame pointer and control left the
  556. // function from within the prologue, then the set frame pointer unwind
  557. // code must be looked up in the unwind codes to detetermine if the
  558. // contents of the stack pointer or the contents of the frame pointer
  559. // should be used for the establisher frame. This may not atually be
  560. // the real establisher frame. In this case the establisher frame may
  561. // not be required since control has not actually entered the function
  562. // and prologue entries cannot refer to the establisher frame before it
  563. // has been established, i.e., if it has not been established, then no
  564. // save unwind codes should be encountered during the unwind operation.
  565. //
  566. // N.B. The correctness of these assumptions is based on the ordering of
  567. // unwind codes.
  568. //
  569. UnwindInfo =
  570. ReadUnwindInfoAmd64(FunctionEntry->UnwindInfoAddress + ImageBase,
  571. FALSE, Process, ReadMemory, UnwindInfoBuffer,
  572. sizeof(UnwindInfoBuffer));
  573. if (UnwindInfo == NULL) {
  574. return FALSE;
  575. }
  576. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  577. UnwindFrameReg = UnwindInfo->FrameRegister;
  578. if (UnwindFrameReg == 0) {
  579. *EstablisherFrame = ContextRecord->Rsp;
  580. } else if ((PrologOffset >= UnwindInfo->SizeOfProlog) ||
  581. ((UnwindInfo->Flags & AMD64_UNW_FLAG_CHAININFO) != 0)) {
  582. *EstablisherFrame = (&ContextRecord->Rax)[UnwindFrameReg];
  583. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  584. } else {
  585. // Read all the data.
  586. UnwindInfo = ReadUnwindInfoAmd64(FunctionEntry->UnwindInfoAddress +
  587. ImageBase, TRUE, Process, ReadMemory,
  588. UnwindInfoBuffer,
  589. sizeof(UnwindInfoBuffer));
  590. if (UnwindInfo == NULL) {
  591. return FALSE;
  592. }
  593. Index = 0;
  594. while (Index < UnwindInfo->CountOfCodes) {
  595. if (UnwindInfo->UnwindCode[Index].UnwindOp == AMD64_UWOP_SET_FPREG) {
  596. break;
  597. }
  598. Index += 1;
  599. }
  600. if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
  601. *EstablisherFrame = (&ContextRecord->Rax)[UnwindFrameReg];
  602. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  603. } else {
  604. *EstablisherFrame = ContextRecord->Rsp;
  605. }
  606. if (UnwindInfo != (PAMD64_UNWIND_INFO)UnwindInfoBuffer) {
  607. MemFree(UnwindInfo);
  608. }
  609. }
  610. if (!ReadMemory(Process, ControlPc, InstrBuffer, sizeof(InstrBuffer),
  611. &InstrBytes)) {
  612. WDB(("Unable to read instruction stream at %I64X\n", ControlPc));
  613. return FALSE;
  614. }
  615. //
  616. // Check for epilogue.
  617. //
  618. // If the point at which control left the specified function is in an
  619. // epilogue, then emulate the execution of the epilogue forward and
  620. // return no exception handler.
  621. //
  622. IntegerRegister = &ContextRecord->Rax;
  623. NextByte = InstrBuffer;
  624. Bytes = InstrBytes;
  625. //
  626. // Check for one of:
  627. //
  628. // add rsp, imm8
  629. // or
  630. // add rsp, imm32
  631. // or
  632. // lea rsp, -disp8[fp]
  633. // or
  634. // lea rsp, -disp32[fp]
  635. //
  636. if (Bytes >= 4 &&
  637. (NextByte[0] == SIZE64_PREFIX) &&
  638. (NextByte[1] == ADD_IMM8_OP) &&
  639. (NextByte[2] == 0xc4)) {
  640. //
  641. // add rsp, imm8.
  642. //
  643. NextByte += 4;
  644. Bytes -= 4;
  645. } else if (Bytes >= 7 &&
  646. (NextByte[0] == SIZE64_PREFIX) &&
  647. (NextByte[1] == ADD_IMM32_OP) &&
  648. (NextByte[2] == 0xc4)) {
  649. //
  650. // add rsp, imm32.
  651. //
  652. NextByte += 7;
  653. Bytes -= 7;
  654. } else if (Bytes >= 4 &&
  655. ((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  656. (NextByte[1] == LEA_OP)) {
  657. FrameRegister = ((NextByte[0] & 0x7) << 3) | (NextByte[2] & 0x7);
  658. if ((FrameRegister != 0) &&
  659. (FrameRegister == UnwindFrameReg)) {
  660. if ((NextByte[2] & 0xf8) == 0x60) {
  661. //
  662. // lea rsp, disp8[fp].
  663. //
  664. NextByte += 4;
  665. Bytes -= 4;
  666. } else if (Bytes >= 7 &&
  667. (NextByte[2] &0xf8) == 0xa0) {
  668. //
  669. // lea rsp, disp32[fp].
  670. //
  671. NextByte += 7;
  672. Bytes -= 7;
  673. }
  674. }
  675. }
  676. //
  677. // Check for any number of:
  678. //
  679. // pop nonvolatile-integer-register[0..15].
  680. //
  681. while (TRUE) {
  682. if (Bytes >= 1 &&
  683. (NextByte[0] & 0xf8) == POP_OP) {
  684. NextByte += 1;
  685. Bytes -= 1;
  686. } else if (Bytes >= 2 &&
  687. ((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  688. ((NextByte[1] & 0xf8) == POP_OP)) {
  689. NextByte += 2;
  690. Bytes -= 2;
  691. } else {
  692. break;
  693. }
  694. }
  695. //
  696. // If the next instruction is a return, then control is currently in
  697. // an epilogue and execution of the epilogue should be emulated.
  698. // Otherwise, execution is not in an epilogue and the prologue should
  699. // be unwound.
  700. //
  701. if (Bytes >= 1 &&
  702. NextByte[0] == RET_OP) {
  703. NextByte = InstrBuffer;
  704. Bytes = InstrBytes;
  705. //
  706. // Emulate one of (if any):
  707. //
  708. // add rsp, imm8
  709. // or
  710. // add rsp, imm32
  711. // or
  712. // lea rsp, disp8[frame-register]
  713. // or
  714. // lea rsp, disp32[frame-register]
  715. //
  716. if (Bytes >= 4 &&
  717. NextByte[1] == ADD_IMM8_OP) {
  718. //
  719. // add rsp, imm8.
  720. //
  721. ContextRecord->Rsp += (CHAR)NextByte[3];
  722. NextByte += 4;
  723. Bytes -= 4;
  724. } else if (Bytes >= 7 &&
  725. NextByte[1] == ADD_IMM32_OP) {
  726. //
  727. // add rsp, imm32.
  728. //
  729. Displacement = NextByte[3] | (NextByte[4] << 8);
  730. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  731. ContextRecord->Rsp += Displacement;
  732. NextByte += 7;
  733. Bytes -= 7;
  734. } else if (Bytes >= 4 &&
  735. NextByte[1] == LEA_OP) {
  736. if ((NextByte[2] & 0xf8) == 0x60) {
  737. //
  738. // lea rsp, disp8[frame-register].
  739. //
  740. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  741. ContextRecord->Rsp += (CHAR)NextByte[3];
  742. NextByte += 4;
  743. Bytes -= 4;
  744. } else if (Bytes >= 7 &&
  745. (NextByte[2] & 0xf8) == 0xa0) {
  746. //
  747. // lea rsp, disp32[frame-register].
  748. //
  749. Displacement = NextByte[3] | (NextByte[4] << 8);
  750. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  751. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  752. ContextRecord->Rsp += Displacement;
  753. NextByte += 7;
  754. Bytes -= 7;
  755. }
  756. }
  757. //
  758. // Emulate any number of (if any):
  759. //
  760. // pop nonvolatile-integer-register.
  761. //
  762. while (TRUE) {
  763. if (Bytes >= 1 &&
  764. (NextByte[0] & 0xf8) == POP_OP) {
  765. //
  766. // pop nonvolatile-integer-register[0..7]
  767. //
  768. RegisterNumber = NextByte[0] & 0x7;
  769. if (!ReadMemory(Process, ContextRecord->Rsp,
  770. &IntegerRegister[RegisterNumber],
  771. sizeof(ULONG64), &Done) ||
  772. Done != sizeof(ULONG64)) {
  773. WDB(("Unable to read stack at %I64X\n",
  774. ContextRecord->Rsp));
  775. return FALSE;
  776. }
  777. ContextRecord->Rsp += 8;
  778. NextByte += 1;
  779. Bytes -= 1;
  780. } else if (Bytes >= 2 &&
  781. (NextByte[0] & 0xf8) == SIZE64_PREFIX &&
  782. (NextByte[1] & 0xf8) == POP_OP) {
  783. //
  784. // pop nonvolatile-integer-register[8..15]
  785. //
  786. RegisterNumber = ((NextByte[0] & 1) << 3) | (NextByte[1] & 0x7);
  787. if (!ReadMemory(Process, ContextRecord->Rsp,
  788. &IntegerRegister[RegisterNumber],
  789. sizeof(ULONG64), &Done) ||
  790. Done != sizeof(ULONG64)) {
  791. WDB(("Unable to read stack at %I64X\n",
  792. ContextRecord->Rsp));
  793. return FALSE;
  794. }
  795. ContextRecord->Rsp += 8;
  796. NextByte += 2;
  797. Bytes -= 2;
  798. } else {
  799. break;
  800. }
  801. }
  802. //
  803. // Emulate return and return null exception handler.
  804. //
  805. if (!ReadMemory(Process, ContextRecord->Rsp,
  806. &ContextRecord->Rip, sizeof(ULONG64),
  807. &Done) ||
  808. Done != sizeof(ULONG64)) {
  809. WDB(("Unable to read stack at %I64X\n",
  810. ContextRecord->Rsp));
  811. return FALSE;
  812. }
  813. ContextRecord->Rsp += 8;
  814. return TRUE;
  815. }
  816. //
  817. // Control left the specified function outside an epilogue. Unwind the
  818. // subject function and any chained unwind information.
  819. //
  820. return RtlpUnwindPrologueAmd64(ImageBase,
  821. ControlPc,
  822. *EstablisherFrame,
  823. FunctionEntry,
  824. ContextRecord,
  825. Process,
  826. ReadMemory);
  827. }
  828. BOOL
  829. WalkAmd64(
  830. HANDLE Process,
  831. LPSTACKFRAME64 StackFrame,
  832. PVOID ContextRecord,
  833. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  834. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  835. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  836. )
  837. {
  838. BOOL rval;
  839. PAMD64_CONTEXT Context = (PAMD64_CONTEXT)ContextRecord;
  840. #if 1
  841. WDB(("WalkAmd64 in: PC %I64X, SP %I64X, FP %I64X, RA %I64X\n",
  842. StackFrame->AddrPC.Offset,
  843. StackFrame->AddrStack.Offset,
  844. StackFrame->AddrFrame.Offset,
  845. StackFrame->AddrReturn.Offset));
  846. #endif
  847. if (StackFrame->Virtual) {
  848. rval = WalkAmd64Next( Process,
  849. StackFrame,
  850. Context,
  851. ReadMemory,
  852. FunctionTableAccess,
  853. GetModuleBase
  854. );
  855. } else {
  856. rval = WalkAmd64Init( Process,
  857. StackFrame,
  858. Context,
  859. ReadMemory,
  860. FunctionTableAccess,
  861. GetModuleBase
  862. );
  863. }
  864. #if 1
  865. WDB(("WalkAmd64 out: succ %d, PC %I64X, SP %I64X, FP %I64X, RA %I64X\n",
  866. rval,
  867. StackFrame->AddrPC.Offset,
  868. StackFrame->AddrStack.Offset,
  869. StackFrame->AddrFrame.Offset,
  870. StackFrame->AddrReturn.Offset));
  871. #endif
  872. return rval;
  873. }
  874. BOOL
  875. UnwindStackFrameAmd64(
  876. IN HANDLE Process,
  877. IN OUT PULONG64 ReturnAddress,
  878. IN OUT PULONG64 StackPointer,
  879. IN OUT PULONG64 FramePointer,
  880. IN PAMD64_CONTEXT Context, // Context members could be modified.
  881. IN PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  882. IN PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  883. IN PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  884. )
  885. {
  886. _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
  887. ULONG64 RetAddr;
  888. BOOL Succ = TRUE;
  889. FunctionEntry = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)
  890. FunctionTableAccess( Process, *ReturnAddress );
  891. if (FunctionEntry != NULL) {
  892. ULONG64 ImageBase;
  893. // Initialized to quiet a PREfix warning.
  894. ULONG64 EstablisherFrame = 0;
  895. //
  896. // The return value coming out of mainCRTStartup is set by some
  897. // run-time routine to be 0; this serves to cause an error if someone
  898. // actually does a return from the mainCRTStartup frame.
  899. //
  900. ImageBase = GetModuleBase(Process, *ReturnAddress);
  901. if (!RtlVirtualUnwindAmd64(ImageBase, *ReturnAddress, FunctionEntry,
  902. Context, &EstablisherFrame,
  903. Process, ReadMemory) ||
  904. Context->Rip == 0 ||
  905. (Context->Rip == *ReturnAddress &&
  906. EstablisherFrame == *FramePointer)) {
  907. Succ = FALSE;
  908. }
  909. *ReturnAddress = Context->Rip;
  910. *StackPointer = Context->Rsp;
  911. // The frame pointer is an artificial value set
  912. // to a pointer below the return address. This
  913. // matches an RBP-chain style of frame while
  914. // also allowing easy access to the return
  915. // address and homed arguments above it.
  916. *FramePointer = Context->Rsp - 2 * sizeof(ULONG64);
  917. } else {
  918. ULONG Done;
  919. // If there's no function entry for a function
  920. // we assume that it's a leaf and that ESP points
  921. // directly to the return address. There's no
  922. // stored frame pointer so we actually need to
  923. // set a virtual frame pointer deeper in the stack
  924. // so that arguments can correctly be read at
  925. // two ULONG64's up from it.
  926. *FramePointer = Context->Rsp - 8;
  927. *StackPointer = Context->Rsp + 8;
  928. Succ = ReadMemory(Process, Context->Rsp,
  929. ReturnAddress, sizeof(*ReturnAddress), &Done) &&
  930. Done == sizeof(*ReturnAddress);
  931. // Update the context values to what they should be in
  932. // the caller.
  933. if (Succ) {
  934. Context->Rsp += 8;
  935. Context->Rip = *ReturnAddress;
  936. }
  937. }
  938. if (Succ) {
  939. ULONG64 CallOffset;
  940. _PIMAGE_RUNTIME_FUNCTION_ENTRY CallFunc;
  941. //
  942. // Calls of __declspec(noreturn) functions may not have any
  943. // code after them to return to since the compiler knows
  944. // that the function will not return. This can confuse
  945. // stack traces because the return address will lie outside
  946. // of the function's address range and FPO data will not
  947. // be looked up correctly. Check and see if the return
  948. // address falls outside of the calling function and, if so,
  949. // adjust the return address back by one byte. It'd be
  950. // better to adjust it back to the call itself so that
  951. // the return address points to valid code but
  952. // backing up in X86 assembly is more or less impossible.
  953. //
  954. CallOffset = *ReturnAddress - 1;
  955. CallFunc = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)
  956. FunctionTableAccess(Process, CallOffset);
  957. if (CallFunc != NULL) {
  958. _IMAGE_RUNTIME_FUNCTION_ENTRY SaveCallFunc = *CallFunc;
  959. _PIMAGE_RUNTIME_FUNCTION_ENTRY RetFunc =
  960. (_PIMAGE_RUNTIME_FUNCTION_ENTRY)
  961. FunctionTableAccess(Process, *ReturnAddress);
  962. if (RetFunc == NULL ||
  963. memcmp(&SaveCallFunc, RetFunc, sizeof(SaveCallFunc))) {
  964. *ReturnAddress = CallOffset;
  965. }
  966. }
  967. }
  968. return Succ;
  969. }
  970. BOOL
  971. ReadFrameArgsAmd64(
  972. LPADDRESS64 FrameOffset,
  973. HANDLE Process,
  974. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  975. PULONG64 Args
  976. )
  977. {
  978. ULONG Done;
  979. if (!ReadMemory(Process, FrameOffset->Offset + 2 * sizeof(ULONG64),
  980. Args, 4 * sizeof(ULONG64), &Done)) {
  981. Done = 0;
  982. }
  983. ZeroMemory((PUCHAR)Args + Done, 4 * sizeof(ULONG64) - Done);
  984. return Done > 0;
  985. }
  986. BOOL
  987. WalkAmd64Init(
  988. HANDLE Process,
  989. LPSTACKFRAME64 StackFrame,
  990. PAMD64_CONTEXT Context,
  991. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  992. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  993. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  994. )
  995. {
  996. AMD64_CONTEXT ContextSave;
  997. DWORD64 PcOffset;
  998. DWORD64 StackOffset;
  999. DWORD64 FrameOffset;
  1000. ZeroMemory( &StackFrame->AddrBStore, sizeof(StackFrame->AddrBStore) );
  1001. StackFrame->FuncTableEntry = NULL;
  1002. ZeroMemory( StackFrame->Params, sizeof(StackFrame->Params) );
  1003. StackFrame->Far = FALSE;
  1004. StackFrame->Virtual = TRUE;
  1005. ZeroMemory( StackFrame->Reserved, sizeof(StackFrame->Reserved) );
  1006. if (!StackFrame->AddrPC.Offset) {
  1007. StackFrame->AddrPC.Offset = Context->Rip;
  1008. StackFrame->AddrPC.Mode = AddrModeFlat;
  1009. }
  1010. if (!StackFrame->AddrStack.Offset) {
  1011. StackFrame->AddrStack.Offset = Context->Rsp;
  1012. StackFrame->AddrStack.Mode = AddrModeFlat;
  1013. }
  1014. if (!StackFrame->AddrFrame.Offset) {
  1015. StackFrame->AddrFrame.Offset = Context->Rbp;
  1016. StackFrame->AddrFrame.Mode = AddrModeFlat;
  1017. }
  1018. if ((StackFrame->AddrPC.Mode != AddrModeFlat) ||
  1019. (StackFrame->AddrStack.Mode != AddrModeFlat) ||
  1020. (StackFrame->AddrFrame.Mode != AddrModeFlat)) {
  1021. return FALSE;
  1022. }
  1023. PcOffset = StackFrame->AddrPC.Offset;
  1024. StackOffset = StackFrame->AddrStack.Offset;
  1025. FrameOffset = StackFrame->AddrFrame.Offset;
  1026. ContextSave = *Context;
  1027. ContextSave.Rip = PcOffset;
  1028. ContextSave.Rsp = StackOffset;
  1029. ContextSave.Rbp = FrameOffset;
  1030. if (!UnwindStackFrameAmd64( Process,
  1031. &PcOffset,
  1032. &StackOffset,
  1033. &FrameOffset,
  1034. &ContextSave,
  1035. ReadMemory,
  1036. FunctionTableAccess,
  1037. GetModuleBase)) {
  1038. return FALSE;
  1039. }
  1040. StackFrame->AddrReturn.Offset = PcOffset;
  1041. StackFrame->AddrReturn.Mode = AddrModeFlat;
  1042. StackFrame->AddrFrame.Offset = FrameOffset;
  1043. ReadFrameArgsAmd64(&StackFrame->AddrFrame, Process,
  1044. ReadMemory, StackFrame->Params);
  1045. return TRUE;
  1046. }
  1047. BOOL
  1048. WalkAmd64Next(
  1049. HANDLE Process,
  1050. LPSTACKFRAME64 StackFrame,
  1051. PAMD64_CONTEXT Context,
  1052. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1053. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
  1054. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  1055. )
  1056. {
  1057. DWORD Done;
  1058. BOOL Succ = TRUE;
  1059. DWORD64 StackAddress;
  1060. _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
  1061. if (!UnwindStackFrameAmd64( Process,
  1062. &StackFrame->AddrPC.Offset,
  1063. &StackFrame->AddrStack.Offset,
  1064. &StackFrame->AddrFrame.Offset,
  1065. Context,
  1066. ReadMemory,
  1067. FunctionTableAccess,
  1068. GetModuleBase)) {
  1069. Succ = FALSE;
  1070. //
  1071. // If the frame could not be unwound or is terminal, see if
  1072. // there is a callback frame:
  1073. //
  1074. if (g.AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame)) {
  1075. DWORD64 ImageBase;
  1076. if (CALLBACK_STACK(StackFrame) & 0x80000000) {
  1077. //
  1078. // it is the pointer to the stack frame that we want
  1079. //
  1080. StackAddress = CALLBACK_STACK(StackFrame);
  1081. } else {
  1082. //
  1083. // if it is a positive integer, it is the offset to
  1084. // the address in the thread.
  1085. // Look up the pointer:
  1086. //
  1087. Succ = ReadMemory(Process,
  1088. (CALLBACK_THREAD(StackFrame) +
  1089. CALLBACK_STACK(StackFrame)),
  1090. &StackAddress,
  1091. sizeof(StackAddress),
  1092. &Done);
  1093. if (!Succ || Done != sizeof(StackAddress) ||
  1094. StackAddress == 0) {
  1095. StackAddress = (DWORD64)-1;
  1096. CALLBACK_STACK(StackFrame) = (DWORD)-1;
  1097. }
  1098. }
  1099. if ((StackAddress == (DWORD64)-1) ||
  1100. (!(FunctionEntry = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)
  1101. FunctionTableAccess(Process, CALLBACK_FUNC(StackFrame))) ||
  1102. !(ImageBase = GetModuleBase(Process,
  1103. CALLBACK_FUNC(StackFrame))))) {
  1104. Succ = FALSE;
  1105. } else {
  1106. if (!ReadMemory(Process,
  1107. (StackAddress + CALLBACK_NEXT(StackFrame)),
  1108. &CALLBACK_STACK(StackFrame),
  1109. sizeof(DWORD64),
  1110. &Done) ||
  1111. Done != sizeof(DWORD64)) {
  1112. Succ = FALSE;
  1113. } else {
  1114. StackFrame->AddrPC.Offset =
  1115. ImageBase + FunctionEntry->BeginAddress;
  1116. StackFrame->AddrStack.Offset = StackAddress;
  1117. Context->Rsp = StackAddress;
  1118. Succ = TRUE;
  1119. }
  1120. }
  1121. }
  1122. }
  1123. if (Succ) {
  1124. AMD64_CONTEXT ContextSave;
  1125. ULONG64 StackOffset = 0;
  1126. ULONG64 FrameOffset = 0;
  1127. //
  1128. // Get the return address.
  1129. //
  1130. ContextSave = *Context;
  1131. StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
  1132. if (!UnwindStackFrameAmd64( Process,
  1133. &StackFrame->AddrReturn.Offset,
  1134. &StackOffset,
  1135. &FrameOffset,
  1136. &ContextSave,
  1137. ReadMemory,
  1138. FunctionTableAccess,
  1139. GetModuleBase)) {
  1140. StackFrame->AddrReturn.Offset = 0;
  1141. }
  1142. StackFrame->AddrFrame.Offset = FrameOffset;
  1143. ReadFrameArgsAmd64(&StackFrame->AddrFrame, Process, ReadMemory,
  1144. StackFrame->Params);
  1145. }
  1146. return Succ;
  1147. }