[2c052c0] | 1 | \chapter{Unwinding in \CFA} |
---|
| 2 | |
---|
[c72ea7a] | 3 | Stack unwinding is the process of removing things from the stack. Within |
---|
| 4 | functions and on function return this is handled directly by the code in the |
---|
| 5 | function itself as it knows exactly what is on the stack just from the |
---|
| 6 | current location in the function. Unwinding across stack frames means that it |
---|
| 7 | is no longer knows exactly what is on the stack or even how much of the stack |
---|
| 8 | needs to be removed. |
---|
| 9 | |
---|
| 10 | Even this is fairly simple if nothing needs to happen when the stack unwinds. |
---|
| 11 | Traditional C can unwind the stack by saving and restoring state (with |
---|
| 12 | \codeC{setjmp} \& \codeC{longjmp}). However many languages define actions that |
---|
| 13 | have to be taken when something is removed from the stack, such as running |
---|
| 14 | a variable's destructor or a \codeCFA{try} statement's \codeCFA{finally} |
---|
| 15 | clause. Handling this requires walking the stack going through each stack |
---|
| 16 | frame. |
---|
| 17 | |
---|
| 18 | For exceptions, this means everything from the point the exception is raised |
---|
| 19 | to the point it is caught, while checking each frame for handlers during the |
---|
| 20 | stack walk to find out where it should be caught. This is where the most of |
---|
| 21 | the expense and complexity of exception handling comes from. |
---|
| 22 | |
---|
| 23 | To do all of this we use libunwind, a low level library that provides tools |
---|
| 24 | for stack walking and stack unwinding. What follows is an overview of all the |
---|
| 25 | relivant features of libunwind and then how \CFA uses them to implement its |
---|
| 26 | exception handling. |
---|
[2c052c0] | 27 | |
---|
| 28 | \section{libunwind Usage} |
---|
| 29 | |
---|
[c72ea7a] | 30 | \CFA uses two primary functions in libunwind to create most of its |
---|
| 31 | exceptional control-flow: \codeC{_Unwind_RaiseException} and |
---|
| 32 | \codeC{_Unwind_ForcedUnwind}. |
---|
[21f914e] | 33 | Their operation is divided into two phases: search and clean-up. The search |
---|
| 34 | phase -- phase 1 -- is used to scan the stack but not unwinding it. The |
---|
[2655031] | 35 | clean-up phase -- phase 2 -- is used for unwinding. |
---|
[2c052c0] | 36 | |
---|
[2655031] | 37 | The raise-exception function uses both phases. It starts by searching for a |
---|
[21f914e] | 38 | handler, and if found, performs a clean-up phase to unwind the stack to the |
---|
[2655031] | 39 | handler. If a handler is not found, control returns allowing the |
---|
[c72ea7a] | 40 | exception-handling policy for unhandled exception to be executed. During both |
---|
[2655031] | 41 | phases, the raise-exception function searches down the stack, calling each |
---|
[21f914e] | 42 | function's \emph{personality function}. |
---|
[2c052c0] | 43 | |
---|
[2655031] | 44 | A personality function performs three tasks, although not all have to be |
---|
| 45 | present. The tasks performed are decided by the actions provided. |
---|
[c72ea7a] | 46 | \codeC{_Unwind_Action} is a bitmask of possible actions and an argument of |
---|
| 47 | this type is passed into the personality function. |
---|
[2c052c0] | 48 | \begin{itemize} |
---|
[c72ea7a] | 49 | \item\codeC{_UA_SEARCH_PHASE} is passed in search phase and tells the |
---|
| 50 | personality function to check for handlers. If there is a handler in this |
---|
| 51 | stack frame, as defined by the language, the personality function should |
---|
| 52 | return \codeC{_URC_HANDLER_FOUND}. Otherwise it should return |
---|
| 53 | \codeC{_URC_CONTINUE_UNWIND}. |
---|
| 54 | \item\codeC{_UA_CLEANUP_PHASE} is passed in during the clean-up phase and |
---|
| 55 | means part or all of the stack frame is removed. The personality function |
---|
| 56 | should do whatever clean-up the language defines |
---|
| 57 | (such as running destructors/finalizers) and then generally returns |
---|
| 58 | \codeC{_URC_CONTINUE_UNWIND}. |
---|
| 59 | \item\codeC{_UA_HANDLER_FRAME} means the personality function must install |
---|
| 60 | a handler. It is also passed in during the clean-up phase and is in addition |
---|
| 61 | to the clean-up action. libunwind provides several helpers for the personality |
---|
[21f914e] | 62 | function here. Once it is done, the personality function must return |
---|
[c72ea7a] | 63 | \codeC{_URC_INSTALL_CONTEXT}. |
---|
[2c052c0] | 64 | \end{itemize} |
---|
[c72ea7a] | 65 | The personality function is given a number of other arguments. Some are for |
---|
| 66 | compatability and there is the \codeC{struct _Unwind_Context} pointer which |
---|
| 67 | passed to many helpers to get information about the current stack frame. |
---|
| 68 | |
---|
| 69 | Forced-unwind only performs the clean-up phase. It takes three arguments: |
---|
| 70 | a pointer to the exception, a pointer to the stop function and a pointer to |
---|
| 71 | the stop parameter. It does most of the same things as phase two of |
---|
| 72 | raise-exception but with some extras. |
---|
| 73 | The first it passes in an extra action to the personality function on each |
---|
| 74 | stack frame, \codeC{_UA_FORCE_UNWIND}, which means a handler cannot be |
---|
| 75 | installed. |
---|
| 76 | |
---|
| 77 | The big change is that forced-unwind calls the stop function. Each time it |
---|
| 78 | steps into a frame, before calling the personality function, it calls the |
---|
| 79 | stop function. The stop function receives all the same arguments as the |
---|
| 80 | personality function will and the stop parameter supplied to forced-unwind. |
---|
| 81 | |
---|
| 82 | The stop function is called one more time at the end of the stack after all |
---|
| 83 | stack frames have been removed. By the standard API this is marked by setting |
---|
| 84 | the stack pointer inside the context passed to the stop function. However both |
---|
| 85 | GCC and Clang add an extra action for this case \codeC{_UA_END_OF_STACK}. |
---|
| 86 | |
---|
| 87 | Each time function the stop function is called it can do one or two things. |
---|
| 88 | When it is not the end of the stack it can return \codeC{_URC_NO_REASON} to |
---|
| 89 | continue unwinding. |
---|
[2c052c0] | 90 | % Is there a reason that NO_REASON is used instead of CONTINUE_UNWIND? |
---|
[c72ea7a] | 91 | Its only other option is to use its own means to transfer control elsewhere |
---|
| 92 | and never return to its caller. It may always do this and no additional tools |
---|
| 93 | are provided to do it. |
---|
[2c052c0] | 94 | |
---|
| 95 | \section{\CFA Implementation} |
---|
| 96 | |
---|
[c72ea7a] | 97 | To use libunwind, \CFA provides several wrappers, its own storage, |
---|
| 98 | personality functions, and a stop function. |
---|
[2c052c0] | 99 | |
---|
[21f914e] | 100 | The wrappers perform three tasks: set-up, clean-up and controlling the |
---|
[2655031] | 101 | unwinding. The set-up allocates a copy of the \CFA exception into a handler to |
---|
[c72ea7a] | 102 | control its lifetime, and stores it in the exception context. Clean-up -- run |
---|
[2655031] | 103 | when control exits a catch clause and returns to normal code -- frees the |
---|
| 104 | exception copy. |
---|
[2c052c0] | 105 | % It however does not set up the unwind exception so we can't use any inter- |
---|
| 106 | % runtime/language features. Also the exception context is global. |
---|
| 107 | |
---|
[c72ea7a] | 108 | The core control code is called every time a throw -- after set-up -- or |
---|
| 109 | re-throw is run. It uses raise-exception to search for a handler and to run it |
---|
| 110 | if one is found. If no handler is found and raise-exception returns then |
---|
| 111 | forced-unwind is called to run all destructors on the stack before terminating |
---|
| 112 | the process. |
---|
[2c052c0] | 113 | |
---|
[c72ea7a] | 114 | The stop function is very simple. It checks the end of stack flag to see if |
---|
| 115 | it is finished unwinding. If so, it calls \codeC{exit} to end the process, |
---|
| 116 | otherwise it returns with no-reason to continue unwinding. |
---|
[2c052c0] | 117 | % Yeah, this is going to have to change. |
---|
| 118 | |
---|
[2655031] | 119 | The personality routine is more complex because it has to obtain information |
---|
| 120 | about the function by scanning the LSDA (Language Specific Data Area). This |
---|
| 121 | step allows a single personality function to be used for multiple functions and |
---|
[c72ea7a] | 122 | let that personaliity function figure out exactly where in the function |
---|
| 123 | execution was, what is currently in the stack frame and what handlers should |
---|
| 124 | be checked. |
---|
[2c052c0] | 125 | % Not that we do that yet. |
---|
| 126 | |
---|
[2655031] | 127 | However, generating the LSDA is difficult. It requires knowledge about the |
---|
[c72ea7a] | 128 | location of the instruction pointer and stack layout, which varies with |
---|
| 129 | compiler and optimization levels. So for frames where there are only |
---|
| 130 | destructors, GCC's attribute cleanup with the \texttt{-fexception} flag is |
---|
| 131 | sufficient to handle unwinding. |
---|
| 132 | |
---|
| 133 | The only functions that require more than that are those that contain |
---|
| 134 | \codeCFA{try} statements. A \codeCFA{try} statement has a \codeCFA{try} |
---|
| 135 | clause, some number of \codeCFA{catch} clauses and \codeCFA{catchResume} |
---|
| 136 | clauses and may have a \codeCFA{finally} clause. Of these only \codeCFA{try} |
---|
| 137 | statements with \codeCFA{catch} clauses need to be transformed and only they |
---|
| 138 | and the \codeCFA{try} clause are involved. |
---|
| 139 | |
---|
| 140 | The \codeCFA{try} statement is converted into a series of closures which can |
---|
| 141 | access other parts of the function according to scoping rules but can be |
---|
| 142 | passed around. The \codeCFA{try} clause is converted into the try functions, |
---|
| 143 | almost entirely unchanged. The \codeCFA{catch} clauses are converted into two |
---|
| 144 | functions; the match function and the catch function. |
---|
| 145 | |
---|
| 146 | Together the match function and the catch function form the code that runs |
---|
| 147 | when an exception passes out of a try block. The match function is used during |
---|
| 148 | the search phase, it is passed an exception and checks each handler to see if |
---|
| 149 | it will handle the exception. It returns an index that repersents which |
---|
| 150 | handler matched or that none of them did. The catch function is used during |
---|
| 151 | the clean-up phase, it is passed an exception and the index of a handler. It |
---|
| 152 | casts the exception to the exception type declared in that handler and then |
---|
| 153 | runs the handler's body. |
---|
| 154 | |
---|
| 155 | These three functions are passed to \codeC{try_terminate}. This is an |
---|
| 156 | % Maybe I shouldn't quote that, it isn't its actual name. |
---|
| 157 | internal hand-written function that has its own personality function and |
---|
| 158 | custom assembly LSD does the exception handling in \CFA. During normal |
---|
| 159 | execution all this function does is call the try function and then return. |
---|
| 160 | It is only when exceptions are thrown that anything interesting happens. |
---|
| 161 | |
---|
| 162 | During the search phase the personality function gets the pointer to the match |
---|
| 163 | function and calls it. If the match function returns a handler index the |
---|
| 164 | personality function saves it and reports that the handler has been found, |
---|
| 165 | otherwise unwinding continues. |
---|
| 166 | During the clean-up phase the personality function only does anything if the |
---|
| 167 | handler was found in this frame. If it was then the personality function |
---|
| 168 | installs the handler, which is setting the instruction pointer in |
---|
| 169 | \codeC{try_terminate} to an otherwise unused section that calls the catch |
---|
| 170 | function, passing it the current exception and handler index. |
---|
| 171 | \codeC{try_terminate} returns as soon as the catch function returns. |
---|
| 172 | |
---|
| 173 | At this point control has returned to normal control flow. |
---|