diff --git a/Makefile b/Makefile index 98f01e49..26764f54 100644 --- a/Makefile +++ b/Makefile @@ -386,13 +386,13 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2 IM = @echo "-> $2 : $1" ; BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1) -B_O = runmain.o bt-exe.o bt-dll.o bcheck.o +EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o # install progs & libs install-unx: $(call BINCHECK) $(call IBw,$(PROGS) *-tcc,"$(bindir)") - $(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)") + $(call IFw,$(LIBTCC1) $(EXTRA_O) $(LIBTCC1_U),"$(tccdir)") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)") $(call IF,$(TOPSRC)/libtcc.h,"$(includedir)") @@ -419,7 +419,7 @@ install-win: $(call BINCHECK) $(call IBw,$(PROGS) *-tcc.exe libtcc.dll,"$(bindir)") $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib") - $(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib") + $(call IFw,libtcc1.a $(EXTRA_O) $(LIBTCC1_W),"$(tccdir)/lib") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples") diff --git a/configure b/configure index 06bb2d50..6522195d 100755 --- a/configure +++ b/configure @@ -365,7 +365,7 @@ case $targetos in default tcc_libpaths "{B}:{R}/lib:/system/lib${S}" default tcc_crtprefix "{R}/lib" default tcc_elfinterp "/system/bin/linker${S}" - default tcc_switches "-Wl,-rpath=$sysroot/lib,-section-alignment=0x1000" + default tcc_switches "-Wl,-rpath=$sysroot/lib" ;; WIN32) mingw32="yes" diff --git a/lib/Makefile b/lib/Makefile index 1a232237..c95a3e30 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -40,7 +40,7 @@ endif $(X)BT_O = bt-exe.o bt-log.o $(X)B_O = $(BCHECK_O) bt-exe.o bt-log.o bt-dll.o endif -$(X)BT_O += tcov.o +$(X)BT_O += runmain.o tcov.o DSO_O = dsohandle.o @@ -67,8 +67,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) OBJ-arm-wince = $(ARM_O) $(WIN_O) OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O) -OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T))) -OBJ-extra += runmain.o +OBJ-extra = $(filter $(B_O) runmain.o,$(OBJ-$T)) OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) diff --git a/lib/bt-log.c b/lib/bt-log.c index 87e411d5..ace51170 100644 --- a/lib/bt-log.c +++ b/lib/bt-log.c @@ -23,19 +23,19 @@ typedef struct rt_frame { } rt_frame; __attribute__((weak)) -int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); +int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap); DLL_EXPORT int tcc_backtrace(const char *fmt, ...) { va_list ap; int ret; - if (__rt_dump) { + if (_tcc_backtrace) { rt_frame f; f.fp = __builtin_frame_address(1); f.ip = __builtin_return_address(0); va_start(ap, fmt); - ret = __rt_dump(&f, NULL, fmt, ap); + ret = _tcc_backtrace(&f, fmt, ap); va_end(ap); } else { const char *p, *nl = "\n"; diff --git a/lib/runmain.c b/lib/runmain.c index 5ebeeec3..53cbe6de 100644 --- a/lib/runmain.c +++ b/lib/runmain.c @@ -29,7 +29,7 @@ static void run_dtors(void) static void *rt_exitfunc[32]; static void *rt_exitarg[32]; -int __rt_nr_exit; +static int __rt_nr_exit; void __run_on_exit(int ret) { @@ -59,16 +59,16 @@ typedef struct rt_frame { void *ip, *fp, *sp; } rt_frame; -void __rt_longjmp(rt_frame *, int); +void __rt_exit(rt_frame *, int); void exit(int code) { rt_frame f; run_dtors(); __run_on_exit(code); - f.fp = __builtin_frame_address(1); - f.ip = __builtin_return_address(0); - __rt_longjmp(&f, code); + f.fp = 0; + f.ip = exit; + __rt_exit(&f, code); } #ifndef _WIN32 @@ -77,7 +77,6 @@ int main(int, char**, char**); int _runmain(int argc, char **argv, char **envp) { int ret; - __rt_nr_exit = 0; run_ctors(argc, argv, envp); ret = main(argc, argv, envp); run_dtors(); diff --git a/libtcc.c b/libtcc.c index a318ea78..393b79f6 100644 --- a/libtcc.c +++ b/libtcc.c @@ -229,7 +229,7 @@ static void *default_reallocator(void *ptr, unsigned long size) return ptr1; } -static void libc_free(void *ptr) +ST_FUNC void libc_free(void *ptr) { free(ptr); } diff --git a/libtcc.h b/libtcc.h index 7e032d80..eb83c74a 100644 --- a/libtcc.h +++ b/libtcc.h @@ -104,12 +104,12 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, /* catch runtime exceptions (optionally limit backtraces at top_func), when using tcc_set_options("-bt") and when not using tcc_run() */ -LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *longjmp, void *jmp_buf, void *top_func); -#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, longjmp, jb, f)) +LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp); +#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp)) -/* set custom error printer for runtime exceptions */ -typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func); -LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*); +/* custom error printer for runtime exceptions. Returning 0 stops backtrace */ +typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg); +LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*); #ifdef __cplusplus } diff --git a/tcc.h b/tcc.h index 16f316d2..1491ee05 100644 --- a/tcc.h +++ b/tcc.h @@ -1003,7 +1003,9 @@ struct TCCState { struct TCCState *next; struct rt_context *rc; /* pointer to backtrace info block */ void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */ - void (*bt_func)(void *, const char*, int, const char*); + TCCBtFunc *bt_func; + void *bt_data; + int run_tid; #endif #ifdef CONFIG_TCC_BACKTRACE @@ -1250,6 +1252,7 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); #endif +ST_FUNC void libc_free(void *ptr); #define free(p) use_tcc_free(p) #define malloc(s) use_tcc_malloc(s) #define realloc(p, s) use_tcc_realloc(p, s) @@ -1982,7 +1985,7 @@ ST_FUNC void wait_sem(TCCSem *p) sem_init(&p->sem, 0, 1), p->init = 1; while (sem_wait(&p->sem) < 0 && errno == EINTR); } -ST_INLN void post_sem(TCCSem *p) +ST_FUNC void post_sem(TCCSem *p) { sem_post(&p->sem); } diff --git a/tccelf.c b/tccelf.c index 049d674f..fab49c48 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1606,7 +1606,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) (uint64_t)1 << 32); #endif } - n = 4 * PTR_SIZE; + n = 3 * PTR_SIZE; #ifdef CONFIG_TCC_BCHECK if (s1->do_bounds_check) { put_ptr(s1, bounds_section, 0); @@ -1617,9 +1617,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) p = section_ptr_add(s, 2 * sizeof (int)); p[0] = s1->rt_num_callers; p[1] = s1->dwarf; - - if (s->data_offset - o != 11 * PTR_SIZE + 2 * sizeof (int)) - exit(99); + // if (s->data_offset - o != 10*PTR_SIZE + 2*sizeof (int)) exit(99); if (s1->output_type == TCC_OUTPUT_MEMORY) { set_global_sym(s1, __rt_info, s, o); @@ -1778,6 +1776,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) if (s1->do_backtrace) { if (s1->output_type & TCC_OUTPUT_EXE) tcc_add_support(s1, "bt-exe.o"); + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_support(s1, "bt-log.o"); tcc_add_btstub(s1); lpthread = 1; } diff --git a/tccpe.c b/tccpe.c index d2a2c8b3..26fb2296 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1943,7 +1943,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) pe_type = PE_EXE; } - if (TCC_OUTPUT_MEMORY == s1->output_type) + if (TCC_OUTPUT_MEMORY == s1->output_type && !s1->nostdlib) start_symbol = run_symbol; } @@ -1961,6 +1961,8 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) tcc_add_support(s1, "bt-exe.o"); if (s1->output_type == TCC_OUTPUT_DLL) tcc_add_support(s1, "bt-dll.o"); + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_support(s1, "bt-log.o"); tcc_add_btstub(s1); } #endif diff --git a/tccrun.c b/tccrun.c index 6ba61a64..d8ae8fa0 100644 --- a/tccrun.c +++ b/tccrun.c @@ -24,6 +24,7 @@ #ifdef TCC_IS_NATIVE #ifdef CONFIG_TCC_BACKTRACE +/* runtime debug info block */ typedef struct rt_context { /* tccelf.c:tcc_add_btstub() wants these in that order: */ @@ -42,32 +43,33 @@ typedef struct rt_context ElfW(Sym) *esym_start; ElfW(Sym) *esym_end; char *elf_str; - // 6 + // 6 * PTR_SIZE addr_t prog_base; void *bounds_start; void *top_func; - TCCState *s1; struct rt_context *next; - // 11 + // 10 * PTR_SIZE int num_callers; int dwarf; -} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */ +} rt_context; + +/* linked list of rt_contexts */ +static rt_context *g_rc; +static int signal_set; +static void set_exception_handler(void); +#endif /* def CONFIG_TCC_BACKTRACE */ typedef struct rt_frame { addr_t ip, fp, sp; } rt_frame; -/* linked list of rt_contexts */ -static rt_context *g_rc; static TCCState *g_s1; /* semaphore to protect it */ TCC_SEM(static rt_sem); -static int signal_set; -static void set_exception_handler(void); static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); } static void rt_post_sem(void) { POST_SEM(&rt_sem); } static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); -#endif /* def CONFIG_TCC_BACKTRACE */ +static void rt_exit(rt_frame *f, int code); /* ------------------------------------------------------------- */ /* defined when included from lib/bt-exe.c */ @@ -79,73 +81,26 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); static int protect_pages(void *ptr, unsigned long length, int mode); static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff); -static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); -static void rt_longjmp(rt_frame *f, int code); +static void st_link(TCCState *s1); +static void st_unlink(TCCState *s1); +#ifdef CONFIG_TCC_BACKTRACE +static int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap); +#endif #ifdef _WIN64 static void *win64_add_function_table(TCCState *s1); static void win64_del_function_table(void *); #endif -static void bt_link(TCCState *s1) -{ -#ifdef CONFIG_TCC_BACKTRACE - rt_context *rc; - void *p; - - if (!s1->do_backtrace) - return; - rc = tcc_get_symbol(s1, "__rt_info"); - if (!rc) - return; - rc->esym_start = (ElfW(Sym) *)(symtab_section->data); - rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); - rc->elf_str = (char *)symtab_section->link->data; - if (PTR_SIZE == 8 && !s1->dwarf) - rc->prog_base &= 0xffffffff00000000ULL; -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - if ((p = tcc_get_symbol(s1, "__bound_init"))) - ((void(*)(void*,int))p)(rc->bounds_start, 1); - } +#ifdef __APPLE__ +# define CONFIG_RUNMEM_ALIGNED 0 +#else +# ifndef CONFIG_RUNMEM_ALIGNED +# define CONFIG_RUNMEM_ALIGNED 1 +# endif +# if CONFIG_RUNMEM_ALIGNED +# include /* memalign() */ +# endif #endif - rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc; - if (0 == signal_set) - set_exception_handler(), signal_set = 1; -#endif -} - -static void bt_unlink(TCCState *s1) -{ -#ifdef CONFIG_TCC_BACKTRACE - rt_context *rc, **pp; - for (pp = &g_rc; rc = *pp, rc; pp = &rc->next) - if (rc->s1 == s1) { - *pp = rc->next; - break; - } -#endif -} - -static void st_link(TCCState *s1) -{ - rt_wait_sem(); - s1->next = g_s1, g_s1 = s1; - bt_link(s1); - rt_post_sem(); -} - -static void st_unlink(TCCState *s1) -{ - TCCState *s2, **pp; - rt_wait_sem(); - bt_unlink(s1); - for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next) - if (s2 == s1) { - *pp = s2->next; - break; - } - rt_post_sem(); -} #if !_WIN32 && !__APPLE__ //#define HAVE_SELINUX 1 @@ -172,7 +127,15 @@ static int rt_mem(TCCState *s1, int size) ptr_diff = (char*)prw - (char*)ptr; /* = size; */ //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff); #else - ptr = tcc_malloc(size); +# if !CONFIG_RUNMEM_ALIGNED + ptr = tcc_malloc(size += PAGESIZE); +# elif _WIN32 + ptr = _aligned_malloc(size, PAGESIZE); +# else + ptr = memalign(PAGESIZE, size); +# endif + if (NULL == ptr) + return tcc_error_noabort("tccrun: could not allocate memory"); #endif s1->run_ptr = ptr; s1->run_size = size; @@ -189,12 +152,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) if (s1->run_ptr) exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported")); - #ifdef CONFIG_TCC_BACKTRACE if (s1->do_backtrace) - tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */ + tcc_add_symbol(s1, "_tcc_backtrace", _tcc_backtrace); /* for bt-log.c */ #endif - size = tcc_relocate_ex(s1, NULL, 0); if (size < 0) return -1; @@ -236,31 +197,24 @@ ST_FUNC void tcc_run_free(TCCState *s1) #else /* unprotect memory to make it usable for malloc again */ protect_pages(ptr, size, 2 /*rw*/); -#ifdef _WIN64 +# ifdef _WIN64 win64_del_function_table(s1->run_function_table); -#endif +# endif +# if !CONFIG_RUNMEM_ALIGNED tcc_free(ptr); +# elif _WIN32 + _aligned_free(ptr); +# else + libc_free(ptr); +# endif #endif } -LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func) -{ - s1->run_lj = p_longjmp; - s1->run_jb = p_jmp_buf; - if (func && s1->rc) - s1->rc->top_func = func; - return p_jmp_buf; -} - -LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func) -{ - s1->bt_func = func; -} - /* launch the compiled program with the given arguments */ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) { int (*prog_main)(int, char **, char **), ret; + const char *top_sym; jmp_buf main_jb; #if defined(__APPLE__) || defined(__FreeBSD__) @@ -276,20 +230,25 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1)) return 0; - tcc_add_support(s1, "runmain.o"); - tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp); - s1->run_main = (s1->nostdlib ? "_start" : "_runmain"); + tcc_add_symbol(s1, "__rt_exit", rt_exit); + if (s1->nostdlib) { + s1->run_main = top_sym = "_start"; + } else { + tcc_add_support(s1, "runmain.o"); + s1->run_main = "_runmain"; + top_sym = "main"; + } if (tcc_relocate(s1) < 0) - return -1; + return 1; prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1); if ((addr_t)-1 == (addr_t)prog_main) - return -1; + return 1; errno = 0; /* clean errno value */ fflush(stdout); fflush(stderr); - ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main")); + ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym)); if (0 == ret) ret = prog_main(argc, argv, envp); else if (256 == ret) @@ -344,8 +303,6 @@ static void cleanup_sections(TCCState *s1) # define CONFIG_RUNMEM_RO 1 #endif -#define DEBUG_RUNMEN 0 - /* 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, unsigned ptr_diff) @@ -367,16 +324,17 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) offset = copy = 0; mem = (addr_t)ptr; - -#if DEBUG_RUNMEN - if (mem) - fprintf(stderr, "X: %p len %5x\n", - ptr, s1->run_size); -#endif - redo: + if (s1->verbose == 2 && copy) { + printf(&"-----------------------------------------------------\n"[PTR_SIZE*2 - 8]); + if (1 == copy) + printf("memory %p len %05x\n", ptr, s1->run_size); + } if (s1->nb_errors) return -1; + if (copy == 2) + return 0; + for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ n = 0; addr = 0; for(i = 1; i < s1->nb_sections; i++) { @@ -389,7 +347,9 @@ redo: length = s->data_offset; if (copy) { /* final step: copy section data to memory */ - void *ptr; + if (s1->verbose == 2) + printf("%d: %-16s %p len %05x align %04x\n", + k, s->name, (void*)s->sh_addr, length, s->sh_addralign); if (addr == 0) addr = s->sh_addr; n = (s->sh_addr - addr) + length; @@ -407,28 +367,25 @@ redo: continue; } - align = s->sh_addralign - 1; + align = s->sh_addralign; if (++n == 1) { #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 /* To avoid that x86 processors would reload cached instructions each time when data is written in the near, we need to make sure that code and data do not share the same 64 byte unit */ - if (align < 63) - align = 63; + if (align < 64) + align = 64; #endif /* start new page for different permissions */ if (CONFIG_RUNMEM_RO || k < 2) - align = PAGESIZE - 1; + align = PAGESIZE; } + s->sh_addralign = align; + addr = k ? mem + ptr_diff : mem; - offset += -(addr + offset) & align; + offset += -(addr + offset) & (align - 1); s->sh_addr = mem ? addr + offset : 0; offset += length; -#if DEBUG_RUNMEN - if (mem) - fprintf(stderr, "%d: %-16s %p len %5x align %04x\n", - k, s->name, (void*)s->sh_addr, length, align + 1); -#endif } if (copy) { /* set permissions */ if (n == 0) /* no data */ @@ -443,30 +400,25 @@ redo: continue; f = 3; /* change only SHF_EXECINSTR to rwx */ } -#if DEBUG_RUNMEN - fprintf(stderr, "protect %3s %p len %5x\n", - &"rx\0r \0rw\0rwx"[f*3], - (void*)addr, (unsigned)((n + PAGESIZE-1) & ~(PAGESIZE-1))); -#endif + n = (n + PAGESIZE-1) & ~(PAGESIZE-1); + if (s1->verbose == 2) { + printf("protect %3s %p len %05x\n", + &"rx\0r \0rw\0rwx"[f*3], (void*)addr, (unsigned)n); + } if (protect_pages((void*)addr, n, f) < 0) return tcc_error_noabort( "mprotect failed (did you mean to configure --with-selinux?)"); } } - if (0 == mem) { - offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1); -#ifndef HAVE_SELINUX - offset += PAGESIZE; /* extra space to align malloc memory start */ -#endif - return offset; - } + if (0 == mem) + return (offset + (PAGESIZE-1)) & ~(PAGESIZE-1); - if (copy) { + if (++copy == 2) { /* remove local symbols and free sections except symtab */ cleanup_symbols(s1); cleanup_sections(s1); - return 0; + goto redo; } /* relocate symbols */ @@ -478,7 +430,6 @@ redo: relocate_plt(s1); #endif relocate_sections(s1); - copy = 1; goto redo; } @@ -546,6 +497,152 @@ static void win64_del_function_table(void *p) } #endif +static void bt_link(TCCState *s1) +{ +#ifdef CONFIG_TCC_BACKTRACE + rt_context *rc; + void *p; + + if (!s1->do_backtrace) + return; + rc = tcc_get_symbol(s1, "__rt_info"); + if (!rc) + return; + rc->esym_start = (ElfW(Sym) *)(symtab_section->data); + rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); + rc->elf_str = (char *)symtab_section->link->data; + if (PTR_SIZE == 8 && !s1->dwarf) + rc->prog_base &= 0xffffffff00000000ULL; +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) { + if ((p = tcc_get_symbol(s1, "__bound_init"))) + ((void(*)(void*,int))p)(rc->bounds_start, 1); + } +#endif + rc->next = g_rc, g_rc = rc, s1->rc = rc; + if (0 == signal_set) + set_exception_handler(), signal_set = 1; +#endif +} + +static void st_link(TCCState *s1) +{ + rt_wait_sem(); + s1->next = g_s1, g_s1 = s1; + bt_link(s1); + rt_post_sem(); +} + +/* remove 'el' from 'list' */ +static void ptr_unlink(void *list, void *e, unsigned next) +{ + void **pp, **nn, *p; + for (pp = list; !!(p = *pp); pp = nn) { + nn = (void*)((char*)p + next); /* nn = &p->next; */ + if (p == e) { + *pp = *nn; + break; + } + } +} + +static void st_unlink(TCCState *s1) +{ + rt_wait_sem(); +#ifdef CONFIG_TCC_BACKTRACE + ptr_unlink(&g_rc, s1->rc, offsetof(rt_context, next)); +#endif + ptr_unlink(&g_s1, s1, offsetof(TCCState, next)); + rt_post_sem(); +} + +#ifdef _WIN32 +# define GETTID() GetCurrentThreadId() +#elif defined __linux__ +# define GETTID() gettid() +#elif 0 +# define GETTID() 1234 // threads not supported +#endif + +LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_jmp_buf, void *func, void *p_longjmp) +{ +#ifdef GETTID + int tid = GETTID(); + TCCState *s; + rt_wait_sem(); + for (s = g_s1; s; s = s->next) + if (s->run_tid == tid) + s->run_tid = -1; + s1->run_tid = (int)tid; + rt_post_sem(); +#endif + s1->run_lj = p_longjmp; + s1->run_jb = p_jmp_buf; +#ifdef CONFIG_TCC_BACKTRACE + if (s1->rc) + s1->rc->top_func = func; +#endif + return p_jmp_buf; +} + +LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void *data, TCCBtFunc *func) +{ + s1->bt_func = func; + s1->bt_data = data; +} + +static TCCState *rt_find_state(rt_frame *f) +{ +#ifdef GETTID + int tid = GETTID(); + TCCState *s; + for (s = g_s1; s; s = s->next) + if (s->run_tid == tid) + break; + return s; +#else + TCCState *s; + int level; + addr_t pc; + + s = g_s1; + if (NULL == s || NULL == s->next) { + /* play it safe in the simple case when there is only one state */ + return s; + } + for (level = 0; level < 8; ++level) { + if (rt_get_caller_pc(&pc, f, level) < 0) + break; + for (s = g_s1; s; s = s->next) { + if (pc >= (addr_t)s->run_ptr + && pc < (addr_t)s->run_ptr + s->run_size) + return s; + } + } + return NULL; +#endif +} + +static void rt_exit(rt_frame *f, int code) +{ + TCCState *s; + rt_wait_sem(); + s = rt_find_state(f); + rt_post_sem(); + if (s && s->run_lj) { + if (code == 0) + code = 256; + ((void(*)(void*,int))s->run_lj)(s->run_jb, code); + } + exit(code); +} + +/* ------------------------------------------------------------- */ +#else // if defined CONFIG_TCC_BACKTRACE_ONLY +static void rt_exit(rt_frame *f, int code) +{ + exit(code); +} #endif //ndef CONFIG_TCC_BACKTRACE_ONLY /* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_BACKTRACE @@ -582,11 +679,17 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr) return NULL; } +typedef struct bt_info +{ + char file[100]; + int line; + char func[100]; + addr_t func_pc; +} bt_info; /* print the position in the source file of PC value 'pc' by reading the stabs debug information */ -static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, - rt_context** prc, const char *msg, const char *skip) +static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, bt_info *bi) { char func_name[128]; addr_t func_addr, last_pc, pc; @@ -595,15 +698,12 @@ static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, const char *str, *p; Stab_Sym *sym; -next: func_name[0] = '\0'; func_addr = 0; incl_index = 0; last_pc = (addr_t)-1; last_line_num = 1; last_incl_index = 0; - if (NULL == rc) - goto found; for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) { str = rc->stab_str + sym->n_strx; @@ -680,50 +780,15 @@ next: break; } } - - func_name[0] = '\0'; - func_addr = 0; - last_incl_index = 0; - - /* we try symtab symbols (no line number info) */ - p = rt_elfsym(rc, wanted_pc, &func_addr); - if (p) { - pstrcpy(func_name, sizeof func_name, p); - goto found; - } - rc = rc->next; - goto next; - + last_incl_index = 0, func_name[0] = 0, func_addr = 0; found: i = last_incl_index; - str = NULL; if (i > 0) { - str = incl_files[--i]; - if (skip[0] && strstr(str, skip)) - return (addr_t)-1; + pstrcpy(bi->file, sizeof bi->file, incl_files[--i]); + bi->line = last_line_num; } - if (rc && rc->s1 && rc->s1->bt_func) { - rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL); - } else { - if (str) - rt_printf("%s:%d: ", str, last_line_num); - else - rt_printf("%08llx : ", (long long)wanted_pc); - rt_printf("%s %s", msg, func_name[0] ? func_name : "???"); - } -#if 0 - if (--i >= 0) { - rt_printf(" (included from "); - for (;;) { - rt_printf("%s", incl_files[i]); - if (--i < 0) - break; - rt_printf(", "); - } - rt_printf(")"); - } -#endif - *prc = rc; + pstrcpy(bi->func, sizeof bi->func, func_name); + bi->func_pc = func_addr; return func_addr; } @@ -793,8 +858,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) return retval; } -static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, - rt_context** prc, const char *msg, const char *skip) +static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, bt_info *bi) { unsigned char *ln; unsigned char *cp; @@ -834,12 +898,10 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, char *filename; char *function; -next: filename = NULL; + function = NULL; func_addr = 0; line = 0; - if (NULL == rc) - goto found; ln = rc->dwarf_line; while (ln < rc->dwarf_line_end) { @@ -1070,44 +1132,28 @@ check_pc: next_line: ln = end; } - - filename = NULL; - func_addr = 0; - /* we try symtab symbols (no line number info) */ - function = rt_elfsym(rc, wanted_pc, &func_addr); - if (function) - goto found; - rc = rc->next; - goto next; - + filename = function = NULL, func_addr = 0; found: - if (rc && rc->s1 && rc->s1->bt_func) { - rc->s1->bt_func((void*)wanted_pc, filename, line, function); - } else { - if (filename) { - if (skip[0] && strstr(filename, skip)) - return (addr_t)-1; - rt_printf("%s:%d: ", filename, line); - } - else - rt_printf("0x%08llx : ", (long long)wanted_pc); - rt_printf("%s %s", msg, function ? function : "???"); - } - *prc = rc; + if (filename) + pstrcpy(bi->file, sizeof bi->file, filename), bi->line = line; + if (function) + pstrcpy(bi->func, sizeof bi->func, function); + bi->func_pc = func_addr; return (addr_t)func_addr; } /* ------------------------------------------------------------- */ #ifndef CONFIG_TCC_BACKTRACE_ONLY static #endif -int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) +int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap) { - rt_context *rc, *rd; - addr_t pc = 0; - char skip[100]; + rt_context *rc, *rc2; + addr_t pc; + char skip[40], msg[200]; int i, level, ret, n, one; const char *a, *b; - addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*); + bt_info bi; + addr_t (*getinfo)(rt_context*, addr_t, bt_info*); skip[0] = 0; /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ @@ -1119,41 +1165,73 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) /* hack for bcheck.c:dprintf(): one level, no newline */ if (fmt[0] == '\001') ++fmt, one = 1; + vsnprintf(msg, sizeof msg, fmt, ap); rt_wait_sem(); rc = g_rc; - printline = rt_printline, n = 6; + getinfo = rt_printline, n = 6; if (rc) { if (rc->dwarf) - printline = rt_printline_dwarf; + getinfo = rt_printline_dwarf; if (rc->num_callers) n = rc->num_callers; } + for (i = level = 0; level < n; i++) { ret = rt_get_caller_pc(&pc, f, i); - if (ret != -1) { - pc = printline(rc, pc, &rd, level ? "by" : "at", skip); - if (pc == (addr_t)-1) - continue; - } - if (level == 0) { - if (rd && rd->s1 && rd->s1->bt_func) + if (ret == -1) + break; + memset(&bi, 0, sizeof bi); + for (rc2 = rc; rc2; rc2 = rc2->next) { + if (getinfo(rc2, pc, &bi)) break; - if (ret != -1) - rt_printf(": "); - if (msg) - rt_printf("%s: ", msg); - rt_vprintf(fmt, ap); - } else if (ret == -1) - break; - if (one) - break; + /* we try symtab symbols (no line number info) */ + if (!!(a = rt_elfsym(rc2, pc, &bi.func_pc))) { + pstrcpy(bi.func, sizeof bi.func, a); + break; + } + } + //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc); + if (skip[0] && strstr(bi.file, skip)) + continue; +#ifndef CONFIG_TCC_BACKTRACE_ONLY + { + TCCState *s = rt_find_state(f); + if (s && s->bt_func) { + ret = s->bt_func( + s->bt_data, + (void*)pc, + bi.file[0] ? bi.file : NULL, + bi.line, + bi.func[0] ? bi.func : NULL, + level == 0 ? msg : NULL + ); + if (ret == 0) + break; + goto check_break; + } + } +#endif + if (bi.file[0]) { + rt_printf("%s:%d", bi.file, bi.line); + } else { + rt_printf("0x%08llx", (long long)pc); + } + rt_printf(": %s %s", level ? "by" : "at", bi.func[0] ? bi.func : "???"); + if (level == 0) { + rt_printf(": %s", msg); + if (one) + break; + } rt_printf("\n"); - if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc)) + + check_break: + if (rc2 + && bi.func_pc + && bi.func_pc == (addr_t)rc2->top_func) break; ++level; } - rt_post_sem(); return 0; } @@ -1161,49 +1239,14 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) /* emit a run time error at position 'pc' */ static int rt_error(rt_frame *f, const char *fmt, ...) { - va_list ap; - int ret; + va_list ap; char msg[200]; int ret; va_start(ap, fmt); - ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap); + snprintf(msg, sizeof msg, "RUNTIME ERROR: %s", fmt); + ret = _tcc_backtrace(f, msg, ap); va_end(ap); return ret; } -static TCCState *rt_find_state(rt_frame *f) -{ - TCCState *s; - int level; - addr_t pc; - - rt_wait_sem(); - for (s = g_s1; s; s = s->next) { - if (0 == s->run_lj) - continue; - for (level = 0; level < 8; ++level) { - if (rt_get_caller_pc(&pc, f, level) < 0) - break; - if (pc >= (addr_t)s->run_ptr - && pc < (addr_t)s->run_ptr + s->run_size) - goto found; - } - } -found: - rt_post_sem(); - //fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr); - return s; -} - -static void rt_longjmp(rt_frame *f, int code) -{ - TCCState *s = rt_find_state(f); - if (s && s->run_lj) { - if (code == 0) - code = 256; - ((void(*)(void*,int))s->run_lj)(s->run_jb, code); - } - exit(code); -} - /* ------------------------------------------------------------- */ #ifndef _WIN32 @@ -1338,8 +1381,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) rt_error(&f, "caught signal %d", signum); break; } - set_exception_handler(); - rt_longjmp(&f, 255); + { + sigset_t s; + sigemptyset(&s); + sigaddset(&s, signum); + sigprocmask(SIG_UNBLOCK, &s, NULL); + } + rt_exit(&f, 255); } #ifndef SA_SIGINFO @@ -1353,12 +1401,11 @@ static void set_exception_handler(void) /* install TCC signal handlers to print debug info on fatal runtime errors */ sigemptyset (&sigact.sa_mask); - sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER; + sigact.sa_flags = SA_SIGINFO; //| SA_RESETHAND; #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes sigact.sa_flags |= SA_ONSTACK; #endif sigact.sa_sigaction = sig_error; - sigemptyset(&sigact.sa_mask); sigaction(SIGFPE, &sigact, NULL); sigaction(SIGILL, &sigact, NULL); sigaction(SIGSEGV, &sigact, NULL); @@ -1406,7 +1453,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) rt_error(&f, "caught exception %08x", code); break; } - rt_longjmp(&f, 255); + rt_exit(&f, 255); return EXCEPTION_EXECUTE_HANDLER; } @@ -1506,6 +1553,14 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) } #endif +#else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */ +static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level) +{ + if (level) + return -1; + *paddr = f->ip; + return 0; +} #endif /* CONFIG_TCC_BACKTRACE */ /* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_STATIC diff --git a/tests/Makefile b/tests/Makefile index 54f7c8b2..3906bf5a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -26,7 +26,9 @@ TESTS = \ # test4_static -- Not all relocation types are implemented yet. # asmtest / asmtest2 -- minor differences with gcc -ifneq ($(CONFIG_bcheck),no) +ifeq ($(CONFIG_backtrace),no) + TESTS := $(filter-out libtest_mt, $(TESTS)) +else ifneq ($(CONFIG_bcheck),no) TESTS += btest test1b tccb endif ifeq ($(CONFIG_dll),no) diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c index 6c712c61..f9c90bd6 100644 --- a/tests/libtcc_test_mt.c +++ b/tests/libtcc_test_mt.c @@ -83,11 +83,13 @@ PROG(my_program) " return add(fib(n-1),fib(n-2));\n" "}\n" "\n" +"void bar(void) { *(void**)0 = 0; }\n" +"\n" "int foo(int n)\n" "{\n" -" if (n >= N_CRASH && n < N_CRASH + 3)\n" -" *(void**)0 = 0;\n" " printf(\" %d\", fib(n));\n" +" if (n >= N_CRASH && n < N_CRASH + 8)\n" +" bar();\n" " return 0;\n" "# warning is this the correct file:line...\n" "}\n"; @@ -113,9 +115,27 @@ void parse_args(TCCState *s) } } -void bt_func(void *pc, const char *file, int line, const char *func) +int backtrace_func( + void *ud, + void *pc, + const char *file, + int line, + const char *func, + const char *msg) { - printf(" *** at %s:%d in '%s'\n", file, line, func); +#if 0 + printf("\n *** %p %s %s:%d in '%s'", + pc, + msg ? "at" : "by", + file ? file : "?", + line, + func ? func : "?"); + return 1; // want more backtrace levels +#else + //printf(" [%d]", *(int*)ud); + printf("!"); + return 0; // cancel backtrace +#endif } TCCState *new_state(int w) @@ -132,9 +152,8 @@ TCCState *new_state(int w) if (w & 2) { tcc_set_options(s, "-bt"); tcc_define_symbol(s, "N_CRASH", str(M/2)); - tcc_set_backtrace_func(s, bt_func); } else - tcc_define_symbol(s, "N_CRASH", "99"); + tcc_define_symbol(s, "N_CRASH", "-1000"); tcc_set_output_type(s, TCC_OUTPUT_MEMORY); return s; } @@ -171,8 +190,7 @@ int state_test(int w) if (c < M) funcs[c] = reloc_state(s[c], "foo"); if (d < M && funcs[d]) { - if ((w & 2) && d == 8) - printf("\n"); + tcc_set_backtrace_func(s[d], &d, backtrace_func); if (0 == tcc_setjmp(s[d], jb, funcs[d])) funcs[d](F(d)); } @@ -189,15 +207,19 @@ TF_TYPE(thread_test_simple, vn) int (*func)(int); int ret; int n = (size_t)vn; + jmp_buf jb; - s = new_state(0); + s = new_state(0); /* '2' for exceptions */ sleep_ms(1); ret = tcc_compile_string(s, my_program); sleep_ms(1); if (ret >= 0) { func = reloc_state(s, "foo"); - if (func) - func(F(n)); + tcc_set_backtrace_func(s, &n, backtrace_func); + if (func) { + if (0 == tcc_setjmp(s, jb, func)) + func(F(n)); + } } tcc_delete(s); return 0; @@ -281,18 +303,20 @@ int main(int argc, char **argv) printf("\n (%u ms)\n", getclock_ms() - t); #endif #if 1 - printf("producing some exceptions\n "), fflush(stdout); + printf("producing some exceptions (!)\n "), fflush(stdout); t = getclock_ms(); state_test(2); printf("\n (%u ms)\n", getclock_ms() - t); #endif #if 1 + //{ int i; for (i = 0; i < 100; ++i) { printf("(%d) ", i); printf("running fib in threads\n "), fflush(stdout); t = getclock_ms(); for (n = 0; n < M; ++n) create_thread(thread_test_simple, n); wait_threads(n); printf("\n (%u ms)\n", getclock_ms() - t); + //}} #endif #if 1 printf("running tcc.c in threads to run fib\n "), fflush(stdout); diff --git a/tests/tcctest.c b/tests/tcctest.c index c48f7778..b49cd450 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3889,7 +3889,7 @@ static void builtin_test_bits(unsigned long long x, int cnt[]) if ((unsigned long) x) cnt[7] += __builtin_ctzl(x); if ((unsigned long long) x) cnt[8] += __builtin_ctzll(x); -#if CC_NAME != CC_clang || GCC_MAJOR >= 11 +#if GCC_MAJOR >= 6 && (CC_NAME != CC_clang || GCC_MAJOR >= 11) /* Apple clang 10 does not have __builtin_clrsb[l[l]] */ cnt[9] += __builtin_clrsb(x); cnt[10] += __builtin_clrsbl(x); diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 6b49aed8..d215e3a8 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -202,4 +202,5 @@ exit /B %ERRORLEVEL% .\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o .\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o .\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o +.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o exit /B %ERRORLEVEL% diff --git a/win32/include/malloc.h b/win32/include/malloc.h index fc783a8e..c2f7f76f 100644 --- a/win32/include/malloc.h +++ b/win32/include/malloc.h @@ -62,8 +62,8 @@ extern "C" { void *__cdecl malloc(size_t _Size); void *__cdecl realloc(void *_Memory,size_t _NewSize); _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - /* _CRTIMP void __cdecl _aligned_free(void *_Memory); - _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ + _CRTIMP void __cdecl _aligned_free(void *_Memory); + _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); diff --git a/win32/include/stdlib.h b/win32/include/stdlib.h index a0ca376f..3a656e70 100644 --- a/win32/include/stdlib.h +++ b/win32/include/stdlib.h @@ -403,8 +403,8 @@ extern "C" { void *__cdecl malloc(size_t _Size); void *__cdecl realloc(void *_Memory,size_t _NewSize); _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - //_CRTIMP void __cdecl _aligned_free(void *_Memory); - //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); + _CRTIMP void __cdecl _aligned_free(void *_Memory); + _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c index 6406ed36..e1910813 100644 --- a/win32/lib/crt1.c +++ b/win32/lib/crt1.c @@ -70,7 +70,6 @@ void _tstart(void) // ============================================= // for 'tcc -run ,,,' -__attribute__((weak)) extern int __rt_nr_exit; __attribute__((weak)) extern int __run_on_exit(); int _runtmain(int argc, /* as tcc passed in */ char **argv) @@ -92,7 +91,6 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) #if defined __i386__ || defined __x86_64__ _controlfp(_PC_53, _MCW_PC); #endif - __rt_nr_exit = 0; run_ctors(__argc, __targv, _tenviron); ret = _tmain(__argc, __targv, _tenviron); run_dtors();