diff options
| author | grischka <grischka> | 2009-12-19 22:22:43 +0100 |
|---|---|---|
| committer | grischka <grischka> | 2009-12-19 22:22:43 +0100 |
| commit | 7fa712e00c5221d9373e8f8fa073e9e6fa064da1 (patch) | |
| tree | 21c5acbfcb4ddaa6d61d30fe79cfaece3ff7b5d9 /tccrun.c | |
| parent | 8bbde91f62291cb0383c2406ae6123be903c944b (diff) | |
| download | tinycc-7fa712e00c5221d9373e8f8fa073e9e6fa064da1.tar.gz tinycc-7fa712e00c5221d9373e8f8fa073e9e6fa064da1.tar.bz2 | |
win32: enable bounds checker & exception handler
exception handler borrowed from k1w1. Thanks.
Diffstat (limited to 'tccrun.c')
| -rw-r--r-- | tccrun.c | 563 |
1 files changed, 321 insertions, 242 deletions
@@ -20,75 +20,167 @@ /* tccrun.c - support for tcc -run */ +#ifdef _WIN32 +#define ucontext_t CONTEXT +#endif -/********************************************************/ -#ifdef CONFIG_TCC_STATIC +static void set_pages_executable(void *ptr, unsigned long length); +static void set_exception_handler(void); +static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level); +static void rt_error(ucontext_t *uc, const char *fmt, ...); +static int tcc_relocate_ex(TCCState *s1, void *ptr); -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 -#define RTLD_DEFAULT NULL +/* ------------------------------------------------------------- */ +/* Do all relocations (needed before using tcc_get_symbol()) + Returns -1 on error. */ -/* dummy function for profiling */ -void *dlopen(const char *filename, int flag) +int tcc_relocate(TCCState *s1) { - return NULL; -} + int ret; -void dlclose(void *p) -{ + ret = tcc_relocate_ex(s1, NULL); + if (-1 != ret) { + s1->runtime_mem = tcc_malloc(ret); + ret = tcc_relocate_ex(s1, s1->runtime_mem); + } + return ret; } -const char *dlerror(void) +/* launch the compiled program with the given arguments */ +int tcc_run(TCCState *s1, int argc, char **argv) { - return "error"; -} + int (*prog_main)(int, char **); -typedef struct TCCSyms { - char *str; - void *ptr; -} TCCSyms; + if (tcc_relocate(s1) < 0) + return -1; -#define TCCSYM(a) { #a, &a, }, + prog_main = tcc_get_symbol_err(s1, "main"); -/* add the symbol you want here if no dynamic linking is done */ -static TCCSyms tcc_syms[] = { -#if !defined(CONFIG_TCCBOOT) - TCCSYM(printf) - TCCSYM(fprintf) - TCCSYM(fopen) - TCCSYM(fclose) +#ifdef CONFIG_TCC_BACKTRACE + if (s1->do_debug) + set_exception_handler(); #endif - { NULL, NULL }, -}; -void *resolve_sym(TCCState *s1, const char *symbol) -{ - TCCSyms *p; - p = tcc_syms; - while (p->str != NULL) { - if (!strcmp(p->str, symbol)) - return p->ptr; - p++; +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) { + void (*bound_init)(void); + void (*bound_exit)(void); + int ret; + /* set error function */ + rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); + rt_prog_main = prog_main; + /* XXX: use .init section so that it also work in binary ? */ + bound_init = tcc_get_symbol_err(s1, "__bound_init"); + bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); + bound_init(); + ret = (*prog_main)(argc, argv); + bound_exit(); + return ret; } - return NULL; +#endif + return (*prog_main)(argc, argv); } -#elif defined(_WIN32) -#define dlclose FreeLibrary +/* relocate code. Return -1 on error, required size if ptr is NULL, + otherwise copy code into buffer passed by the caller */ +static int tcc_relocate_ex(TCCState *s1, void *ptr) +{ + Section *s; + unsigned long offset, length; + uplong mem; + int i; + + if (0 == s1->runtime_added) { + s1->runtime_added = 1; + s1->nb_errors = 0; +#ifdef TCC_TARGET_PE + pe_output_file(s1, NULL); #else -#include <dlfcn.h> + tcc_add_runtime(s1); + relocate_common_syms(); + tcc_add_linker_symbols(s1); + build_got_entries(s1); +#endif + if (s1->nb_errors) + return -1; + } -void *resolve_sym(TCCState *s1, const char *sym) -{ - return dlsym(RTLD_DEFAULT, sym); + offset = 0, mem = (uplong)ptr; + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (0 == (s->sh_flags & SHF_ALLOC)) + continue; + length = s->data_offset; + s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0; + offset = (offset + length + 15) & ~15; + } + offset += 16; + + /* relocate symbols */ + relocate_syms(s1, 1); + if (s1->nb_errors) + return -1; + +#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE + s1->runtime_plt_and_got_offset = 0; + s1->runtime_plt_and_got = (char *)(mem + offset); + /* double the size of the buffer for got and plt entries + XXX: calculate exact size for them? */ + offset *= 2; +#endif + + if (0 == mem) + return offset; + + /* relocate each section */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->reloc) + relocate_section(s1, s); + } + + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (0 == (s->sh_flags & SHF_ALLOC)) + continue; + length = s->data_offset; + // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); + ptr = (void*)(uplong)s->sh_addr; + if (NULL == s->data || s->sh_type == SHT_NOBITS) + memset(ptr, 0, length); + else + memcpy(ptr, s->data, length); + /* mark executable sections as executable in memory */ + if (s->sh_flags & SHF_EXECINSTR) + set_pages_executable(ptr, length); + } + +#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE + set_pages_executable(s1->runtime_plt_and_got, + s1->runtime_plt_and_got_offset); +#endif + return 0; } -#endif /* defined CONFIG_TCC_STATIC */ +/* ------------------------------------------------------------- */ +/* allow to run code in memory */ -/********************************************************/ +static void set_pages_executable(void *ptr, unsigned long length) +{ +#ifdef _WIN32 + unsigned long old_protect; + VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); +#else + unsigned long start, end; + start = (unsigned long)ptr & ~(PAGESIZE - 1); + end = (unsigned long)ptr + length; + end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); + mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); +#endif +} +/* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_BACKTRACE /* print the position in the source file of PC value 'pc' by reading @@ -215,7 +307,92 @@ static unsigned long rt_printline(unsigned long wanted_pc) return func_addr; } +/* emit a run time error at position 'pc' */ +static void rt_error(ucontext_t *uc, const char *fmt, ...) +{ + va_list ap; + unsigned long pc; + int i; + + va_start(ap, fmt); + fprintf(stderr, "Runtime error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + + for(i=0;i<num_callers;i++) { + if (rt_get_caller_pc(&pc, uc, i) < 0) + break; + if (i == 0) + fprintf(stderr, "at "); + else + fprintf(stderr, "by "); + pc = rt_printline(pc); + if (pc == (unsigned long)rt_prog_main && pc) + break; + } + exit(255); + va_end(ap); +} + +/* ------------------------------------------------------------- */ +#ifndef _WIN32 + +/* signal handler for fatal errors */ +static void sig_error(int signum, siginfo_t *siginf, void *puc) +{ + ucontext_t *uc = puc; + + switch(signum) { + case SIGFPE: + switch(siginf->si_code) { + case FPE_INTDIV: + case FPE_FLTDIV: + rt_error(uc, "division by zero"); + break; + default: + rt_error(uc, "floating point exception"); + break; + } + break; + case SIGBUS: + case SIGSEGV: + if (rt_bound_error_msg && *rt_bound_error_msg) + rt_error(uc, *rt_bound_error_msg); + else + rt_error(uc, "dereferencing invalid pointer"); + break; + case SIGILL: + rt_error(uc, "illegal instruction"); + break; + case SIGABRT: + rt_error(uc, "abort() called"); + break; + default: + rt_error(uc, "caught signal %d", signum); + break; + } + exit(255); +} + +/* Generate a stack backtrace when a CPU exception occurs. */ +static void set_exception_handler(void) +{ + struct sigaction sigact; + /* install TCC signal handlers to print debug info on fatal + runtime errors */ + sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; + sigact.sa_sigaction = sig_error; + sigemptyset(&sigact.sa_mask); + sigaction(SIGFPE, &sigact, NULL); + sigaction(SIGILL, &sigact, NULL); + sigaction(SIGSEGV, &sigact, NULL); + sigaction(SIGBUS, &sigact, NULL); + sigaction(SIGABRT, &sigact, NULL); +} + +/* ------------------------------------------------------------- */ #ifdef __i386__ + /* fix for glibc 2.1 */ #ifndef REG_EIP #define REG_EIP EIP @@ -223,8 +400,7 @@ static unsigned long rt_printline(unsigned long wanted_pc) #endif /* return the PC at frame level 'level'. Return non zero if not found */ -static int rt_get_caller_pc(unsigned long *paddr, - ucontext_t *uc, int level) +static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level) { unsigned long fp; int i; @@ -256,7 +432,10 @@ static int rt_get_caller_pc(unsigned long *paddr, return 0; } } + +/* ------------------------------------------------------------- */ #elif defined(__x86_64__) + /* return the PC at frame level 'level'. Return non zero if not found */ static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level) @@ -288,236 +467,136 @@ static int rt_get_caller_pc(unsigned long *paddr, return 0; } } + +/* ------------------------------------------------------------- */ #else + #warning add arch specific rt_get_caller_pc() static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level) { return -1; } -#endif -/* emit a run time error at position 'pc' */ -void rt_error(ucontext_t *uc, const char *fmt, ...) -{ - va_list ap; - unsigned long pc; - int i; +#endif /* !__i386__ */ - va_start(ap, fmt); - fprintf(stderr, "Runtime error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - for(i=0;i<num_callers;i++) { - if (rt_get_caller_pc(&pc, uc, i) < 0) - break; - if (i == 0) - fprintf(stderr, "at "); - else - fprintf(stderr, "by "); - pc = rt_printline(pc); - if (pc == rt_prog_main && pc) - break; - } - exit(255); - va_end(ap); -} +/* ------------------------------------------------------------- */ +#else /* WIN32 */ -/* signal handler for fatal errors */ -static void sig_error(int signum, siginfo_t *siginf, void *puc) +static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) { - ucontext_t *uc = puc; - - switch(signum) { - case SIGFPE: - switch(siginf->si_code) { - case FPE_INTDIV: - case FPE_FLTDIV: - rt_error(uc, "division by zero"); - break; - default: - rt_error(uc, "floating point exception"); - break; - } - break; - case SIGBUS: - case SIGSEGV: - if (rt_bound_error_msg && *rt_bound_error_msg) - rt_error(uc, *rt_bound_error_msg); - else - rt_error(uc, "dereferencing invalid pointer"); - break; - case SIGILL: - rt_error(uc, "illegal instruction"); - break; - case SIGABRT: - rt_error(uc, "abort() called"); - break; - default: - rt_error(uc, "caught signal %d", signum); - break; - } + CONTEXT *uc = ex_info->ContextRecord; +/* + EXCEPTION_RECORD *er = ex_info->ExceptionRecord; + printf("CPU exception: code=%08lx addr=%p\n", + er->ExceptionCode, er->ExceptionAddress); +*/ + if (rt_bound_error_msg && *rt_bound_error_msg) + rt_error(uc, *rt_bound_error_msg); + else + rt_error(uc, "dereferencing invalid pointer"); exit(255); + //return EXCEPTION_CONTINUE_SEARCH; } -#endif /* defined CONFIG_TCC_BACKTRACE */ - -/********************************************************/ - -void set_pages_executable(void *ptr, unsigned long length) +/* Generate a stack backtrace when a CPU exception occurs. */ +static void set_exception_handler(void) { -#ifdef _WIN32 - unsigned long old_protect; - VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); -#else - unsigned long start, end; - start = (unsigned long)ptr & ~(PAGESIZE - 1); - end = (unsigned long)ptr + length; - end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); - mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); -#endif + SetUnhandledExceptionFilter(cpu_exception_handler); } -/* relocate code. Return -1 on error, required size if ptr is NULL, - otherwise copy code into buffer passed by the caller */ -static int tcc_relocate_ex(TCCState *s1, void *ptr) +/* return the PC at frame level 'level'. Return non zero if not found */ +static int rt_get_caller_pc(unsigned long *paddr, + CONTEXT *uc, int level) { - Section *s; - unsigned long offset, length; - uplong mem; + unsigned long fp; int i; - if (0 == s1->runtime_added) { - s1->runtime_added = 1; - s1->nb_errors = 0; -#ifdef TCC_TARGET_PE - pe_output_file(s1, NULL); -#else - tcc_add_runtime(s1); - relocate_common_syms(); - tcc_add_linker_symbols(s1); - build_got_entries(s1); -#endif - if (s1->nb_errors) - return -1; - } - - offset = 0, mem = (uplong)ptr; - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (0 == (s->sh_flags & SHF_ALLOC)) - continue; - length = s->data_offset; - s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0; - offset = (offset + length + 15) & ~15; + if (level == 0) { + *paddr = uc->Eip; + return 0; + } else { + fp = uc->Ebp; + for(i=1;i<level;i++) { + /* XXX: check address validity with program info */ + if (fp <= 0x1000 || fp >= 0xc0000000) + return -1; + fp = ((unsigned long *)fp)[0]; + } + *paddr = ((unsigned long *)fp)[1]; + return 0; } - offset += 16; - - /* relocate symbols */ - relocate_syms(s1, 1); - if (s1->nb_errors) - return -1; - -#ifndef TCC_TARGET_PE -#ifdef TCC_TARGET_X86_64 - s1->runtime_plt_and_got_offset = 0; - s1->runtime_plt_and_got = (char *)(mem + offset); - /* double the size of the buffer for got and plt entries - XXX: calculate exact size for them? */ - offset *= 2; -#endif -#endif +} - if (0 == mem) - return offset; +#endif /* _WIN32 */ +#endif /* CONFIG_TCC_BACKTRACE */ +/* ------------------------------------------------------------- */ - /* relocate each section */ - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->reloc) - relocate_section(s1, s); - } +#ifdef CONFIG_TCC_STATIC - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (0 == (s->sh_flags & SHF_ALLOC)) - continue; - length = s->data_offset; - // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); - ptr = (void*)(uplong)s->sh_addr; - if (NULL == s->data || s->sh_type == SHT_NOBITS) - memset(ptr, 0, length); - else - memcpy(ptr, s->data, length); - /* mark executable sections as executable in memory */ - if (s->sh_flags & SHF_EXECINSTR) - set_pages_executable(ptr, length); - } +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 +#define RTLD_DEFAULT NULL -#ifndef TCC_TARGET_PE -#ifdef TCC_TARGET_X86_64 - set_pages_executable(s1->runtime_plt_and_got, - s1->runtime_plt_and_got_offset); -#endif -#endif - return 0; +/* dummy function for profiling */ +void *dlopen(const char *filename, int flag) +{ + return NULL; } -/* Do all relocations (needed before using tcc_get_symbol()) - Returns -1 on error. */ -int tcc_relocate(TCCState *s1) +void dlclose(void *p) { - int ret = tcc_relocate_ex(s1, NULL); - if (-1 == ret) - return ret; - s1->runtime_mem = tcc_malloc(ret); - return tcc_relocate_ex(s1, s1->runtime_mem); } -/* launch the compiled program with the given arguments */ -int tcc_run(TCCState *s1, int argc, char **argv) +const char *dlerror(void) { - int (*prog_main)(int, char **); + return "error"; +} - if (tcc_relocate(s1) < 0) - return -1; +typedef struct TCCSyms { + char *str; + void *ptr; +} TCCSyms; - prog_main = tcc_get_symbol_err(s1, "main"); +#define TCCSYM(a) { #a, &a, }, - if (s1->do_debug) { -#ifdef CONFIG_TCC_BACKTRACE - struct sigaction sigact; - /* install TCC signal handlers to print debug info on fatal - runtime errors */ - sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; - sigact.sa_sigaction = sig_error; - sigemptyset(&sigact.sa_mask); - sigaction(SIGFPE, &sigact, NULL); - sigaction(SIGILL, &sigact, NULL); - sigaction(SIGSEGV, &sigact, NULL); - sigaction(SIGBUS, &sigact, NULL); - sigaction(SIGABRT, &sigact, NULL); -#else - error("debug mode not available"); +/* add the symbol you want here if no dynamic linking is done */ +static TCCSyms tcc_syms[] = { +#if !defined(CONFIG_TCCBOOT) + TCCSYM(printf) + TCCSYM(fprintf) + TCCSYM(fopen) + TCCSYM(fclose) #endif + { NULL, NULL }, +}; + +void *resolve_sym(TCCState *s1, const char *symbol) +{ + TCCSyms *p; + p = tcc_syms; + while (p->str != NULL) { + if (!strcmp(p->str, symbol)) + return p->ptr; + p++; } + return NULL; +} -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - void (*bound_init)(void); - void (*bound_exit)(void); - /* set error function */ - rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); - rt_prog_main = (unsigned long)prog_main; - /* XXX: use .init section so that it also work in binary ? */ - bound_init = tcc_get_symbol_err(s1, "__bound_init"); - bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); - bound_init(); - ret = (*prog_main)(argc, argv); - bound_exit(); - } else -#endif - return (*prog_main)(argc, argv); +#elif defined(_WIN32) + +#define dlclose FreeLibrary + +#else + +#include <dlfcn.h> + +void *resolve_sym(TCCState *s1, const char *sym) +{ + return dlsym(RTLD_DEFAULT, sym); } -/********************************************************/ +#endif /* CONFIG_TCC_STATIC */ + +/* ------------------------------------------------------------- */ |
