/* Compiled and loaded by win32-foreign-stack-unwind.impure.lisp
*
* establish_return_frame(callback_ptr) establishes an SEH frame
* that will cause an unwind to itself followed by a return on
* any exception, and then calls the callback_ptr.
*
* perform_test_unwind() does an unwind to the SEH frame
* established by establish_return_frame().
*
* The name of the game for the tests is to establish a callback
* that establishes something with a dynamic contour and
* possibly a control transfer semantic (such as a binding or an
* unwind-protect) and then call perform_test_unwind() or cause
* an exception that should be handled by SBCL and see what
* breaks.
*/
/* This software is part of the SBCL system. See the README file for
* more information.
*
* While most of SBCL is derived from the CMU CL system, the test
* files (like this one) were written from scratch after the fork
* from CMU CL.
*
* This software is in the public domain and is provided with
* absolutely no warranty. See the COPYING and CREDITS files for
* more information.
*/
#include <stdio.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <excpt.h>
/* The "public" API */
typedef void (*callback_ptr)(void);
void establish_return_frame(callback_ptr callback);
void perform_test_unwind(void);
/* The implementation */
static
void **saved_exception_frame;
static
DWORD saved_ebp;
static void *get_seh_frame(void)
{
void* retval;
asm volatile ("movl %%fs:0,%0": "=r" (retval));
return retval;
}
static void set_seh_frame(void *frame)
{
asm volatile ("movl %0,%%fs:0": : "r" (frame));
}
static
EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *exception_record,
void **exception_frame,
CONTEXT *context,
void *dc)
{
/* If an exception occurs and is passed to us to handle, just
* unwind. One or more test cases check for SBCL handling
* breakpoint exceptions properly. This makes sure that it
* doesn't unless a new exception frame is estabished when a
* callback occurs. */
if (!(exception_record->ExceptionFlags
& (EH_UNWINDING | EH_EXIT_UNWIND))) {
perform_test_unwind();
}
return ExceptionContinueSearch;
}
static void invoke_callback(callback_ptr callback, DWORD *unwind_token);
asm("_invoke_callback:"
"pushl %ebp; movl %esp, %ebp;"
"movl 12(%ebp), %eax;"
"movl %ebp, (%eax);"
"call *8(%ebp);"
"movl %ebp, %esp; popl %ebp; ret");
static void do_unwind(void *target_frame, DWORD unwind_token);
asm("_do_unwind:"
"pushl $target; pushl %ebp; movl %esp, %ebp;"
"pushl $0xcafe; pushl $0; pushl $-1; pushl 12(%ebp); call _RtlUnwind@16;"
"target:"
"movl 16(%ebp), %esp; popl %ebp; ret");
void establish_return_frame(callback_ptr callback)
{
void *exception_frame[2];
saved_exception_frame = exception_frame;
exception_frame[0] = get_seh_frame();
exception_frame[1] = handle_exception;
set_seh_frame(exception_frame);
invoke_callback(callback, &saved_ebp);
if (exception_frame != get_seh_frame()) {
/* It is never good for this to happen. */
printf("exception frame mismatch on callback return.\n");
}
set_seh_frame(exception_frame[0]);
}
void perform_test_unwind(void)
{
do_unwind(saved_exception_frame, saved_ebp);
}
/* EOF */
syntax highlighted by Code2HTML, v. 0.9.1