Don't delete the XEP when &optional dispatch never reaches the main entry.
[sbcl.git] / tests / win32-stack-unwind.c
blob4e7cfd9c41298c5c001df750588525defd480d50
1 /* Compiled and loaded by win32-foreign-stack-unwind.impure.lisp
3 * establish_return_frame(callback_ptr) establishes an SEH frame
4 * that will cause an unwind to itself followed by a return on
5 * any exception, and then calls the callback_ptr.
7 * perform_test_unwind() does an unwind to the SEH frame
8 * established by establish_return_frame().
10 * The name of the game for the tests is to establish a callback
11 * that establishes something with a dynamic contour and
12 * possibly a control transfer semantic (such as a binding or an
13 * unwind-protect) and then call perform_test_unwind() or cause
14 * an exception that should be handled by SBCL and see what
15 * breaks.
18 /* This software is part of the SBCL system. See the README file for
19 * more information.
21 * While most of SBCL is derived from the CMU CL system, the test
22 * files (like this one) were written from scratch after the fork
23 * from CMU CL.
25 * This software is in the public domain and is provided with
26 * absolutely no warranty. See the COPYING and CREDITS files for
27 * more information.
30 #include <stdio.h>
31 #include <stdlib.h>
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <excpt.h>
37 #include <setjmp.h>
39 #ifndef EH_UNWINDING
40 #define EH_UNWINDING 0x02
41 #define EH_EXIT_UNWIND 0x04
42 #endif
44 /* The "public" API */
46 typedef void (*callback_ptr)(void);
48 void establish_return_frame(callback_ptr callback);
49 void perform_test_unwind(void);
52 /* The implementation */
54 static
55 void **saved_exception_frame;
57 static
58 DWORD saved_ebp;
60 static void *get_seh_frame(void)
62 void* retval;
63 asm volatile ("movl %%fs:0,%0": "=r" (retval));
64 return retval;
67 static void set_seh_frame(void *frame)
69 asm volatile ("movl %0,%%fs:0": : "r" (frame));
73 static
74 EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *exception_record,
75 void **exception_frame,
76 CONTEXT *context,
77 void *dc)
79 /* If an exception occurs and is passed to us to handle, just
80 * unwind. One or more test cases check for SBCL handling
81 * breakpoint exceptions properly. This makes sure that it
82 * doesn't unless a new exception frame is estabished when a
83 * callback occurs. */
84 if (!(exception_record->ExceptionFlags
85 & (EH_UNWINDING | EH_EXIT_UNWIND))) {
86 perform_test_unwind();
89 return ExceptionContinueSearch;
92 static void
93 __attribute__((returns_twice))
94 invoke_callback(callback_ptr callback, DWORD *unwind_token);
96 asm("_invoke_callback:"
97 "pushl %ebp; movl %esp, %ebp;"
98 "movl 12(%ebp), %eax;"
99 "movl %ebp, (%eax);"
100 "call *8(%ebp);"
101 "movl %ebp, %esp; popl %ebp; ret");
103 static void do_unwind(void *target_frame, DWORD unwind_token);
104 asm("_do_unwind:"
105 "pushl $target; pushl %ebp; movl %esp, %ebp;"
106 "pushl $0xcafe; pushl $0; pushl $-1; pushl 12(%ebp); call _RtlUnwind@16;"
107 "target:"
108 "movl 16(%ebp), %esp; popl %ebp; ret");
111 void establish_return_frame(callback_ptr callback)
113 void *exception_frame[2];
115 saved_exception_frame = exception_frame;
116 exception_frame[0] = get_seh_frame();
117 exception_frame[1] = handle_exception;
118 set_seh_frame(exception_frame);
120 /* Do a setjmp just to explicitly spill callee-saved registers, i.e.
121 * the portable equivalent of:
122 * asm("" : : : "%esi", "%edi", "%ebx");
123 * which is needed because otherwise those registers would be trashed
124 * following the stack unwind, and leave us with a likely crash upon
125 * return to call_into_c.
127 * The returns_twice attribute on invoke_callback should take care
128 * of this already, but does not seem to take effect, at least with
129 * the version of gcc I am using.
131 * Note: __builtin_setjmp, not setjmp, because only the former has
132 * the desired effect on the immediate call site. */
133 jmp_buf env;
134 __builtin_setjmp(env);
136 invoke_callback(callback, &saved_ebp);
138 if (exception_frame != get_seh_frame()) {
139 /* It is never good for this to happen. */
140 printf("exception frame mismatch on callback return.\n");
143 set_seh_frame(exception_frame[0]);
146 void perform_test_unwind(void)
148 do_unwind(saved_exception_frame, saved_ebp);
151 /* EOF */