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.

1699 lines
66 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. walkalpha.c
  5. Abstract:
  6. This file implements the ALPHA stack walking api.
  7. Author:
  8. Wesley Witt (wesw) 1-Oct-1993
  9. Environment:
  10. User Mode
  11. --*/
  12. #define _IMAGEHLP_SOURCE_
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include "private.h"
  17. #define NOEXTAPI
  18. #include "wdbgexts.h"
  19. #include "ntdbg.h"
  20. #include "symbols.h"
  21. #include "alphaops.h"
  22. #include <stdlib.h>
  23. #include <stddef.h>
  24. #include <globals.h>
  25. #include "fecache.hpp"
  26. #ifdef __cplusplus
  27. extern "C"
  28. #endif
  29. BOOL
  30. WalkAlphaInit(
  31. HANDLE hProcess,
  32. LPSTACKFRAME64 StackFrame,
  33. PALPHA_NT5_CONTEXT Context,
  34. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  35. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  36. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  37. BOOL Use64
  38. );
  39. BOOL
  40. WalkAlphaNext(
  41. HANDLE hProcess,
  42. LPSTACKFRAME64 StackFrame,
  43. PALPHA_NT5_CONTEXT Context,
  44. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  45. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  46. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  47. BOOL Use64
  48. );
  49. BOOL
  50. WalkAlphaGetStackFrame(
  51. HANDLE hProcess,
  52. PULONG64 ReturnAddress,
  53. PULONG64 FramePointer,
  54. PALPHA_NT5_CONTEXT Context,
  55. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  56. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  57. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  58. PKDHELP64 KdHelp,
  59. BOOL Use64
  60. );
  61. VOID
  62. GetUnwindFunctionEntry(
  63. HANDLE hProcess,
  64. ULONG64 ControlPc,
  65. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  66. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  67. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  68. BOOL Use64,
  69. FeCacheEntry* FunctionEntry,
  70. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY UnwindFunctionEntry,
  71. PULONG StackAdjust,
  72. PULONG64 FixedReturn
  73. );
  74. #define ZERO 0x0 /* integer register 0 */
  75. #define SP 0x1d /* integer register 29 */
  76. #define RA 0x1f /* integer register 31 */
  77. #define SAVED_FLOATING_MASK 0xfff00000 /* saved floating registers */
  78. #define SAVED_INTEGER_MASK 0xf3ffff02 /* saved integer registers */
  79. #define IS_FLOATING_SAVED(Register) ((SAVED_FLOATING_MASK >> Register) & 1L)
  80. #define IS_INTEGER_SAVED(Register) ((SAVED_INTEGER_MASK >> Register) & 1L)
  81. #define IS_HANDLER_DEFINED(FunctionEntry) \
  82. (RF_EXCEPTION_HANDLER(FunctionEntry) != 0)
  83. BOOL
  84. WalkAlpha(
  85. HANDLE hProcess,
  86. LPSTACKFRAME64 StackFrame,
  87. PVOID ContextRecord,
  88. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  89. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  90. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  91. BOOL Use64
  92. )
  93. {
  94. BOOL rval;
  95. PALPHA_NT5_CONTEXT Context = (PALPHA_NT5_CONTEXT)ContextRecord;
  96. if (StackFrame->Virtual) {
  97. rval = WalkAlphaNext( hProcess,
  98. StackFrame,
  99. Context,
  100. ReadMemory,
  101. GetModuleBase,
  102. GetFunctionEntry,
  103. Use64
  104. );
  105. } else {
  106. rval = WalkAlphaInit( hProcess,
  107. StackFrame,
  108. Context,
  109. ReadMemory,
  110. GetModuleBase,
  111. GetFunctionEntry,
  112. Use64
  113. );
  114. }
  115. return rval;
  116. }
  117. ULONG64
  118. VirtualUnwind (
  119. HANDLE hProcess,
  120. ULONG64 ControlPc,
  121. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY FunctionEntry,
  122. ULONG StackAdjust,
  123. ULONG64 FixedReturn,
  124. PALPHA_NT5_CONTEXT Context,
  125. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
  126. // PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
  127. )
  128. /*++
  129. Routine Description:
  130. This function virtually unwinds the specified function by executing its
  131. prologue code backwards. Given the current context and the instructions
  132. that preserve registers in the prologue, it is possible to recreate the
  133. nonvolatile context at the point the function was called.
  134. If the function is a leaf function, then the address where control left
  135. the previous frame is obtained from the context record. If the function
  136. is a nested function, but not an exception or interrupt frame, then the
  137. prologue code is executed backwards and the address where control left
  138. the previous frame is obtained from the updated context record.
  139. Otherwise, an exception or interrupt entry to the system is being unwound
  140. and a specially coded prologue restores the return address twice. Once
  141. from the fault instruction address and once from the saved return address
  142. register. The first restore is returned as the function value and the
  143. second restore is placed in the updated context record.
  144. During the unwind, the virtual and real frame pointers for the function
  145. are calculated and returned in the given frame pointers structure.
  146. If a context pointers record is specified, then the address where each
  147. register is restored from is recorded in the appropriate element of the
  148. context pointers record.
  149. Arguments:
  150. ControlPc - Supplies the address where control left the specified
  151. function.
  152. FunctionEntry - Supplies the address of the function table entry for the
  153. specified function.
  154. ContextRecord - Supplies the address of a context record.
  155. ContextPointers - Supplies an optional pointer to a context pointers
  156. record.
  157. Return Value:
  158. The address where control left the previous frame is returned as the
  159. function value.
  160. Implementation Notes:
  161. N.B. "where control left" is not the "return address" of the call in the
  162. previous frame. For normal frames, NextPc points to the last instruction
  163. that completed in the previous frame (the JSR/BSR). The difference between
  164. NextPc and NextPc + 4 (return address) is important for correct behavior
  165. in boundary cases of exception addresses and scope tables.
  166. For exception and interrupt frames, NextPc is obtained from the trap frame
  167. contination address (Fir). For faults and synchronous traps, NextPc is both
  168. the last instruction to execute in the previous frame and the next
  169. instruction to execute if the function were to return. For asynchronous
  170. traps, NextPc is the continuation address. It is the responsibility of the
  171. compiler to insert TRAPB instructions to insure asynchronous traps do not
  172. occur outside the scope from the instruction(s) that caused them.
  173. N.B. in this and other files where RtlVirtualUnwind is used, the variable
  174. named NextPc is perhaps more accurately, LastPc - the last PC value in
  175. the previous frame, or CallPc - the address of the call instruction, or
  176. ControlPc - the address where control left the previous frame. Instead
  177. think of NextPc as the next PC to use in another call to virtual unwind.
  178. The Alpha version of virtual unwind is similar in design, but slightly
  179. more complex than the Mips version. This is because Alpha compilers
  180. are given more flexibility to optimize generated code and instruction
  181. sequences, including within procedure prologues. And also because of
  182. compiler design issues, the function must manage both virtual and real
  183. frame pointers.
  184. Version Information: This version was taken from exdspatch.c@v37 (Feb 1993)
  185. --*/
  186. {
  187. ALPHA_INSTRUCTION FollowingInstruction;
  188. ALPHA_INSTRUCTION Instruction;
  189. ULONGLONG Address;
  190. ULONG DecrementOffset;
  191. ULONG DecrementRegister;
  192. PULONGLONG FloatingRegister;
  193. ULONG FrameSize;
  194. ULONG Function;
  195. PULONGLONG IntegerRegister;
  196. ULONG Literal8;
  197. ULONGLONG NextPc;
  198. LONG Offset16;
  199. ULONG Opcode;
  200. ULONG Ra;
  201. ULONG Rb;
  202. ULONG Rc;
  203. BOOLEAN RestoredRa;
  204. BOOLEAN RestoredSp;
  205. DWORD cb;
  206. PVOID Prolog;
  207. //
  208. // perf hack: fill cache with prolog
  209. // skip it if this is a secondary function entry
  210. //
  211. if (FunctionEntry &&
  212. (ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) > ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) &&
  213. (ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) < ALPHA_RF_END_ADDRESS(FunctionEntry)) ) {
  214. cb = (ULONG)(ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) - ALPHA_RF_BEGIN_ADDRESS(FunctionEntry));
  215. //
  216. // If the function is a leaf it doesn't have a prolog, skip this
  217. // optimization.
  218. //
  219. if (cb != 0) {
  220. Prolog = (PVOID) MemAlloc( cb );
  221. if (!ReadMemory( hProcess,
  222. ALPHA_RF_BEGIN_ADDRESS(FunctionEntry),
  223. Prolog,
  224. cb,
  225. &cb )) {
  226. return 0;
  227. }
  228. MemFree(Prolog);
  229. }
  230. }
  231. //
  232. // Set the base address of the integer and floating register arrays within
  233. // the context record. Each set of 32 registers is known to be contiguous.
  234. //
  235. // assuming that quad values are together in context.
  236. IntegerRegister = &Context->IntV0;
  237. FloatingRegister = &Context->FltF0;
  238. //
  239. // Handle the epilogue case where the next instruction is a return.
  240. //
  241. // Exception handlers cannot be called if the ControlPc is within the
  242. // epilogue because exception handlers expect to operate with a current
  243. // stack frame. The value of SP is not current within the epilogue.
  244. //
  245. if (!ReadMemory(hProcess, ControlPc, &Instruction.Long, 4, &cb)) {
  246. return(0);
  247. }
  248. if (IS_RETURN_0001_INSTRUCTION(Instruction.Long)) {
  249. Rb = Instruction.Jump.Rb;
  250. NextPc = IntegerRegister[Rb] - 4;
  251. //
  252. // The instruction at the point where control left the specified
  253. // function is a return, so any saved registers have already been
  254. // restored, and the stack pointer has already been adjusted. The
  255. // stack does not need to be unwound in this case and the saved
  256. // return address register is returned as the function value.
  257. //
  258. // In fact, reverse execution of the prologue is not possible in
  259. // this case: the stack pointer has already been incremented and
  260. // so, for this frame, neither a valid stack pointer nor frame
  261. // pointer exists from which to begin reverse execution of the
  262. // prologue. In addition, the integrity of any data on the stack
  263. // below the stack pointer is never guaranteed (due to interrupts
  264. // and exceptions).
  265. //
  266. // The epilogue instruction sequence is:
  267. //
  268. // ==> ret zero, (Ra), 1 // return
  269. // or
  270. //
  271. // mov ra, Rx // save return address
  272. // ...
  273. // ==> ret zero, (Rx), 1 // return
  274. //
  275. return NextPc;
  276. }
  277. //
  278. // Handle the epilogue case where the next two instructions are a stack
  279. // frame deallocation and a return.
  280. //
  281. if (!ReadMemory(hProcess,(ControlPc+4),&FollowingInstruction.Long,4,&cb)) {
  282. return 0;
  283. }
  284. if (IS_RETURN_0001_INSTRUCTION(FollowingInstruction.Long)) {
  285. Rb = FollowingInstruction.Jump.Rb;
  286. NextPc = IntegerRegister[Rb] - 4;
  287. //
  288. // The second instruction following the point where control
  289. // left the specified function is a return. If the instruction
  290. // before the return is a stack increment instruction, then all
  291. // saved registers have already been restored except for SP.
  292. // The value of the stack pointer register cannot be recovered
  293. // through reverse execution of the prologue because in order
  294. // to begin reverse execution either the stack pointer or the
  295. // frame pointer (if any) must still be valid.
  296. //
  297. // Instead, the effect that the stack increment instruction
  298. // would have had on the context is manually applied to the
  299. // current context. This is forward execution of the epilogue
  300. // rather than reverse execution of the prologue.
  301. //
  302. // In an epilogue, as in a prologue, the stack pointer is always
  303. // adjusted with a single instruction: either an immediate-value
  304. // (lda) or a register-value (addq) add instruction.
  305. //
  306. Function = Instruction.OpReg.Function;
  307. Offset16 = Instruction.Memory.MemDisp;
  308. Opcode = Instruction.OpReg.Opcode;
  309. Ra = Instruction.OpReg.Ra;
  310. Rb = Instruction.OpReg.Rb;
  311. Rc = Instruction.OpReg.Rc;
  312. if ((Opcode == LDA_OP) && (Ra == SP_REG)) {
  313. //
  314. // Load Address instruction.
  315. //
  316. // Since the destination (Ra) register is SP, an immediate-
  317. // value stack deallocation operation is being performed. The
  318. // displacement value should be added to SP. The displacement
  319. // value is assumed to be positive. The amount of stack
  320. // deallocation possible using this instruction ranges from
  321. // 16 to 32752 (32768 - 16) bytes. The base register (Rb) is
  322. // usually SP, but may be another register.
  323. //
  324. // The epilogue instruction sequence is:
  325. //
  326. // ==> lda sp, +N(sp) // deallocate stack frame
  327. // ret zero, (ra) // return
  328. // or
  329. //
  330. // ==> lda sp, +N(Rx) // restore SP and deallocate frame
  331. // ret zero, (ra) // return
  332. //
  333. Context->IntSp = Offset16 + IntegerRegister[Rb];
  334. return NextPc;
  335. } else if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC) &&
  336. (Rc == SP_REG) &&
  337. (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) {
  338. //
  339. // Add Quadword instruction.
  340. //
  341. // Since both source operands are registers, and the
  342. // destination register is SP, a register-value stack
  343. // deallocation is being performed. The value of the two
  344. // source registers should be added and this is the new
  345. // value of SP. One of the source registers is usually SP,
  346. // but may be another register.
  347. //
  348. // The epilogue instruction sequence is:
  349. //
  350. // ldiq Rx, N // set [large] frame size
  351. // ...
  352. // ==> addq sp, Rx, sp // deallocate stack frame
  353. // ret zero, (ra) // return
  354. // or
  355. //
  356. // ==> addq Rx, Ry, sp // restore SP and deallocate frame
  357. // ret zero, (ra) // return
  358. //
  359. Context->IntSp = IntegerRegister[Ra] + IntegerRegister[Rb];
  360. return NextPc;
  361. }
  362. }
  363. //
  364. // By default set the frame pointers to the current value of SP.
  365. //
  366. // When a procedure is called, the value of SP before the stack
  367. // allocation instruction is the virtual frame pointer. When reverse
  368. // executing instructions in the prologue, the value of SP before the
  369. // stack allocation instruction is encountered is the real frame
  370. // pointer. This is the current value of SP unless the procedure uses
  371. // a frame pointer (e.g., FP_REG).
  372. //
  373. //
  374. // If the address where control left the specified function is beyond
  375. // the end of the prologue, then the control PC is considered to be
  376. // within the function and the control address is set to the end of
  377. // the prologue. Otherwise, the control PC is not considered to be
  378. // within the function (i.e., the prologue).
  379. //
  380. // N.B. PrologEndAddress is equal to BeginAddress for a leaf function.
  381. //
  382. // The low-order two bits of PrologEndAddress are reserved for the IEEE
  383. // exception mode and so must be masked out.
  384. //
  385. if ((ControlPc < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
  386. (ControlPc >= ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry))) {
  387. ControlPc = ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry);
  388. }
  389. //
  390. // Scan backward through the prologue to reload callee saved registers
  391. // that were stored or copied and to increment the stack pointer if it
  392. // was decremented.
  393. //
  394. DecrementRegister = ZERO_REG;
  395. NextPc = Context->IntRa - 4;
  396. RestoredRa = FALSE;
  397. RestoredSp = FALSE;
  398. while (ControlPc > ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) {
  399. //
  400. // Get instruction value, decode fields, case on opcode value, and
  401. // reverse register store and stack decrement operations.
  402. // N.B. The location of Opcode, Ra, Rb, and Rc is the same across
  403. // all opcode formats. The same is not true for Function.
  404. //
  405. ControlPc -= 4;
  406. if (!ReadMemory(hProcess, ControlPc, &Instruction.Long, 4, &cb)) {
  407. return 0;
  408. }
  409. Function = Instruction.OpReg.Function;
  410. Literal8 = Instruction.OpLit.Literal;
  411. Offset16 = Instruction.Memory.MemDisp;
  412. Opcode = Instruction.OpReg.Opcode;
  413. Ra = Instruction.OpReg.Ra;
  414. Rb = Instruction.OpReg.Rb;
  415. Rc = Instruction.OpReg.Rc;
  416. //
  417. // Compare against each instruction type that will affect the context
  418. // and that is allowed in a prologue. Any other instructions found
  419. // in the prologue will be ignored since they are assumed to have no
  420. // effect on the context.
  421. //
  422. switch (Opcode) {
  423. case STQ_OP :
  424. //
  425. // Store Quad instruction.
  426. //
  427. // If the base register is SP, then reload the source register
  428. // value from the value stored on the stack.
  429. //
  430. // The prologue instruction sequence is:
  431. //
  432. // ==> stq Rx, N(sp) // save integer register Rx
  433. //
  434. if ((Rb == SP_REG) && (Ra != ZERO_REG)) {
  435. //
  436. // Reload the register by retrieving the value previously
  437. // stored on the stack.
  438. //
  439. Address = (Offset16 + Context->IntSp);
  440. if (!ReadMemory(hProcess, Address, &IntegerRegister[Ra], 8L, &cb)) {
  441. return 0;
  442. }
  443. //
  444. // If the destination register is RA and this is the first
  445. // time that RA is being restored, then set the address of
  446. // where control left the previous frame. Otherwise, if this
  447. // is the second time RA is being restored, then the first
  448. // one was an interrupt or exception address and the return
  449. // PC should not have been biased by 4.
  450. //
  451. if (Ra == RA_REG) {
  452. if (RestoredRa == FALSE) {
  453. NextPc = Context->IntRa - 4;
  454. RestoredRa = TRUE;
  455. } else {
  456. NextPc += 4;
  457. }
  458. //
  459. // Otherwise, if the destination register is SP and this is
  460. // the first time that SP is being restored, then set the
  461. // establisher frame pointers.
  462. //
  463. } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) {
  464. RestoredSp = TRUE;
  465. }
  466. //
  467. // If a context pointer record is specified, then record
  468. // the address where the destination register contents
  469. // are stored.
  470. //
  471. //if (ContextPointers != (PKNONVOLATILE_CONTEXT_POINTERS) NULL) {
  472. // ContextPointers->IntegerContext[Ra] = (PULONGLONG)Address;
  473. //}
  474. }
  475. break;
  476. case LDAH_OP :
  477. Offset16 <<= 16;
  478. case LDA_OP :
  479. //
  480. // Load Address High, Load Address instruction.
  481. //
  482. // There are several cases where the lda and/or ldah instructions
  483. // are used: one to decrement the stack pointer directly, and the
  484. // others to load immediate values into another register and that
  485. // register is then used to decrement the stack pointer.
  486. //
  487. // In the examples below, as a single instructions or as a pair,
  488. // a lda may be substituted for a ldah and visa-versa.
  489. //
  490. if (Ra == SP_REG) {
  491. if (Rb == SP_REG) {
  492. //
  493. // If both the destination (Ra) and base (Rb) registers
  494. // are SP, then a standard stack allocation was performed
  495. // and the negated displacement value is the stack frame
  496. // size. The amount of stack allocation possible using
  497. // the lda instruction ranges from 16 to 32768 bytes and
  498. // the amount of stack allocation possible using the ldah
  499. // instruction ranges from 65536 to 2GB in multiples of
  500. // 65536 bytes. It is rare for the ldah instruction to be
  501. // used in this manner.
  502. //
  503. // The prologue instruction sequence is:
  504. //
  505. // ==> lda sp, -N(sp) // allocate stack frame
  506. //
  507. FrameSize = -Offset16;
  508. goto StackAllocation;
  509. } else {
  510. //
  511. // The destination register is SP and the base register
  512. // is not SP, so this instruction must be the second
  513. // half of an instruction pair to allocate a large size
  514. // (>32768 bytes) stack frame. Save the displacement value
  515. // as the partial decrement value and postpone adjusting
  516. // the value of SP until the first instruction of the pair
  517. // is encountered.
  518. //
  519. // The prologue instruction sequence is:
  520. //
  521. // ldah Rx, -N(sp) // prepare new SP (upper)
  522. // ==> lda sp, sN(Rx) // allocate stack frame
  523. //
  524. DecrementRegister = Rb;
  525. DecrementOffset = Offset16;
  526. }
  527. } else if (Ra == DecrementRegister) {
  528. if (Rb == DecrementRegister) {
  529. //
  530. // Both the destination and base registers are the
  531. // decrement register, so this instruction exists as the
  532. // second half of a two instruction pair to load a
  533. // 31-bit immediate value into the decrement register.
  534. // Save the displacement value as the partial decrement
  535. // value.
  536. //
  537. // The prologue instruction sequence is:
  538. //
  539. // ldah Rx, +N(zero) // set frame size (upper)
  540. // ==> lda Rx, sN(Rx) // set frame size (+lower)
  541. // ...
  542. // subq sp, Rx, sp // allocate stack frame
  543. //
  544. DecrementOffset += Offset16;
  545. } else if (Rb == ZERO_REG) {
  546. //
  547. // The destination register is the decrement register and
  548. // the base register is zero, so this instruction exists
  549. // to load an immediate value into the decrement register.
  550. // The stack frame size is the new displacement value added
  551. // to the previous displacement value, if any.
  552. //
  553. // The prologue instruction sequence is:
  554. //
  555. // ==> lda Rx, +N(zero) // set frame size
  556. // ...
  557. // subq sp, Rx, sp // allocate stack frame
  558. // or
  559. //
  560. // ==> ldah Rx, +N(zero) // set frame size (upper)
  561. // lda Rx, sN(Rx) // set frame size (+lower)
  562. // ...
  563. // subq sp, Rx, sp // allocate stack frame
  564. //
  565. FrameSize = (Offset16 + DecrementOffset);
  566. goto StackAllocation;
  567. } else if (Rb == SP_REG) {
  568. //
  569. // The destination (Ra) register is SP and the base (Rb)
  570. // register is the decrement register, so a two
  571. // instruction, large size (>32768 bytes) stack frame
  572. // allocation was performed. Add the new displacement
  573. // value to the previous displacement value. The negated
  574. // displacement value is the stack frame size.
  575. //
  576. // The prologue instruction sequence is:
  577. //
  578. // ==> ldah Rx, -N(sp) // prepare new SP (upper)
  579. // lda sp, sN(Rx) // allocate stack frame
  580. //
  581. FrameSize = -(Offset16 + (LONG)DecrementOffset);
  582. goto StackAllocation;
  583. }
  584. }
  585. break;
  586. case ARITH_OP :
  587. if ((Function == ADDQ_FUNC) &&
  588. (Instruction.OpReg.RbvType != RBV_REGISTER_FORMAT)) {
  589. //
  590. // Add Quadword (immediate) instruction.
  591. //
  592. // If the first source register is zero, and the second
  593. // operand is a literal, and the destination register is
  594. // the decrement register, then the instruction exists
  595. // to load an unsigned immediate value less than 256 into
  596. // the decrement register. The immediate value is the stack
  597. // frame size.
  598. //
  599. // The prologue instruction sequence is:
  600. //
  601. // ==> addq zero, N, Rx // set frame size
  602. // ...
  603. // subq sp, Rx, sp // allocate stack frame
  604. //
  605. if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) {
  606. FrameSize = Literal8;
  607. goto StackAllocation;
  608. }
  609. } else if ((Function == SUBQ_FUNC) &&
  610. (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) {
  611. //
  612. // Subtract Quadword (register) instruction.
  613. //
  614. // If both source operands are registers and the first
  615. // source (minuend) register and the destination
  616. // (difference) register are both SP, then a register value
  617. // stack allocation was performed and the second source
  618. // (subtrahend) register value will be added to SP when its
  619. // value is known. Until that time save the register number of
  620. // this decrement register.
  621. //
  622. // The prologue instruction sequence is:
  623. //
  624. // ldiq Rx, N // set frame size
  625. // ...
  626. // ==> subq sp, Rx, sp // allocate stack frame
  627. //
  628. if ((Ra == SP_REG) && (Rc == SP_REG)) {
  629. DecrementRegister = Rb;
  630. DecrementOffset = 0;
  631. }
  632. }
  633. break;
  634. case BIT_OP :
  635. //
  636. // If the second operand is a register the bit set instruction
  637. // may be a register move instruction, otherwise if the second
  638. // operand is a literal, the bit set instruction may be a load
  639. // immediate value instruction.
  640. //
  641. if ((Function == BIS_FUNC) && (Rc != ZERO_REG)) {
  642. if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) {
  643. //
  644. // Bit Set (register move) instruction.
  645. //
  646. // If both source registers are the same register, or
  647. // one of the source registers is zero, then this is a
  648. // register move operation. Restore the value of the
  649. // source register by copying the current destination
  650. // register value back to the source register.
  651. //
  652. // The prologue instruction sequence is:
  653. //
  654. // ==> bis Rx, Rx, Ry // copy register Rx
  655. // or
  656. //
  657. // ==> bis Rx, zero, Ry // copy register Rx
  658. // or
  659. //
  660. // ==> bis zero, Rx, Ry // copy register Rx
  661. //
  662. if (Ra == ZERO_REG) {
  663. //
  664. // Map the third case above to the first case.
  665. //
  666. Ra = Rb;
  667. } else if (Rb == ZERO_REG) {
  668. //
  669. // Map the second case above to the first case.
  670. //
  671. Rb = Ra;
  672. }
  673. if ((Ra == Rb) && (Ra != ZERO_REG)) {
  674. IntegerRegister[Ra] = IntegerRegister[Rc];
  675. //
  676. // If the destination register is RA and this is the
  677. // first time that RA is being restored, then set the
  678. // address of where control left the previous frame.
  679. // Otherwise, if this is the second time RA is being
  680. // restored, then the first one was an interrupt or
  681. // exception address and the return PC should not
  682. // have been biased by 4.
  683. //
  684. if (Ra == RA_REG) {
  685. if (RestoredRa == FALSE) {
  686. NextPc = Context->IntRa - 4;
  687. RestoredRa = TRUE;
  688. } else {
  689. NextPc += 4;
  690. }
  691. }
  692. //
  693. // If the source register is SP and this is the first
  694. // time SP is set, then this is a frame pointer set
  695. // instruction. Reset the frame pointers to this new
  696. // value of SP.
  697. //
  698. if ((Ra == SP_REG) && (RestoredSp == FALSE)) {
  699. RestoredSp = TRUE;
  700. }
  701. }
  702. } else {
  703. //
  704. // Bit Set (load immediate) instruction.
  705. //
  706. // If the first source register is zero, and the second
  707. // operand is a literal, and the destination register is
  708. // the decrement register, then this instruction exists
  709. // to load an unsigned immediate value less than 256 into
  710. // the decrement register. The decrement register value is
  711. // the stack frame size.
  712. //
  713. // The prologue instruction sequence is:
  714. //
  715. // ==> bis zero, N, Rx // set frame size
  716. // ...
  717. // subq sp, Rx, sp // allocate stack frame
  718. //
  719. if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) {
  720. FrameSize = Literal8;
  721. StackAllocation:
  722. //
  723. // Add the frame size to SP to reverse the stack frame
  724. // allocation, leave the real frame pointer as is, set
  725. // the virtual frame pointer with the updated SP value,
  726. // and clear the decrement register.
  727. //
  728. Context->IntSp += FrameSize;
  729. DecrementRegister = ZERO_REG;
  730. }
  731. }
  732. }
  733. break;
  734. case STT_OP :
  735. //
  736. // Store T-Floating (quadword integer) instruction.
  737. //
  738. // If the base register is SP, then reload the source register
  739. // value from the value stored on the stack.
  740. //
  741. // The prologue instruction sequence is:
  742. //
  743. // ==> stt Fx, N(sp) // save floating register Fx
  744. //
  745. if ((Rb == SP_REG) && (Ra != FZERO_REG)) {
  746. //
  747. // Reload the register by retrieving the value previously
  748. // stored on the stack.
  749. //
  750. Address = (Offset16 + Context->IntSp);
  751. if (!ReadMemory(hProcess, Address, &FloatingRegister[Ra], 8L, &cb)) {
  752. return 0;
  753. }
  754. //
  755. // If a context pointer record is specified, then record
  756. // the address where the destination register contents are
  757. // stored.
  758. //
  759. //if (ContextPointers != (PKNONVOLATILE_CONTEXT_POINTERS) NULL) {
  760. // ContextPointers->FloatingContext[Ra] = (PULONGLONG)Address;
  761. //}
  762. }
  763. break;
  764. case STS_OP :
  765. //
  766. // Store T-Floating (dword integer) instruction.
  767. //
  768. // If the base register is SP, then reload the source register
  769. // value from the value stored on the stack.
  770. //
  771. // The prologue instruction sequence is:
  772. //
  773. // ==> stt Fx, N(sp) // save floating register Fx
  774. //
  775. if ((Rb == SP_REG) && (Ra != FZERO_REG)) {
  776. //
  777. // Reload the register by retrieving the value previously
  778. // stored on the stack.
  779. //
  780. float f;
  781. Address = (Offset16 + Context->IntSp);
  782. if (!ReadMemory(hProcess, Address, &f, sizeof(float), &cb)) {
  783. return 0;
  784. }
  785. //
  786. // value was stored as a float. Do a conversion to a
  787. // double, since registers are Always read as doubles
  788. //
  789. FloatingRegister[Ra] = (ULONGLONG)(double)f;
  790. //
  791. // If a context pointer record is specified, then record
  792. // the address where the destination register contents are
  793. // stored.
  794. //
  795. //if (ContextPointers != (PKNONVOLATILE_CONTEXT_POINTERS) NULL) {
  796. // ContextPointers->FloatingContext[Ra] = (PULONGLONG)Address;
  797. //}
  798. }
  799. break;
  800. case FPOP_OP :
  801. //
  802. // N.B. The floating operate function field is not the same as
  803. // the integer operate nor the jump function fields.
  804. //
  805. if (Instruction.FpOp.Function == CPYS_FUNC) {
  806. //
  807. // Copy Sign (floating-point move) instruction.
  808. //
  809. // If both source registers are the same register, then this is
  810. // a floating-point register move operation. Restore the value
  811. // of the source register by copying the current destination
  812. // register value to the source register.
  813. //
  814. // The prologue instruction sequence is:
  815. //
  816. // ==> cpys Fx, Fx, Fy // copy floating register Fx
  817. //
  818. if ((Ra == Rb) && (Ra != FZERO_REG)) {
  819. FloatingRegister[Ra] = FloatingRegister[Rc];
  820. }
  821. }
  822. default :
  823. break;
  824. }
  825. }
  826. if (StackAdjust) {
  827. // Check for exlicit stack adjust amount
  828. Context->IntSp += StackAdjust;
  829. }
  830. if (FixedReturn != 0) {
  831. NextPc = FixedReturn;
  832. }
  833. return NextPc;
  834. }
  835. BOOL
  836. WalkAlphaGetStackFrame(
  837. HANDLE hProcess,
  838. PULONG64 ReturnAddress,
  839. PULONG64 FramePointer,
  840. PALPHA_NT5_CONTEXT Context,
  841. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  842. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  843. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  844. PKDHELP64 KdHelp,
  845. BOOL Use64
  846. )
  847. {
  848. FeCacheEntry* CacheEntry;
  849. FeCacheEntry UnwindFunctionEntry;
  850. ULONG64 NextPc = Context->IntRa;
  851. BOOL rval = TRUE;
  852. ULONG cb;
  853. ULONG StackAdjust;
  854. ULONG64 FixedReturn;
  855. if (*ReturnAddress == 0) {
  856. return FALSE;
  857. }
  858. __try {
  859. FunctionEntryCache* Cache =
  860. GetFeCache(Use64 ?
  861. IMAGE_FILE_MACHINE_ALPHA64 : IMAGE_FILE_MACHINE_ALPHA,
  862. TRUE);
  863. if (Cache != NULL) {
  864. CacheEntry = Cache->Find(hProcess, *ReturnAddress, ReadMemory,
  865. GetModuleBase, GetFunctionEntry);
  866. } else {
  867. CacheEntry = NULL;
  868. }
  869. if (CacheEntry != NULL) {
  870. // Construct a function entry suitable for unwinding from ControlPc
  871. UnwindFunctionEntry.Address = 0;
  872. UnwindFunctionEntry.Process = 0;
  873. GetUnwindFunctionEntry( hProcess, *ReturnAddress, ReadMemory, GetModuleBase, GetFunctionEntry, Use64, CacheEntry,
  874. &UnwindFunctionEntry.Data.Axp64, &StackAdjust, &FixedReturn );
  875. FE_SET_DESC(&UnwindFunctionEntry, "from UnwindFunctionEntry");
  876. FE_ShowRuntimeFunctionAxp64((&UnwindFunctionEntry,
  877. "VirtualUnwind: unwind function entry"));
  878. #if DBG
  879. if (tlsvar(DebugFunctionEntries)) {
  880. dbPrint(" FixedReturn = %16.8I64x\n", FixedReturn );
  881. dbPrint(" StackAdjust = %16x\n", StackAdjust );
  882. }
  883. #endif
  884. NextPc = VirtualUnwind( hProcess, *ReturnAddress, &UnwindFunctionEntry.Data.Axp64, StackAdjust, FixedReturn, Context, ReadMemory);
  885. #if DBG
  886. if (tlsvar(DebugFunctionEntries)) {
  887. dbPrint("NextPc = %.8I64x\n", NextPc );
  888. }
  889. #endif
  890. if (!NextPc) {
  891. rval = FALSE;
  892. }
  893. //
  894. // The Ra value coming out of mainCRTStartup is set by some RTL
  895. // routines to be "1"; return out of mainCRTStartup is actually
  896. // done through Jump/Unwind, so this serves to cause an error if
  897. // someone actually does a return. That's why we check here for
  898. // NextPc == 1 - this happens when in the frame for CRTStartup.
  899. //
  900. // We test for (0-4) and (1-4) because on ALPHA, the value returned by
  901. // VirtualUnwind is the value to be passed to the next call to
  902. // VirtualUnwind, which is NOT the same as the Ra - it's sometimes
  903. // decremented by four - this gives the faulting instruction -
  904. // in particular, we want the fault instruction so we can get the
  905. // correct scope in the case of an exception.
  906. //
  907. if ((NextPc == 1) || (NextPc == 4) || (NextPc == (0-4)) || (NextPc == (1-4)) ) {
  908. NextPc = 0;
  909. }
  910. if ( !NextPc || (NextPc == *ReturnAddress && *FramePointer == Context->IntSp) ) {
  911. rval = FALSE;
  912. }
  913. *ReturnAddress = NextPc;
  914. *FramePointer = Context->IntSp;
  915. } else {
  916. if ( (NextPc == *ReturnAddress && *FramePointer == Context->IntSp) ||
  917. (NextPc == 1) || (NextPc == 0) || (NextPc == (-4)) ) {
  918. rval = FALSE;
  919. }
  920. *ReturnAddress = Context->IntRa;
  921. *FramePointer = Context->IntSp;
  922. }
  923. } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  924. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  925. rval = FALSE;
  926. }
  927. return rval;
  928. }
  929. BOOL
  930. WalkAlphaInit(
  931. HANDLE hProcess,
  932. LPSTACKFRAME64 StackFrame,
  933. PALPHA_NT5_CONTEXT Context,
  934. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  935. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  936. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  937. BOOL Use64
  938. )
  939. {
  940. ALPHA_NT5_CONTEXT ContextSave;
  941. ULONG64 PcOffset;
  942. ULONG64 FrameOffset;
  943. DWORD cb;
  944. ALPHA_KEXCEPTION_FRAME ExceptionFrame;
  945. PALPHA_KEXCEPTION_FRAME pef = &ExceptionFrame;
  946. DWORD Result;
  947. if (StackFrame->AddrFrame.Offset) {
  948. #if 0
  949. if (ReadMemory( hProcess,
  950. StackFrame->AddrFrame.Offset,
  951. &ExceptionFrame,
  952. sizeof(ALPHA_KEXCEPTION_FRAME),
  953. &cb )) {
  954. //
  955. // successfully read an exception frame from the stack
  956. //
  957. Context->IntSp = StackFrame->AddrFrame.Offset;
  958. Context->Fir = pef->SwapReturn;
  959. Context->IntRa = pef->SwapReturn;
  960. Context->IntS0 = pef->IntS0;
  961. Context->IntS1 = pef->IntS1;
  962. Context->IntS2 = pef->IntS2;
  963. Context->IntS3 = pef->IntS3;
  964. Context->IntS4 = pef->IntS4;
  965. Context->IntS5 = pef->IntS5;
  966. Context->Psr = pef->Psr;
  967. } else {
  968. return FALSE;
  969. }
  970. #endif
  971. }
  972. ZeroMemory( StackFrame, FIELD_OFFSET( STACKFRAME64, KdHelp.ThCallbackBStore) );
  973. StackFrame->Virtual = TRUE;
  974. StackFrame->AddrPC.Offset = Context->Fir;
  975. StackFrame->AddrPC.Mode = AddrModeFlat;
  976. StackFrame->AddrFrame.Offset = Context->IntSp;
  977. StackFrame->AddrFrame.Mode = AddrModeFlat;
  978. ContextSave = *Context;
  979. PcOffset = StackFrame->AddrPC.Offset;
  980. FrameOffset = StackFrame->AddrFrame.Offset;
  981. if (!WalkAlphaGetStackFrame( hProcess,
  982. &PcOffset,
  983. &FrameOffset,
  984. &ContextSave,
  985. ReadMemory,
  986. GetModuleBase,
  987. GetFunctionEntry,
  988. &StackFrame->KdHelp,
  989. Use64) ) {
  990. StackFrame->AddrReturn.Offset = Context->IntRa;
  991. } else {
  992. StackFrame->AddrReturn.Offset = PcOffset;
  993. }
  994. StackFrame->AddrReturn.Mode = AddrModeFlat;
  995. //
  996. // get the arguments to the function
  997. //
  998. StackFrame->Params[0] = Context->IntA0;
  999. StackFrame->Params[1] = Context->IntA1;
  1000. StackFrame->Params[2] = Context->IntA2;
  1001. StackFrame->Params[3] = Context->IntA3;
  1002. return TRUE;
  1003. }
  1004. BOOL
  1005. WalkAlphaNext(
  1006. HANDLE hProcess,
  1007. LPSTACKFRAME64 StackFrame,
  1008. PALPHA_NT5_CONTEXT Context,
  1009. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1010. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1011. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  1012. BOOL Use64
  1013. )
  1014. {
  1015. DWORD cb;
  1016. ALPHA_NT5_CONTEXT ContextSave;
  1017. BOOL rval = TRUE;
  1018. ULONG64 Address;
  1019. FunctionEntryCache* Cache;
  1020. FeCacheEntry* CacheEntry;
  1021. ULONG64 SystemRangeStart;
  1022. DWORD dw;
  1023. ULONG64 qw;
  1024. if (!WalkAlphaGetStackFrame( hProcess,
  1025. &StackFrame->AddrPC.Offset,
  1026. &StackFrame->AddrFrame.Offset,
  1027. Context,
  1028. ReadMemory,
  1029. GetModuleBase,
  1030. GetFunctionEntry,
  1031. &StackFrame->KdHelp,
  1032. Use64) ) {
  1033. rval = FALSE;
  1034. //
  1035. // If the frame could not be unwound or is terminal, see if
  1036. // there is a callback frame:
  1037. //
  1038. if (g.AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame)) {
  1039. if (g.AppVersion.Revision >= 6) {
  1040. SystemRangeStart = SYSTEM_RANGE_START(StackFrame);
  1041. } else {
  1042. //
  1043. // This might not really work right with old debuggers, but it keeps
  1044. // us from looking off the end of the structure anyway.
  1045. //
  1046. SystemRangeStart = 0x80000000;
  1047. }
  1048. if (CALLBACK_STACK(StackFrame) >= SystemRangeStart) {
  1049. //
  1050. // it is the pointer to the stack frame that we want,
  1051. // or -1.
  1052. Address = CALLBACK_STACK(StackFrame);
  1053. } else {
  1054. //
  1055. // if it is a positive integer, it is the offset to
  1056. // the address in the thread.
  1057. // Look up the pointer:
  1058. //
  1059. if (Use64) {
  1060. rval = ReadMemory(hProcess,
  1061. (CALLBACK_THREAD(StackFrame) +
  1062. CALLBACK_STACK(StackFrame)),
  1063. &Address,
  1064. sizeof(ULONG64),
  1065. &cb);
  1066. } else {
  1067. rval = ReadMemory(hProcess,
  1068. (CALLBACK_THREAD(StackFrame) +
  1069. CALLBACK_STACK(StackFrame)),
  1070. &dw,
  1071. sizeof(DWORD),
  1072. &cb);
  1073. Address = (ULONG64)(LONG64)(LONG)dw;
  1074. }
  1075. if (!rval || Address == 0) {
  1076. Address = (ULONG64)-1;
  1077. CALLBACK_STACK(StackFrame) = (DWORD)-1;
  1078. }
  1079. }
  1080. if ( (Address == (ULONG64)-1) ||
  1081. (Cache = GetFeCache(Use64 ?
  1082. IMAGE_FILE_MACHINE_ALPHA64 :
  1083. IMAGE_FILE_MACHINE_ALPHA,
  1084. TRUE)) == NULL ||
  1085. (CacheEntry = Cache->Find(hProcess, CALLBACK_FUNC(StackFrame),
  1086. ReadMemory, GetModuleBase,
  1087. GetFunctionEntry)) == NULL ) {
  1088. rval = FALSE;
  1089. } else {
  1090. if (Use64) {
  1091. ReadMemory(hProcess,
  1092. (Address + CALLBACK_NEXT(StackFrame)),
  1093. &CALLBACK_STACK(StackFrame),
  1094. sizeof(ULONG64),
  1095. &cb);
  1096. StackFrame->AddrPC.Offset = ALPHA_RF_PROLOG_END_ADDRESS(&CacheEntry->Data.Axp64);
  1097. } else {
  1098. ReadMemory(hProcess,
  1099. (Address + CALLBACK_NEXT(StackFrame)),
  1100. &dw,
  1101. sizeof(DWORD),
  1102. &cb);
  1103. CALLBACK_STACK(StackFrame) = dw;
  1104. StackFrame->AddrPC.Offset = ALPHA_RF_PROLOG_END_ADDRESS((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)&CacheEntry->Data.Axp64);
  1105. }
  1106. StackFrame->AddrFrame.Offset = Address;
  1107. Context->IntSp = Address;
  1108. rval = TRUE;
  1109. }
  1110. }
  1111. }
  1112. //
  1113. // get the return address
  1114. //
  1115. ContextSave = *Context;
  1116. StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
  1117. qw = 0;
  1118. if (!WalkAlphaGetStackFrame( hProcess,
  1119. &StackFrame->AddrReturn.Offset,
  1120. &qw,
  1121. &ContextSave,
  1122. ReadMemory,
  1123. GetModuleBase,
  1124. GetFunctionEntry,
  1125. &StackFrame->KdHelp,
  1126. Use64) ) {
  1127. StackFrame->AddrReturn.Offset = 0;
  1128. }
  1129. //
  1130. // get the arguments to the function
  1131. //
  1132. StackFrame->Params[0] = ContextSave.IntA0;
  1133. StackFrame->Params[1] = ContextSave.IntA1;
  1134. StackFrame->Params[2] = ContextSave.IntA2;
  1135. StackFrame->Params[3] = ContextSave.IntA3;
  1136. return rval;
  1137. }
  1138. VOID
  1139. GetUnwindFunctionEntry(
  1140. HANDLE hProcess,
  1141. ULONG64 ControlPc,
  1142. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  1143. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  1144. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  1145. BOOL Use64,
  1146. FeCacheEntry* CacheEntry,
  1147. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY UnwindFunctionEntry,
  1148. PULONG StackAdjust,
  1149. PULONG64 FixedReturn
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. This function returns a function entry (RUNTIME_FUNCTION) suitable
  1154. for unwinding from ControlPc. It encapsulates the handling of primary
  1155. and secondary function entries so that this processing is not duplicated
  1156. in VirtualUnwind and other similar functions.
  1157. Arguments:
  1158. ControlPc - Supplies the address where control left the specified
  1159. function.
  1160. FunctionEntry - Supplies the address of the function table entry for the
  1161. specified function.
  1162. UnwindFunctionEntry - Supplies the address of a function table entry which
  1163. will be setup with appropriate fields for unwinding from ControlPc
  1164. Return Value:
  1165. None.
  1166. --*/
  1167. {
  1168. ULONG EntryType = 0;
  1169. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY SecondaryFunctionEntry = NULL;
  1170. ULONG64 AlternateProlog;
  1171. FeCacheEntry LocalCache;
  1172. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY FunctionEntry;
  1173. FunctionEntryCache* Cache;
  1174. FeCacheEntry* SecCache;
  1175. *FixedReturn = 0;
  1176. *StackAdjust = 0;
  1177. #if DBG
  1178. if (ControlPc & 0x3) {
  1179. dbPrint("GetUnwindFunctionEntry: invalid PC for unwinding (low bits set): %16.8I64x\n", ControlPc);
  1180. }
  1181. #endif
  1182. Cache = GetFeCache(Use64 ?
  1183. IMAGE_FILE_MACHINE_ALPHA64 : IMAGE_FILE_MACHINE_ALPHA,
  1184. TRUE);
  1185. // CacheEntry should never be null, but if it is create one that
  1186. // looks like a leaf entry for ControlPc
  1187. if (Cache == NULL || CacheEntry == NULL) {
  1188. #if DBG
  1189. dbPrint("\nGetUnwindFunctionEntry: Null function table entry for unwinding\n");
  1190. #endif
  1191. UnwindFunctionEntry->BeginAddress = ControlPc;
  1192. UnwindFunctionEntry->EndAddress = ControlPc+4;
  1193. UnwindFunctionEntry->ExceptionHandler = 0;
  1194. UnwindFunctionEntry->HandlerData = 0;
  1195. UnwindFunctionEntry->PrologEndAddress = ControlPc;
  1196. return;
  1197. }
  1198. // Work off a local copy of the function entry passed in
  1199. // as later function entry lookups may cause it to be
  1200. // evicted from the cache, invalidating the pointer.
  1201. LocalCache = *CacheEntry;
  1202. CacheEntry = &LocalCache;
  1203. FunctionEntry = &CacheEntry->Data.Axp64;
  1204. //
  1205. // Because of the secondary-to-primary function entry indirection applied by
  1206. // Find() ControlPc may not be within the range described
  1207. // by the supplied function entry. Call FindDirect()
  1208. // to recover the actual (secondary) function entry. If we don't get a
  1209. // valid associated function entry then process the unwind with the one
  1210. // supplied, trusting that the caller has supplied the given entry intentionally.
  1211. //
  1212. // A secondary function entry is a RUNTIME_FUNCTION entry where
  1213. // PrologEndAddress is not in the range of BeginAddress to EndAddress.
  1214. // There are three types of secondary function entries. They are
  1215. // distinquished by the Entry Type field (2 bits):
  1216. //
  1217. // ALPHA_RF_NOT_CONTIGUOUS - discontiguous code
  1218. // ALPHA_RF_ALT_ENT_PROLOG - alternate entry point prologue
  1219. // ALPHA_RF_NULL_CONTEXT - null-context code
  1220. //
  1221. if ((ControlPc < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
  1222. (ControlPc >= ALPHA_RF_END_ADDRESS(FunctionEntry))) {
  1223. // ControlPC is not in the range of the supplied function entry.
  1224. // Get the actual function entry which is expected to be the
  1225. // associated secondary function entry or a fixed return primary function.
  1226. #if DBG
  1227. if (tlsvar(DebugFunctionEntries)) {
  1228. dbPrint("\nGetUnwindFunctionEntry:LookupDirectFunctionEntry(ControlPc=%.8I64x,Use64=%d)\n", ControlPc, Use64 );
  1229. }
  1230. #endif
  1231. SecCache = Cache->
  1232. FindDirect( hProcess, ControlPc, ReadMemory, GetModuleBase,
  1233. GetFunctionEntry );
  1234. if (SecCache != NULL) {
  1235. SecondaryFunctionEntry = &SecCache->Data.Axp64;
  1236. } else {
  1237. SecondaryFunctionEntry = NULL;
  1238. }
  1239. if (SecondaryFunctionEntry) {
  1240. FE_ShowRuntimeFunctionAxp64((SecCache, "GetUnwindFunctionEntry: LookupDirectFunctionEntry"));
  1241. // If this is a null-context tail region then unwind with a null-context-like descriptor
  1242. if ((ControlPc >= ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry)-(ALPHA_RF_NULL_CONTEXT_COUNT(SecondaryFunctionEntry)*4)) &&
  1243. (ControlPc < ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry))) {
  1244. // Use the secondary function entry with PrologEndAddress = BeginAddress.
  1245. // This ensures that the prologue is not reverse executed.
  1246. UnwindFunctionEntry->BeginAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1247. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry);
  1248. UnwindFunctionEntry->ExceptionHandler = 0;
  1249. UnwindFunctionEntry->HandlerData = 0;
  1250. UnwindFunctionEntry->PrologEndAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1251. return;
  1252. }
  1253. if ((SecondaryFunctionEntry->PrologEndAddress < ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) ||
  1254. (SecondaryFunctionEntry->PrologEndAddress > ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry))) {
  1255. // Got a secondary function entry as expected. But if indirection doesn't point
  1256. // to FunctionEntry then ignore it and use the caller supplied FunctionEntry.
  1257. if (ALPHA_RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry) != CacheEntry->Address) {
  1258. FE_ShowRuntimeFunctionAxp64((SecCache,
  1259. "GetUnwindFunctionEntry: unexpected secondary function entry from LookupDirectFunctionEntry"));
  1260. SecondaryFunctionEntry = NULL;
  1261. }
  1262. } else if (ALPHA_RF_IS_FIXED_RETURN(SecondaryFunctionEntry)) {
  1263. // Got a fixed return entry. Switch to using the fixed return entry as the primary.
  1264. FunctionEntry = SecondaryFunctionEntry;
  1265. CacheEntry = SecCache;
  1266. SecondaryFunctionEntry = NULL;
  1267. } else {
  1268. // Got a primary function entry. Ignore it and use caller supplied FunctionEntry.
  1269. FE_ShowRuntimeFunctionAxp64((SecCache,
  1270. "GetUnwindFunctionEntry: unexpected primary function entry from LookupDirectFunctionEntry"));
  1271. SecondaryFunctionEntry = NULL;
  1272. }
  1273. #if DBG
  1274. } else {
  1275. ShowRuntimeFunctionAxp64(SecCache, "GetUnwindFunctionEntry: LookupDirectFunctionEntry returned NULL");
  1276. #endif
  1277. }
  1278. } else {
  1279. // ControlPC is in the range of the supplied function entry.
  1280. // If this is a null-context tail region then unwind with a null-context-like descriptor
  1281. if ((ControlPc >= ALPHA_RF_END_ADDRESS(FunctionEntry)-(ALPHA_RF_NULL_CONTEXT_COUNT(FunctionEntry)*4)) &&
  1282. (ControlPc < ALPHA_RF_END_ADDRESS(FunctionEntry))) {
  1283. // Use the secondary function entry with PrologEndAddress = BeginAddress.
  1284. // This ensures that the prologue is not reverse executed.
  1285. UnwindFunctionEntry->BeginAddress = ALPHA_RF_BEGIN_ADDRESS(FunctionEntry);
  1286. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(FunctionEntry);
  1287. UnwindFunctionEntry->ExceptionHandler = 0;
  1288. UnwindFunctionEntry->HandlerData = 0;
  1289. UnwindFunctionEntry->PrologEndAddress = ALPHA_RF_BEGIN_ADDRESS(FunctionEntry);
  1290. return;
  1291. }
  1292. // Check if it is a secondary function entry. This shouldn't happen because
  1293. // LookupFunctionEntry is always supposed to return a primary function entry.
  1294. // But if we get passed a secondary, then switch to it's primary. However note
  1295. // that we've gone through this pass
  1296. if ((FunctionEntry->PrologEndAddress < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
  1297. (FunctionEntry->PrologEndAddress > ALPHA_RF_END_ADDRESS(FunctionEntry))) {
  1298. SecondaryFunctionEntry = FunctionEntry;
  1299. SecCache = Cache->ReadImage
  1300. ( hProcess,
  1301. ALPHA_RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry),
  1302. ReadMemory, GetModuleBase );
  1303. if (SecCache != NULL) {
  1304. SecondaryFunctionEntry = &SecCache->Data.Axp64;
  1305. } else {
  1306. SecondaryFunctionEntry = NULL;
  1307. }
  1308. FE_ShowRuntimeFunctionAxp64((SecCache,
  1309. "GetUnwindFunctionEntry: received secondary function entry"));
  1310. }
  1311. }
  1312. // FunctionEntry is now the primary function entry and if SecondaryFunctionEntry is
  1313. // not NULL then it is the secondary function entry that contains the ControlPC. Setup a
  1314. // copy of the FunctionEntry suitable for unwinding. By default use the supplied FunctionEntry.
  1315. if (SecondaryFunctionEntry) {
  1316. // Extract the secondary function entry type.
  1317. EntryType = ALPHA_RF_ENTRY_TYPE(SecondaryFunctionEntry);
  1318. if (EntryType == ALPHA_RF_NOT_CONTIGUOUS) {
  1319. // The exception happened in the body of the procedure but in a non-contiguous
  1320. // section of code. Regardless of what entry point was used, it is normally valid
  1321. // to unwind using the primary entry point prologue. The only exception is when an
  1322. // alternate prologue is specified However, there may be an
  1323. // alternate prologue end addresss specified in which case unwind using this
  1324. // block as though it were the primary.
  1325. AlternateProlog = ALPHA_RF_ALT_PROLOG64(SecondaryFunctionEntry);
  1326. if ((AlternateProlog >= ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) &&
  1327. (AlternateProlog < ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry))) {
  1328. // If the control PC is in the alternate prologue, use the secondary.
  1329. // The control Pc is not in procedure context.
  1330. if ((ControlPc >= ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) &&
  1331. (ControlPc < ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry))) {
  1332. UnwindFunctionEntry->BeginAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1333. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry);
  1334. UnwindFunctionEntry->ExceptionHandler = 0;
  1335. UnwindFunctionEntry->HandlerData = 0;
  1336. UnwindFunctionEntry->PrologEndAddress = AlternateProlog;
  1337. return;
  1338. }
  1339. }
  1340. // Fall out of the if statement to pick up the primary function entry below.
  1341. // This code is in-procedure-context and subject to the primary's prologue
  1342. // and exception handlers.
  1343. } else if (EntryType == ALPHA_RF_ALT_ENT_PROLOG) {
  1344. // Exception occured in an alternate entry point prologue.
  1345. // Use the secondary function entry with a fixed-up PrologEndAddress.
  1346. UnwindFunctionEntry->BeginAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1347. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry);
  1348. UnwindFunctionEntry->ExceptionHandler = 0;
  1349. UnwindFunctionEntry->HandlerData = 0;
  1350. UnwindFunctionEntry->PrologEndAddress = ALPHA_RF_END_ADDRESS(UnwindFunctionEntry);
  1351. // Check for an alternate prologue.
  1352. AlternateProlog = ALPHA_RF_ALT_PROLOG64(SecondaryFunctionEntry);
  1353. if (AlternateProlog >= UnwindFunctionEntry->BeginAddress &&
  1354. AlternateProlog < UnwindFunctionEntry->EndAddress ) {
  1355. // The prologue is only part of the procedure
  1356. UnwindFunctionEntry->PrologEndAddress = AlternateProlog;
  1357. }
  1358. return;
  1359. } else if (EntryType == ALPHA_RF_NULL_CONTEXT) {
  1360. // Exception occured in null-context code associated with a primary function.
  1361. // Use the secondary function entry with a PrologEndAddress = BeginAddress.
  1362. // There is no prologue for null-context code.
  1363. *StackAdjust = ALPHA_RF_STACK_ADJUST(SecondaryFunctionEntry);
  1364. UnwindFunctionEntry->BeginAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1365. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(SecondaryFunctionEntry);
  1366. UnwindFunctionEntry->ExceptionHandler = 0;
  1367. UnwindFunctionEntry->HandlerData = 0;
  1368. UnwindFunctionEntry->PrologEndAddress = ALPHA_RF_BEGIN_ADDRESS(SecondaryFunctionEntry);
  1369. return;
  1370. }
  1371. }
  1372. // FunctionEntry is only null if there was an error fetching it from a passed in
  1373. // secondary function entry.
  1374. if (FunctionEntry == NULL) {
  1375. #if DBG
  1376. dbPrint("\nGetUnwindFunctionEntry: Error in FetchFunctionEntry\n");
  1377. #endif
  1378. UnwindFunctionEntry->BeginAddress = ControlPc;
  1379. UnwindFunctionEntry->EndAddress = ControlPc+4;
  1380. UnwindFunctionEntry->ExceptionHandler = 0;
  1381. UnwindFunctionEntry->HandlerData = 0;
  1382. UnwindFunctionEntry->PrologEndAddress = ControlPc;
  1383. return;
  1384. }
  1385. #if DBG
  1386. if (ALPHA_RF_BEGIN_ADDRESS(FunctionEntry) >= ALPHA_RF_END_ADDRESS(FunctionEntry)) {
  1387. ShowRuntimeFunctionAxp64(CacheEntry, "GetUnwindFunctionEntry: Warning - BeginAddress < EndAddress.");
  1388. } else if (FunctionEntry->PrologEndAddress < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) {
  1389. ShowRuntimeFunctionAxp64(CacheEntry, "GetUnwindFunctionEntry: Warning - PrologEndAddress < BeginAddress.");
  1390. } else if (FunctionEntry->PrologEndAddress > ALPHA_RF_END_ADDRESS(FunctionEntry)) {
  1391. ShowRuntimeFunctionAxp64(CacheEntry, "GetUnwindFunctionEntry: Warning - PrologEndAddress > EndAddress.");
  1392. }
  1393. #endif
  1394. // Use the primary function entry
  1395. *UnwindFunctionEntry = *FunctionEntry;
  1396. UnwindFunctionEntry->EndAddress = ALPHA_RF_END_ADDRESS(UnwindFunctionEntry); // Remove null-context count
  1397. // If the primary has a fixed return address, pull that out now.
  1398. if (ALPHA_RF_IS_FIXED_RETURN(FunctionEntry)) {
  1399. *FixedReturn = ALPHA_RF_FIXED_RETURN64(FunctionEntry);
  1400. UnwindFunctionEntry->ExceptionHandler = 0;
  1401. UnwindFunctionEntry->HandlerData = 0;
  1402. }
  1403. }