Windows NT 4.0 source code leak
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.

501 lines
15 KiB

4 years ago
  1. // TITLE("Miscellaneous Exception Handling")
  2. //++
  3. //
  4. // Copyright (c) 1990 Microsoft Corporation
  5. // Copyright (c) 1992 Digital Equipment Corporation
  6. //
  7. // Module Name:
  8. //
  9. // xcptmisc.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements miscellaneous routines that are required to
  14. // support exception handling. Functions are provided to call an exception
  15. // handler for an exception, call an exception handler for unwinding, call
  16. // an exception filter, call a termination handler, and get the caller's
  17. // stack limits.
  18. //
  19. // Author:
  20. //
  21. // David N. Cutler (davec) 12-Sep-1990
  22. //
  23. // Environment:
  24. //
  25. // Any mode.
  26. //
  27. // Revision History:
  28. //
  29. // Thomas Van Baak (tvb) 7-May-1992
  30. //
  31. // Adapted for Alpha AXP.
  32. //
  33. //--
  34. #include "ksalpha.h"
  35. //
  36. // Define call frame for calling exception handlers.
  37. //
  38. .struct 0
  39. CfRa: .space 8 // saved return address
  40. CfA3: .space 8 // save area for argument a3
  41. .space 0 * 8 // 16-byte stack alignment
  42. CfFrameLength: // length of stack frame
  43. SBTTL("Execute Handler for Exception")
  44. //++
  45. //
  46. // EXCEPTION_DISPOSITION
  47. // RtlpExecuteHandlerForException (
  48. // IN PEXCEPTION_RECORD ExceptionRecord,
  49. // IN ULONG EstablisherFrame,
  50. // IN OUT PCONTEXT ContextRecord,
  51. // IN OUT PDISPATCHER_CONTEXT DispatcherContext,
  52. // IN PEXCEPTION_ROUTINE ExceptionRoutine
  53. // )
  54. //
  55. // Routine Description:
  56. //
  57. // This function allocates a call frame, stores the establisher frame
  58. // pointer in the frame, establishes an exception handler, and then calls
  59. // the specified exception handler as an exception handler. If a nested
  60. // exception occurs, then the exception handler of this function is called
  61. // and the establisher frame pointer is returned to the exception dispatcher
  62. // via the dispatcher context parameter. If control is returned to this
  63. // routine, then the frame is deallocated and the disposition status is
  64. // returned to the exception dispatcher.
  65. //
  66. // Arguments:
  67. //
  68. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  69. //
  70. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  71. // of the exception handler that is to be called.
  72. //
  73. // ContextRecord (a2) - Supplies a pointer to a context record.
  74. //
  75. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  76. // record.
  77. //
  78. // ExceptionRoutine (a4) - Supplies a pointer to the exception handler that
  79. // is to be called.
  80. //
  81. // Return Value:
  82. //
  83. // The disposition value returned by the specified exception handler is
  84. // returned as the function value.
  85. //
  86. //--
  87. //
  88. // N.B. This function specifies its own private exception handler.
  89. //
  90. EXCEPTION_HANDLER(RtlpExceptionHandler)
  91. NESTED_ENTRY(RtlpExecuteHandlerForException, CfFrameLength, zero)
  92. lda sp, -CfFrameLength(sp) // allocate stack frame
  93. stq ra, CfRa(sp) // save return address
  94. PROLOGUE_END
  95. //
  96. // Save the address of the dispatcher context record in our stack frame so
  97. // that our own exception handler (not the one we're calling) can retrieve it.
  98. //
  99. stq a3, CfA3(sp) // save address of dispatcher context
  100. //
  101. // Now call the exception handler and return its return value as ours.
  102. //
  103. bic a4, 3, a4 // clear low-order bits (IEEE mode)
  104. jsr ra, (a4) // call exception handler
  105. ldq ra, CfRa(sp) // restore return address
  106. lda sp, CfFrameLength(sp) // deallocate stack frame
  107. ret zero, (ra) // return
  108. .end RtlpExecuteHandlerForException
  109. SBTTL("Local Exception Handler")
  110. //++
  111. //
  112. // EXCEPTION_DISPOSITION
  113. // RtlpExceptionHandler (
  114. // IN PEXCEPTION_RECORD ExceptionRecord,
  115. // IN ULONG EstablisherFrame,
  116. // IN OUT PCONTEXT ContextRecord,
  117. // IN OUT PDISPATCHER_CONTEXT DispatcherContext
  118. // )
  119. //
  120. // Routine Description:
  121. //
  122. // This function is called when a nested exception occurs. Its function
  123. // is to retrieve the establisher frame pointer from its establisher's
  124. // call frame, store this information in the dispatcher context record,
  125. // and return a disposition value of nested exception.
  126. //
  127. // Arguments:
  128. //
  129. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  130. //
  131. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  132. // of this exception handler.
  133. //
  134. // ContextRecord (a2) - Supplies a pointer to a context record.
  135. //
  136. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  137. // record.
  138. //
  139. // Return Value:
  140. //
  141. // A disposition value ExceptionNestedException is returned if an unwind
  142. // is not in progress. Otherwise a value of ExceptionContinueSearch is
  143. // returned.
  144. //
  145. //--
  146. LEAF_ENTRY(RtlpExceptionHandler)
  147. ldl t0, ErExceptionFlags(a0) // get exception flags
  148. and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress
  149. bne t0, 10f // if neq, unwind in progress
  150. //
  151. // Unwind is not in progress - return nested exception disposition.
  152. //
  153. //
  154. // Convert the given establisher virtual frame pointer (a1) to a real frame
  155. // pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to
  156. // the dispatcher context that earlier was stored in the stack frame.
  157. //
  158. ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address
  159. ldl t1, DcEstablisherFrame(t0) // copy the establisher frame pointer
  160. stl t1, DcEstablisherFrame(a3) // to current dispatcher context
  161. ldil v0, ExceptionNestedException // set disposition value
  162. ret zero, (ra) // return
  163. //
  164. // Unwind is in progress - return continue search disposition.
  165. //
  166. 10: ldil v0, ExceptionContinueSearch // set disposition value
  167. ret zero, (ra) // return
  168. .end RtlpExceptionHandler
  169. SBTTL("Execute Handler for Unwind")
  170. //++
  171. //
  172. // EXCEPTION_DISPOSITION
  173. // RtlpExecuteHandlerForUnwind (
  174. // IN PEXCEPTION_RECORD ExceptionRecord,
  175. // IN PVOID EstablisherFrame,
  176. // IN OUT PCONTEXT ContextRecord,
  177. // IN OUT PVOID DispatcherContext,
  178. // IN PEXCEPTION_ROUTINE ExceptionRoutine
  179. // )
  180. //
  181. // Routine Description:
  182. //
  183. // This function allocates a call frame, stores the establisher frame
  184. // pointer and the context record address in the frame, establishes an
  185. // exception handler, and then calls the specified exception handler as
  186. // an unwind handler. If a collided unwind occurs, then the exception
  187. // handler of this function is called and the establisher frame pointer
  188. // and context record address are returned to the unwind dispatcher via
  189. // the dispatcher context parameter. If control is returned to this routine,
  190. // then the frame is deallocated and the disposition status is returned to
  191. // the unwind dispatcher.
  192. //
  193. // Arguments:
  194. //
  195. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  196. //
  197. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  198. // of the exception handler that is to be called.
  199. //
  200. // ContextRecord (a2) - Supplies a pointer to a context record.
  201. //
  202. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  203. // record.
  204. //
  205. // ExceptionRoutine (a4) - Supplies a pointer to the exception handler that
  206. // is to be called.
  207. //
  208. // Return Value:
  209. //
  210. // The disposition value returned by the specified exception handler is
  211. // returned as the function value.
  212. //
  213. //--
  214. //
  215. // N.B. This function specifies its own private exception handler.
  216. //
  217. EXCEPTION_HANDLER(RtlpUnwindHandler)
  218. NESTED_ENTRY(RtlpExecuteHandlerForUnwind, CfFrameLength, zero)
  219. lda sp, -CfFrameLength(sp) // allocate stack frame
  220. stq ra, CfRa(sp) // save return address
  221. PROLOGUE_END
  222. //
  223. // Save the address of the dispatcher context record in our stack frame so
  224. // that our own exception handler (not the one we're calling) can retrieve it.
  225. //
  226. stq a3, CfA3(sp) // save address of dispatcher context
  227. //
  228. // Now call the exception handler and return its return value as our return
  229. // value.
  230. //
  231. bic a4, 3, a4 // clear low-order bits (IEEE mode)
  232. jsr ra, (a4) // call exception handler
  233. ldq ra, CfRa(sp) // restore return address
  234. lda sp, CfFrameLength(sp) // deallocate stack frame
  235. ret zero, (ra) // return
  236. .end RtlpExecuteHandlerForUnwind
  237. SBTTL("Local Unwind Handler")
  238. //++
  239. //
  240. // EXCEPTION_DISPOSITION
  241. // RtlpUnwindHandler (
  242. // IN PEXCEPTION_RECORD ExceptionRecord,
  243. // IN PVOID EstablisherFrame,
  244. // IN OUT PCONTEXT ContextRecord,
  245. // IN OUT PVOID DispatcherContext
  246. // )
  247. //
  248. // Routine Description:
  249. //
  250. // This function is called when a collided unwind occurs. Its function
  251. // is to retrieve the establisher dispatcher context, copy it to the
  252. // current dispatcher context, and return a disposition value of nested
  253. // unwind.
  254. //
  255. // Arguments:
  256. //
  257. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  258. //
  259. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  260. // of this exception handler.
  261. //
  262. // ContextRecord (a2) - Supplies a pointer to a context record.
  263. //
  264. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  265. // record.
  266. //
  267. // Return Value:
  268. //
  269. // A disposition value ExceptionCollidedUnwind is returned if an unwind is
  270. // in progress. Otherwise, a value of ExceptionContinueSearch is returned.
  271. //
  272. //--
  273. LEAF_ENTRY(RtlpUnwindHandler)
  274. ldl t0, ErExceptionFlags(a0) // get exception flags
  275. and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress
  276. beq t0, 10f // if eq, unwind not in progress
  277. //
  278. // Unwind is in progress - return collided unwind disposition.
  279. //
  280. //
  281. // Convert the given establisher virtual frame pointer (a1) to a real frame
  282. // pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to
  283. // the dispatcher context that earlier was stored in the stack frame.
  284. //
  285. ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address
  286. ldl t1, DcControlPc(t0) // copy the entire dispatcher
  287. ldl t2, DcFunctionEntry(t0) // context of the establisher
  288. ldl t3, DcEstablisherFrame(t0) // frame...
  289. ldl t4, DcContextRecord(t0) //
  290. stl t1, DcControlPc(a3) // to the current dispatcher
  291. stl t2, DcFunctionEntry(a3) // context (it's four words
  292. stl t3, DcEstablisherFrame(a3) // long).
  293. stl t4, DcContextRecord(a3) //
  294. ldil v0, ExceptionCollidedUnwind // set disposition value
  295. ret zero, (ra) // return
  296. //
  297. // Unwind is not in progress - return continue search disposition.
  298. //
  299. 10: ldil v0, ExceptionContinueSearch // set disposition value
  300. ret zero, (ra) // return
  301. .end RtlpUnwindHandler
  302. SBTTL("Execute Exception Filter")
  303. //++
  304. //
  305. // ULONG
  306. // RtlpExecuteExceptionFilter (
  307. // PEXCEPTION_POINTERS ExceptionPointers,
  308. // EXCEPTION_FILTER ExceptionFilter,
  309. // ULONG EstablisherFrame
  310. // )
  311. //
  312. // Routine Description:
  313. //
  314. // This function sets the static link and transfers control to the specified
  315. // exception filter routine.
  316. //
  317. // Arguments:
  318. //
  319. // ExceptionPointers (a0) - Supplies a pointer to the exception pointers
  320. // structure.
  321. //
  322. // ExceptionFilter (a1) - Supplies the address of the exception filter
  323. // routine.
  324. //
  325. // EstablisherFrame (a2) - Supplies the establisher frame pointer.
  326. //
  327. // Return Value:
  328. //
  329. // The value returned by the exception filter routine.
  330. //
  331. //--
  332. LEAF_ENTRY(RtlpExecuteExceptionFilter)
  333. //
  334. // The protocol for calling exception filters used by the acc C-compiler is
  335. // that the uplevel frame pointer is passed in register v0 and the pointer
  336. // to the exception pointers structure is passed in register a0. The Gem
  337. // compiler expects the static link in t0. Here we do both.
  338. //
  339. mov a2, v0 // set static link
  340. mov a2, t0 // set alternate static link
  341. jmp zero, (a1) // transfer control to exception filter
  342. .end RtlpExecuteExceptionFilter
  343. SBTTL("Execute Termination Handler")
  344. //++
  345. //
  346. // VOID
  347. // RtlpExecuteTerminationHandler (
  348. // BOOLEAN AbnormalTermination,
  349. // TERMINATION_HANDLER TerminationHandler,
  350. // ULONG EstablisherFrame
  351. // )
  352. //
  353. // Routine Description:
  354. //
  355. // This function sets the static link and transfers control to the specified
  356. // termination handler routine.
  357. //
  358. // Arguments:
  359. //
  360. // AbnormalTermination (a0) - Supplies a boolean value that determines
  361. // whether the termination is abnormal.
  362. //
  363. // TerminationHandler (a1) - Supplies the address of the termination handler
  364. // routine.
  365. //
  366. // EstablisherFrame (a2) - Supplies the establisher frame pointer.
  367. //
  368. // Return Value:
  369. //
  370. // None.
  371. //
  372. //--
  373. LEAF_ENTRY(RtlpExecuteTerminationHandler)
  374. //
  375. // The protocol for calling termination handlers used by the acc C-compiler
  376. // is that the uplevel frame pointer is passed in register v0 and the boolean
  377. // abnormal termination value is passed in register a0. The Gem compiler
  378. // expects the static link in t0. Here we do both.
  379. //
  380. mov a2, v0 // set static link
  381. mov a2, t0 // set alternate static link
  382. jmp zero, (a1) // transfer control to termination handler
  383. .end RtlpExecuteTerminationHandler
  384. SBTTL("Get Stack Limits")
  385. //++
  386. //
  387. // VOID
  388. // RtlpGetStackLimits (
  389. // OUT PULONG LowLimit,
  390. // OUT PULONG HighLimit
  391. // )
  392. //
  393. // Routine Description:
  394. //
  395. // This function returns the current stack limits based on the current
  396. // processor mode.
  397. //
  398. // Arguments:
  399. //
  400. // LowLimit (a0) - Supplies a pointer to a variable that is to receive
  401. // the low limit of the stack.
  402. //
  403. // HighLimit (a1) - Supplies a pointer to a variable that is to receive
  404. // the high limit of the stack.
  405. //
  406. // Return Value:
  407. //
  408. // None.
  409. //
  410. //--
  411. LEAF_ENTRY(RtlpGetStackLimits)
  412. #if defined(NTOS_KERNEL_RUNTIME)
  413. //
  414. // Current mode is kernel - compute stack limits.
  415. //
  416. GET_INITIAL_KERNEL_STACK // get initial kernel stack in v0
  417. mov v0, t1 // copy high limit of kernel stack
  418. GET_CURRENT_THREAD // get current thread in v0
  419. ldl t2, ThStackLimit(v0) // get low limit of kernel stack
  420. #else
  421. //
  422. // Current mode is user - get stack limits from the TEB.
  423. //
  424. GET_THREAD_ENVIRONMENT_BLOCK // get address of TEB in v0
  425. ldl t1, TeStackBase(v0) // get high limit of user stack
  426. ldl t2, TeStackLimit(v0) // get low limit of user stack
  427. #endif
  428. stl t2, 0(a0) // store low stack limit
  429. stl t1, 0(a1) // store high stack limit
  430. ret zero, (ra) // return
  431. .end RtlpGetStackLimits