win32 seh changes

erg 2006-08-03 18:27:34 +00:00
parent b308d389d8
commit 48daad545e
1 changed files with 273 additions and 234 deletions

View File

@ -1,234 +1,273 @@
#include "factor.h" #include "factor.h"
/* frees memory allocated by win32 api calls */ /* frees memory allocated by win32 api calls */
char *buffer_to_char_string(char *buffer) char *buffer_to_char_string(char *buffer)
{ {
int capacity = strlen(buffer); int capacity = strlen(buffer);
F_STRING *_c_str = allot_string(capacity / CHARS + 1); F_STRING *_c_str = allot_string(capacity / CHARS + 1);
u8 *c_str = (u8*)(_c_str + 1); u8 *c_str = (u8*)(_c_str + 1);
strcpy(c_str, buffer); strcpy(c_str, buffer);
LocalFree(buffer); LocalFree(buffer);
return (char*)c_str; return (char*)c_str;
} }
F_STRING *get_error_message() F_STRING *get_error_message()
{ {
DWORD id = GetLastError(); DWORD id = GetLastError();
return from_char_string(error_message(id)); return from_char_string(error_message(id));
} }
char *error_message(DWORD id) char *error_message(DWORD id)
{ {
char *buffer; char *buffer;
int index; int index;
FormatMessage( FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_FROM_SYSTEM,
NULL, NULL,
id, id,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buffer, (LPTSTR) &buffer,
0, NULL); 0, NULL);
/* strip whitespace from end */ /* strip whitespace from end */
index = strlen(buffer) - 1; index = strlen(buffer) - 1;
while(index >= 0 && isspace(buffer[index])) while(index >= 0 && isspace(buffer[index]))
buffer[index--] = 0; buffer[index--] = 0;
return buffer_to_char_string(buffer); return buffer_to_char_string(buffer);
} }
s64 current_millis(void) s64 current_millis(void)
{ {
FILETIME t; FILETIME t;
GetSystemTimeAsFileTime(&t); GetSystemTimeAsFileTime(&t);
return (((s64)t.dwLowDateTime | (s64)t.dwHighDateTime<<32) - EPOCH_OFFSET) return (((s64)t.dwLowDateTime | (s64)t.dwHighDateTime<<32) - EPOCH_OFFSET)
/ 10000; / 10000;
} }
void ffi_dlopen (DLL *dll, bool error) void ffi_dlopen (DLL *dll, bool error)
{ {
HMODULE module; HMODULE module;
char *path = to_char_string(untag_string(dll->path),true); char *path = to_char_string(untag_string(dll->path),true);
module = LoadLibrary(path); module = LoadLibrary(path);
if (!module) if (!module)
{ {
dll->dll = NULL; dll->dll = NULL;
if(error) if(error)
general_error(ERROR_FFI, tag_object(get_error_message()),F,true); general_error(ERROR_FFI, tag_object(get_error_message()),F,true);
else else
return; return;
} }
dll->dll = module; dll->dll = module;
} }
void *ffi_dlsym (DLL *dll, F_STRING *symbol, bool error) void *ffi_dlsym (DLL *dll, F_STRING *symbol, bool error)
{ {
void *sym = GetProcAddress(dll ? (HMODULE)dll->dll : GetModuleHandle(NULL), void *sym = GetProcAddress(dll ? (HMODULE)dll->dll : GetModuleHandle(NULL),
to_char_string(symbol,true)); to_char_string(symbol,true));
if (!sym) if (!sym)
{ {
if(error) if(error)
general_error(ERROR_FFI, tag_object(get_error_message()),F,true); general_error(ERROR_FFI, tag_object(get_error_message()),F,true);
else else
return NULL; return NULL;
} }
return sym; return sym;
} }
void ffi_dlclose (DLL *dll) void ffi_dlclose (DLL *dll)
{ {
FreeLibrary((HMODULE)dll->dll); FreeLibrary((HMODULE)dll->dll);
dll->dll = NULL; dll->dll = NULL;
} }
void primitive_stat(void) void primitive_stat(void)
{ {
F_STRING *path; F_STRING *path;
WIN32_FILE_ATTRIBUTE_DATA st; WIN32_FILE_ATTRIBUTE_DATA st;
maybe_gc(0); maybe_gc(0);
path = untag_string(dpop()); path = untag_string(dpop());
if(!GetFileAttributesEx(to_char_string(path,true), GetFileExInfoStandard, &st)) if(!GetFileAttributesEx(to_char_string(path,true), GetFileExInfoStandard, &st))
{ {
dpush(F); dpush(F);
} }
else else
{ {
CELL dirp = tag_boolean(st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); CELL dirp = tag_boolean(st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
CELL size = tag_bignum(s48_long_long_to_bignum( CELL size = tag_bignum(s48_long_long_to_bignum(
(s64)st.nFileSizeLow | (s64)st.nFileSizeHigh << 32)); (s64)st.nFileSizeLow | (s64)st.nFileSizeHigh << 32));
CELL mtime = tag_integer((int) CELL mtime = tag_integer((int)
((*(s64*)&st.ftLastWriteTime - EPOCH_OFFSET) / 10000000)); ((*(s64*)&st.ftLastWriteTime - EPOCH_OFFSET) / 10000000));
dpush(make_array_4(dirp,tag_fixnum(0),size,mtime)); dpush(make_array_4(dirp,tag_fixnum(0),size,mtime));
} }
} }
void primitive_read_dir(void) void primitive_read_dir(void)
{ {
F_STRING *path; F_STRING *path;
HANDLE dir; HANDLE dir;
WIN32_FIND_DATA find_data; WIN32_FIND_DATA find_data;
F_ARRAY *result; F_ARRAY *result;
CELL result_count = 0; CELL result_count = 0;
maybe_gc(0); maybe_gc(0);
result = array(ARRAY_TYPE,100,F); result = array(ARRAY_TYPE,100,F);
path = untag_string(dpop()); path = untag_string(dpop());
if (INVALID_HANDLE_VALUE != (dir = FindFirstFile(".\\*", &find_data))) if (INVALID_HANDLE_VALUE != (dir = FindFirstFile(".\\*", &find_data)))
{ {
do do
{ {
CELL name = tag_object(from_char_string( CELL name = tag_object(from_char_string(
find_data.cFileName)); find_data.cFileName));
if(result_count == array_capacity(result)) if(result_count == array_capacity(result))
{ {
result = resize_array(result, result = resize_array(result,
result_count * 2,F); result_count * 2,F);
} }
put(AREF(result,result_count),name); put(AREF(result,result_count),name);
result_count++; result_count++;
} }
while (FindNextFile(dir, &find_data)); while (FindNextFile(dir, &find_data));
CloseHandle(dir); CloseHandle(dir);
} }
result = resize_array(result,result_count,F); result = resize_array(result,result_count,F);
dpush(tag_object(result)); dpush(tag_object(result));
} }
void primitive_cwd(void) void primitive_cwd(void)
{ {
char buf[MAX_PATH]; char buf[MAX_PATH];
maybe_gc(0); maybe_gc(0);
if(!GetCurrentDirectory(MAX_PATH, buf)) if(!GetCurrentDirectory(MAX_PATH, buf))
io_error(); io_error();
box_char_string(buf); box_char_string(buf);
} }
void primitive_cd(void) void primitive_cd(void)
{ {
maybe_gc(0); maybe_gc(0);
SetCurrentDirectory(unbox_char_string()); SetCurrentDirectory(unbox_char_string());
} }
BOUNDED_BLOCK *alloc_bounded_block(CELL size) BOUNDED_BLOCK *alloc_bounded_block(CELL size)
{ {
SYSTEM_INFO si; SYSTEM_INFO si;
char *mem; char *mem;
DWORD ignore; DWORD ignore;
GetSystemInfo(&si); GetSystemInfo(&si);
if((mem = (char *)VirtualAlloc(NULL, si.dwPageSize*2 + size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0) if((mem = (char *)VirtualAlloc(NULL, si.dwPageSize*2 + size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0)
fatal_error("VirtualAlloc() failed in alloc_bounded_block()",0); fatal_error("VirtualAlloc() failed in alloc_bounded_block()",0);
if (!VirtualProtect(mem, si.dwPageSize, PAGE_NOACCESS, &ignore)) if (!VirtualProtect(mem, si.dwPageSize, PAGE_NOACCESS, &ignore))
fatal_error("Cannot allocate low guard page", (CELL)mem); fatal_error("Cannot allocate low guard page", (CELL)mem);
if (!VirtualProtect(mem+size+si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &ignore)) if (!VirtualProtect(mem+size+si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &ignore))
fatal_error("Cannot allocate high guard page", (CELL)mem); fatal_error("Cannot allocate high guard page", (CELL)mem);
BOUNDED_BLOCK *block = safe_malloc(sizeof(BOUNDED_BLOCK)); BOUNDED_BLOCK *block = safe_malloc(sizeof(BOUNDED_BLOCK));
block->start = (int)mem + si.dwPageSize; block->start = (int)mem + si.dwPageSize;
block->size = size; block->size = size;
return block; return block;
} }
void dealloc_bounded_block(BOUNDED_BLOCK *block) void dealloc_bounded_block(BOUNDED_BLOCK *block)
{ {
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);
if(!VirtualFree((void*)(block->start - si.dwPageSize), 0, MEM_RELEASE)) if(!VirtualFree((void*)(block->start - si.dwPageSize), 0, MEM_RELEASE))
fatal_error("VirtualFree() failed",0); fatal_error("VirtualFree() failed",0);
free(block); free(block);
} }
/* SEH support. Proceed with caution. */ /* SEH support. Proceed with caution. */
typedef long exception_handler_t( typedef long exception_handler_t(
void *rec, void *frame, void *context, void *dispatch); void *rec, void *frame, void *context, void *dispatch);
typedef struct exception_record { typedef struct exception_record {
struct exception_record *next_handler; struct exception_record *next_handler;
void *handler_func; void *handler_func;
} exception_record_t; } exception_record_t;
void seh_call(void (*func)(), exception_handler_t *handler) void seh_call(void (*func)(), exception_handler_t *handler)
{ {
exception_record_t record; exception_record_t record;
asm("mov %%fs:0, %0" : "=r" (record.next_handler)); asm("mov %%fs:0, %0" : "=r" (record.next_handler));
asm("mov %0, %%fs:0" : : "r" (&record)); asm("mov %0, %%fs:0" : : "r" (&record));
record.handler_func = handler; record.handler_func = handler;
func(); func();
asm("mov %0, %%fs:0" : "=r" (record.next_handler)); asm("mov %0, %%fs:0" : "=r" (record.next_handler));
} }
static long exception_handler(void *rec, void *frame, void *ctx, void *dispatch) static long getpagesize (void) {
{ static long g_pagesize = 0;
signal_error(SIGSEGV); if (! g_pagesize) {
} SYSTEM_INFO system_info;
GetSystemInfo (&system_info);
void platform_run(void) g_pagesize = system_info.dwPageSize;
{ }
seh_call(run_toplevel, exception_handler); return g_pagesize;
} }
const char *default_image_path(void) /* this function tests if a given faulting location is in a poison page. The
{ page address is taken from area + round_up_to_page_size(area_size) +
return "factor.image"; pagesize*offset */
} static bool in_page(void *fault, void *i_area, CELL area_size, int offset)
{
const int pagesize = getpagesize();
intptr_t area = (intptr_t) i_area;
area += pagesize * ((area_size + (pagesize - 1)) / pagesize);
area += offset * pagesize;
const int page = area / pagesize;
const int fault_page = (intptr_t)fault / pagesize;
return page == fault_page;
}
//static long exception_handler(void *rec, void *frame, void *ctx, void *dispatch)
static long exception_handler(PEXCEPTION_RECORD rec, void *frame, void *ctx, void *dispatch)
{
if(in_page((void*)rec->ExceptionInformation[1], (void *) ds_bot, 0, -1))
general_error(ERROR_DS_UNDERFLOW,F,F,false);
else if(in_page((void*)rec->ExceptionInformation[1], (void *) ds_bot, ds_size, 0))
general_error(ERROR_DS_OVERFLOW,F,F,false);
else if(in_page((void*)rec->ExceptionInformation[1], (void *) rs_bot, 0, -1))
general_error(ERROR_RS_UNDERFLOW,F,F,false);
else if(in_page((void*)rec->ExceptionInformation[1], (void *) rs_bot, rs_size, 0))
general_error(ERROR_RS_OVERFLOW,F,F,false);
else if(in_page((void*)rec->ExceptionInformation[1], (void *) cs_bot, 0, -1))
general_error(ERROR_CS_UNDERFLOW,F,F,false);
else if(in_page((void*)rec->ExceptionInformation[1], (void *) cs_bot, cs_size, 0))
general_error(ERROR_CS_OVERFLOW,F,F,false);
else
signal_error(SIGSEGV);
}
void platform_run(void)
{
seh_call(run_toplevel, exception_handler);
}
const char *default_image_path(void)
{
return "factor.image";
}