source: doc/theses/andrew_beach_MMath/unwinding.tex @ 2c052c0

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 2c052c0 was 2c052c0, checked in by Andrew Beach <ajbeach@…>, 4 years ago

First rough draft of how unwinding works in ABMM.

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