1 | \chapter{Unwinding in \CFA} |
---|
2 | |
---|
3 | Stack unwinding is the process of removing things from the stack from outside |
---|
4 | the functions there. In languages that don't provide a way to garrenty that |
---|
5 | code will run when the program leaves a scope or finishes a function, this |
---|
6 | can be relatively trivial. C does this with \codeC{longjmp} by setting the |
---|
7 | stack pointer and a few other registers. |
---|
8 | |
---|
9 | \section{libunwind Usage} |
---|
10 | |
---|
11 | There are two primary functions that \CFA uses in libunwind that create most |
---|
12 | of the control flow. These are \codeC{\_Unwind\_RaiseException} and |
---|
13 | \codeC{\_Unwind\_ForcedUnwind}. |
---|
14 | |
---|
15 | Their operation is divided amoung two phases, search and clean-up. The search |
---|
16 | phase -- phase 1 -- is used while scanning the stack while not actually |
---|
17 | unwinding it while the clean-up phase -- phase 2 -- is used while the actual |
---|
18 | unwinding is under way. |
---|
19 | |
---|
20 | % Somewhere around here I need to talk about the control structures. |
---|
21 | % \codeC{\_Unwind\_Exception} is used to carry the API's universal data. Some |
---|
22 | % of this is internal, other fields are used to communicate between different |
---|
23 | % exception handling mechanisms in different runtimes. |
---|
24 | % \codeC{\_Unwind\_Context} is an opaque data structure that is used to pass |
---|
25 | % information to helper functions. |
---|
26 | |
---|
27 | Raise exception can cover both phases. It starts by searching for the handler |
---|
28 | and if it finds it preforms a clean-up phase to unwind the stack to the |
---|
29 | hander. If not it returns allowing the program to decide what to do with all |
---|
30 | the state and stack that were in place before the call. During both phases |
---|
31 | the raise exception function will search down the stack, calling each |
---|
32 | function's personality function as they are found. |
---|
33 | |
---|
34 | Personality functions must be able to preform three tasks, although not all |
---|
35 | of them have to be preformed in a given call. Which tasks must be preformed |
---|
36 | are decided by the actions provided. |
---|
37 | % Something argument something bitmask. |
---|
38 | \begin{itemize} |
---|
39 | \item\codeC{\_UA\_SEARCH\_PHASE} this is being called during the clean-up |
---|
40 | phase and means search for handlers. If the hander is found the personality |
---|
41 | function should return \codeC{\_URC\_HANDLER\_FOUND}, otherise it should |
---|
42 | return \codeC{\_URC\_CONTINUE\_UNWIND}. |
---|
43 | \item\codeC{\_UA\_CLEANUP\_PHASE} is passed in during the clean-up phase and |
---|
44 | means that part or all of the stack frame is being removed. The personality |
---|
45 | function should do whatever clean-up the language defines (such as running |
---|
46 | destructors) and then generally returns \codeC{\_URC\_CONTINUE\_UNWIND}. |
---|
47 | \item\codeC{\_UA\_HANDLER\_FRAME} means that the personality function must |
---|
48 | install a handler. It is also passing in during the clean-up phase and will |
---|
49 | be in addition to the clean-up action. Libunwind provides several helpers |
---|
50 | for the personality function here. Once it is done the personality function |
---|
51 | must return \codeC{\_URC\_INSTALL\_CONTEXT}. |
---|
52 | \end{itemize} |
---|
53 | |
---|
54 | Forced unwind only preforms the clean-up phase. It is similar to the phase 2 |
---|
55 | section of raise exception with a few changes. A simple one is that |
---|
56 | it passes in an extra action to the personality function |
---|
57 | \codeC{\_UA\_FORCE\_UNWIND} which means a handler cannot be installed. The |
---|
58 | most significant is the addition of the stop function, which is passed in as |
---|
59 | an argument to the forced unwind. |
---|
60 | |
---|
61 | The stop function is a lot like a personality function. It takes an extra |
---|
62 | argument, a void pointer passed into force unwind. It may return |
---|
63 | \codeC{\_URC\_NO\_REASON} to continue unwinding or it can transfer control |
---|
64 | out of the unwind code using its own mechanism. |
---|
65 | % Is there a reason that NO_REASON is used instead of CONTINUE_UNWIND? |
---|
66 | The stop function is called once on every stack frame and once at the end of |
---|
67 | the stack. In a stack frame it is called before the personality routine with |
---|
68 | the same arguments (except for the extra void pointer). At the end of the |
---|
69 | stack the arguments are mostly the same, except the stack pointer stored in |
---|
70 | the context is set to null. Because of the significance of that change both |
---|
71 | GCC and Clang add an extra action in this case \codeC{\_UA\_END\_OF\_STACK}. |
---|
72 | The stop function may not return at the end of the stack. |
---|
73 | |
---|
74 | \section{\CFA Implementation} |
---|
75 | |
---|
76 | To use libunwind \CFA provides several wrappers, its own storage, the |
---|
77 | personality functions and a stop function. |
---|
78 | |
---|
79 | The wrappers preform three tasks: set-up, clean-up and controlling the |
---|
80 | unwinding. The set-up allocates a copy of the \CFA exception into the hander |
---|
81 | so it can control its lifetime and stores it in the exception context while |
---|
82 | clean-up -- run when control exits a catch clause and return to normal code -- |
---|
83 | frees the exception copy. |
---|
84 | % It however does not set up the unwind exception so we can't use any inter- |
---|
85 | % runtime/language features. Also the exception context is global. |
---|
86 | |
---|
87 | The control code in the middle is run every time a throw or re-throw is |
---|
88 | called. It uses raise exception to search for a hander and to run it if one |
---|
89 | is found. Otherwise it uses forced unwind to unwind the stack, running all |
---|
90 | destructors, before terminating the process. |
---|
91 | |
---|
92 | The stop function is very simple, it checks the end of stack flag to see if |
---|
93 | it is finished unwinding. If so it calls exit to end the process, otherwise |
---|
94 | it tells the system to continue unwinding. |
---|
95 | % Yeah, this is going to have to change. |
---|
96 | |
---|
97 | The personality routine is much more complicated. |
---|
98 | First because it has to get some information about the function by scanning |
---|
99 | the LSDA (Language Specific Data Area). This allows a single personality |
---|
100 | function to be used for multiple functions and it accounts for multiple |
---|
101 | regions and possible handlers in a single function. |
---|
102 | % Not that we do that yet. |
---|
103 | |
---|
104 | However generating the LSDA is very difficult. It requires a lot of knowledge |
---|
105 | about the location of the instruction pointer and stack layout that can be |
---|
106 | broken by optimization. So instead for frames where there are only destructors |
---|
107 | we use GCC's attribute cleanup and the -fexception flag to handle unwinding |
---|
108 | without adding our own functionality. |
---|
109 | |
---|
110 | For functions that do have handlers (defined in try statements) the function |
---|
111 | is split into several functions. Everything outside the try statement is the |
---|
112 | first function, which has then has only destructors to be run during |
---|
113 | unwinding. The clauses of the try block are then converted into GCC inner |
---|
114 | functions which can be passed around with function pointers while still having |
---|
115 | access to the outer function's scope. \codeC{catchResume} and \codeC{finally} |
---|
116 | clauses are handled seperately and will not be discussed here. |
---|
117 | |
---|
118 | The \codeC{try} clause is convered to a function directly. The \codeC{catch} |
---|
119 | clauses are combined and then create two functions. The first is the match |
---|
120 | function which is used during the search phase to see if any of the handler |
---|
121 | here. The second it the catch function, which is a large switch-case block |
---|
122 | with the different handlers. All of these function do not interact with |
---|
123 | unwinding except for running destructors and so can be handled by GCC. |
---|
124 | |
---|
125 | These three functions are passed into \codeC{try\_terminate}, an internal |
---|
126 | function that repersents the try statement. This is the only function with |
---|
127 | our personality function as well as assembly statements that create the LSDA. |
---|
128 | In normal execution all the function does is call the try block closure and |
---|
129 | return once that has finished executing. However using libunwind its |
---|
130 | personality function now handles exception matching and catching. |
---|
131 | |
---|
132 | During the search phase the personality function retreaves the match function |
---|
133 | from the stack using the saved stack pointer. The function is called, either |
---|
134 | returning 0 for no match or the index (a positive integer) of the handler |
---|
135 | that will handle it. The if a handler was found the personality function |
---|
136 | reports it after saving the index to the exception context. |
---|
137 | |
---|
138 | During the clean-up phase there is nothing for the personality function to |
---|
139 | clean-up in \codeC{try\_terminate}. So if this is not the handler frame |
---|
140 | unwinding continues. If this is the handler frame than control is transfered |
---|
141 | to the catch function, giving it the exception and the handler index. |
---|