Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2388 lines
75 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 LEA_OP 0x8d
  62. #define POP_OP 0x58
  63. #define RET_OP 0xc3
  64. //
  65. // Define lookup table for providing the number of slots used by each unwind
  66. // code.
  67. //
  68. UCHAR RtlpUnwindOpSlotTable[] = {
  69. 1, // UWOP_PUSH_NONVOL
  70. 2, // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
  71. 1, // UWOP_ALLOC_SMALL
  72. 1, // UWOP_SET_FPREG
  73. 2, // UWOP_SAVE_NONVOL
  74. 3, // UWOP_SAVE_NONVOL_FAR
  75. 2, // UWOP_SAVE_XMM
  76. 3, // UWOP_SAVE_XMM_FAR
  77. 2, // UWOP_SAVE_XMM128
  78. 3, // UWOP_SAVE_XMM128_FAR
  79. 1 // UWOP_PUSH_MACHFRAME
  80. };
  81. //
  82. // Define forward referenced function prototypes.
  83. //
  84. VOID
  85. RtlpCopyContext (
  86. OUT PCONTEXT Destination,
  87. IN PCONTEXT Source
  88. );
  89. BOOLEAN
  90. RtlDispatchException (
  91. IN PEXCEPTION_RECORD ExceptionRecord,
  92. IN PCONTEXT ContextRecord
  93. )
  94. /*++
  95. Routine Description:
  96. This function attempts to dispatch an exception to a frame based
  97. handler by searching backwards through the stack based call frames.
  98. The search begins with the frame specified in the context record and
  99. continues backward until either a handler is found that handles the
  100. exception, the stack is found to be invalid (i.e., out of limits or
  101. unaligned), or the end of the call hierarchy is reached.
  102. As each frame is encounter, the PC where control left the corresponding
  103. function is determined and used to lookup exception handler information
  104. in the runtime function table built by the linker. If the respective
  105. routine has an exception handler, then the handler is called. If the
  106. handler does not handle the exception, then the prologue of the routine
  107. is executed backwards to "unwind" the effect of the prologue and then
  108. the next frame is examined.
  109. Arguments:
  110. ExceptionRecord - Supplies a pointer to an exception record.
  111. ContextRecord - Supplies a pointer to a context record.
  112. Return Value:
  113. If the exception is handled by one of the frame based handlers, then
  114. a value of TRUE is returned. Otherwise a value of FALSE is returned.
  115. --*/
  116. {
  117. CONTEXT ContextRecord1;
  118. ULONG64 ControlPc;
  119. DISPATCHER_CONTEXT DispatcherContext;
  120. EXCEPTION_DISPOSITION Disposition;
  121. ULONG64 EstablisherFrame;
  122. ULONG ExceptionFlags;
  123. PEXCEPTION_ROUTINE ExceptionRoutine;
  124. PRUNTIME_FUNCTION FunctionEntry;
  125. PVOID HandlerData;
  126. ULONG64 HighLimit;
  127. PUNWIND_HISTORY_TABLE HistoryTable;
  128. ULONG64 ImageBase;
  129. ULONG Index;
  130. ULONG64 LowLimit;
  131. ULONG64 NestedFrame;
  132. UNWIND_HISTORY_TABLE UnwindTable;
  133. //
  134. // Attempt to dispatch the exception using a vectored exception handler.
  135. //
  136. #if !defined(NTOS_KERNEL_RUNTIME)
  137. if (RtlCallVectoredExceptionHandlers(ExceptionRecord, ContextRecord) != FALSE) {
  138. return TRUE;
  139. }
  140. #endif
  141. //
  142. // Get current stack limits, copy the context record, get the initial
  143. // PC value, capture the exception flags, and set the nested exception
  144. // frame pointer.
  145. //
  146. RtlpGetStackLimits(&LowLimit, &HighLimit);
  147. RtlpCopyContext(&ContextRecord1, ContextRecord);
  148. ControlPc = (ULONG64)ExceptionRecord->ExceptionAddress;
  149. ExceptionFlags = ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE;
  150. NestedFrame = 0;
  151. //
  152. // Initialize the unwind history table.
  153. //
  154. HistoryTable = &UnwindTable;
  155. HistoryTable->Count = 0;
  156. HistoryTable->Search = UNWIND_HISTORY_TABLE_NONE;
  157. HistoryTable->LowAddress = - 1;
  158. HistoryTable->HighAddress = 0;
  159. //
  160. // Start with the frame specified by the context record and search
  161. // backwards through the call frame hierarchy attempting to find an
  162. // exception handler that will handle the exception.
  163. //
  164. do {
  165. //
  166. // Lookup the function table entry using the point at which control
  167. // left the procedure.
  168. //
  169. FunctionEntry = RtlLookupFunctionEntry(ControlPc,
  170. &ImageBase,
  171. HistoryTable);
  172. //
  173. // If there is a function table entry for the routine, then virtually
  174. // unwind to the caller of the current routine to obtain the virtual
  175. // frame pointer of the establisher and check if there is an exception
  176. // handler for the frame.
  177. //
  178. if (FunctionEntry != NULL) {
  179. ExceptionRoutine = RtlVirtualUnwind(UNW_FLAG_EHANDLER,
  180. ImageBase,
  181. ControlPc,
  182. FunctionEntry,
  183. &ContextRecord1,
  184. &HandlerData,
  185. &EstablisherFrame,
  186. NULL);
  187. //
  188. // If the establisher frame pointer is not within the specified
  189. // stack limits or the established frame pointer is unaligned,
  190. // then set the stack invalid flag in the exception record and
  191. // return exception not handled. Otherwise, check if the current
  192. // routine has an exception handler.
  193. //
  194. if ((EstablisherFrame < LowLimit) ||
  195. (EstablisherFrame > HighLimit) ||
  196. ((EstablisherFrame & 0xf) != 0)) {
  197. ExceptionFlags |= EXCEPTION_STACK_INVALID;
  198. break;
  199. } else if (ExceptionRoutine != NULL) {
  200. //
  201. // The frame has an exception handler.
  202. //
  203. // A linkage routine written in assembler is used to actually
  204. // call the actual exception handler. This is required by the
  205. // exception handler that is associated with the linkage
  206. // routine so it can have access to two sets of dispatcher
  207. // context when it is called.
  208. //
  209. do {
  210. //
  211. // Log the exception if exception logging is enabled.
  212. //
  213. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  214. if ((NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) != 0) {
  215. Index = RtlpLogExceptionHandler(ExceptionRecord,
  216. &ContextRecord1,
  217. ControlPc,
  218. FunctionEntry,
  219. sizeof(RUNTIME_FUNCTION));
  220. }
  221. //
  222. // Clear collided unwind, set the dispatcher context, and
  223. // call the exception handler.
  224. //
  225. ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
  226. DispatcherContext.ControlPc = ControlPc;
  227. DispatcherContext.ImageBase = ImageBase;
  228. DispatcherContext.FunctionEntry = FunctionEntry;
  229. DispatcherContext.EstablisherFrame = EstablisherFrame;
  230. DispatcherContext.ContextRecord = &ContextRecord1;
  231. DispatcherContext.LanguageHandler = ExceptionRoutine;
  232. DispatcherContext.HandlerData = HandlerData;
  233. DispatcherContext.HistoryTable = HistoryTable;
  234. Disposition =
  235. RtlpExecuteHandlerForException(ExceptionRecord,
  236. EstablisherFrame,
  237. ContextRecord,
  238. &DispatcherContext);
  239. if ((NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) != 0) {
  240. RtlpLogLastExceptionDisposition(Index, Disposition);
  241. }
  242. //
  243. // Propagate noncontinuable exception flag.
  244. //
  245. ExceptionFlags |=
  246. (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE);
  247. //
  248. // If the current scan is within a nested context and the
  249. // frame just examined is the end of the nested region,
  250. // then clear the nested context frame and the nested
  251. // exception flag in the exception flags.
  252. //
  253. if (NestedFrame == EstablisherFrame) {
  254. ExceptionFlags &= (~EXCEPTION_NESTED_CALL);
  255. NestedFrame = 0;
  256. }
  257. //
  258. // Case on the handler disposition.
  259. //
  260. switch (Disposition) {
  261. //
  262. // The disposition is to continue execution.
  263. //
  264. // If the exception is not continuable, then raise
  265. // the exception STATUS_NONCONTINUABLE_EXCEPTION.
  266. // Otherwise return exception handled.
  267. //
  268. case ExceptionContinueExecution :
  269. if ((ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) {
  270. RtlRaiseStatus(STATUS_NONCONTINUABLE_EXCEPTION);
  271. } else {
  272. return TRUE;
  273. }
  274. //
  275. // The disposition is to continue the search.
  276. //
  277. // Get next frame address and continue the search.
  278. //
  279. case ExceptionContinueSearch :
  280. break;
  281. //
  282. // The disposition is nested exception.
  283. //
  284. // Set the nested context frame to the establisher frame
  285. // address and set the nested exception flag in the
  286. // exception flags.
  287. //
  288. case ExceptionNestedException :
  289. ExceptionFlags |= EXCEPTION_NESTED_CALL;
  290. if (DispatcherContext.EstablisherFrame > NestedFrame) {
  291. NestedFrame = DispatcherContext.EstablisherFrame;
  292. }
  293. break;
  294. //
  295. // The dispostion is collided unwind.
  296. //
  297. // A collided unwind occurs when an exception dispatch
  298. // encounters a previous call to an unwind handler. In
  299. // this case the previous unwound frames must be skipped.
  300. //
  301. case ExceptionCollidedUnwind:
  302. ControlPc = DispatcherContext.ControlPc;
  303. ImageBase = DispatcherContext.ImageBase;
  304. FunctionEntry = DispatcherContext.FunctionEntry;
  305. EstablisherFrame = DispatcherContext.EstablisherFrame;
  306. RtlpCopyContext(&ContextRecord1,
  307. DispatcherContext.ContextRecord);
  308. ExceptionRoutine = DispatcherContext.LanguageHandler;
  309. HandlerData = DispatcherContext.HandlerData;
  310. HistoryTable = DispatcherContext.HistoryTable;
  311. ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
  312. break;
  313. //
  314. // All other disposition values are invalid.
  315. //
  316. // Raise invalid disposition exception.
  317. //
  318. default :
  319. RtlRaiseStatus(STATUS_INVALID_DISPOSITION);
  320. }
  321. } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
  322. }
  323. } else {
  324. //
  325. // Set the point where control left the current function by
  326. // obtaining the return address from the top of the stack.
  327. //
  328. ContextRecord1.Rip = *(PULONG64)(ContextRecord1.Rsp);
  329. ContextRecord1.Rsp += 8;
  330. }
  331. //
  332. // If the old control PC is the same as the new control PC, then
  333. // no progress is being made and the function tables are most likely
  334. // malformed.
  335. //
  336. if (ControlPc == ContextRecord1.Rip) {
  337. break;
  338. }
  339. //
  340. // Set point at which control left the previous routine.
  341. //
  342. ControlPc = ContextRecord1.Rip;
  343. } while ((ULONG64)ContextRecord1.Rsp < HighLimit);
  344. //
  345. // Set final exception flags and return exception not handled.
  346. //
  347. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  348. return FALSE;
  349. }
  350. VOID
  351. RtlUnwind (
  352. IN PVOID TargetFrame OPTIONAL,
  353. IN PVOID TargetIp OPTIONAL,
  354. IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
  355. IN PVOID ReturnValue
  356. )
  357. /*++
  358. Routine Description:
  359. This function initiates an unwind of procedure call frames. The machine
  360. state at the time of the call to unwind is captured in a context record
  361. and the unwinding flag is set in the exception flags of the exception
  362. record. If the TargetFrame parameter is not specified, then the exit unwind
  363. flag is also set in the exception flags of the exception record. A backward
  364. scan through the procedure call frames is then performed to find the target
  365. of the unwind operation.
  366. As each frame is encounter, the PC where control left the corresponding
  367. function is determined and used to lookup exception handler information
  368. in the runtime function table built by the linker. If the respective
  369. routine has an exception handler, then the handler is called.
  370. Arguments:
  371. TargetFrame - Supplies an optional pointer to the call frame that is the
  372. target of the unwind. If this parameter is not specified, then an exit
  373. unwind is performed.
  374. TargetIp - Supplies an optional instruction address that specifies the
  375. continuation address of the unwind. This address is ignored if the
  376. target frame parameter is not specified.
  377. ExceptionRecord - Supplies an optional pointer to an exception record.
  378. ReturnValue - Supplies a value that is to be placed in the integer
  379. function return register just before continuing execution.
  380. Return Value:
  381. None.
  382. --*/
  383. {
  384. CONTEXT ContextRecord;
  385. //
  386. // Call real unwind routine specifying a local context record and history
  387. // table address as extra arguments.
  388. //
  389. RtlUnwindEx(TargetFrame,
  390. TargetIp,
  391. ExceptionRecord,
  392. ReturnValue,
  393. &ContextRecord,
  394. NULL);
  395. return;
  396. }
  397. VOID
  398. RtlUnwindEx (
  399. IN PVOID TargetFrame OPTIONAL,
  400. IN PVOID TargetIp OPTIONAL,
  401. IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
  402. IN PVOID ReturnValue,
  403. IN PCONTEXT OriginalContext,
  404. IN PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL
  405. )
  406. /*++
  407. Routine Description:
  408. This function initiates an unwind of procedure call frames. The machine
  409. state at the time of the call to unwind is captured in a context record
  410. and the unwinding flag is set in the exception flags of the exception
  411. record. If the TargetFrame parameter is not specified, then the exit unwind
  412. flag is also set in the exception flags of the exception record. A backward
  413. scan through the procedure call frames is then performed to find the target
  414. of the unwind operation.
  415. As each frame is encounter, the PC where control left the corresponding
  416. function is determined and used to lookup exception handler information
  417. in the runtime function table built by the linker. If the respective
  418. routine has an exception handler, then the handler is called.
  419. Arguments:
  420. TargetFrame - Supplies an optional pointer to the call frame that is the
  421. target of the unwind. If this parameter is not specified, then an exit
  422. unwind is performed.
  423. TargetIp - Supplies an optional instruction address that specifies the
  424. continuation address of the unwind. This address is ignored if the
  425. target frame parameter is not specified.
  426. ExceptionRecord - Supplies an optional pointer to an exception record.
  427. ReturnValue - Supplies a value that is to be placed in the integer
  428. function return register just before continuing execution.
  429. OriginalContext - Supplies a pointer to a context record that can be used
  430. to store context druing the unwind operation.
  431. HistoryTable - Supplies an optional pointer to an unwind history table.
  432. Return Value:
  433. None.
  434. --*/
  435. {
  436. ULONG64 ControlPc;
  437. PCONTEXT CurrentContext;
  438. DISPATCHER_CONTEXT DispatcherContext;
  439. EXCEPTION_DISPOSITION Disposition;
  440. ULONG64 EstablisherFrame;
  441. ULONG ExceptionFlags;
  442. EXCEPTION_RECORD ExceptionRecord1;
  443. PEXCEPTION_ROUTINE ExceptionRoutine;
  444. PRUNTIME_FUNCTION FunctionEntry;
  445. PVOID HandlerData;
  446. ULONG64 HighLimit;
  447. ULONG64 ImageBase;
  448. CONTEXT LocalContext;
  449. ULONG64 LowLimit;
  450. PCONTEXT PreviousContext;
  451. PCONTEXT TempContext;
  452. //
  453. // Get current stack limits, capture the current context, virtually
  454. // unwind to the caller of this routine, get the initial PC value, and
  455. // set the unwind target address.
  456. //
  457. CurrentContext = OriginalContext;
  458. PreviousContext = &LocalContext;
  459. RtlpGetStackLimits(&LowLimit, &HighLimit);
  460. RtlCaptureContext(CurrentContext);
  461. //
  462. // If a history table is specified, then set to search history table.
  463. //
  464. if (ARGUMENT_PRESENT(HistoryTable)) {
  465. HistoryTable->Search = UNWIND_HISTORY_TABLE_GLOBAL;
  466. }
  467. //
  468. // If an exception record is not specified, then build a local exception
  469. // record for use in calling exception handlers during the unwind operation.
  470. //
  471. if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) {
  472. ExceptionRecord = &ExceptionRecord1;
  473. ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
  474. ExceptionRecord1.ExceptionRecord = NULL;
  475. ExceptionRecord1.ExceptionAddress = (PVOID)CurrentContext->Rip;
  476. ExceptionRecord1.NumberParameters = 0;
  477. }
  478. //
  479. // If the target frame of the unwind is specified, then a normal unwind
  480. // is being performed. Otherwise, an exit unwind is being performed.
  481. //
  482. ExceptionFlags = EXCEPTION_UNWINDING;
  483. if (ARGUMENT_PRESENT(TargetFrame) == FALSE) {
  484. ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
  485. }
  486. //
  487. // Scan backward through the call frame hierarchy and call exception
  488. // handlers until the target frame of the unwind is reached.
  489. //
  490. do {
  491. //
  492. // Lookup the function table entry using the point at which control
  493. // left the procedure.
  494. //
  495. ControlPc = CurrentContext->Rip;
  496. FunctionEntry = RtlLookupFunctionEntry(ControlPc,
  497. &ImageBase,
  498. HistoryTable);
  499. //
  500. // If there is a function table entry for the routine, then virtually
  501. // unwind to the caller of the routine to obtain the virtual frame
  502. // pointer of the establisher, but don't update the context record.
  503. //
  504. if (FunctionEntry != NULL) {
  505. RtlpCopyContext(PreviousContext, CurrentContext);
  506. ExceptionRoutine = RtlVirtualUnwind(UNW_FLAG_UHANDLER,
  507. ImageBase,
  508. ControlPc,
  509. FunctionEntry,
  510. PreviousContext,
  511. &HandlerData,
  512. &EstablisherFrame,
  513. NULL);
  514. //
  515. // If the establisher frame pointer is not within the specified
  516. // stack limits, the establisher frame pointer is unaligned, or
  517. // the target frame is below the establisher frame and an exit
  518. // unwind is not being performed, then raise a bad stack status.
  519. // Otherwise, check to determine if the current routine has an
  520. // exception handler.
  521. //
  522. if ((EstablisherFrame < LowLimit) ||
  523. (EstablisherFrame > HighLimit) ||
  524. ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
  525. ((ULONG64)TargetFrame < EstablisherFrame)) ||
  526. ((EstablisherFrame & 0xf) != 0)) {
  527. RtlRaiseStatus(STATUS_BAD_STACK);
  528. } else if (ExceptionRoutine != NULL) {
  529. //
  530. // The frame has a exception handler.
  531. //
  532. // A linkage routine written in assembler is used to actually
  533. // call the actual exception handler. This is required by the
  534. // exception handler that is associated with the linkage
  535. // routine so it can have access to two sets of dispatcher
  536. // context when it is called.
  537. //
  538. DispatcherContext.TargetIp = (ULONG64)TargetIp;
  539. do {
  540. //
  541. // If the establisher frame is the target of the unwind
  542. // operation, then set the target unwind flag.
  543. //
  544. if ((ULONG64)TargetFrame == EstablisherFrame) {
  545. ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
  546. }
  547. ExceptionRecord->ExceptionFlags = ExceptionFlags;
  548. //
  549. // Set the specified return value and target IP in case
  550. // the exception handler directly continues execution.
  551. //
  552. CurrentContext->Rax = (ULONG64)ReturnValue;
  553. //
  554. // Set the dispatcher context and call the termination
  555. // handler.
  556. //
  557. DispatcherContext.ControlPc = ControlPc;
  558. DispatcherContext.ImageBase = ImageBase;
  559. DispatcherContext.FunctionEntry = FunctionEntry;
  560. DispatcherContext.EstablisherFrame = EstablisherFrame;
  561. DispatcherContext.ContextRecord = CurrentContext;
  562. DispatcherContext.LanguageHandler = ExceptionRoutine;
  563. DispatcherContext.HandlerData = HandlerData;
  564. DispatcherContext.HistoryTable = HistoryTable;
  565. Disposition =
  566. RtlpExecuteHandlerForUnwind(ExceptionRecord,
  567. EstablisherFrame,
  568. CurrentContext,
  569. &DispatcherContext);
  570. //
  571. // Clear target unwind and collided unwind flags.
  572. //
  573. ExceptionFlags &=
  574. ~(EXCEPTION_COLLIDED_UNWIND | EXCEPTION_TARGET_UNWIND);
  575. //
  576. // Case on the handler disposition.
  577. //
  578. switch (Disposition) {
  579. //
  580. // The disposition is to continue the search.
  581. //
  582. // If the target frame has not been reached, then
  583. // swap context pointers.
  584. //
  585. case ExceptionContinueSearch :
  586. if (EstablisherFrame != (ULONG64)TargetFrame) {
  587. TempContext = CurrentContext;
  588. CurrentContext = PreviousContext;
  589. PreviousContext = TempContext;
  590. }
  591. break;
  592. //
  593. // The disposition is collided unwind.
  594. //
  595. // Copy the context of the previous unwind and
  596. // virtually unwind to the caller of the extablisher,
  597. // then set the target of the current unwind to the
  598. // dispatcher context of the previous unwind, and
  599. // reexecute the exception handler from the collided
  600. // frame with the collided unwind flag set in the
  601. // exception record.
  602. //
  603. case ExceptionCollidedUnwind :
  604. ControlPc = DispatcherContext.ControlPc;
  605. ImageBase = DispatcherContext.ImageBase;
  606. FunctionEntry = DispatcherContext.FunctionEntry;
  607. RtlpCopyContext(OriginalContext,
  608. DispatcherContext.ContextRecord);
  609. CurrentContext = OriginalContext;
  610. PreviousContext = &LocalContext;
  611. RtlpCopyContext(PreviousContext, CurrentContext);
  612. RtlVirtualUnwind(UNW_FLAG_NHANDLER,
  613. ImageBase,
  614. ControlPc,
  615. FunctionEntry,
  616. PreviousContext,
  617. &HandlerData,
  618. &EstablisherFrame,
  619. NULL);
  620. EstablisherFrame = DispatcherContext.EstablisherFrame;
  621. ExceptionRoutine = DispatcherContext.LanguageHandler;
  622. HandlerData = DispatcherContext.HandlerData;
  623. HistoryTable = DispatcherContext.HistoryTable;
  624. ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
  625. break;
  626. //
  627. // All other disposition values are invalid.
  628. //
  629. // Raise invalid disposition exception.
  630. //
  631. default :
  632. RtlRaiseStatus(STATUS_INVALID_DISPOSITION);
  633. }
  634. } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
  635. } else {
  636. //
  637. // If the target frame has not been reached, then swap
  638. // context pointers.
  639. //
  640. if (EstablisherFrame != (ULONG64)TargetFrame) {
  641. TempContext = CurrentContext;
  642. CurrentContext = PreviousContext;
  643. PreviousContext = TempContext;
  644. }
  645. }
  646. } else {
  647. //
  648. // Set the point where control left the current function by
  649. // obtaining the return address from the top of the stack.
  650. //
  651. CurrentContext->Rip = *(PULONG64)(CurrentContext->Rsp);
  652. CurrentContext->Rsp += 8;
  653. }
  654. } while ((EstablisherFrame < HighLimit) &&
  655. (EstablisherFrame != (ULONG64)TargetFrame) &&
  656. (ControlPc != CurrentContext->Rip));
  657. //
  658. // If the establisher stack pointer is equal to the target frame pointer,
  659. // then continue execution. Otherwise, an exit unwind was performed or the
  660. // target of the unwind did not exist and the debugger and subsystem are
  661. // given a second chance to handle the unwind.
  662. //
  663. if (EstablisherFrame == (ULONG64)TargetFrame) {
  664. CurrentContext->Rax = (ULONG64)ReturnValue;
  665. if (!ARGUMENT_PRESENT(ExceptionRecord) ||
  666. (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. LONG Displacement;
  1014. ULONG FrameRegister;
  1015. ULONG Index;
  1016. PULONG64 IntegerRegister;
  1017. PUCHAR NextByte;
  1018. ULONG PrologOffset;
  1019. ULONG RegisterNumber;
  1020. PUNWIND_INFO UnwindInfo;
  1021. //
  1022. // If the specified function does not use a frame pointer, then the
  1023. // establisher frame is the contents of the stack pointer. This may
  1024. // not actually be the real establisher frame if control left the
  1025. // function from within the prologue. In this case the establisher
  1026. // frame may be not required since control has not actually entered
  1027. // the function and prologue entries cannot refer to the establisher
  1028. // frame before it has been established, i.e., if it has not been
  1029. // established, then no save unwind codes should be encountered during
  1030. // the unwind operation.
  1031. //
  1032. // If the specified function uses a frame pointer and control left the
  1033. // function outside of the prologue or the unwind information contains
  1034. // a chained information structure, then the establisher frame is the
  1035. // contents of the frame pointer.
  1036. //
  1037. // If the specified function uses a frame pointer and control left the
  1038. // function from within the prologue, then the set frame pointer unwind
  1039. // code must be looked up in the unwind codes to detetermine if the
  1040. // contents of the stack pointer or the contents of the frame pointer
  1041. // should be used for the establisher frame. This may not atually be
  1042. // the real establisher frame. In this case the establisher frame may
  1043. // not be required since control has not actually entered the function
  1044. // and prologue entries cannot refer to the establisher frame before it
  1045. // has been established, i.e., if it has not been established, then no
  1046. // save unwind codes should be encountered during the unwind operation.
  1047. //
  1048. // N.B. The correctness of these assumptions is based on the ordering of
  1049. // unwind codes.
  1050. //
  1051. UnwindInfo = (PUNWIND_INFO)(FunctionEntry->UnwindData + ImageBase);
  1052. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  1053. if (UnwindInfo->FrameRegister == 0) {
  1054. *EstablisherFrame = ContextRecord->Rsp;
  1055. } else if ((PrologOffset >= UnwindInfo->SizeOfProlog) ||
  1056. ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0)) {
  1057. *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
  1058. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  1059. } else {
  1060. Index = 0;
  1061. while (Index < UnwindInfo->CountOfCodes) {
  1062. if (UnwindInfo->UnwindCode[Index].UnwindOp == UWOP_SET_FPREG) {
  1063. break;
  1064. }
  1065. Index += 1;
  1066. }
  1067. if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
  1068. *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
  1069. *EstablisherFrame -= UnwindInfo->FrameOffset * 16;
  1070. } else {
  1071. *EstablisherFrame = ContextRecord->Rsp;
  1072. }
  1073. }
  1074. //
  1075. // Check for epilogue.
  1076. //
  1077. // If the point at which control left the specified function is in an
  1078. // epilogue, then emulate the execution of the epilogue forward and
  1079. // return no exception handler.
  1080. //
  1081. IntegerRegister = &ContextRecord->Rax;
  1082. NextByte = (PUCHAR)ControlPc;
  1083. //
  1084. // Check for one of:
  1085. //
  1086. // add rsp, imm8
  1087. // or
  1088. // add rsp, imm32
  1089. // or
  1090. // lea rsp, -disp8[fp]
  1091. // or
  1092. // lea rsp, -disp32[fp]
  1093. //
  1094. if ((NextByte[0] == SIZE64_PREFIX) &&
  1095. (NextByte[1] == ADD_IMM8_OP) &&
  1096. (NextByte[2] == 0xc4)) {
  1097. //
  1098. // add rsp, imm8.
  1099. //
  1100. NextByte += 4;
  1101. } else if ((NextByte[0] == SIZE64_PREFIX) &&
  1102. (NextByte[1] == ADD_IMM32_OP) &&
  1103. (NextByte[2] == 0xc4)) {
  1104. //
  1105. // add rsp, imm32.
  1106. //
  1107. NextByte += 7;
  1108. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1109. (NextByte[1] == LEA_OP)) {
  1110. FrameRegister = ((NextByte[0] & 0x7) << 3) | (NextByte[2] & 0x7);
  1111. if ((FrameRegister != 0) &&
  1112. (FrameRegister == UnwindInfo->FrameRegister)) {
  1113. if ((NextByte[2] & 0xf8) == 0x60) {
  1114. //
  1115. // lea rsp, disp8[fp].
  1116. //
  1117. NextByte += 4;
  1118. } else if ((NextByte[2] &0xf8) == 0xa0) {
  1119. //
  1120. // lea rsp, disp32[fp].
  1121. //
  1122. NextByte += 7;
  1123. }
  1124. }
  1125. }
  1126. //
  1127. // Check for any number of:
  1128. //
  1129. // pop nonvolatile-integer-register[0..15].
  1130. //
  1131. while (TRUE) {
  1132. if ((NextByte[0] & 0xf8) == POP_OP) {
  1133. NextByte += 1;
  1134. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1135. ((NextByte[1] & 0xf8) == POP_OP)) {
  1136. NextByte += 2;
  1137. } else {
  1138. break;
  1139. }
  1140. }
  1141. //
  1142. // If the next instruction is a return, then control is currently in
  1143. // an epilogue and execution of the epilogue should be emulated.
  1144. // Otherwise, execution is not in an epilogue and the prologue should
  1145. // be unwound.
  1146. //
  1147. if (NextByte[0] == RET_OP) {
  1148. NextByte = (PUCHAR)ControlPc;
  1149. //
  1150. // Emulate one of (if any):
  1151. //
  1152. // add rsp, imm8
  1153. // or
  1154. // add rsp, imm32
  1155. // or
  1156. // lea rsp, disp8[frame-register]
  1157. // or
  1158. // lea rsp, disp32[frame-register]
  1159. //
  1160. if (NextByte[1] == ADD_IMM8_OP) {
  1161. //
  1162. // add rsp, imm8.
  1163. //
  1164. ContextRecord->Rsp += (CHAR)NextByte[3];
  1165. NextByte += 4;
  1166. } else if (NextByte[1] == ADD_IMM32_OP) {
  1167. //
  1168. // add rsp, imm32.
  1169. //
  1170. Displacement = NextByte[3] | (NextByte[4] << 8);
  1171. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  1172. ContextRecord->Rsp += Displacement;
  1173. NextByte += 7;
  1174. } else if (NextByte[1] == LEA_OP) {
  1175. if ((NextByte[2] & 0xf8) == 0x60) {
  1176. //
  1177. // lea rsp, disp8[frame-register].
  1178. //
  1179. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  1180. ContextRecord->Rsp += (CHAR)NextByte[3];
  1181. NextByte += 4;
  1182. } else if ((NextByte[2] & 0xf8) == 0xa0) {
  1183. //
  1184. // lea rsp, disp32[frame-register].
  1185. //
  1186. Displacement = NextByte[3] | (NextByte[4] << 8);
  1187. Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
  1188. ContextRecord->Rsp = IntegerRegister[FrameRegister];
  1189. ContextRecord->Rsp += Displacement;
  1190. NextByte += 7;
  1191. }
  1192. }
  1193. //
  1194. // Emulate any number of (if any):
  1195. //
  1196. // pop nonvolatile-integer-register.
  1197. //
  1198. while (TRUE) {
  1199. if ((NextByte[0] & 0xf8) == POP_OP) {
  1200. //
  1201. // pop nonvolatile-integer-register[0..7]
  1202. //
  1203. RegisterNumber = NextByte[0] & 0x7;
  1204. IntegerRegister[RegisterNumber] = *(PULONG64)(ContextRecord->Rsp);
  1205. ContextRecord->Rsp += 8;
  1206. NextByte += 1;
  1207. } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
  1208. ((NextByte[1] & 0xf8) == POP_OP)) {
  1209. //
  1210. // pop nonvolatile-integer-regiser[8..15]
  1211. //
  1212. RegisterNumber = ((NextByte[0] & 1) << 3) | (NextByte[1] & 0x7);
  1213. IntegerRegister[RegisterNumber] = *(PULONG64)(ContextRecord->Rsp);
  1214. ContextRecord->Rsp += 8;
  1215. NextByte += 2;
  1216. } else {
  1217. break;
  1218. }
  1219. }
  1220. //
  1221. // Emulate return and return null exception handler.
  1222. //
  1223. ContextRecord->Rip = *(PULONG64)(ContextRecord->Rsp);
  1224. ContextRecord->Rsp += 8;
  1225. return NULL;
  1226. }
  1227. //
  1228. // Control left the specified function outside an epilogue. Unwind the
  1229. // subject function and any chained unwind information.
  1230. //
  1231. FunctionEntry = RtlpUnwindPrologue(ImageBase,
  1232. ControlPc,
  1233. *EstablisherFrame,
  1234. FunctionEntry,
  1235. ContextRecord,
  1236. ContextPointers);
  1237. //
  1238. // If control left the specified function outside of the prologue and
  1239. // the function has a handler that matches the specified type, then
  1240. // return the address of the language specific exception handler.
  1241. // Otherwise, return NULL.
  1242. //
  1243. UnwindInfo = (PUNWIND_INFO)(FunctionEntry->UnwindData + ImageBase);
  1244. PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
  1245. if ((PrologOffset >= UnwindInfo->SizeOfProlog) &&
  1246. ((UnwindInfo->Flags & HandlerType) != 0)) {
  1247. Index = UnwindInfo->CountOfCodes;
  1248. if ((Index & 1) != 0) {
  1249. Index += 1;
  1250. }
  1251. *HandlerData = &UnwindInfo->UnwindCode[Index + 2];
  1252. return (PEXCEPTION_ROUTINE)(*((PULONG)&UnwindInfo->UnwindCode[Index]) + ImageBase);
  1253. } else {
  1254. return NULL;
  1255. }
  1256. }
  1257. VOID
  1258. RtlpGetStackLimits (
  1259. OUT PULONG64 LowLimit,
  1260. OUT PULONG64 HighLimit
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This function returns the current stack limits.
  1265. Arguments:
  1266. LowLimit - Supplies a pointer to a variable that is to receive
  1267. the low limit of the stack.
  1268. HighLimit - Supplies a pointer to a variable that is to receive
  1269. the high limit of the stack.
  1270. Return Value:
  1271. None.
  1272. --*/
  1273. {
  1274. #if defined(NTOS_KERNEL_RUNTIME)
  1275. PKTHREAD Thread;
  1276. Thread = KeGetCurrentThread();
  1277. *LowLimit = (ULONG64)Thread->StackLimit;
  1278. *HighLimit = (ULONG64)Thread->StackBase;
  1279. #else
  1280. *LowLimit = __readgsqword(FIELD_OFFSET(NT_TIB, StackLimit));
  1281. *HighLimit = __readgsqword(FIELD_OFFSET(NT_TIB, StackBase));
  1282. #endif
  1283. return;
  1284. }
  1285. #if !defined(NTOS_KERNEL_RUNTIME)
  1286. LIST_ENTRY RtlpDynamicFunctionTable;
  1287. PLIST_ENTRY
  1288. RtlGetFunctionTableListHead (
  1289. VOID
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This function returns the address of the dynamic function table list head.
  1294. Arguments:
  1295. None.
  1296. Return value:
  1297. The address of the dynamic function table list head is returned.
  1298. --*/
  1299. {
  1300. return &RtlpDynamicFunctionTable;
  1301. }
  1302. BOOLEAN
  1303. RtlAddFunctionTable (
  1304. IN PRUNTIME_FUNCTION FunctionTable,
  1305. IN ULONG EntryCount,
  1306. IN ULONG64 BaseAddress
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. This function adds a dynamic function table to the dynamic function table
  1311. list. A dynamic function table describe code that is generated at runtime.
  1312. The function table entries need not be sorted, however, if they are sorted
  1313. a binary search can be employed to find a particular entry. The function
  1314. table entries are scanned to determine is they are sorted and a minimum
  1315. and maximum address range is computed.
  1316. Arguments:
  1317. FunctionTable - Supplies a pointer to a function table.
  1318. EntryCount - Supplies the number of entries in the function table.
  1319. BaseAddress - Supplies the base address of the image containing the
  1320. described functions.
  1321. Return value:
  1322. If the function table is successfuly added, then a value of TRUE is
  1323. returned. Otherwise, FALSE is returned.
  1324. --*/
  1325. {
  1326. PRUNTIME_FUNCTION FunctionEntry;
  1327. ULONG Index;
  1328. PDYNAMIC_FUNCTION_TABLE NewTable;
  1329. //
  1330. // Allocate a new dynamic function table.
  1331. //
  1332. NewTable = RtlAllocateHeap(RtlProcessHeap(),
  1333. 0,
  1334. sizeof(DYNAMIC_FUNCTION_TABLE));
  1335. //
  1336. // If the allocation is successful, then add dynamic function table.
  1337. //
  1338. if (NewTable != NULL) {
  1339. NewTable->FunctionTable = FunctionTable;
  1340. NewTable->EntryCount = EntryCount;
  1341. NtQuerySystemTime(&NewTable->TimeStamp);
  1342. //
  1343. // Scan the function table for the minimum/maximum range and determine
  1344. // if the function table entries are sorted.
  1345. //
  1346. FunctionEntry = FunctionTable;
  1347. NewTable->MinimumAddress = FunctionEntry->BeginAddress;
  1348. NewTable->MaximumAddress = FunctionEntry->EndAddress;
  1349. NewTable->Type = RF_SORTED;
  1350. NewTable->BaseAddress = BaseAddress;
  1351. FunctionEntry += 1;
  1352. for (Index = 1; Index < EntryCount; Index += 1) {
  1353. if ((NewTable->Type == RF_SORTED) &&
  1354. (FunctionEntry->BeginAddress < FunctionTable[Index - 1].BeginAddress)) {
  1355. NewTable->Type = RF_UNSORTED;
  1356. }
  1357. if (FunctionEntry->BeginAddress < NewTable->MinimumAddress) {
  1358. NewTable->MinimumAddress = FunctionEntry->BeginAddress;
  1359. }
  1360. if (FunctionEntry->EndAddress > NewTable->MaximumAddress) {
  1361. NewTable->MaximumAddress = FunctionEntry->EndAddress;
  1362. }
  1363. FunctionEntry += 1;
  1364. }
  1365. //
  1366. // Compute the real minimum and maximum addresses and insert the new
  1367. // dyanmic function table in the dynamic function table list.
  1368. //
  1369. NewTable->MinimumAddress += BaseAddress;
  1370. NewTable->MaximumAddress += BaseAddress;
  1371. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1372. InsertTailList(&RtlpDynamicFunctionTable, &NewTable->ListEntry);
  1373. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1374. return TRUE;
  1375. } else {
  1376. return FALSE;
  1377. }
  1378. }
  1379. BOOLEAN
  1380. RtlInstallFunctionTableCallback (
  1381. IN ULONG64 TableIdentifier,
  1382. IN ULONG64 BaseAddress,
  1383. IN ULONG Length,
  1384. IN PGET_RUNTIME_FUNCTION_CALLBACK Callback,
  1385. IN PVOID Context,
  1386. IN PCWSTR OutOfProcessCallbackDll OPTIONAL
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. This function adds a dynamic function table to the dynamic function table
  1391. list. A dynamic function table describe code that is generated at runtime.
  1392. Arguments:
  1393. TableIdentifier - Supplies a value that identifies the dynamic function
  1394. table callback.
  1395. N.B. The two low order bits of this value must be set.
  1396. BaseAddress - Supplies the base address of the code region covered by
  1397. callback function.
  1398. Length - Supplies the length of code region covered by the callback
  1399. function.
  1400. Callback - Supplies the address of the callback function that will be
  1401. called to get function table entries for the functions covered by
  1402. the specified region.
  1403. Context - Supplies a context parameter that will be passed to the callback
  1404. routine.
  1405. OutOfProcessCallbackDll - Supplies an optional pointer to the path name of
  1406. a DLL that can be used by the debugger to obtain function table entries
  1407. from outside the process.
  1408. Return Value
  1409. If the function table is successfully installed, then TRUE is returned.
  1410. Otherwise, FALSE is returned.
  1411. --*/
  1412. {
  1413. PDYNAMIC_FUNCTION_TABLE NewTable;
  1414. SIZE_T Size;
  1415. //
  1416. // If the table identifier does not have the two low bits set, then return
  1417. // FALSE.
  1418. //
  1419. // N.B. The two low order bits are required to be set in order to ensure
  1420. // that the table identifier does not collide with an actual address
  1421. // of a function table, i.e., this value is used to delete the entry.
  1422. //
  1423. if ((TableIdentifier & 0x3) != 3) {
  1424. return FALSE;
  1425. }
  1426. //
  1427. // If the length of the code region is greater than 2gb, then return
  1428. // FALSE.
  1429. //
  1430. if ((LONG)Length < 0) {
  1431. return FALSE;
  1432. }
  1433. //
  1434. // Allocate a new dynamic function table.
  1435. //
  1436. Size = 0;
  1437. if (ARGUMENT_PRESENT(OutOfProcessCallbackDll)) {
  1438. Size = (wcslen(OutOfProcessCallbackDll) + 1) * sizeof(WCHAR);
  1439. }
  1440. NewTable = RtlAllocateHeap(RtlProcessHeap(),
  1441. 0,
  1442. sizeof(DYNAMIC_FUNCTION_TABLE) + Size);
  1443. //
  1444. // If the allocation is successful, then add dynamic function table.
  1445. //
  1446. if (NewTable != NULL) {
  1447. //
  1448. // Initialize the dynamic function table callback entry.
  1449. //
  1450. NewTable->FunctionTable = (PRUNTIME_FUNCTION)TableIdentifier;
  1451. NtQuerySystemTime(&NewTable->TimeStamp);
  1452. NewTable->MinimumAddress = BaseAddress;
  1453. NewTable->MaximumAddress = BaseAddress + Length;
  1454. NewTable->BaseAddress = BaseAddress;
  1455. NewTable->Callback = Callback;
  1456. NewTable->Context = Context;
  1457. NewTable->Type = RF_CALLBACK;
  1458. NewTable->OutOfProcessCallbackDll = NULL;
  1459. if (ARGUMENT_PRESENT(OutOfProcessCallbackDll)) {
  1460. NewTable->OutOfProcessCallbackDll = (PWSTR)(NewTable + 1);
  1461. wcscpy((PWSTR)(NewTable + 1), OutOfProcessCallbackDll);
  1462. }
  1463. //
  1464. // Insert the new dyanamic function table in the dynamic function table
  1465. // list.
  1466. //
  1467. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1468. InsertTailList(&RtlpDynamicFunctionTable, &NewTable->ListEntry);
  1469. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1470. return TRUE;
  1471. } else {
  1472. return FALSE;
  1473. }
  1474. }
  1475. BOOLEAN
  1476. RtlDeleteFunctionTable (
  1477. IN PRUNTIME_FUNCTION FunctionTable
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. This function deletes a dynamic function table from the dynamic function
  1482. table list.
  1483. Arguments:
  1484. FunctionTable - Supplies a pointer to a function table.
  1485. Return Value
  1486. If the function table is successfully deleted, then TRUE is returned.
  1487. Otherwise, FALSE is returned.
  1488. --*/
  1489. {
  1490. PDYNAMIC_FUNCTION_TABLE CurrentTable;
  1491. PLIST_ENTRY ListHead;
  1492. PLIST_ENTRY NextEntry;
  1493. BOOLEAN Status = FALSE;
  1494. //
  1495. // Search the dynamic function table list for a match on the the function
  1496. // table address.
  1497. //
  1498. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1499. ListHead = &RtlpDynamicFunctionTable;
  1500. NextEntry = ListHead->Flink;
  1501. while (NextEntry != ListHead) {
  1502. CurrentTable = CONTAINING_RECORD(NextEntry,
  1503. DYNAMIC_FUNCTION_TABLE,
  1504. ListEntry);
  1505. if (CurrentTable->FunctionTable == FunctionTable) {
  1506. RemoveEntryList(&CurrentTable->ListEntry);
  1507. RtlFreeHeap(RtlProcessHeap(), 0, CurrentTable);
  1508. Status = TRUE;
  1509. break;
  1510. }
  1511. NextEntry = NextEntry->Flink;
  1512. }
  1513. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1514. return Status;
  1515. }
  1516. PRUNTIME_FUNCTION
  1517. RtlpLookupDynamicFunctionEntry (
  1518. IN ULONG64 ControlPc,
  1519. OUT PULONG64 ImageBase
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. This function searches the dynamic function table list for an entry that
  1524. contains the specified control PC. If a dynamic function table is located,
  1525. then its associated function table is search for a function table entry
  1526. that contains the specified control PC.
  1527. Arguments:
  1528. ControlPc - Supplies the control PC that is used as the key for the search.
  1529. ImageBase - Supplies the address of a variable that receives the image base
  1530. if a function table entry contains the specified control PC.
  1531. Return Value
  1532. If a function table entry cannot be located that contains the specified
  1533. control PC, then NULL is returned. Otherwise, the address of the function
  1534. table entry is returned and the image base is set to the base address of
  1535. the image containing the function.
  1536. --*/
  1537. {
  1538. ULONG64 BaseAddress;
  1539. PGET_RUNTIME_FUNCTION_CALLBACK Callback;
  1540. PVOID Context;
  1541. PDYNAMIC_FUNCTION_TABLE CurrentTable;
  1542. PRUNTIME_FUNCTION FunctionEntry;
  1543. PRUNTIME_FUNCTION FunctionTable;
  1544. LONG High;
  1545. ULONG Index;
  1546. PLIST_ENTRY ListHead;
  1547. LONG Low;
  1548. LONG Middle;
  1549. PLIST_ENTRY NextEntry;
  1550. //
  1551. // Search the dynamic function table list. If an entry is found that
  1552. // contains the specified control PC, then search the assoicated function
  1553. // table.
  1554. //
  1555. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1556. ListHead = &RtlpDynamicFunctionTable;
  1557. NextEntry = ListHead->Flink;
  1558. while (NextEntry != ListHead) {
  1559. CurrentTable = CONTAINING_RECORD(NextEntry,
  1560. DYNAMIC_FUNCTION_TABLE,
  1561. ListEntry);
  1562. //
  1563. // If the control PC is within the range of this dynamic function
  1564. // table, then search the associaed function table.
  1565. //
  1566. if ((ControlPc >= CurrentTable->MinimumAddress) &&
  1567. (ControlPc < CurrentTable->MaximumAddress)) {
  1568. //
  1569. // If this function table is sorted do a binary search. Otherwise,
  1570. // do a linear search.
  1571. //
  1572. FunctionTable = CurrentTable->FunctionTable;
  1573. BaseAddress = CurrentTable->BaseAddress;
  1574. if (CurrentTable->Type == RF_SORTED) {
  1575. //
  1576. // Perform binary search on the function table for a function table
  1577. // entry that contains the specified control PC.
  1578. //
  1579. ControlPc -= BaseAddress;
  1580. Low = 0;
  1581. High = CurrentTable->EntryCount - 1;
  1582. while (High >= Low) {
  1583. //
  1584. // Compute next probe index and test entry. If the specified PC
  1585. // is greater than of equal to the beginning address and less
  1586. // than the ending address of the function table entry, then
  1587. // return the address of the function table entry. Otherwise,
  1588. // continue the search.
  1589. //
  1590. Middle = (Low + High) >> 1;
  1591. FunctionEntry = &FunctionTable[Middle];
  1592. if (ControlPc < FunctionEntry->BeginAddress) {
  1593. High = Middle - 1;
  1594. } else if (ControlPc >= FunctionEntry->EndAddress) {
  1595. Low = Middle + 1;
  1596. } else {
  1597. *ImageBase = BaseAddress;
  1598. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1599. return FunctionEntry;
  1600. }
  1601. }
  1602. } else if (CurrentTable->Type == RF_UNSORTED) {
  1603. //
  1604. // Perform a linear seach on the function table for a function
  1605. // entry that contains the specified control PC.
  1606. //
  1607. ControlPc -= BaseAddress;
  1608. FunctionEntry = CurrentTable->FunctionTable;
  1609. for (Index = 0; Index < CurrentTable->EntryCount; Index += 1) {
  1610. if ((ControlPc >= FunctionEntry->BeginAddress) &&
  1611. (ControlPc < FunctionEntry->EndAddress)) {
  1612. *ImageBase = BaseAddress;
  1613. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1614. return FunctionEntry;
  1615. }
  1616. FunctionEntry += 1;
  1617. }
  1618. } else {
  1619. //
  1620. // Perform a callback to obtain the runtime function table
  1621. // entry that contains the specified control PC.
  1622. //
  1623. Callback = CurrentTable->Callback;
  1624. Context = CurrentTable->Context;
  1625. *ImageBase = BaseAddress;
  1626. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1627. return (Callback)(ControlPc, Context);
  1628. }
  1629. break;
  1630. }
  1631. NextEntry = NextEntry->Flink;
  1632. }
  1633. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1634. return NULL;
  1635. }
  1636. #endif
  1637. ULONG HistoryTotal = 0;
  1638. ULONG HistoryGlobal = 0;
  1639. ULONG HistoryGlobalHits = 0;
  1640. ULONG HistorySearch = 0;
  1641. ULONG HistorySearchHits = 0;
  1642. ULONG HistoryInsert = 0;
  1643. ULONG HistoryInsertHits = 0;
  1644. PRUNTIME_FUNCTION
  1645. RtlLookupFunctionEntry (
  1646. IN ULONG64 ControlPc,
  1647. OUT PULONG64 ImageBase,
  1648. IN OUT PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. This function searches the currently active function tables for an entry
  1653. that corresponds to the specified control PC.
  1654. Arguments:
  1655. ControlPc - Supplies the address of an instruction within the specified
  1656. function.
  1657. ImageBase - Supplies the address of a variable that receives the image base
  1658. if a function table entry contains the specified control PC.
  1659. HistoryTable - Supplies an optional pointer to an unwind history table.
  1660. Return Value:
  1661. If there is no entry in the function table for the specified PC, then
  1662. NULL is returned. Otherwise, the address of the function table entry
  1663. that corresponds to the specified PC is returned.
  1664. --*/
  1665. {
  1666. ULONG64 BaseAddress;
  1667. ULONG64 BeginAddress;
  1668. ULONG64 EndAddress;
  1669. PRUNTIME_FUNCTION FunctionEntry;
  1670. PRUNTIME_FUNCTION FunctionTable;
  1671. LONG High;
  1672. ULONG Index;
  1673. LONG Low;
  1674. LONG Middle;
  1675. ULONG RelativePc;
  1676. ULONG SizeOfTable;
  1677. //
  1678. // Attempt to find an image that contains the specified control PC. If
  1679. // an image is found, then search its function table for a function table
  1680. // entry that contains the specified control PC. If an image is not found
  1681. // then search the dynamic function table for an image that contains the
  1682. // specified control PC.
  1683. //
  1684. // If a history table is supplied and search is specfied, then the current
  1685. // operation that is being performed is the unwind phase of an exception
  1686. // dispatch followed by a unwind.
  1687. //
  1688. if ((ARGUMENT_PRESENT(HistoryTable)) &&
  1689. (HistoryTable->Search != UNWIND_HISTORY_TABLE_NONE)) {
  1690. HistoryTotal += 1;
  1691. //
  1692. // Search the global unwind history table if there is a chance of a
  1693. // match.
  1694. //
  1695. if (HistoryTable->Search == UNWIND_HISTORY_TABLE_GLOBAL) {
  1696. if ((ControlPc >= RtlpUnwindHistoryTable.LowAddress) &&
  1697. (ControlPc < RtlpUnwindHistoryTable.HighAddress)) {
  1698. HistoryGlobal += 1;
  1699. for (Index = 0; Index < RtlpUnwindHistoryTable.Count; Index += 1) {
  1700. BaseAddress = RtlpUnwindHistoryTable.Entry[Index].ImageBase;
  1701. FunctionEntry = RtlpUnwindHistoryTable.Entry[Index].FunctionEntry;
  1702. BeginAddress = FunctionEntry->BeginAddress + BaseAddress;
  1703. EndAddress = FunctionEntry->EndAddress + BaseAddress;
  1704. if ((ControlPc >= BeginAddress) && (ControlPc < EndAddress)) {
  1705. *ImageBase = BaseAddress;
  1706. HistoryGlobalHits += 1;
  1707. return FunctionEntry;
  1708. }
  1709. }
  1710. }
  1711. HistoryTable->Search = UNWIND_HISTORY_TABLE_LOCAL;
  1712. }
  1713. //
  1714. // Search the dynamic unwind history table if there is a chance of a
  1715. // match.
  1716. //
  1717. if ((ControlPc >= HistoryTable->LowAddress) &&
  1718. (ControlPc < HistoryTable->HighAddress)) {
  1719. HistorySearch += 1;
  1720. for (Index = 0; Index < HistoryTable->Count; Index += 1) {
  1721. BaseAddress = HistoryTable->Entry[Index].ImageBase;
  1722. FunctionEntry = HistoryTable->Entry[Index].FunctionEntry;
  1723. BeginAddress = FunctionEntry->BeginAddress + BaseAddress;
  1724. EndAddress = FunctionEntry->EndAddress + BaseAddress;
  1725. if ((ControlPc >= BeginAddress) && (ControlPc < EndAddress)) {
  1726. *ImageBase = BaseAddress;
  1727. HistorySearchHits += 1;
  1728. return FunctionEntry;
  1729. }
  1730. }
  1731. }
  1732. }
  1733. //
  1734. // There was not a match in either of the unwind history tables so attempt
  1735. // to find a matching entry in the loaded module list.
  1736. //
  1737. FunctionTable = RtlpLookupFunctionTable((PVOID)ControlPc,
  1738. (PVOID *)ImageBase,
  1739. &SizeOfTable);
  1740. //
  1741. // If a function table is located, then search for a function table
  1742. // entry that contains the specified control PC.
  1743. //
  1744. if (FunctionTable != NULL) {
  1745. Low = 0;
  1746. High = (SizeOfTable / sizeof(RUNTIME_FUNCTION)) - 1;
  1747. RelativePc = (ULONG)(ControlPc - *ImageBase);
  1748. while (High >= Low) {
  1749. //
  1750. // Compute next probe index and test entry. If the specified
  1751. // control PC is greater than of equal to the beginning address
  1752. // and less than the ending address of the function table entry,
  1753. // then return the address of the function table entry. Otherwise,
  1754. // continue the search.
  1755. //
  1756. Middle = (Low + High) >> 1;
  1757. FunctionEntry = &FunctionTable[Middle];
  1758. if (RelativePc < FunctionEntry->BeginAddress) {
  1759. High = Middle - 1;
  1760. } else if (RelativePc >= FunctionEntry->EndAddress) {
  1761. Low = Middle + 1;
  1762. } else {
  1763. break;
  1764. }
  1765. }
  1766. if (High < Low) {
  1767. FunctionEntry = NULL;
  1768. }
  1769. } else {
  1770. //
  1771. // There was not a match in the loaded module list so attempt to find
  1772. // a matching entry in the dynamic function table list.
  1773. //
  1774. #if !defined(NTOS_KERNEL_RUNTIME)
  1775. FunctionEntry = RtlpLookupDynamicFunctionEntry(ControlPc, ImageBase);
  1776. #else
  1777. FunctionEntry = NULL;
  1778. #endif // NTOS_KERNEL_RUNTIME
  1779. }
  1780. //
  1781. // If a function table entry was located, search is not specified, and
  1782. // the specfied history table is not full, then attempt to make an entry
  1783. // in the history table.
  1784. //
  1785. if (ARGUMENT_PRESENT(HistoryTable) &&
  1786. (HistoryTable->Search == UNWIND_HISTORY_TABLE_NONE)) {
  1787. HistoryInsert += 1;
  1788. }
  1789. if (FunctionEntry != NULL) {
  1790. if (ARGUMENT_PRESENT(HistoryTable) &&
  1791. (HistoryTable->Search == UNWIND_HISTORY_TABLE_NONE) &&
  1792. (HistoryTable->Count < UNWIND_HISTORY_TABLE_SIZE)) {
  1793. Index = HistoryTable->Count;
  1794. HistoryTable->Count += 1;
  1795. HistoryTable->Entry[Index].ImageBase = *ImageBase;
  1796. HistoryTable->Entry[Index].FunctionEntry = FunctionEntry;
  1797. BeginAddress = FunctionEntry->BeginAddress + *ImageBase;
  1798. EndAddress = FunctionEntry->EndAddress + *ImageBase;
  1799. if (BeginAddress < HistoryTable->LowAddress) {
  1800. HistoryTable->LowAddress = BeginAddress;
  1801. }
  1802. if (EndAddress > HistoryTable->HighAddress) {
  1803. HistoryTable->HighAddress = EndAddress;
  1804. }
  1805. HistoryInsertHits += 1;
  1806. }
  1807. }
  1808. return FunctionEntry;
  1809. }
  1810. VOID
  1811. RtlpCopyContext (
  1812. OUT PCONTEXT Destination,
  1813. IN PCONTEXT Source
  1814. )
  1815. /*++
  1816. Routine Description:
  1817. This function copies the nonvolatile context required for exception
  1818. dispatch and unwind from the specified source context record to the
  1819. specified destination context record.
  1820. Arguments:
  1821. Destination - Supplies a pointer to the destination context record.
  1822. Source - Supplies a pointer to the source context record.
  1823. Return Value:
  1824. None.
  1825. --*/
  1826. {
  1827. //
  1828. // Copy nonvolatile context required for exception dispatch and unwind.
  1829. //
  1830. Destination->Rip = Source->Rip;
  1831. Destination->Rbx = Source->Rbx;
  1832. Destination->Rsp = Source->Rsp;
  1833. Destination->Rbp = Source->Rbp;
  1834. Destination->Rsi = Source->Rsi;
  1835. Destination->Rdi = Source->Rdi;
  1836. Destination->R12 = Source->R12;
  1837. Destination->R13 = Source->R13;
  1838. Destination->R14 = Source->R14;
  1839. Destination->R15 = Source->R15;
  1840. Destination->Xmm7 = Source->Xmm7;
  1841. Destination->Xmm8 = Source->Xmm8;
  1842. Destination->Xmm9 = Source->Xmm9;
  1843. Destination->Xmm10 = Source->Xmm10;
  1844. Destination->Xmm11 = Source->Xmm11;
  1845. Destination->Xmm12 = Source->Xmm12;
  1846. Destination->Xmm13 = Source->Xmm13;
  1847. Destination->Xmm14 = Source->Xmm14;
  1848. Destination->Xmm15 = Source->Xmm15;
  1849. Destination->SegCs = Source->SegCs;
  1850. Destination->SegSs = Source->SegSs;
  1851. Destination->MxCsr = Source->MxCsr;
  1852. Destination->EFlags = Source->EFlags;
  1853. return;
  1854. }