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.

2443 lines
79 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. exdsptch.c
  5. Abstract:
  6. This module implements the dispatching of exception and the unwinding of
  7. procedure call frames.
  8. Author:
  9. David N. Cutler (davec) 26-Oct-2000
  10. Environment:
  11. Any mode.
  12. --*/
  13. #include "ntrtlp.h"
  14. #if defined(NTOS_KERNEL_RUNTIME)
  15. //
  16. // Define function address table for kernel mode.
  17. //
  18. // This table is used to initialize the global history table.
  19. //
  20. VOID
  21. KiDispatchException (
  22. IN PEXCEPTION_RECORD ExceptionRecord,
  23. IN PKEXCEPTION_FRAME ExceptionFrame,
  24. IN PKTRAP_FRAME TrapFrame,
  25. IN KPROCESSOR_MODE PreviousMode,
  26. IN BOOLEAN FirstChance
  27. );
  28. VOID
  29. KiExceptionDispatch (
  30. VOID
  31. );
  32. PVOID RtlpFunctionAddressTable[] = {
  33. &KiExceptionDispatch,
  34. &KiDispatchException,
  35. &RtlDispatchException,
  36. &RtlpExecuteHandlerForException,
  37. &__C_specific_handler,
  38. &RtlUnwindEx,
  39. NULL
  40. };
  41. #else
  42. VOID
  43. KiUserExceptionDispatch (
  44. VOID
  45. );
  46. PVOID RtlpFunctionAddressTable[] = {
  47. &KiUserExceptionDispatch,
  48. &RtlDispatchException,
  49. &RtlpExecuteHandlerForException,
  50. &__C_specific_handler,
  51. &RtlUnwindEx,
  52. NULL
  53. };
  54. #endif
  55. //
  56. // ****** temp - define elsewhere ******
  57. //
  58. #define SIZE64_PREFIX 0x48
  59. #define ADD_IMM8_OP 0x83
  60. #define ADD_IMM32_OP 0x81
  61. #define JMP_IMM8_OP 0xeb
  62. #define JMP_IMM32_OP 0xe9
  63. #define LEA_OP 0x8d
  64. #define POP_OP 0x58
  65. #define RET_OP 0xc3
  66. //
  67. // Define lookup table for providing the number of slots used by each unwind
  68. // code.
  69. //
  70. UCHAR RtlpUnwindOpSlotTable[] = {
  71. 1, // UWOP_PUSH_NONVOL
  72. 2, // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
  73. 1, // UWOP_ALLOC_SMALL
  74. 1, // UWOP_SET_FPREG
  75. 2, // UWOP_SAVE_NONVOL
  76. 3, // UWOP_SAVE_NONVOL_FAR
  77. 2, // UWOP_SAVE_XMM
  78. 3, // UWOP_SAVE_XMM_FAR
  79. 2, // UWOP_SAVE_XMM128
  80. 3, // UWOP_SAVE_XMM128_FAR
  81. 1 // UWOP_PUSH_MACHFRAME
  82. };
  83. //
  84. // Define forward referenced function prototypes.
  85. //
  86. VOID
  87. RtlpCopyContext (
  88. OUT PCONTEXT Destination,
  89. IN PCONTEXT Source
  90. );
  91. BOOLEAN
  92. RtlDispatchException (
  93. IN PEXCEPTION_RECORD ExceptionRecord,
  94. IN PCONTEXT ContextRecord
  95. )
  96. /*++
  97. Routine Description:
  98. This function attempts to dispatch an exception to a frame based
  99. handler by searching backwards through the stack based call frames.
  100. The search begins with the frame specified in the context record and
  101. continues backward until either a handler is found that handles the
  102. exception, the stack is found to be invalid (i.e., out of limits or
  103. unaligned), or the end of the call hierarchy is reached.
  104. As each frame is encounter, the PC where control left the corresponding
  105. function is determined and used to lookup exception handler information
  106. in the runtime function table built by the linker. If the respective
  107. routine has an exception handler, then the handler is called. If the
  108. handler does not handle the exception, then the prologue of the routine
  109. is executed backwards to "unwind" the effect of the prologue and then
  110. the next frame is examined.
  111. Arguments:
  112. ExceptionRecord - Supplies a pointer to an exception record.
  113. ContextRecord - Supplies a pointer to a context record.
  114. Return Value:
  115. If the exception is handled by one of the frame based handlers, then
  116. a value of TRUE is returned. Otherwise a value of FALSE is returned.
  117. --*/
  118. {
  119. CONTEXT ContextRecord1;
  120. ULONG64 ControlPc;
  121. DISPATCHER_CONTEXT DispatcherContext;
  122. EXCEPTION_DISPOSITION Disposition;
  123. ULONG64 EstablisherFrame;
  124. ULONG ExceptionFlags;
  125. PEXCEPTION_ROUTINE ExceptionRoutine;
  126. PRUNTIME_FUNCTION FunctionEntry;
  127. PVOID HandlerData;
  128. ULONG64 HighLimit;
  129. PUNWIND_HISTORY_TABLE HistoryTable;
  130. ULONG64 ImageBase;
  131. ULONG Index;
  132. ULONG64 LowLimit;
  133. ULONG64 NestedFrame;
  134. UNWIND_HISTORY_TABLE UnwindTable;
  135. //
  136. // Attempt to dispatch the exception using a vectored exception handler.
  137. //
  138. #if !defined(NTOS_KERNEL_RUNTIME)
  139. if (RtlCallVectoredExceptionHandlers(ExceptionRecord, ContextRecord) != FALSE) {
  140. return TRUE;
  141. }
  142. #endif
  143. //
  144. // Get current stack limits, copy the context record, get the initial
  145. // PC value, capture the exception flags, and set the nested exception
  146. // frame pointer.
  147. //
  148. RtlpGetStackLimits(&LowLimit, &HighLimit);
  149. RtlpCopyContext(&ContextRecord1, ContextRecord);
  150. ControlPc = (ULONG64)ExceptionRecord->ExceptionAddress;
  151. ExceptionFlags = ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE;
  152. NestedFrame = 0;
  153. //
  154. // Initialize the unwind history table.
  155. //
  156. HistoryTable = &UnwindTable;
  157. HistoryTable->Count = 0;
  158. HistoryTable->Search = UNWIND_HISTORY_TABLE_NONE;
  159. HistoryTable->LowAddress = - 1;
  160. HistoryTable->HighAddress = 0;
  161. //
  162. // Start with the frame specified by the context record and search
  163. // backwards through the call frame hierarchy attempting to find an
  164. // exception handler that will handle the exception.
  165. //
  166. do {
  167. //
  168. // Lookup the function table entry using the point at which control
  169. // left the procedure.
  170. //
  171. FunctionEntry = RtlLookupFunctionEntry(ControlPc,
  172. &ImageBase,
  173. HistoryTable);
  174. //
  175. // If there is a function table entry for the routine, then virtually
  176. // unwind to the caller of the current routine to obtain the virtual
  177. // frame pointer of the establisher and check if there is an exception
  178. // handler for the frame.
  179. //
  180. if (FunctionEntry != NULL) {
  181. ExceptionRoutine = RtlVirtualUnwind(UNW_FLAG_EHANDLER,
  182. ImageBase,
  183. ControlPc,
  184. FunctionEntry,
  185. &ContextRecord1,
  186. &HandlerData,
  187. &EstablisherFrame,
  188. NULL);
  189. //
  190. // If the establisher frame pointer is not within the specified
  191. // stack limits or the established frame pointer is unaligned,
  192. // then set the stack invalid flag in the exception record and
  193. // return exception not handled. Otherwise, check if the current
  194. // routine has an exception handler.
  195. //
  196. if ((EstablisherFrame < LowLimit) ||
  197. (EstablisherFrame > HighLimit) ||
  198. ((EstablisherFrame & 0x7) != 0)) {
  199. ExceptionFlags |= EXCEPTION_STACK_INVALID;
  200. break;
  201. } else if (ExceptionRoutine != NULL) {
  202. //
  203. // The frame has an exception handler.
  204. //
  205. // A linkage routine written in assembler is used to actually
  206. // call the actual exception handler. This is required by the
  207. // exception handler that is associated with the linkage
  208. // routine so it can have access to two sets of dispatcher
  209. // context when it is called.
  210. //
  211. do {
  212. //
  213. // Log the exception if exception logging is enabled.
  214. //
  215. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  216. if ((NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) != 0) {
  217. Index = RtlpLogExceptionHandler(ExceptionRecord,
  218. &ContextRecord1,
  219. ControlPc,
  220. FunctionEntry,
  221. sizeof(RUNTIME_FUNCTION));
  222. }
  223. //
  224. // Clear collided unwind, set the dispatcher context, and
  225. // call the exception handler.
  226. //
  227. ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
  228. DispatcherContext.ControlPc = ControlPc;
  229. DispatcherContext.ImageBase = ImageBase;
  230. DispatcherContext.FunctionEntry = FunctionEntry;
  231. DispatcherContext.EstablisherFrame = EstablisherFrame;
  232. DispatcherContext.ContextRecord = &ContextRecord1;
  233. DispatcherContext.LanguageHandler = ExceptionRoutine;
  234. DispatcherContext.HandlerData = HandlerData;
  235. DispatcherContext.HistoryTable = HistoryTable;
  236. Disposition =
  237. RtlpExecuteHandlerForException(ExceptionRecord,
  238. EstablisherFrame,
  239. ContextRecord,
  240. &DispatcherContext);
  241. if ((NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) != 0) {
  242. RtlpLogLastExceptionDisposition(Index, Disposition);
  243. }
  244. //
  245. // Propagate noncontinuable exception flag.
  246. //
  247. ExceptionFlags |=
  248. (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE);
  249. //
  250. // If the current scan is within a nested context and the
  251. // frame just examined is the end of the nested region,
  252. // then clear the nested context frame and the nested
  253. // exception flag in the exception flags.
  254. //
  255. if (NestedFrame == EstablisherFrame) {
  256. ExceptionFlags &= (~EXCEPTION_NESTED_CALL);
  257. NestedFrame = 0;
  258. }
  259. //
  260. // Case on the handler disposition.
  261. //
  262. switch (Disposition) {
  263. //
  264. // The disposition is to continue execution.
  265. //
  266. // If the exception is not continuable, then raise
  267. // the exception STATUS_NONCONTINUABLE_EXCEPTION.
  268. // Otherwise return exception handled.
  269. //
  270. case ExceptionContinueExecution :
  271. if ((ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) {
  272. RtlRaiseStatus(STATUS_NONCONTINUABLE_EXCEPTION);
  273. } else {
  274. return TRUE;
  275. }
  276. //
  277. // The disposition is to continue the search.
  278. //
  279. // Get next frame address and continue the search.
  280. //
  281. case ExceptionContinueSearch :
  282. break;
  283. //
  284. // The disposition is nested exception.
  285. //
  286. // Set the nested context frame to the establisher frame
  287. // address and set the nested exception flag in the
  288. // exception flags.
  289. //
  290. case ExceptionNestedException :
  291. ExceptionFlags |= EXCEPTION_NESTED_CALL;
  292. if (DispatcherContext.EstablisherFrame > NestedFrame) {
  293. NestedFrame = DispatcherContext.EstablisherFrame;
  294. }
  295. break;
  296. //
  297. // The dispostion is collided unwind.
  298. //
  299. // A collided unwind occurs when an exception dispatch
  300. // encounters a previous call to an unwind handler. In
  301. // this case the previous unwound frames must be skipped.
  302. //
  303. case ExceptionCollidedUnwind:
  304. ControlPc = DispatcherContext.ControlPc;
  305. ImageBase = DispatcherContext.ImageBase;
  306. FunctionEntry = DispatcherContext.FunctionEntry;
  307. EstablisherFrame = DispatcherContext.EstablisherFrame;
  308. RtlpCopyContext(&ContextRecord1,
  309. DispatcherContext.ContextRecord);
  310. ExceptionRoutine = DispatcherContext.LanguageHandler;
  311. HandlerData = DispatcherContext.HandlerData;
  312. HistoryTable = DispatcherContext.HistoryTable;
  313. ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
  314. break;
  315. //
  316. // All other disposition values are invalid.
  317. //
  318. // Raise invalid disposition exception.
  319. //
  320. default :
  321. RtlRaiseStatus(STATUS_INVALID_DISPOSITION);
  322. }
  323. } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
  324. }
  325. } else {
  326. //
  327. // If the old control PC is the same as the return address,
  328. // then no progress is being made and the function tables are
  329. // most likely malformed.
  330. //
  331. if (ControlPc == *(PULONG64)(ContextRecord1.Rsp)) {
  332. break;
  333. }
  334. //
  335. // Set the point where control left the current function by
  336. // obtaining the return address from the top of the stack.
  337. //
  338. ContextRecord1.Rip = *(PULONG64)(ContextRecord1.Rsp);
  339. ContextRecord1.Rsp += 8;
  340. }
  341. //
  342. // Set point at which control left the previous routine.
  343. //
  344. ControlPc = ContextRecord1.Rip;
  345. } while ((ULONG64)ContextRecord1.Rsp < HighLimit);
  346. //
  347. // Set final exception flags and return exception not handled.
  348. //
  349. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  350. return FALSE;
  351. }
  352. VOID
  353. RtlUnwind (
  354. IN PVOID TargetFrame OPTIONAL,
  355. IN PVOID TargetIp OPTIONAL,
  356. IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
  357. IN PVOID ReturnValue
  358. )
  359. /*++
  360. Routine Description:
  361. This function initiates an unwind of procedure call frames. The machine
  362. state at the time of the call to unwind is captured in a context record
  363. and the unwinding flag is set in the exception flags of the exception
  364. record. If the TargetFrame parameter is not specified, then the exit unwind
  365. flag is also set in the exception flags of the exception record. A backward
  366. scan through the procedure call frames is then performed to find the target
  367. of the unwind operation.
  368. As each frame is encounter, the PC where control left the corresponding
  369. function is determined and used to lookup exception handler information
  370. in the runtime function table built by the linker. If the respective
  371. routine has an exception handler, then the handler is called.
  372. Arguments:
  373. TargetFrame - Supplies an optional pointer to the call frame that is the
  374. target of the unwind. If this parameter is not specified, then an exit
  375. unwind is performed.
  376. TargetIp - Supplies an optional instruction address that specifies the
  377. continuation address of the unwind. This address is ignored if the
  378. target frame parameter is not specified.
  379. ExceptionRecord - Supplies an optional pointer to an exception record.
  380. ReturnValue - Supplies a value that is to be placed in the integer
  381. function return register just before continuing execution.
  382. Return Value:
  383. None.
  384. --*/
  385. {
  386. CONTEXT ContextRecord;
  387. //
  388. // Call real unwind routine specifying a local context record and history
  389. // table address as extra arguments.
  390. //
  391. RtlUnwindEx(TargetFrame,
  392. TargetIp,
  393. ExceptionRecord,
  394. ReturnValue,
  395. &ContextRecord,
  396. NULL);
  397. return;
  398. }
  399. VOID
  400. RtlUnwindEx (
  401. IN PVOID TargetFrame OPTIONAL,
  402. IN PVOID TargetIp OPTIONAL,
  403. IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
  404. IN PVOID ReturnValue,
  405. IN PCONTEXT OriginalContext,
  406. IN PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL
  407. )
  408. /*++
  409. Routine Description:
  410. This function initiates an unwind of procedure call frames. The machine
  411. state at the time of the call to unwind is captured in a context record
  412. and the unwinding flag is set in the exception flags of the exception
  413. record. If the TargetFrame parameter is not specified, then the exit unwind
  414. flag is also set in the exception flags of the exception record. A backward
  415. scan through the procedure call frames is then performed to find the target
  416. of the unwind operation.
  417. As each frame is encounter, the PC where control left the corresponding
  418. function is determined and used to lookup exception handler information
  419. in the runtime function table built by the linker. If the respective
  420. routine has an exception handler, then the handler is called.
  421. Arguments:
  422. TargetFrame - Supplies an optional pointer to the call frame that is the
  423. target of the unwind. If this parameter is not specified, then an exit
  424. unwind is performed.
  425. TargetIp - Supplies an optional instruction address that specifies the
  426. continuation address of the unwind. This address is ignored if the
  427. target frame parameter is not specified.
  428. ExceptionRecord - Supplies an optional pointer to an exception record.
  429. ReturnValue - Supplies a value that is to be placed in the integer
  430. function return register just before continuing execution.
  431. OriginalContext - Supplies a pointer to a context record that can be used
  432. to store context druing the unwind operation.
  433. HistoryTable - Supplies an optional pointer to an unwind history table.
  434. Return Value:
  435. None.
  436. --*/
  437. {
  438. ULONG64 ControlPc;
  439. PCONTEXT CurrentContext;
  440. DISPATCHER_CONTEXT DispatcherContext;
  441. EXCEPTION_DISPOSITION Disposition;
  442. ULONG64 EstablisherFrame;
  443. ULONG ExceptionFlags;
  444. EXCEPTION_RECORD ExceptionRecord1;
  445. PEXCEPTION_ROUTINE ExceptionRoutine;
  446. PRUNTIME_FUNCTION FunctionEntry;
  447. PVOID HandlerData;
  448. ULONG64 HighLimit;
  449. ULONG64 ImageBase;
  450. CONTEXT LocalContext;
  451. ULONG64 LowLimit;
  452. PCONTEXT PreviousContext;
  453. PCONTEXT TempContext;
  454. //
  455. // Get current stack limits, capture the current context, virtually
  456. // unwind to the caller of this routine, get the initial PC value, and
  457. // set the unwind target address.
  458. //
  459. CurrentContext = OriginalContext;
  460. PreviousContext = &LocalContext;
  461. RtlpGetStackLimits(&LowLimit, &HighLimit);
  462. RtlCaptureContext(CurrentContext);
  463. //
  464. // If a history table is specified, then set to search history table.
  465. //
  466. if (ARGUMENT_PRESENT(HistoryTable)) {
  467. HistoryTable->Search = UNWIND_HISTORY_TABLE_GLOBAL;
  468. }
  469. //
  470. // If an exception record is not specified, then build a local exception
  471. // record for use in calling exception handlers during the unwind operation.
  472. //
  473. if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) {
  474. ExceptionRecord = &ExceptionRecord1;
  475. ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
  476. ExceptionRecord1.ExceptionRecord = NULL;
  477. ExceptionRecord1.ExceptionAddress = (PVOID)CurrentContext->Rip;
  478. ExceptionRecord1.NumberParameters = 0;
  479. }
  480. //
  481. // If the target frame of the unwind is specified, then a normal unwind
  482. // is being performed. Otherwise, an exit unwind is being performed.
  483. //
  484. ExceptionFlags = EXCEPTION_UNWINDING;
  485. if (ARGUMENT_PRESENT(TargetFrame) == FALSE) {
  486. ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
  487. }
  488. //
  489. // Scan backward through the call frame hierarchy and call exception
  490. // handlers until the target frame of the unwind is reached.
  491. //
  492. do {
  493. //
  494. // Lookup the function table entry using the point at which control
  495. // left the procedure.
  496. //
  497. ControlPc = CurrentContext->Rip;
  498. FunctionEntry = RtlLookupFunctionEntry(ControlPc,
  499. &ImageBase,
  500. HistoryTable);
  501. //
  502. // If there is a function table entry for the routine, then virtually
  503. // unwind to the caller of the routine to obtain the virtual frame
  504. // pointer of the establisher, but don't update the context record.
  505. //
  506. if (FunctionEntry != NULL) {
  507. RtlpCopyContext(PreviousContext, CurrentContext);
  508. ExceptionRoutine = RtlVirtualUnwind(UNW_FLAG_UHANDLER,
  509. ImageBase,
  510. ControlPc,
  511. FunctionEntry,
  512. PreviousContext,
  513. &HandlerData,
  514. &EstablisherFrame,
  515. NULL);
  516. //
  517. // If the establisher frame pointer is not within the specified
  518. // stack limits, the establisher frame pointer is unaligned, or
  519. // the target frame is below the establisher frame and an exit
  520. // unwind is not being performed, then raise a bad stack status.
  521. // Otherwise, check to determine if the current routine has an
  522. // exception handler.
  523. //
  524. if ((EstablisherFrame < LowLimit) ||
  525. (EstablisherFrame > HighLimit) ||
  526. ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
  527. ((ULONG64)TargetFrame < EstablisherFrame)) ||
  528. ((EstablisherFrame & 0x7) != 0)) {
  529. RtlRaiseStatus(STATUS_BAD_STACK);
  530. } else if (ExceptionRoutine != NULL) {
  531. //
  532. // The frame has a exception handler.
  533. //
  534. // A linkage routine written in assembler is used to actually
  535. // call the actual exception handler. This is required by the
  536. // exception handler that is associated with the linkage
  537. // routine so it can have access to two sets of dispatcher
  538. // context when it is called.
  539. //
  540. DispatcherContext.TargetIp = (ULONG64)TargetIp;
  541. do {
  542. //
  543. // If the establisher frame is the target of the unwind
  544. // operation, then set the target unwind flag.
  545. //
  546. if ((ULONG64)TargetFrame == EstablisherFrame) {
  547. ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
  548. }
  549. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  550. //
  551. // Set the specified return value and target IP in case
  552. // the exception handler directly continues execution.
  553. //
  554. CurrentContext->Rax = (ULONG64)ReturnValue;
  555. //
  556. // Set the dispatcher context and call the termination
  557. // handler.
  558. //
  559. DispatcherContext.ControlPc = ControlPc;
  560. DispatcherContext.ImageBase = ImageBase;
  561. DispatcherContext.FunctionEntry = FunctionEntry;
  562. DispatcherContext.EstablisherFrame = EstablisherFrame;
  563. DispatcherContext.ContextRecord = CurrentContext;
  564. DispatcherContext.LanguageHandler = ExceptionRoutine;
  565. DispatcherContext.HandlerData = HandlerData;
  566. DispatcherContext.HistoryTable = HistoryTable;
  567. Disposition =
  568. RtlpExecuteHandlerForUnwind(ExceptionRecord,
  569. EstablisherFrame,
  570. CurrentContext,
  571. &DispatcherContext);
  572. //
  573. // Clear target unwind and collided unwind flags.
  574. //
  575. ExceptionFlags &=
  576. ~(EXCEPTION_COLLIDED_UNWIND | EXCEPTION_TARGET_UNWIND);
  577. //
  578. // Case on the handler disposition.
  579. //
  580. switch (Disposition) {
  581. //
  582. // The disposition is to continue the search.
  583. //
  584. // If the target frame has not been reached, then
  585. // swap context pointers.
  586. //
  587. case ExceptionContinueSearch :
  588. if (EstablisherFrame != (ULONG64)TargetFrame) {
  589. TempContext = CurrentContext;
  590. CurrentContext = PreviousContext;
  591. PreviousContext = TempContext;
  592. }
  593. break;
  594. //
  595. // The disposition is collided unwind.
  596. //
  597. // Copy the context of the previous unwind and
  598. // virtually unwind to the caller of the extablisher,
  599. // then set the target of the current unwind to the
  600. // dispatcher context of the previous unwind, and
  601. // reexecute the exception handler from the collided
  602. // frame with the collided unwind flag set in the
  603. // exception record.
  604. //
  605. case ExceptionCollidedUnwind :
  606. ControlPc = DispatcherContext.ControlPc;
  607. ImageBase = DispatcherContext.ImageBase;
  608. FunctionEntry = DispatcherContext.FunctionEntry;
  609. RtlpCopyContext(OriginalContext,
  610. DispatcherContext.ContextRecord);
  611. CurrentContext = OriginalContext;
  612. PreviousContext = &LocalContext;
  613. RtlpCopyContext(PreviousContext, CurrentContext);
  614. RtlVirtualUnwind(UNW_FLAG_NHANDLER,
  615. ImageBase,
  616. ControlPc,
  617. FunctionEntry,
  618. PreviousContext,
  619. &HandlerData,
  620. &EstablisherFrame,
  621. NULL);
  622. EstablisherFrame = DispatcherContext.EstablisherFrame;
  623. ExceptionRoutine = DispatcherContext.LanguageHandler;
  624. HandlerData = DispatcherContext.HandlerData;
  625. HistoryTable = DispatcherContext.HistoryTable;
  626. ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
  627. break;
  628. //
  629. // All other disposition values are invalid.
  630. //
  631. // Raise invalid disposition exception.
  632. //
  633. default :
  634. RtlRaiseStatus(STATUS_INVALID_DISPOSITION);
  635. }
  636. } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
  637. } else {
  638. //
  639. // If the target frame has not been reached, then swap
  640. // context pointers.
  641. //
  642. if (EstablisherFrame != (ULONG64)TargetFrame) {
  643. TempContext = CurrentContext;
  644. CurrentContext = PreviousContext;
  645. PreviousContext = TempContext;
  646. }
  647. }
  648. } else {
  649. //
  650. // Set the point where control left the current function by
  651. // obtaining the return address from the top of the stack.
  652. //
  653. CurrentContext->Rip = *(PULONG64)(CurrentContext->Rsp);
  654. CurrentContext->Rsp += 8;
  655. }
  656. } while ((EstablisherFrame < HighLimit) &&
  657. (EstablisherFrame != (ULONG64)TargetFrame));
  658. //
  659. // If the establisher stack pointer is equal to the target frame pointer,
  660. // then continue execution. Otherwise, an exit unwind was performed or the
  661. // target of the unwind did not exist and the debugger and subsystem are
  662. // given a second chance to handle the unwind.
  663. //
  664. if (EstablisherFrame == (ULONG64)TargetFrame) {
  665. CurrentContext->Rax = (ULONG64)ReturnValue;
  666. if (ExceptionRecord->ExceptionCode != STATUS_UNWIND_CONSOLIDATE) {
  667. CurrentContext->Rip = (ULONG64)TargetIp;
  668. }
  669. RtlRestoreContext(CurrentContext, ExceptionRecord);
  670. } else {
  671. //
  672. // If the old control PC is the same as the new control PC, then
  673. // no progress is being made and the function tables are most likely
  674. // malformed. Otherwise, give the debugger and subsystem a second
  675. // chance to handle the exception.
  676. if (ControlPc == CurrentContext->Rip) {
  677. RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE);
  678. } else {
  679. ZwRaiseException(ExceptionRecord, CurrentContext, FALSE);
  680. }
  681. }
  682. }
  683. PRUNTIME_FUNCTION
  684. RtlpUnwindPrologue (
  685. IN ULONG64 ImageBase,
  686. IN ULONG64 ControlPc,
  687. IN ULONG64 FrameBase,
  688. IN PRUNTIME_FUNCTION FunctionEntry,
  689. IN OUT PCONTEXT ContextRecord,
  690. IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
  691. )
  692. /*++
  693. Routine Description:
  694. This function processes unwind codes and reverses the state change
  695. effects of a prologue. If the specified unwind information contains
  696. chained unwind information, then that prologue is unwound recursively.
  697. As the prologue is unwound state changes are recorded in the specified
  698. context structure and optionally in the specified context pointers
  699. structures.
  700. Arguments:
  701. ImageBase - Supplies the base address of the image that contains the
  702. function being unwound.
  703. ControlPc - Supplies the address where control left the specified
  704. function.
  705. FrameBase - Supplies the base of the stack frame subject function stack
  706. frame.
  707. FunctionEntry - Supplies the address of the function table entry for the
  708. specified function.
  709. ContextRecord - Supplies the address of a context record.
  710. ContextPointers - Supplies an optional pointer to a context pointers
  711. record.
  712. Return Value:
  713. --*/
  714. {
  715. PM128 FloatingAddress;
  716. PM128 FloatingRegister;
  717. ULONG FrameOffset;
  718. ULONG Index;
  719. PULONG64 IntegerAddress;
  720. PULONG64 IntegerRegister;
  721. BOOLEAN MachineFrame;
  722. ULONG OpInfo;
  723. ULONG PrologOffset;
  724. PULONG64 RegisterAddress;
  725. PULONG64 ReturnAddress;
  726. PULONG64 StackAddress;
  727. PUNWIND_CODE UnwindCode;
  728. PUNWIND_INFO UnwindInfo;
  729. ULONG UnwindOp;
  730. //
  731. // Process the unwind codes.
  732. //
  733. FloatingRegister = &ContextRecord->Xmm0;
  734. IntegerRegister = &ContextRecord->Rax;
  735. Index = 0;
  736. MachineFrame = FALSE;
  737. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  738. UnwindInfo = (PUNWIND_INFO)(FunctionEntry->UnwindData + ImageBase);
  739. while (Index < UnwindInfo->CountOfCodes) {
  740. //
  741. // If the prologue offset is greater than the next unwind code offset,
  742. // then simulate the effect of the unwind code.
  743. //
  744. UnwindOp = UnwindInfo->UnwindCode[Index].UnwindOp;
  745. OpInfo = UnwindInfo->UnwindCode[Index].OpInfo;
  746. if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
  747. switch (UnwindOp) {
  748. //
  749. // Push nonvolatile integer register.
  750. //
  751. // The operation information is the register number of the
  752. // register than was pushed.
  753. //
  754. case UWOP_PUSH_NONVOL:
  755. IntegerAddress = (PULONG64)(ContextRecord->Rsp);
  756. IntegerRegister[OpInfo] = *IntegerAddress;
  757. if (ARGUMENT_PRESENT(ContextPointers)) {
  758. ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
  759. }
  760. ContextRecord->Rsp += 8;
  761. break;
  762. //
  763. // Allocate a large sized area on the stack.
  764. //
  765. // The operation information determines if the size is
  766. // 16- or 32-bits.
  767. //
  768. case UWOP_ALLOC_LARGE:
  769. Index += 1;
  770. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset;
  771. if (OpInfo != 0) {
  772. Index += 1;
  773. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  774. } else {
  775. FrameOffset *= 8;
  776. }
  777. ContextRecord->Rsp += FrameOffset;
  778. break;
  779. //
  780. // Allocate a small sized area on the stack.
  781. //
  782. // The operation information is the size of the unscaled
  783. // allocation size (8 is the scale factor) minus 8.
  784. //
  785. case UWOP_ALLOC_SMALL:
  786. ContextRecord->Rsp += (OpInfo * 8) + 8;
  787. break;
  788. //
  789. // Establish the the frame pointer register.
  790. //
  791. // The operation information is not used.
  792. //
  793. case UWOP_SET_FPREG:
  794. ContextRecord->Rsp = IntegerRegister[UnwindInfo->FrameRegister];
  795. ContextRecord->Rsp -= UnwindInfo->FrameOffset * 16;
  796. break;
  797. //
  798. // Save nonvolatile integer register on the stack using a
  799. // 16-bit displacment.
  800. //
  801. // The operation information is the register number.
  802. //
  803. case UWOP_SAVE_NONVOL:
  804. Index += 1;
  805. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 8;
  806. IntegerAddress = (PULONG64)(FrameBase + FrameOffset);
  807. IntegerRegister[OpInfo] = *IntegerAddress;
  808. if (ARGUMENT_PRESENT(ContextPointers)) {
  809. ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
  810. }
  811. break;
  812. //
  813. // Save nonvolatile integer register on the stack using a
  814. // 32-bit displacment.
  815. //
  816. // The operation information is the register number.
  817. //
  818. case UWOP_SAVE_NONVOL_FAR:
  819. Index += 2;
  820. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  821. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  822. IntegerAddress = (PULONG64)(FrameBase + FrameOffset);
  823. IntegerRegister[OpInfo] = *IntegerAddress;
  824. if (ARGUMENT_PRESENT(ContextPointers)) {
  825. ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
  826. }
  827. break;
  828. //
  829. // Save a nonvolatile XMM(64) register on the stack using a
  830. // 16-bit displacement.
  831. //
  832. // The operation information is the register number.
  833. //
  834. case UWOP_SAVE_XMM:
  835. Index += 1;
  836. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 8;
  837. FloatingAddress = (PM128)(FrameBase + FrameOffset);
  838. FloatingRegister[OpInfo].Low = FloatingAddress->Low;
  839. FloatingRegister[OpInfo].High = 0;
  840. if (ARGUMENT_PRESENT(ContextPointers)) {
  841. ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
  842. }
  843. break;
  844. //
  845. // Save a nonvolatile XMM(64) register on the stack using a
  846. // 32-bit displacement.
  847. //
  848. // The operation information is the register number.
  849. //
  850. case UWOP_SAVE_XMM_FAR:
  851. Index += 2;
  852. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  853. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  854. FloatingAddress = (PM128)(FrameBase + FrameOffset);
  855. FloatingRegister[OpInfo].Low = FloatingAddress->Low;
  856. FloatingRegister[OpInfo].High = 0;
  857. if (ARGUMENT_PRESENT(ContextPointers)) {
  858. ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
  859. }
  860. break;
  861. //
  862. // Save a nonvolatile XMM(128) register on the stack using a
  863. // 16-bit displacement.
  864. //
  865. // The operation information is the register number.
  866. //
  867. case UWOP_SAVE_XMM128:
  868. Index += 1;
  869. FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 16;
  870. FloatingAddress = (PM128)(FrameBase + FrameOffset);
  871. FloatingRegister[OpInfo].Low = FloatingAddress->Low;
  872. FloatingRegister[OpInfo].High = FloatingAddress->High;
  873. if (ARGUMENT_PRESENT(ContextPointers)) {
  874. ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
  875. }
  876. break;
  877. //
  878. // Save a nonvolatile XMM(128) register on the stack using a
  879. // 32-bit displacement.
  880. //
  881. // The operation information is the register number.
  882. //
  883. case UWOP_SAVE_XMM128_FAR:
  884. Index += 2;
  885. FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
  886. FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
  887. FloatingAddress = (PM128)(FrameBase + FrameOffset);
  888. FloatingRegister[OpInfo].Low = FloatingAddress->Low;
  889. FloatingRegister[OpInfo].High = FloatingAddress->High;
  890. if (ARGUMENT_PRESENT(ContextPointers)) {
  891. ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
  892. }
  893. break;
  894. //
  895. // Push a machine frame on the stack.
  896. //
  897. // The operation information determines whether the machine
  898. // frame contains an error code or not.
  899. //
  900. case UWOP_PUSH_MACHFRAME:
  901. MachineFrame = TRUE;
  902. ReturnAddress = (PULONG64)(ContextRecord->Rsp);
  903. StackAddress = (PULONG64)(ContextRecord->Rsp + (3 * 8));
  904. if (OpInfo != 0) {
  905. ReturnAddress += 1;
  906. StackAddress += 1;
  907. }
  908. ContextRecord->Rip = *ReturnAddress;
  909. ContextRecord->Rsp = *StackAddress;
  910. break;
  911. //
  912. // Unused codes.
  913. //
  914. default:
  915. break;
  916. }
  917. Index += 1;
  918. } else {
  919. //
  920. // Skip this unwind operation by advancing the slot index by the
  921. // number of slots consumed by this operation.
  922. //
  923. Index += RtlpUnwindOpSlotTable[UnwindOp];
  924. //
  925. // Special case any unwind operations that can consume a variable
  926. // number of slots.
  927. //
  928. switch (UnwindOp) {
  929. //
  930. // A non-zero operation information indicates that an
  931. // additional slot is consumed.
  932. //
  933. case UWOP_ALLOC_LARGE:
  934. if (OpInfo != 0) {
  935. Index += 1;
  936. }
  937. break;
  938. //
  939. // No other special cases.
  940. //
  941. default:
  942. break;
  943. }
  944. }
  945. }
  946. //
  947. // If chained unwind information is specified, then recursively unwind
  948. // the chained information. Otherwise, determine the return address if
  949. // a machine frame was not encountered during the scan of the unwind
  950. // codes.
  951. //
  952. if ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0) {
  953. Index = UnwindInfo->CountOfCodes;
  954. if ((Index & 1) != 0) {
  955. Index += 1;
  956. }
  957. FunctionEntry = (PRUNTIME_FUNCTION)(*(PULONG *)(&UnwindInfo->UnwindCode[Index]) + ImageBase);
  958. return RtlpUnwindPrologue(ImageBase,
  959. ControlPc,
  960. FrameBase,
  961. FunctionEntry,
  962. ContextRecord,
  963. ContextPointers);
  964. } else {
  965. if (MachineFrame == FALSE) {
  966. ContextRecord->Rip = *(PULONG64)(ContextRecord->Rsp);
  967. ContextRecord->Rsp += 8;
  968. }
  969. return FunctionEntry;
  970. }
  971. }
  972. PEXCEPTION_ROUTINE
  973. RtlVirtualUnwind (
  974. IN ULONG HandlerType,
  975. IN ULONG64 ImageBase,
  976. IN ULONG64 ControlPc,
  977. IN PRUNTIME_FUNCTION FunctionEntry,
  978. IN OUT PCONTEXT ContextRecord,
  979. OUT PVOID *HandlerData,
  980. OUT PULONG64 EstablisherFrame,
  981. IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
  982. )
  983. /*++
  984. Routine Description:
  985. This function virtually unwinds the specified function by executing its
  986. prologue code backward or its epilogue code forward.
  987. If a context pointers record is specified, then the address where each
  988. nonvolatile registers is restored from is recorded in the appropriate
  989. element of the context pointers record.
  990. Arguments:
  991. HandlerType - Supplies the handler type expected for the virtual unwind.
  992. This may be either an exception or an unwind handler.
  993. ImageBase - Supplies the base address of the image that contains the
  994. function being unwound.
  995. ControlPc - Supplies the address where control left the specified
  996. function.
  997. FunctionEntry - Supplies the address of the function table entry for the
  998. specified function.
  999. ContextRecord - Supplies the address of a context record.
  1000. HandlerData - Supplies a pointer to a variable that receives a pointer
  1001. the the language handler data.
  1002. EstablisherFrame - Supplies a pointer to a variable that receives the
  1003. the establisher frame pointer value.
  1004. ContextPointers - Supplies an optional pointer to a context pointers
  1005. record.
  1006. Return Value:
  1007. If control did not leave the specified function in either the prologue
  1008. or an epilogue and a handler of the proper type is associated with the
  1009. function, then the address of the language specific exception handler
  1010. is returned. Otherwise, NULL is returned.
  1011. --*/
  1012. {
  1013. ULONG64 BranchTarget;
  1014. LONG Displacement;
  1015. ULONG FrameRegister;
  1016. ULONG Index;
  1017. LOGICAL InEpilogue;
  1018. PULONG64 IntegerAddress;
  1019. PULONG64 IntegerRegister;
  1020. PUCHAR NextByte;
  1021. ULONG PrologOffset;
  1022. ULONG RegisterNumber;
  1023. PUNWIND_INFO UnwindInfo;
  1024. //
  1025. // If the specified function does not use a frame pointer, then the
  1026. // establisher frame is the contents of the stack pointer. This may
  1027. // not actually be the real establisher frame if control left the
  1028. // function from within the prologue. In this case the establisher
  1029. // frame may be not required since control has not actually entered
  1030. // the function and prologue entries cannot refer to the establisher
  1031. // frame before it has been established, i.e., if it has not been
  1032. // established, then no save unwind codes should be encountered during
  1033. // the unwind operation.
  1034. //
  1035. // If the specified function uses a frame pointer and control left the
  1036. // function outside of the prologue or the unwind information contains
  1037. // a chained information structure, then the establisher frame is the
  1038. // contents of the frame pointer.
  1039. //
  1040. // If the specified function uses a frame pointer and control left the
  1041. // function from within the prologue, then the set frame pointer unwind
  1042. // code must be looked up in the unwind codes to detetermine if the
  1043. // contents of the stack pointer or the contents of the frame pointer
  1044. // should be used for the establisher frame. This may not atually be
  1045. // the real establisher frame. In this case the establisher frame may
  1046. // not be required since control has not actually entered the function
  1047. // and prologue entries cannot refer to the establisher frame before it
  1048. // has been established, i.e., if it has not been established, then no
  1049. // save unwind codes should be encountered during the unwind operation.
  1050. //
  1051. // N.B. The correctness of these assumptions is based on the ordering of
  1052. // unwind codes.
  1053. //
  1054. UnwindInfo = (PUNWIND_INFO)(FunctionEntry->UnwindData + ImageBase);
  1055. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  1056. if (UnwindInfo->FrameRegister == 0) {
  1057. *EstablisherFrame = ContextRecord->Rsp;
  1058. } else if ((PrologOffset >= UnwindInfo->SizeOfProlog) ||
  1059. ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0)) {
  1060. *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
  1061. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  1062. } else {
  1063. Index = 0;
  1064. while (Index < UnwindInfo->CountOfCodes) {
  1065. if (UnwindInfo->UnwindCode[Index].UnwindOp == UWOP_SET_FPREG) {
  1066. break;
  1067. }
  1068. Index += 1;
  1069. }
  1070. if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
  1071. *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
  1072. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  1073. } else {
  1074. *EstablisherFrame = ContextRecord->Rsp;
  1075. }
  1076. }
  1077. //
  1078. // Check for epilogue.
  1079. //
  1080. // If the point at which control left the specified function is in an
  1081. // epilogue, then emulate the execution of the epilogue forward and
  1082. // return no exception handler.
  1083. //
  1084. IntegerRegister = &ContextRecord->Rax;
  1085. NextByte = (PUCHAR)ControlPc;
  1086. //
  1087. // Check for one of:
  1088. //
  1089. // add rsp, imm8
  1090. // or
  1091. // add rsp, imm32
  1092. // or
  1093. // lea rsp, -disp8[fp]
  1094. // or
  1095. // lea rsp, -disp32[fp]
  1096. //
  1097. if ((NextByte[0] == SIZE64_PREFIX) &&
  1098. (NextByte[1] == ADD_IMM8_OP) &&
  1099. (NextByte[2] == 0xc4)) {
  1100. //
  1101. // add rsp, imm8.
  1102. //
  1103. NextByte += 4;
  1104. } else if ((NextByte[0] == SIZE64_PREFIX) &&
  1105. (NextByte[1] == ADD_IMM32_OP) &&
  1106. (NextByte[2] == 0xc4)) {
  1107. //
  1108. // add rsp, imm32.
  1109. //
  1110. NextByte += 7;
  1111. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1112. (NextByte[1] == LEA_OP)) {
  1113. FrameRegister = ((NextByte[0] & 0x7) << 3) | (NextByte[2] & 0x7);
  1114. if ((FrameRegister != 0) &&
  1115. (FrameRegister == UnwindInfo->FrameRegister)) {
  1116. if ((NextByte[2] & 0xf8) == 0x60) {
  1117. //
  1118. // lea rsp, disp8[fp].
  1119. //
  1120. NextByte += 4;
  1121. } else if ((NextByte[2] &0xf8) == 0xa0) {
  1122. //
  1123. // lea rsp, disp32[fp].
  1124. //
  1125. NextByte += 7;
  1126. }
  1127. }
  1128. }
  1129. //
  1130. // Check for any number of:
  1131. //
  1132. // pop nonvolatile-integer-register[0..15].
  1133. //
  1134. while (TRUE) {
  1135. if ((NextByte[0] & 0xf8) == POP_OP) {
  1136. NextByte += 1;
  1137. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1138. ((NextByte[1] & 0xf8) == POP_OP)) {
  1139. NextByte += 2;
  1140. } else {
  1141. break;
  1142. }
  1143. }
  1144. //
  1145. // If the next instruction is a return, then control is currently in
  1146. // an epilogue and execution of the epilogue should be emulated.
  1147. // Otherwise, execution is not in an epilogue and the prologue should
  1148. // be unwound.
  1149. //
  1150. InEpilogue = FALSE;
  1151. if (NextByte[0] == RET_OP) {
  1152. //
  1153. // A return is an unambiguous indication of an epilogue
  1154. //
  1155. InEpilogue = TRUE;
  1156. } else if (NextByte[0] == JMP_IMM8_OP || NextByte[0] == JMP_IMM32_OP) {
  1157. //
  1158. // An unconditional branch to a target that is equal to the start of
  1159. // or outside of this routine is logically a call to another function.
  1160. //
  1161. BranchTarget = (ULONG64)NextByte - ImageBase;
  1162. if (NextByte[0] == JMP_IMM8_OP) {
  1163. BranchTarget += 2 + (CHAR)NextByte[1];
  1164. } else {
  1165. BranchTarget += 5 + *((LONG UNALIGNED *)&NextByte[1]);
  1166. }
  1167. //
  1168. // Now determine whether the branch target refers to code within this
  1169. // function. If not, then it is an epilogue indicator.
  1170. //
  1171. if (BranchTarget <= FunctionEntry->BeginAddress ||
  1172. BranchTarget > FunctionEntry->EndAddress) {
  1173. InEpilogue = TRUE;
  1174. }
  1175. }
  1176. if (InEpilogue != FALSE) {
  1177. NextByte = (PUCHAR)ControlPc;
  1178. //
  1179. // Emulate one of (if any):
  1180. //
  1181. // add rsp, imm8
  1182. // or
  1183. // add rsp, imm32
  1184. // or
  1185. // lea rsp, disp8[frame-register]
  1186. // or
  1187. // lea rsp, disp32[frame-register]
  1188. //
  1189. if ((NextByte[0] & 0xf8) == SIZE64_PREFIX) {
  1190. if (NextByte[1] == ADD_IMM8_OP) {
  1191. //
  1192. // add rsp, imm8.
  1193. //
  1194. ContextRecord->Rsp += (CHAR)NextByte[3];
  1195. NextByte += 4;
  1196. } else if (NextByte[1] == ADD_IMM32_OP) {
  1197. //
  1198. // add rsp, imm32.
  1199. //
  1200. Displacement = NextByte[3] | (NextByte[4] << 8);
  1201. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  1202. ContextRecord->Rsp += Displacement;
  1203. NextByte += 7;
  1204. } else if (NextByte[1] == LEA_OP) {
  1205. if ((NextByte[2] & 0xf8) == 0x60) {
  1206. //
  1207. // lea rsp, disp8[frame-register].
  1208. //
  1209. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  1210. ContextRecord->Rsp += (CHAR)NextByte[3];
  1211. NextByte += 4;
  1212. } else if ((NextByte[2] & 0xf8) == 0xa0) {
  1213. //
  1214. // lea rsp, disp32[frame-register].
  1215. //
  1216. Displacement = NextByte[3] | (NextByte[4] << 8);
  1217. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  1218. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  1219. ContextRecord->Rsp += Displacement;
  1220. NextByte += 7;
  1221. }
  1222. }
  1223. }
  1224. //
  1225. // Emulate any number of (if any):
  1226. //
  1227. // pop nonvolatile-integer-register.
  1228. //
  1229. while (TRUE) {
  1230. if ((NextByte[0] & 0xf8) == POP_OP) {
  1231. //
  1232. // pop nonvolatile-integer-register[0..7]
  1233. //
  1234. RegisterNumber = NextByte[0] & 0x7;
  1235. IntegerAddress = (PULONG64)ContextRecord->Rsp;
  1236. IntegerRegister[RegisterNumber] = *IntegerAddress;
  1237. if (ARGUMENT_PRESENT(ContextPointers)) {
  1238. ContextPointers->IntegerContext[RegisterNumber] = IntegerAddress;
  1239. }
  1240. ContextRecord->Rsp += 8;
  1241. NextByte += 1;
  1242. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1243. ((NextByte[1] & 0xf8) == POP_OP)) {
  1244. //
  1245. // pop nonvolatile-integer-regiser[8..15]
  1246. //
  1247. RegisterNumber = ((NextByte[0] & 1) << 3) | (NextByte[1] & 0x7);
  1248. IntegerAddress = (PULONG64)ContextRecord->Rsp;
  1249. IntegerRegister[RegisterNumber] = *IntegerAddress;
  1250. if (ARGUMENT_PRESENT(ContextPointers)) {
  1251. ContextPointers->IntegerContext[RegisterNumber] = IntegerAddress;
  1252. }
  1253. ContextRecord->Rsp += 8;
  1254. NextByte += 2;
  1255. } else {
  1256. break;
  1257. }
  1258. }
  1259. //
  1260. // Emulate return and return null exception handler.
  1261. //
  1262. // Note: this instruction might in fact be a jmp, however
  1263. // we want to emulate a return regardless.
  1264. //
  1265. ContextRecord->Rip = *(PULONG64)(ContextRecord->Rsp);
  1266. ContextRecord->Rsp += 8;
  1267. return NULL;
  1268. }
  1269. //
  1270. // Control left the specified function outside an epilogue. Unwind the
  1271. // subject function and any chained unwind information.
  1272. //
  1273. FunctionEntry = RtlpUnwindPrologue(ImageBase,
  1274. ControlPc,
  1275. *EstablisherFrame,
  1276. FunctionEntry,
  1277. ContextRecord,
  1278. ContextPointers);
  1279. //
  1280. // If control left the specified function outside of the prologue and
  1281. // the function has a handler that matches the specified type, then
  1282. // return the address of the language specific exception handler.
  1283. // Otherwise, return NULL.
  1284. //
  1285. UnwindInfo = (PUNWIND_INFO)(FunctionEntry->UnwindData + ImageBase);
  1286. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  1287. if ((PrologOffset >= UnwindInfo->SizeOfProlog) &&
  1288. ((UnwindInfo->Flags & HandlerType) != 0)) {
  1289. Index = UnwindInfo->CountOfCodes;
  1290. if ((Index & 1) != 0) {
  1291. Index += 1;
  1292. }
  1293. *HandlerData = &UnwindInfo->UnwindCode[Index + 2];
  1294. return (PEXCEPTION_ROUTINE)(*((PULONG)&UnwindInfo->UnwindCode[Index]) + ImageBase);
  1295. } else {
  1296. return NULL;
  1297. }
  1298. }
  1299. VOID
  1300. RtlpGetStackLimits (
  1301. OUT PULONG64 LowLimit,
  1302. OUT PULONG64 HighLimit
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This function returns the current stack limits.
  1307. Arguments:
  1308. LowLimit - Supplies a pointer to a variable that is to receive
  1309. the low limit of the stack.
  1310. HighLimit - Supplies a pointer to a variable that is to receive
  1311. the high limit of the stack.
  1312. Return Value:
  1313. None.
  1314. --*/
  1315. {
  1316. #if defined(NTOS_KERNEL_RUNTIME)
  1317. PKTHREAD Thread;
  1318. Thread = KeGetCurrentThread();
  1319. *LowLimit = (ULONG64)Thread->StackLimit;
  1320. *HighLimit = (ULONG64)Thread->StackBase;
  1321. #else
  1322. *LowLimit = __readgsqword(FIELD_OFFSET(NT_TIB, StackLimit));
  1323. *HighLimit = __readgsqword(FIELD_OFFSET(NT_TIB, StackBase));
  1324. #endif
  1325. return;
  1326. }
  1327. #if !defined(NTOS_KERNEL_RUNTIME)
  1328. LIST_ENTRY RtlpDynamicFunctionTable;
  1329. PLIST_ENTRY
  1330. RtlGetFunctionTableListHead (
  1331. VOID
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This function returns the address of the dynamic function table list head.
  1336. Arguments:
  1337. None.
  1338. Return value:
  1339. The address of the dynamic function table list head is returned.
  1340. --*/
  1341. {
  1342. return &RtlpDynamicFunctionTable;
  1343. }
  1344. BOOLEAN
  1345. RtlAddFunctionTable (
  1346. IN PRUNTIME_FUNCTION FunctionTable,
  1347. IN ULONG EntryCount,
  1348. IN ULONG64 BaseAddress
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. This function adds a dynamic function table to the dynamic function table
  1353. list. A dynamic function table describe code that is generated at runtime.
  1354. The function table entries need not be sorted, however, if they are sorted
  1355. a binary search can be employed to find a particular entry. The function
  1356. table entries are scanned to determine is they are sorted and a minimum
  1357. and maximum address range is computed.
  1358. Arguments:
  1359. FunctionTable - Supplies a pointer to a function table.
  1360. EntryCount - Supplies the number of entries in the function table.
  1361. BaseAddress - Supplies the base address of the image containing the
  1362. described functions.
  1363. Return value:
  1364. If the function table is successfuly added, then a value of TRUE is
  1365. returned. Otherwise, FALSE is returned.
  1366. --*/
  1367. {
  1368. PRUNTIME_FUNCTION FunctionEntry;
  1369. ULONG Index;
  1370. PDYNAMIC_FUNCTION_TABLE NewTable;
  1371. //
  1372. // Allocate a new dynamic function table.
  1373. //
  1374. NewTable = RtlAllocateHeap(RtlProcessHeap(),
  1375. 0,
  1376. sizeof(DYNAMIC_FUNCTION_TABLE));
  1377. //
  1378. // If the allocation is successful, then add dynamic function table.
  1379. //
  1380. if (NewTable != NULL) {
  1381. NewTable->FunctionTable = FunctionTable;
  1382. NewTable->EntryCount = EntryCount;
  1383. NtQuerySystemTime(&NewTable->TimeStamp);
  1384. //
  1385. // Scan the function table for the minimum/maximum range and determine
  1386. // if the function table entries are sorted.
  1387. //
  1388. FunctionEntry = FunctionTable;
  1389. NewTable->MinimumAddress = FunctionEntry->BeginAddress;
  1390. NewTable->MaximumAddress = FunctionEntry->EndAddress;
  1391. NewTable->Type = RF_SORTED;
  1392. NewTable->BaseAddress = BaseAddress;
  1393. FunctionEntry += 1;
  1394. for (Index = 1; Index < EntryCount; Index += 1) {
  1395. if ((NewTable->Type == RF_SORTED) &&
  1396. (FunctionEntry->BeginAddress < FunctionTable[Index - 1].BeginAddress)) {
  1397. NewTable->Type = RF_UNSORTED;
  1398. }
  1399. if (FunctionEntry->BeginAddress < NewTable->MinimumAddress) {
  1400. NewTable->MinimumAddress = FunctionEntry->BeginAddress;
  1401. }
  1402. if (FunctionEntry->EndAddress > NewTable->MaximumAddress) {
  1403. NewTable->MaximumAddress = FunctionEntry->EndAddress;
  1404. }
  1405. FunctionEntry += 1;
  1406. }
  1407. //
  1408. // Compute the real minimum and maximum addresses and insert the new
  1409. // dyanmic function table in the dynamic function table list.
  1410. //
  1411. NewTable->MinimumAddress += BaseAddress;
  1412. NewTable->MaximumAddress += BaseAddress;
  1413. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1414. InsertTailList(&RtlpDynamicFunctionTable, &NewTable->ListEntry);
  1415. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1416. return TRUE;
  1417. } else {
  1418. return FALSE;
  1419. }
  1420. }
  1421. BOOLEAN
  1422. RtlInstallFunctionTableCallback (
  1423. IN ULONG64 TableIdentifier,
  1424. IN ULONG64 BaseAddress,
  1425. IN ULONG Length,
  1426. IN PGET_RUNTIME_FUNCTION_CALLBACK Callback,
  1427. IN PVOID Context,
  1428. IN PCWSTR OutOfProcessCallbackDll OPTIONAL
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. This function adds a dynamic function table to the dynamic function table
  1433. list. A dynamic function table describe code that is generated at runtime.
  1434. Arguments:
  1435. TableIdentifier - Supplies a value that identifies the dynamic function
  1436. table callback.
  1437. N.B. The two low order bits of this value must be set.
  1438. BaseAddress - Supplies the base address of the code region covered by
  1439. callback function.
  1440. Length - Supplies the length of code region covered by the callback
  1441. function.
  1442. Callback - Supplies the address of the callback function that will be
  1443. called to get function table entries for the functions covered by
  1444. the specified region.
  1445. Context - Supplies a context parameter that will be passed to the callback
  1446. routine.
  1447. OutOfProcessCallbackDll - Supplies an optional pointer to the path name of
  1448. a DLL that can be used by the debugger to obtain function table entries
  1449. from outside the process.
  1450. Return Value
  1451. If the function table is successfully installed, then TRUE is returned.
  1452. Otherwise, FALSE is returned.
  1453. --*/
  1454. {
  1455. PDYNAMIC_FUNCTION_TABLE NewTable;
  1456. SIZE_T Size;
  1457. //
  1458. // If the table identifier does not have the two low bits set, then return
  1459. // FALSE.
  1460. //
  1461. // N.B. The two low order bits are required to be set in order to ensure
  1462. // that the table identifier does not collide with an actual address
  1463. // of a function table, i.e., this value is used to delete the entry.
  1464. //
  1465. if ((TableIdentifier & 0x3) != 3) {
  1466. return FALSE;
  1467. }
  1468. //
  1469. // If the length of the code region is greater than 2gb, then return
  1470. // FALSE.
  1471. //
  1472. if ((LONG)Length < 0) {
  1473. return FALSE;
  1474. }
  1475. //
  1476. // Allocate a new dynamic function table.
  1477. //
  1478. Size = 0;
  1479. if (ARGUMENT_PRESENT(OutOfProcessCallbackDll)) {
  1480. Size = (wcslen(OutOfProcessCallbackDll) + 1) * sizeof(WCHAR);
  1481. }
  1482. NewTable = RtlAllocateHeap(RtlProcessHeap(),
  1483. 0,
  1484. sizeof(DYNAMIC_FUNCTION_TABLE) + Size);
  1485. //
  1486. // If the allocation is successful, then add dynamic function table.
  1487. //
  1488. if (NewTable != NULL) {
  1489. //
  1490. // Initialize the dynamic function table callback entry.
  1491. //
  1492. NewTable->FunctionTable = (PRUNTIME_FUNCTION)TableIdentifier;
  1493. NtQuerySystemTime(&NewTable->TimeStamp);
  1494. NewTable->MinimumAddress = BaseAddress;
  1495. NewTable->MaximumAddress = BaseAddress + Length;
  1496. NewTable->BaseAddress = BaseAddress;
  1497. NewTable->Callback = Callback;
  1498. NewTable->Context = Context;
  1499. NewTable->Type = RF_CALLBACK;
  1500. NewTable->OutOfProcessCallbackDll = NULL;
  1501. if (ARGUMENT_PRESENT(OutOfProcessCallbackDll)) {
  1502. NewTable->OutOfProcessCallbackDll = (PWSTR)(NewTable + 1);
  1503. wcscpy((PWSTR)(NewTable + 1), OutOfProcessCallbackDll);
  1504. }
  1505. //
  1506. // Insert the new dyanamic function table in the dynamic function table
  1507. // list.
  1508. //
  1509. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1510. InsertTailList(&RtlpDynamicFunctionTable, &NewTable->ListEntry);
  1511. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1512. return TRUE;
  1513. } else {
  1514. return FALSE;
  1515. }
  1516. }
  1517. BOOLEAN
  1518. RtlDeleteFunctionTable (
  1519. IN PRUNTIME_FUNCTION FunctionTable
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. This function deletes a dynamic function table from the dynamic function
  1524. table list.
  1525. Arguments:
  1526. FunctionTable - Supplies a pointer to a function table.
  1527. Return Value
  1528. If the function table is successfully deleted, then TRUE is returned.
  1529. Otherwise, FALSE is returned.
  1530. --*/
  1531. {
  1532. PDYNAMIC_FUNCTION_TABLE CurrentTable;
  1533. PLIST_ENTRY ListHead;
  1534. PLIST_ENTRY NextEntry;
  1535. BOOLEAN Status = FALSE;
  1536. //
  1537. // Search the dynamic function table list for a match on the the function
  1538. // table address.
  1539. //
  1540. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1541. ListHead = &RtlpDynamicFunctionTable;
  1542. NextEntry = ListHead->Flink;
  1543. while (NextEntry != ListHead) {
  1544. CurrentTable = CONTAINING_RECORD(NextEntry,
  1545. DYNAMIC_FUNCTION_TABLE,
  1546. ListEntry);
  1547. if (CurrentTable->FunctionTable == FunctionTable) {
  1548. RemoveEntryList(&CurrentTable->ListEntry);
  1549. RtlFreeHeap(RtlProcessHeap(), 0, CurrentTable);
  1550. Status = TRUE;
  1551. break;
  1552. }
  1553. NextEntry = NextEntry->Flink;
  1554. }
  1555. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1556. return Status;
  1557. }
  1558. PRUNTIME_FUNCTION
  1559. RtlpLookupDynamicFunctionEntry (
  1560. IN ULONG64 ControlPc,
  1561. OUT PULONG64 ImageBase
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This function searches the dynamic function table list for an entry that
  1566. contains the specified control PC. If a dynamic function table is located,
  1567. then its associated function table is search for a function table entry
  1568. that contains the specified control PC.
  1569. Arguments:
  1570. ControlPc - Supplies the control PC that is used as the key for the search.
  1571. ImageBase - Supplies the address of a variable that receives the image base
  1572. if a function table entry contains the specified control PC.
  1573. Return Value
  1574. If a function table entry cannot be located that contains the specified
  1575. control PC, then NULL is returned. Otherwise, the address of the function
  1576. table entry is returned and the image base is set to the base address of
  1577. the image containing the function.
  1578. --*/
  1579. {
  1580. ULONG64 BaseAddress;
  1581. PGET_RUNTIME_FUNCTION_CALLBACK Callback;
  1582. PVOID Context;
  1583. PDYNAMIC_FUNCTION_TABLE CurrentTable;
  1584. PRUNTIME_FUNCTION FunctionEntry;
  1585. PRUNTIME_FUNCTION FunctionTable;
  1586. LONG High;
  1587. ULONG Index;
  1588. PLIST_ENTRY ListHead;
  1589. LONG Low;
  1590. LONG Middle;
  1591. PLIST_ENTRY NextEntry;
  1592. //
  1593. // Search the dynamic function table list. If an entry is found that
  1594. // contains the specified control PC, then search the assoicated function
  1595. // table.
  1596. //
  1597. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1598. ListHead = &RtlpDynamicFunctionTable;
  1599. NextEntry = ListHead->Flink;
  1600. while (NextEntry != ListHead) {
  1601. CurrentTable = CONTAINING_RECORD(NextEntry,
  1602. DYNAMIC_FUNCTION_TABLE,
  1603. ListEntry);
  1604. //
  1605. // If the control PC is within the range of this dynamic function
  1606. // table, then search the associaed function table.
  1607. //
  1608. if ((ControlPc >= CurrentTable->MinimumAddress) &&
  1609. (ControlPc < CurrentTable->MaximumAddress)) {
  1610. //
  1611. // If this function table is sorted do a binary search. Otherwise,
  1612. // do a linear search.
  1613. //
  1614. FunctionTable = CurrentTable->FunctionTable;
  1615. BaseAddress = CurrentTable->BaseAddress;
  1616. if (CurrentTable->Type == RF_SORTED) {
  1617. //
  1618. // Perform binary search on the function table for a function table
  1619. // entry that contains the specified control PC.
  1620. //
  1621. ControlPc -= BaseAddress;
  1622. Low = 0;
  1623. High = CurrentTable->EntryCount - 1;
  1624. while (High >= Low) {
  1625. //
  1626. // Compute next probe index and test entry. If the specified PC
  1627. // is greater than of equal to the beginning address and less
  1628. // than the ending address of the function table entry, then
  1629. // return the address of the function table entry. Otherwise,
  1630. // continue the search.
  1631. //
  1632. Middle = (Low + High) >> 1;
  1633. FunctionEntry = &FunctionTable[Middle];
  1634. if (ControlPc < FunctionEntry->BeginAddress) {
  1635. High = Middle - 1;
  1636. } else if (ControlPc >= FunctionEntry->EndAddress) {
  1637. Low = Middle + 1;
  1638. } else {
  1639. *ImageBase = BaseAddress;
  1640. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1641. return FunctionEntry;
  1642. }
  1643. }
  1644. } else if (CurrentTable->Type == RF_UNSORTED) {
  1645. //
  1646. // Perform a linear seach on the function table for a function
  1647. // entry that contains the specified control PC.
  1648. //
  1649. ControlPc -= BaseAddress;
  1650. FunctionEntry = CurrentTable->FunctionTable;
  1651. for (Index = 0; Index < CurrentTable->EntryCount; Index += 1) {
  1652. if ((ControlPc >= FunctionEntry->BeginAddress) &&
  1653. (ControlPc < FunctionEntry->EndAddress)) {
  1654. *ImageBase = BaseAddress;
  1655. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1656. return FunctionEntry;
  1657. }
  1658. FunctionEntry += 1;
  1659. }
  1660. } else {
  1661. //
  1662. // Perform a callback to obtain the runtime function table
  1663. // entry that contains the specified control PC.
  1664. //
  1665. Callback = CurrentTable->Callback;
  1666. Context = CurrentTable->Context;
  1667. *ImageBase = BaseAddress;
  1668. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1669. return (Callback)(ControlPc, Context);
  1670. }
  1671. break;
  1672. }
  1673. NextEntry = NextEntry->Flink;
  1674. }
  1675. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1676. return NULL;
  1677. }
  1678. #endif
  1679. ULONG HistoryTotal = 0;
  1680. ULONG HistoryGlobal = 0;
  1681. ULONG HistoryGlobalHits = 0;
  1682. ULONG HistorySearch = 0;
  1683. ULONG HistorySearchHits = 0;
  1684. ULONG HistoryInsert = 0;
  1685. ULONG HistoryInsertHits = 0;
  1686. PRUNTIME_FUNCTION
  1687. RtlLookupFunctionEntry (
  1688. IN ULONG64 ControlPc,
  1689. OUT PULONG64 ImageBase,
  1690. IN OUT PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL
  1691. )
  1692. /*++
  1693. Routine Description:
  1694. This function searches the currently active function tables for an entry
  1695. that corresponds to the specified control PC.
  1696. Arguments:
  1697. ControlPc - Supplies the address of an instruction within the specified
  1698. function.
  1699. ImageBase - Supplies the address of a variable that receives the image base
  1700. if a function table entry contains the specified control PC.
  1701. HistoryTable - Supplies an optional pointer to an unwind history table.
  1702. Return Value:
  1703. If there is no entry in the function table for the specified PC, then
  1704. NULL is returned. Otherwise, the address of the function table entry
  1705. that corresponds to the specified PC is returned.
  1706. --*/
  1707. {
  1708. ULONG64 BaseAddress;
  1709. ULONG64 BeginAddress;
  1710. ULONG64 EndAddress;
  1711. PRUNTIME_FUNCTION FunctionEntry;
  1712. PRUNTIME_FUNCTION FunctionTable;
  1713. LONG High;
  1714. ULONG Index;
  1715. LONG Low;
  1716. LONG Middle;
  1717. ULONG RelativePc;
  1718. ULONG SizeOfTable;
  1719. //
  1720. // Attempt to find an image that contains the specified control PC. If
  1721. // an image is found, then search its function table for a function table
  1722. // entry that contains the specified control PC. If an image is not found
  1723. // then search the dynamic function table for an image that contains the
  1724. // specified control PC.
  1725. //
  1726. // If a history table is supplied and search is specfied, then the current
  1727. // operation that is being performed is the unwind phase of an exception
  1728. // dispatch followed by a unwind.
  1729. //
  1730. if ((ARGUMENT_PRESENT(HistoryTable)) &&
  1731. (HistoryTable->Search != UNWIND_HISTORY_TABLE_NONE)) {
  1732. HistoryTotal += 1;
  1733. //
  1734. // Search the global unwind history table if there is a chance of a
  1735. // match.
  1736. //
  1737. if (HistoryTable->Search == UNWIND_HISTORY_TABLE_GLOBAL) {
  1738. if ((ControlPc >= RtlpUnwindHistoryTable.LowAddress) &&
  1739. (ControlPc < RtlpUnwindHistoryTable.HighAddress)) {
  1740. HistoryGlobal += 1;
  1741. for (Index = 0; Index < RtlpUnwindHistoryTable.Count; Index += 1) {
  1742. BaseAddress = RtlpUnwindHistoryTable.Entry[Index].ImageBase;
  1743. FunctionEntry = RtlpUnwindHistoryTable.Entry[Index].FunctionEntry;
  1744. BeginAddress = FunctionEntry->BeginAddress + BaseAddress;
  1745. EndAddress = FunctionEntry->EndAddress + BaseAddress;
  1746. if ((ControlPc >= BeginAddress) && (ControlPc < EndAddress)) {
  1747. *ImageBase = BaseAddress;
  1748. HistoryGlobalHits += 1;
  1749. return FunctionEntry;
  1750. }
  1751. }
  1752. }
  1753. HistoryTable->Search = UNWIND_HISTORY_TABLE_LOCAL;
  1754. }
  1755. //
  1756. // Search the dynamic unwind history table if there is a chance of a
  1757. // match.
  1758. //
  1759. if ((ControlPc >= HistoryTable->LowAddress) &&
  1760. (ControlPc < HistoryTable->HighAddress)) {
  1761. HistorySearch += 1;
  1762. for (Index = 0; Index < HistoryTable->Count; Index += 1) {
  1763. BaseAddress = HistoryTable->Entry[Index].ImageBase;
  1764. FunctionEntry = HistoryTable->Entry[Index].FunctionEntry;
  1765. BeginAddress = FunctionEntry->BeginAddress + BaseAddress;
  1766. EndAddress = FunctionEntry->EndAddress + BaseAddress;
  1767. if ((ControlPc >= BeginAddress) && (ControlPc < EndAddress)) {
  1768. *ImageBase = BaseAddress;
  1769. HistorySearchHits += 1;
  1770. return FunctionEntry;
  1771. }
  1772. }
  1773. }
  1774. }
  1775. //
  1776. // There was not a match in either of the unwind history tables so attempt
  1777. // to find a matching entry in the loaded module list.
  1778. //
  1779. FunctionTable = RtlLookupFunctionTable((PVOID)ControlPc,
  1780. (PVOID *)ImageBase,
  1781. &SizeOfTable);
  1782. //
  1783. // If a function table is located, then search for a function table
  1784. // entry that contains the specified control PC.
  1785. //
  1786. if (FunctionTable != NULL) {
  1787. Low = 0;
  1788. High = (SizeOfTable / sizeof(RUNTIME_FUNCTION)) - 1;
  1789. RelativePc = (ULONG)(ControlPc - *ImageBase);
  1790. while (High >= Low) {
  1791. //
  1792. // Compute next probe index and test entry. If the specified
  1793. // control PC is greater than of equal to the beginning address
  1794. // and less than the ending address of the function table entry,
  1795. // then return the address of the function table entry. Otherwise,
  1796. // continue the search.
  1797. //
  1798. Middle = (Low + High) >> 1;
  1799. FunctionEntry = &FunctionTable[Middle];
  1800. if (RelativePc < FunctionEntry->BeginAddress) {
  1801. High = Middle - 1;
  1802. } else if (RelativePc >= FunctionEntry->EndAddress) {
  1803. Low = Middle + 1;
  1804. } else {
  1805. break;
  1806. }
  1807. }
  1808. if (High < Low) {
  1809. FunctionEntry = NULL;
  1810. }
  1811. } else {
  1812. //
  1813. // There was not a match in the loaded module list so attempt to find
  1814. // a matching entry in the dynamic function table list.
  1815. //
  1816. #if !defined(NTOS_KERNEL_RUNTIME)
  1817. FunctionEntry = RtlpLookupDynamicFunctionEntry(ControlPc, ImageBase);
  1818. #else
  1819. FunctionEntry = NULL;
  1820. #endif // NTOS_KERNEL_RUNTIME
  1821. }
  1822. //
  1823. // If a function table entry was located, search is not specified, and
  1824. // the specfied history table is not full, then attempt to make an entry
  1825. // in the history table.
  1826. //
  1827. if (ARGUMENT_PRESENT(HistoryTable) &&
  1828. (HistoryTable->Search == UNWIND_HISTORY_TABLE_NONE)) {
  1829. HistoryInsert += 1;
  1830. }
  1831. if (FunctionEntry != NULL) {
  1832. if (ARGUMENT_PRESENT(HistoryTable) &&
  1833. (HistoryTable->Search == UNWIND_HISTORY_TABLE_NONE) &&
  1834. (HistoryTable->Count < UNWIND_HISTORY_TABLE_SIZE)) {
  1835. Index = HistoryTable->Count;
  1836. HistoryTable->Count += 1;
  1837. HistoryTable->Entry[Index].ImageBase = *ImageBase;
  1838. HistoryTable->Entry[Index].FunctionEntry = FunctionEntry;
  1839. BeginAddress = FunctionEntry->BeginAddress + *ImageBase;
  1840. EndAddress = FunctionEntry->EndAddress + *ImageBase;
  1841. if (BeginAddress < HistoryTable->LowAddress) {
  1842. HistoryTable->LowAddress = BeginAddress;
  1843. }
  1844. if (EndAddress > HistoryTable->HighAddress) {
  1845. HistoryTable->HighAddress = EndAddress;
  1846. }
  1847. HistoryInsertHits += 1;
  1848. }
  1849. }
  1850. return FunctionEntry;
  1851. }
  1852. VOID
  1853. RtlpCopyContext (
  1854. OUT PCONTEXT Destination,
  1855. IN PCONTEXT Source
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. This function copies the nonvolatile context required for exception
  1860. dispatch and unwind from the specified source context record to the
  1861. specified destination context record.
  1862. Arguments:
  1863. Destination - Supplies a pointer to the destination context record.
  1864. Source - Supplies a pointer to the source context record.
  1865. Return Value:
  1866. None.
  1867. --*/
  1868. {
  1869. //
  1870. // Copy nonvolatile context required for exception dispatch and unwind.
  1871. //
  1872. Destination->Rip = Source->Rip;
  1873. Destination->Rbx = Source->Rbx;
  1874. Destination->Rsp = Source->Rsp;
  1875. Destination->Rbp = Source->Rbp;
  1876. Destination->Rsi = Source->Rsi;
  1877. Destination->Rdi = Source->Rdi;
  1878. Destination->R12 = Source->R12;
  1879. Destination->R13 = Source->R13;
  1880. Destination->R14 = Source->R14;
  1881. Destination->R15 = Source->R15;
  1882. Destination->Xmm6 = Source->Xmm6;
  1883. Destination->Xmm7 = Source->Xmm7;
  1884. Destination->Xmm8 = Source->Xmm8;
  1885. Destination->Xmm9 = Source->Xmm9;
  1886. Destination->Xmm10 = Source->Xmm10;
  1887. Destination->Xmm11 = Source->Xmm11;
  1888. Destination->Xmm12 = Source->Xmm12;
  1889. Destination->Xmm13 = Source->Xmm13;
  1890. Destination->Xmm14 = Source->Xmm14;
  1891. Destination->Xmm15 = Source->Xmm15;
  1892. Destination->SegCs = Source->SegCs;
  1893. Destination->SegSs = Source->SegSs;
  1894. Destination->MxCsr = Source->MxCsr;
  1895. Destination->EFlags = Source->EFlags;
  1896. return;
  1897. }