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
18 /* This software is part of the SBCL system. See the README file for
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
25 * This software is in the public domain and is provided with
26 * absolutely no warranty. See the COPYING and CREDITS files for
33 #define WIN32_LEAN_AND_MEAN
39 /* The "public" API */
41 typedef void (*callback_ptr
)(void);
43 void establish_return_frame(callback_ptr callback
);
44 void perform_test_unwind(void);
47 /* The implementation */
50 void **saved_exception_frame
;
55 static void *get_seh_frame(void)
58 asm volatile ("movl %%fs:0,%0": "=r" (retval
));
62 static void set_seh_frame(void *frame
)
64 asm volatile ("movl %0,%%fs:0": : "r" (frame
));
69 EXCEPTION_DISPOSITION
handle_exception(EXCEPTION_RECORD
*exception_record
,
70 void **exception_frame
,
74 /* If an exception occurs and is passed to us to handle, just
75 * unwind. One or more test cases check for SBCL handling
76 * breakpoint exceptions properly. This makes sure that it
77 * doesn't unless a new exception frame is estabished when a
79 if (!(exception_record
->ExceptionFlags
80 & (EH_UNWINDING
| EH_EXIT_UNWIND
))) {
81 perform_test_unwind();
84 return ExceptionContinueSearch
;
88 __attribute__((returns_twice
))
89 invoke_callback(callback_ptr callback
, DWORD
*unwind_token
);
91 asm("_invoke_callback:"
92 "pushl %ebp; movl %esp, %ebp;"
93 "movl 12(%ebp), %eax;"
96 "movl %ebp, %esp; popl %ebp; ret");
98 static void do_unwind(void *target_frame
, DWORD unwind_token
);
100 "pushl $target; pushl %ebp; movl %esp, %ebp;"
101 "pushl $0xcafe; pushl $0; pushl $-1; pushl 12(%ebp); call _RtlUnwind@16;"
103 "movl 16(%ebp), %esp; popl %ebp; ret");
106 void establish_return_frame(callback_ptr callback
)
108 void *exception_frame
[2];
110 saved_exception_frame
= exception_frame
;
111 exception_frame
[0] = get_seh_frame();
112 exception_frame
[1] = handle_exception
;
113 set_seh_frame(exception_frame
);
115 /* Do a setjmp just to explicitly spill callee-saved registers, i.e.
116 * the portable equivalent of:
117 * asm("" : : : "%esi", "%edi", "%ebx");
118 * which is needed because otherwise those registers would be trashed
119 * following the stack unwind, and leave us with a likely crash upon
120 * return to call_into_c.
122 * The returns_twice attribute on invoke_callback should take care
123 * of this already, but does not seem to take effect, at least with
124 * the version of gcc I am using.
126 * Note: __builtin_setjmp, not setjmp, because only the former has
127 * the desired effect on the immediate call site. */
129 __builtin_setjmp(env
);
131 invoke_callback(callback
, &saved_ebp
);
133 if (exception_frame
!= get_seh_frame()) {
134 /* It is never good for this to happen. */
135 printf("exception frame mismatch on callback return.\n");
138 set_seh_frame(exception_frame
[0]);
141 void perform_test_unwind(void)
143 do_unwind(saved_exception_frame
, saved_ebp
);