source: doc/working/exception/impl/main.c @ 6b72040

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since 6b72040 was 6b72040, checked in by Andrew Beach <ajbeach@…>, 5 years ago

The try exception handler function is now generic.

  • Property mode set to 100644
File size: 5.0 KB
Line 
1#include <stdio.h>
2#include "except.h"
3
4// Requires -fexceptions to work.
5
6#define EXCEPTION 2
7
8struct type_raii_t {
9        char * msg;
10};
11
12//Dtor function to test clean up routines
13void dtor( struct type_raii_t * this ) {
14        printf("%s\n", this->msg);
15}
16
17//Type macro use to make scope unwinding easier to see.
18#define raii_t __attribute__(( cleanup(dtor) )) struct type_raii_t
19
20//Leaf functions that raises exception
21void bar() {
22        raii_t a = { "Bar dtor" };
23
24        throw( EXCEPTION );
25}
26
27//Matcher function which will check if the exception was correctly caught
28extern int this_exception;
29_Unwind_Reason_Code foo_try_match() {
30        printf(" (foo_try_match called)");
31        return this_exception == EXCEPTION ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
32}
33
34//Try statements are hoisted out see comments for details
35//With this could probably be unique and simply linked from
36//libcfa but there is one problem left, see the exception table
37//for details
38__attribute__((noinline))
39void try( void (*try_block)(), void (*catch_block)(),
40          _Unwind_Reason_Code (*match_block)() )
41{
42        volatile int xy = 0;
43        printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
44
45        //Setup statments
46        //These 2 statments won't actually result in any code,
47        //they only setup global tables.
48        //However, they clobber gcc cancellation support from gcc.
49        //We can replace the personality routine but replacing the exception
50        //table gcc generates is not really doable, it generates labels based
51        //on how the assembly works.
52        //Setup the personality routine
53        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
54        //Setup the exception table
55        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
56
57        //Label which defines the start of the area for which the handler is setup
58        asm volatile (".TRYSTART:");
59
60        //The actual statements of the try blocks
61        try_block();
62
63        //asm statement to prevent deadcode removal
64        asm volatile goto ("" : : : : CATCH );
65
66        //Normal return
67        return;
68
69        //Exceptionnal path
70        CATCH : __attribute__(( unused ));
71        //Label which defines the end of the area for which the handler is setup
72        asm volatile (".TRYEND:");
73        //Label which defines the start of the exception landing pad
74        //basically what will be called when the exception is caught
75        //Note, if multiple handlers are given, the multiplexing should be done
76        //by the generated code, not the exception runtime
77        asm volatile (".CATCH:");
78
79        //Exception handler
80        catch_block();
81}
82
83//Exception table data we need to generate
84//While this is almost generic, the custom data refers to
85//foo_try_match try match, which is no way generic
86//Some more works need to be done if we want to have a single
87//call to the try routine
88asm (
89        //HEADER
90        ".LFECFA1:\n"
91        "       .globl  __gcfa_personality_v0\n"
92        "       .section        .gcc_except_table,\"a\",@progbits\n"
93        ".LLSDACFA2:\n"                                                 //TABLE header
94        "       .byte   0xff\n"
95        "       .byte   0xff\n"
96        "       .byte   0x1\n"
97        "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"         //BODY length
98        //Body uses language specific data and therefore could be modified arbitrarily
99        ".LLSDACSBCFA2:\n"                                              //BODY start
100        "       .uleb128 .TRYSTART-try\n"                               //Handled area start  (relative to start of function)
101        "       .uleb128 .TRYEND-.TRYSTART\n"                           //Handled area length
102        "       .uleb128 .CATCH-try\n"                          //Hanlder landing pad adress  (relative to start of function)
103        "       .uleb128 1\n"                                           //Action code, gcc seems to use always 0
104        ".LLSDACSECFA2:\n"                                              //BODY end
105        "       .text\n"                                                        //TABLE footer
106        "       .size   try, .-try\n"
107        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
108        "       .section        .note.GNU-stack,\"x\",@progbits\n"
109);
110
111void foo() {
112        raii_t a = { "Foo dtor" };
113
114        //Since try will clobber the gcc exception table assembly,
115        //We need to nest this to have gcc regenerate the data
116        void foo_try_block() {
117                raii_t b = { "Foo try dtor" };
118
119                bar();
120
121                printf("Called bar successfully\n");
122        }
123
124        void foo_catch_block() {
125                printf("Exception caught\n");
126        }
127
128        //Actual call to the try block
129        try( foo_try_block, foo_catch_block, foo_try_match );
130
131        printf( "Foo exited normally\n" );
132}
133
134// Not in main.cfa
135void fy() {
136        // Currently not destroyed if the exception is caught in fee.
137        raii_t a = { "Fy dtor" };
138
139        void fy_try_block() {
140                raii_t b = { "Fy try dtor" };
141
142                throw( 3 );
143        }
144
145        void fy_catch_block() {
146                printf("Fy caught exception\n");
147        }
148
149        _Unwind_Reason_Code fy_match_block() {
150                return this_exception == 2 ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
151        }
152
153        try(fy_try_block, fy_catch_block, fy_match_block);
154
155        printf( "Fy exited normally\n" );
156}
157
158void fee() {
159        raii_t a = { "Fee dtor" };
160
161        void fee_try_block() {
162                raii_t b = { "Fee try dtor" };
163
164                fy();
165
166                printf("fy returned\n");
167        }
168
169        void fee_catch_block() {
170                printf("Fee caught exception\n");
171        }
172
173        _Unwind_Reason_Code fee_match_block() {
174                return this_exception == 3 ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
175        }
176
177        try(fee_try_block, fee_catch_block, fee_match_block);
178
179        printf( "Fee exited normally\n" );
180}
181// End not in main.cfa
182
183int main() {
184        raii_t a = { "Main dtor" };
185
186        //for (unsigned int i = 0 ; i < 100000000 ; ++i)
187        foo();
188        fee();
189
190        printf("End of program reached\n");
191}
Note: See TracBrowser for help on using the repository browser.