From ef42295fe802c881a42c8983f1638ff302e63a6c Mon Sep 17 00:00:00 2001 From: gr Date: Fri, 17 Jan 2020 22:58:39 +0100 Subject: [PATCH] tccrun.c: standalone backtraces with -bt[N] or -b This makes it possible to get backtraces with executables (including DLLs/SOs) like we had it already with -g -run. Option -b includes -bt, and -bt includes -g. - new file lib/bt-exe.c: used to link rt_printline and the exception handler from tccrun.c into executables/DLLs. - new file lib/bt-log.c: provides a function that may be called from user code to print out a backtrace with a message (currently for i386/x86_64 only): int (*tcc_backtrace)(const char *fmt, ...); As an extra hack, if 'fmt' is prefixed like "^file.c^..." then the backtrace will skip calls from within 'file.c'. - new file lib/bt-dll.c: used on win32 to link the backtrace and bcheck functions with the main module at runtime - bcheck.c: now uses the tcc_backtrace function from above - tccgen.c: minor cleanups - tccelf.c: stab sections get SHF_ALLOC for easy access. Also in relocate_section(): 64bit relocations for stabs in DLLs cannot work. To find DLL addresses, the DLL base is added manually in tccrun.c via rc.prog_base instead. - tccpe.c: there are some changes to allow merging sections, used to merge .finit_array into .data in the first place. - tccpp.c: tcc -run now #defines __TCC_RUN__ also: refactor a line in tal_realloc that was incompatible with bcheck - tcctest.c: fixed a problem with r12 which tcc cannot preserve as well as gcc does. - tests2/112_backtrace.c: test the feature and the bcheck test18 that previously was in boundtest.c --- Makefile | 5 +- arm-gen.c | 2 +- lib/Makefile | 22 +- lib/bcheck.c | 161 +++++----- lib/bt-dll.c | 67 ++++ lib/bt-exe.c | 43 +++ lib/bt-log.c | 36 +++ libtcc.c | 8 +- tcc-doc.texi | 9 +- tcc.c | 2 +- tcc.h | 26 +- tccelf.c | 261 +++++++++------- tccgen.c | 86 ++---- tccpe.c | 324 +++++++++++--------- tccpp.c | 17 +- tccrun.c | 341 ++++++++++++--------- tests/Makefile | 46 +-- tests/boundtest.c | 217 +------------ tests/libtcc_test_mt.c | 21 +- tests/tcctest.c | 24 +- tests/tests2/112_backtrace.c | 165 ++++++++++ tests/tests2/112_backtrace.expect | 164 ++++++++++ tests/tests2/60_errors_and_warnings.expect | 1 + tests/tests2/Makefile | 10 +- win32/build-tcc.bat | 10 +- win32/lib/crt1.c | 2 +- x86_64-link.c | 1 + 27 files changed, 1216 insertions(+), 855 deletions(-) create mode 100644 lib/bt-dll.c create mode 100644 lib/bt-exe.c create mode 100644 lib/bt-log.c create mode 100644 tests/tests2/112_backtrace.c create mode 100644 tests/tests2/112_backtrace.expect diff --git a/Makefile b/Makefile index 7679b688..2c048d01 100644 --- a/Makefile +++ b/Makefile @@ -281,11 +281,12 @@ IBw = $(call IB,$(wildcard $1),$2) IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2) IFw = $(call IF,$(wildcard $1),$2) IR = mkdir -p $2 && cp -r $1/. $2 +B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o # install progs & libs install-unx: $(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)") - $(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)") + $(call IFw,$(LIBTCC1) $(B_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)") @@ -310,7 +311,7 @@ uninstall-unx: install-win: $(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)") $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib") - $(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib") + $(call IFw,libtcc1.a $(B_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/arm-gen.c b/arm-gen.c index a34d3cdb..a4912b34 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -171,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s) float_abi = s->float_abi; #ifndef TCC_ARM_HARDFLOAT - tcc_warning("soft float ABI currently not supported: default to softfp"); +# warning "soft float ABI currently not supported: default to softfp" #endif } #else diff --git a/lib/Makefile b/lib/Makefile index b8c878bb..9d74dc35 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -13,7 +13,7 @@ XCC = $(XTCC) XAR = $(XTCC) -ar XFLAGS-unx = -B$(TOPSRC) XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -XFLAGS = $(XFLAGS$(XCFG)) +XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP) XCFG = $(or $(findstring -win,$T),-unx) # in order to use gcc, tyoe: make -libtcc1-usegcc=yes @@ -27,6 +27,8 @@ endif # only for native compiler $(X)BCHECK_O = bcheck.o +$(X)BT_O = bt-exe.o bt-log.o +$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes) BCHECK_O = @@ -38,18 +40,18 @@ ifdef CONFIG_OSX XFLAGS += -D_ANSI_SOURCE endif -I386_O = libtcc1.o alloca86.o alloca86-bt.o -X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o -ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o -ARM64_O = lib-arm64.o -RISCV64_O = lib-arm64.o +I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O) +X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O) +ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O) +ARM64_O = lib-arm64.o $(BT_O) +RISCV64_O = lib-arm64.o $(BT_O) WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O) OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O) OBJ-x86_64-osx = $(X86_64_O) va_list.o -OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O) -OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O) +OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O) +OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O) OBJ-arm64 = $(ARM64_O) $(DSO_O) OBJ-arm = $(ARM_O) $(DSO_O) OBJ-arm-fpa = $(ARM_O) $(DSO_O) @@ -60,7 +62,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) OBJ-arm-wince = $(ARM_O) $(WIN_O) OBJ-riscv64 = $(RISCV64_O) $(DSO_O) -OBJ-extra = $(filter bcheck.o,$(OBJ-$T)) +OBJ-extra = $(filter $(B_O),$(OBJ-$T)) OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) @@ -80,8 +82,10 @@ $(TOP)/%.o : %.c $(XCC) -c $< -o $@ $(XFLAGS) $(TOP)/bcheck.o : XFLAGS += -g +$(TOP)/bt-exe.o : $(TOP)/tccrun.c $(X)crt1w.o : crt1.c $(X)wincrt1w.o : wincrt1.c + clean : rm -f *.a *.o $(ALL) diff --git a/lib/bcheck.c b/lib/bcheck.c index 29c20285..1e90aa9a 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -49,6 +49,12 @@ #endif #define FASTCALL __attribute__((regparm(3))) +#ifdef _WIN32 +# define DLL_EXPORT __declspec(dllexport) +#else +# define DLL_EXPORT +#endif + #if defined(__FreeBSD__) \ || defined(__FreeBSD_kernel__) \ || defined(__DragonFly__) \ @@ -162,16 +168,16 @@ void splay_printtree(Tree * t, int d); /* external interface */ void __bound_checking (int no_check); void __bound_never_fatal (int no_check); -void * __bound_ptr_add(void *p, size_t offset); -void * __bound_ptr_indir1(void *p, size_t offset); -void * __bound_ptr_indir2(void *p, size_t offset); -void * __bound_ptr_indir4(void *p, size_t offset); -void * __bound_ptr_indir8(void *p, size_t offset); -void * __bound_ptr_indir12(void *p, size_t offset); -void * __bound_ptr_indir16(void *p, size_t offset); -void FASTCALL __bound_local_new(void *p1); -void FASTCALL __bound_local_delete(void *p1); -void __bound_init(void); +DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset); +DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset); +DLL_EXPORT void FASTCALL __bound_local_new(void *p1); +DLL_EXPORT void FASTCALL __bound_local_delete(void *p1); +void __bound_init(size_t *); void __bound_main_arg(char **p); void __bound_exit(void); #if !defined(_WIN32) @@ -179,35 +185,32 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd, off_t offset); int __bound_munmap (void *start, size_t size); #endif -void __bound_new_region(void *p, size_t size); -void *__bound_memcpy(void *dst, const void *src, size_t size); -int __bound_memcmp(const void *s1, const void *s2, size_t size); -void *__bound_memmove(void *dst, const void *src, size_t size); -void *__bound_memset(void *dst, int c, size_t size); -int __bound_strlen(const char *s); -char *__bound_strcpy(char *dst, const char *src); -char *__bound_strncpy(char *dst, const char *src, size_t n); -int __bound_strcmp(const char *s1, const char *s2); -int __bound_strncmp(const char *s1, const char *s2, size_t n); -char *__bound_strcat(char *dest, const char *src); -char *__bound_strchr(const char *string, int ch); -char *__bound_strdup(const char *s); +DLL_EXPORT void __bound_new_region(void *p, size_t size); +DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size); +DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size); +DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size); +DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size); +DLL_EXPORT int __bound_strlen(const char *s); +DLL_EXPORT char *__bound_strcpy(char *dst, const char *src); +DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n); +DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2); +DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n); +DLL_EXPORT char *__bound_strcat(char *dest, const char *src); +DLL_EXPORT char *__bound_strchr(const char *string, int ch); +DLL_EXPORT char *__bound_strdup(const char *s); #if !MALLOC_REDIR -void *__bound_malloc(size_t size, const void *caller); -void *__bound_memalign(size_t size, size_t align, const void *caller); -void __bound_free(void *ptr, const void *caller); -void *__bound_realloc(void *ptr, size_t size, const void *caller); -void *__bound_calloc(size_t nmemb, size_t size); +DLL_EXPORT void *__bound_malloc(size_t size, const void *caller); +DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller); +DLL_EXPORT void __bound_free(void *ptr, const void *caller); +DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller); +DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size); #endif #define FREE_REUSE_SIZE (100) static unsigned int free_reuse_index; static void *free_reuse_list[FREE_REUSE_SIZE]; -/* error message, just for TCC */ -const char *__bound_error_msg; - static Tree *tree = NULL; #define TREE_REUSE (1) #if TREE_REUSE @@ -296,14 +299,18 @@ void __bound_never_fatal (int neverfatal) fetch_and_add (&never_fatal, neverfatal); } +int tcc_backtrace(const char *fmt, ...); + /* print a bound error message */ -static void bound_error(const char *error) -{ - __bound_error_msg = error; - fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error); - if (never_fatal == 0) - *(void **)0 = 0; /* force a runtime error */ -} +#define bound_warning(...) \ + tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__) + +#define bound_error(...) \ + do { \ + bound_warning(__VA_ARGS__); \ + if (never_fatal == 0) \ + exit(255); \ + } while (0) static void bound_alloc_error(const char *s) { @@ -317,20 +324,6 @@ static void bound_not_found_warning(const char *file, const char *function, dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr); } -static void bound_ptr_add_warning(const char *file, const char *function, - void *ptr) -{ - fprintf(stderr,"%s%s %s(): %p is outside of the region\n", - exec, file, function, ptr); -} - -static void bound_ptr_indir_error(const char *file, const char *function, - void *ptr) -{ - fprintf(stderr,"%s%s %s(): %p is outside of the region\n", - exec, file, function, ptr); -} - /* return '(p + offset)' for pointer arithmetic (a pointer can reach the end of a region in this case */ void * __bound_ptr_add(void *p, size_t offset) @@ -360,8 +353,7 @@ void * __bound_ptr_add(void *p, size_t offset) if (addr <= tree->size) { if (tree->is_invalid || addr + offset > tree->size) { POST_SEM (); - if (print_warn_ptr_add) - bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset); + bound_warning("%p is outside of the region", p + offset); if (never_fatal <= 0) return INVALID_POINTER; /* return an invalid pointer */ return p + offset; @@ -407,8 +399,7 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \ if (addr <= tree->size) { \ if (tree->is_invalid || addr + offset + dsize > tree->size) { \ POST_SEM (); \ - bound_ptr_indir_error (__FILE__, __FUNCTION__, \ - p + offset); \ + bound_warning("%p is outside of the region", p + offset); \ if (never_fatal <= 0) \ return INVALID_POINTER; /* return an invalid pointer */ \ return p + offset; \ @@ -460,8 +451,7 @@ void FASTCALL __bound_local_new(void *p1) WAIT_SEM (); while ((addr = p[0])) { INCR_COUNT(bound_local_new_count); - if (addr != 1) - tree = splay_insert(addr + fp, p[1], tree); + tree = splay_insert(addr + fp, p[1], tree); p += 2; } POST_SEM (); @@ -498,7 +488,10 @@ void FASTCALL __bound_local_delete(void *p1) WAIT_SEM (); while ((addr = p[0])) { INCR_COUNT(bound_local_delete_count); - if (addr == 1) { + tree = splay_delete(addr + fp, tree); + p += 2; + } + { alloca_list_type *last = NULL; alloca_list_type *cur = alloca_list; @@ -518,11 +511,8 @@ void FASTCALL __bound_local_delete(void *p1) cur = cur->next; } } - } - else - tree = splay_delete(addr + fp, tree); - p += 2; } + POST_SEM (); while (free_list) { alloca_list_type *next = free_list->next; @@ -607,14 +597,14 @@ void __bound_new_region(void *p, size_t size) #pragma GCC diagnostic pop #endif -void __attribute__((constructor)) __bound_init(void) +void __bound_init(size_t *p) { - extern size_t __bounds_start[]; - size_t *p; - - if (inited) - return; + dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__); + if (inited) { + WAIT_SEM(); + goto add_bounds; + } inited = 1; print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL; @@ -623,8 +613,6 @@ void __attribute__((constructor)) __bound_init(void) print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL; never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL; - dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__); - INIT_SEM (); #if MALLOC_REDIR @@ -724,27 +712,26 @@ void __attribute__((constructor)) __bound_init(void) tree = splay_insert((size_t) (&errno), sizeof (int), tree); #endif +add_bounds: + if (!p) + goto no_bounds; + /* add all static bound check values */ - p = __bounds_start; while (p[0] != 0) { tree = splay_insert(p[0], p[1], tree); - p += 2; - } - POST_SEM (); #if BOUND_DEBUG - if (print_calls) { - p = __bounds_start; - while (p[0] != 0) { + if (print_calls) { dprintf(stderr, "%s, %s(): static var %p 0x%lx\n", __FILE__, __FUNCTION__, (void *) p[0], (unsigned long) p[1]); - p += 2; } - } #endif + p += 2; + } +no_bounds: + POST_SEM (); no_checking = 0; - dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__); } @@ -931,7 +918,7 @@ void *__bound_malloc(size_t size, const void *caller) #if MALLOC_REDIR /* This will catch the first dlsym call from __bound_init */ if (malloc_redir == NULL) { - __bound_init (); + __bound_init (0); if (malloc_redir == NULL) { ptr = &initial_pool[pool_index]; pool_index = (pool_index + size + 15) & ~15; @@ -1113,7 +1100,7 @@ void *__bound_calloc(size_t nmemb, size_t size) #if MALLOC_REDIR /* This will catch the first dlsym call from __bound_init */ if (malloc_redir == NULL) { - __bound_init (); + __bound_init (0); if (malloc_redir == NULL) { ptr = &initial_pool[pool_index]; pool_index = (pool_index + size + 15) & ~15; @@ -1190,10 +1177,8 @@ static void __bound_check(const void *p, size_t size, const char *function) { if (no_checking == 0 && size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) { - static char line[100]; - sprintf(line, "invalid pointer %p, size 0x%lx in %s", + bound_error("invalid pointer %p, size 0x%lx in %s", p, (unsigned long)size, function); - bound_error(line); } } @@ -1207,10 +1192,8 @@ static int check_overlap (const void *p1, size_t n1, if (no_checking == 0 && n1 != 0 && n2 !=0 && ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */ (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */ - static char line[100]; - sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s", + bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s", p1, (unsigned long)n1, p2, (unsigned long)n2, function); - bound_error(line); return never_fatal < 0; } return 0; diff --git a/lib/bt-dll.c b/lib/bt-dll.c new file mode 100644 index 00000000..fab08e81 --- /dev/null +++ b/lib/bt-dll.c @@ -0,0 +1,67 @@ +/* ------------------------------------------------------------- */ +/* stubs for calling bcheck functions from a dll. */ + +#include +#include + +#define REDIR_ALL \ + REDIR(__bt_init) \ + REDIR(tcc_backtrace) \ + \ + REDIR(__bound_ptr_add) \ + REDIR(__bound_ptr_indir1) \ + REDIR(__bound_ptr_indir2) \ + REDIR(__bound_ptr_indir4) \ + REDIR(__bound_ptr_indir8) \ + REDIR(__bound_ptr_indir12) \ + REDIR(__bound_ptr_indir16) \ + REDIR(__bound_local_new) \ + REDIR(__bound_local_delete) \ + REDIR(__bound_new_region) \ + \ + REDIR(__bound_free) \ + REDIR(__bound_malloc) \ + REDIR(__bound_realloc) \ + REDIR(__bound_memcpy) \ + REDIR(__bound_memcmp) \ + REDIR(__bound_memmove) \ + REDIR(__bound_memset) \ + REDIR(__bound_strlen) \ + REDIR(__bound_strcpy) \ + REDIR(__bound_strncpy) \ + REDIR(__bound_strcmp) \ + REDIR(__bound_strncmp) \ + REDIR(__bound_strcat) \ + REDIR(__bound_strchr) \ + REDIR(__bound_strdup) + +#define REDIR(s) void *s; +static struct { REDIR_ALL } all_ptrs; +#undef REDIR +#define REDIR(s) #s"\0" +static const char all_names[] = REDIR_ALL; +#undef REDIR +#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) ); +static void all_jmps() { REDIR_ALL } +#undef REDIR + +void __bt_init_dll(int bcheck) +{ + const char *s = all_names; + void **p = (void**)&all_ptrs; + do { + *p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s); + if (NULL == *p) { + char buf[100]; + sprintf(buf, + "Error: function '%s()' not found in executable. " + "(Need -bt or -b for linking the exe.)", s); + if (GetStdHandle(STD_ERROR_HANDLE)) + fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr); + else + MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR); + ExitProcess(1); + } + s = strchr(s,'\0') + 1, ++p; + } while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add)); +} diff --git a/lib/bt-exe.c b/lib/bt-exe.c new file mode 100644 index 00000000..350261a8 --- /dev/null +++ b/lib/bt-exe.c @@ -0,0 +1,43 @@ +/* ------------------------------------------------------------- */ +/* for linking rt_printline and the signal/exception handler + from tccrun.c into executables. */ + +#define CONFIG_TCC_BACKTRACE_ONLY +#include "../tccrun.c" + +int (*__rt_error)(void*, void*, const char *, va_list); + +#ifndef _WIN32 +# define __declspec(n) +#endif + +__declspec(dllexport) +void __bt_init(rt_context *p, int num_callers) +{ + __attribute__((weak)) int main(); + __attribute__((weak)) void __bound_init(void*); + struct rt_context *rc = &g_rtctxt; + //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr); + if (num_callers) { + memcpy(rc, p, offsetof(rt_context, next)); + rc->num_callers = num_callers - 1; + rc->top_func = main; + __rt_error = _rt_error; + set_exception_handler(); + } else { + p->next = rc->next, rc->next = p; + } + if (__bound_init && p->bounds_start) + __bound_init(p->bounds_start); +} + +/* copy a string and truncate it. */ +static char *pstrcpy(char *buf, size_t buf_size, const char *s) +{ + int l = strlen(s); + if (l >= buf_size) + l = buf_size - 1; + memcpy(buf, s, l); + buf[l] = 0; + return buf; +} diff --git a/lib/bt-log.c b/lib/bt-log.c new file mode 100644 index 00000000..73e0067f --- /dev/null +++ b/lib/bt-log.c @@ -0,0 +1,36 @@ +/* ------------------------------------------------------------- */ +/* function to get a stack backtrace on demand with a message */ + +#include +#include + +int (*__rt_error)(void*, void*, const char *, va_list); + +#ifdef _WIN32 +# define DLL_EXPORT __declspec(dllexport) +#else +# define DLL_EXPORT +#endif + +DLL_EXPORT int tcc_backtrace(const char *fmt, ...) +{ + va_list ap; + int ret; + + if (__rt_error) { + void *fp = __builtin_frame_address(1); + void *ip = __builtin_return_address(0); + va_start(ap, fmt); + ret = __rt_error(fp, ip, fmt, ap); + va_end(ap); + } else { + const char *p; + if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0]))) + fmt = p + 1; + va_start(ap, fmt); + ret = vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"), fflush(stderr); + } + return ret; +} diff --git a/libtcc.c b/libtcc.c index 13be5133..a7882196 100644 --- a/libtcc.c +++ b/libtcc.c @@ -776,9 +776,6 @@ LIBTCCAPI TCCState *tcc_new(void) /* enable this if you want symbols with leading underscore on windows: */ #if 0 /* def TCC_TARGET_PE */ s->leading_underscore = 1; -#endif -#ifdef CONFIG_TCC_BACKTRACE - s->rt_num_callers = 6; #endif s->ppfp = stdout; /* might be used in error() before preprocess_start() */ @@ -1556,7 +1553,7 @@ static const TCCOption tcc_options[] = { { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG }, { "bench", TCC_OPTION_bench, 0 }, #ifdef CONFIG_TCC_BACKTRACE - { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, + { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, #endif #ifdef CONFIG_TCC_BCHECK { "b", TCC_OPTION_b, 0 }, @@ -1809,11 +1806,14 @@ reparse: #ifdef CONFIG_TCC_BACKTRACE case TCC_OPTION_bt: s->rt_num_callers = atoi(optarg); + s->do_backtrace = 1; + s->do_debug = 1; break; #endif #ifdef CONFIG_TCC_BCHECK case TCC_OPTION_b: s->do_bounds_check = 1; + s->do_backtrace = 1; s->do_debug = 1; break; #endif diff --git a/tcc-doc.texi b/tcc-doc.texi index 0717bc3d..976c5757 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -372,9 +372,12 @@ Try to continue in case of a bound checking error. Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment. -@item -bt N -Display N callers in stack traces. This is useful with @option{-g} or -@option{-b}. +@item -bt[N] +Display N callers in stack traces. This is useful with @option{-g} or @option{-b}. +With executables, additional support for stack traces is included. + +A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided +to trigger a stack trace with a message on demand. @end table diff --git a/tcc.c b/tcc.c index cbb3581b..34bfa004 100644 --- a/tcc.c +++ b/tcc.c @@ -61,7 +61,7 @@ static const char help[] = " -b compile with built-in memory and bounds checker (implies -g)\n" #endif #ifdef CONFIG_TCC_BACKTRACE - " -bt N show N callers in stack traces\n" + " -bt[N] link with backtrace (stack dump) support [show max N callers]\n" #endif "Misc. options:\n" " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n" diff --git a/tcc.h b/tcc.h index 9013e87d..adb5a248 100644 --- a/tcc.h +++ b/tcc.h @@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr); #ifndef TCC_LIBTCC1 # define TCC_LIBTCC1 "libtcc1.a" #endif -#ifndef TCC_LIBBCHECK -# define TCC_LIBBCHECK "bcheck.o" -#endif /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ #if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC @@ -475,7 +472,7 @@ struct SymAttr { nodecorate : 1, dllimport : 1, addrtaken : 1, - unused : 3; + xxxx : 3; /* not used */ }; /* function attributes or temporary attributes for parsing */ @@ -484,7 +481,8 @@ struct FuncAttr { func_call : 3, /* calling convention (0..5), see below */ func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */ func_noreturn : 1, /* attribute((noreturn)) */ - xxxx : 2, + func_ctor : 1, /* attribute((constructor)) */ + func_dtor : 1, /* attribute((destructor)) */ func_args : 8; /* PE __stdcall args */ }; @@ -619,8 +617,6 @@ typedef struct TokenString { typedef struct AttributeDef { struct SymAttr a; struct FuncAttr f; - unsigned short constructor:1; - unsigned short destructor:1; struct Section *section; Sym *cleanup_func; int alias_target; /* token */ @@ -718,6 +714,7 @@ struct TCCState { /* compile with debug symbol (and use them if error during execution) */ unsigned char do_debug; + unsigned char do_backtrace; #ifdef CONFIG_TCC_BCHECK /* compile with built-in memory and bounds checker */ unsigned char do_bounds_check; @@ -884,11 +881,7 @@ struct TCCState { const char *runtime_main; void **runtime_mem; int nb_runtime_mem; -#ifdef CONFIG_TCC_BACKTRACE int rt_num_callers; - const char **rt_bound_error_msg; - void *rt_prog_main; -#endif #endif int fd, cc; /* used by tcc_load_ldscript */ @@ -1259,6 +1252,9 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); #ifdef CONFIG_TCC_BCHECK ST_FUNC void tcc_add_bcheck(TCCState *s1); #endif +#ifdef CONFIG_TCC_BACKTRACE +ST_FUNC void tcc_add_btstub(TCCState *s1); +#endif ST_FUNC void tcc_add_pragma_libs(TCCState *s1); PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); @@ -1485,9 +1481,6 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type); #endif ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); -ST_FUNC void add_init_array (TCCState *s1, Sym *sym); -ST_FUNC void add_fini_array (TCCState *s1, Sym *sym); - ST_FUNC int put_elf_str(Section *s, const char *sym); ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); @@ -1506,7 +1499,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s); ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h); ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte); -ST_FUNC void tcc_add_runtime(TCCState *s1); +ST_FUNC void add_array(TCCState *s1, const char *sec, int c); #ifndef ELF_OBJ_ONLY ST_FUNC void build_got_entries(TCCState *s1); @@ -1521,9 +1514,12 @@ ST_FUNC void list_elf_symbols(TCCState *s, void *ctx, ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name); #endif +ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs); + #ifndef TCC_TARGET_PE ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd); +ST_FUNC void tcc_add_runtime(TCCState *s1); #endif /* ------------ xxx-link.c ------------ */ diff --git a/tccelf.c b/tccelf.c index 2577ac5b..1e2751c4 100644 --- a/tccelf.c +++ b/tccelf.c @@ -85,33 +85,21 @@ ST_FUNC void tccelf_bounds_new(TCCState *s) lbounds_section = new_section(s, ".lbounds", SHT_PROGBITS, SHF_ALLOC); } - -ST_FUNC void tcc_add_bcheck(TCCState *s1) -{ - addr_t *ptr; - - if (0 == s1->do_bounds_check) - return; - ptr = section_ptr_add(bounds_section, sizeof(*ptr)); - *ptr = 0; - set_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - bounds_section->sh_num, "__bounds_start"); - /* pull bcheck.o from libtcc1.a */ - set_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, "__bound_init"); -} #endif ST_FUNC void tccelf_stab_new(TCCState *s) { TCCState *s1 = s; - stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); + int shf = 0; +#ifdef CONFIG_TCC_BACKTRACE + /* include stab info with standalone backtrace support */ + if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY) + shf = SHF_ALLOC; +#endif + stab_section = new_section(s, ".stab", SHT_PROGBITS, shf); stab_section->sh_entsize = sizeof(Stab_Sym); - stab_section->sh_addralign = 4; - stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0); - put_elf_str(stab_section->link, ""); + stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value; + stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf); /* put first entry */ put_stabs(s, "", 0, 0, 0, 0); } @@ -803,6 +791,17 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d { Stab_Sym *sym; + unsigned offset; + if (type == N_SLINE + && (offset = stab_section->data_offset) + && (sym = (Stab_Sym*)(stab_section->data + offset) - 1) + && sym->n_type == type + && sym->n_value == value) { + /* just update line_number in previous entry */ + sym->n_desc = desc; + return; + } + sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); if (str) { sym->n_strx = put_elf_str(stab_section->link, str); @@ -818,10 +817,11 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index) { - put_stabs(s1, str, type, other, desc, value); put_elf_reloc(symtab_section, stab_section, - stab_section->data_offset - sizeof(unsigned int), - R_DATA_32, sym_index); + stab_section->data_offset + 8, + sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32, + sym_index); + put_stabs(s1, str, type, other, desc, value); } ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value) @@ -990,8 +990,16 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) relocate(s1, rel, type, ptr, addr, tgt); } /* if the relocation is allocated, we change its symbol table */ - if (sr->sh_flags & SHF_ALLOC) + if (sr->sh_flags & SHF_ALLOC) { sr->link = s1->dynsym; + if (s1->output_type == TCC_OUTPUT_DLL) { + size_t r = (uint8_t*)qrel - sr->data; + if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE + && 0 == strcmp(s->name, ".stab")) + r = 0; /* cannot apply 64bit relocation to 32bit value */ + sr->data_offset = sr->sh_size = r; + } + } } #ifndef ELF_OBJ_ONLY @@ -1268,16 +1276,20 @@ static void put_dt(Section *dynamic, int dt, addr_t val) } #endif +ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs) +{ + int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF; + if (sec && offs == -1) + offs = sec->data_offset; + return set_elf_sym(symtab_section, offs, 0, + ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); +} + static void add_init_array_defines(TCCState *s1, const char *section_name) { Section *s; long end_offset; - char sym_start[1024]; - char sym_end[1024]; - - snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1); - snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1); - + char buf[1024]; s = find_section(s1, section_name); if (!s) { end_offset = 0; @@ -1285,15 +1297,10 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) } else { end_offset = s->data_offset; } - - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, sym_start); - set_elf_sym(symtab_section, - end_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, sym_end); + snprintf(buf, sizeof(buf), "__%s_start", section_name + 1); + set_global_sym(s1, buf, s, 0); + snprintf(buf, sizeof(buf), "__%s_end", section_name + 1); + set_global_sym(s1, buf, s, end_offset); } #ifndef TCC_TARGET_PE @@ -1305,33 +1312,92 @@ static int tcc_add_support(TCCState *s1, const char *filename) } #endif -static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type) +ST_FUNC void add_array (TCCState *s1, const char *sec, int c) { Section *s; - unsigned char *ptr; - - s = find_section(s1, section); - if (s) { - s->sh_flags |= SHF_WRITE; + s = find_section(s1, sec); + s->sh_flags |= SHF_WRITE; #ifndef TCC_TARGET_PE - s->sh_type = sh_type; + s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; #endif - ptr = section_ptr_add(s, PTR_SIZE); - memset (ptr, 0, PTR_SIZE); - put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c); + put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); + section_ptr_add(s, PTR_SIZE); +} + +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void tcc_add_bcheck(TCCState *s1) +{ + if (0 == s1->do_bounds_check) + return; + section_ptr_add(bounds_section, sizeof(addr_t)); +} +#endif + +#ifdef CONFIG_TCC_BACKTRACE +static void put_ptr(TCCState *s1, Section *s, int offs) +{ + int c; + c = set_global_sym(s1, NULL, s, offs); + s = data_section; + put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); + section_ptr_add(s, PTR_SIZE); +} + +/* set symbol to STB_LOCAL and resolve. The point is to not export it as + a dynamic symbol to allow so's to have one each with a different value. */ +static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset) +{ + int c = find_elf_sym(s1->symtab, name); + if (c) { + ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c; + esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE); + esym->st_value = offset; + esym->st_shndx = s->sh_num; } } -ST_FUNC void add_init_array (TCCState *s1, Sym *sym) +ST_FUNC void tcc_add_btstub(TCCState *s1) { - add_array (".init_array", s1, sym, SHT_INIT_ARRAY); -} + Section *s; + int n, o, b; + CString cstr; -ST_FUNC void add_fini_array (TCCState *s1, Sym *sym) -{ - add_array (".fini_array", s1, sym, SHT_FINI_ARRAY); -} + s = data_section; + o = s->data_offset; + /* create (part of) a struct rt_context (see tccrun.c) */ + put_ptr(s1, stab_section, 0); + put_ptr(s1, stab_section, -1); + put_ptr(s1, stab_section->link, 0); + section_ptr_add(s, 3 * PTR_SIZE); + /* prog_base */ + put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0); + section_ptr_add(s, PTR_SIZE); + n = 2 * PTR_SIZE, b = 0; +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) { + put_ptr(s1, bounds_section, 0); + n -= PTR_SIZE, b = 1; + } +#endif + section_ptr_add(s, n); + cstr_new(&cstr); + cstr_printf(&cstr, + " extern void __bt_init(),*__rt_info[],__bt_init_dll();" + "__attribute__((constructor)) static void __bt_init_rt(){"); +#ifdef TCC_TARGET_PE + if (s1->output_type == TCC_OUTPUT_DLL) + cstr_printf(&cstr, "__bt_init_dll(%d);", b); +#endif + cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", + s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); + tcc_compile_string(s1, cstr.data); + cstr_free(&cstr); + set_local_sym(s1, "__rt_info", s, o); +} +#endif + +#ifndef TCC_TARGET_PE /* add tcc runtime libraries */ ST_FUNC void tcc_add_runtime(TCCState *s1) { @@ -1340,7 +1406,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) tcc_add_bcheck(s1); #endif tcc_add_pragma_libs(s1); -#ifndef TCC_TARGET_PE /* add libc */ if (!s1->nostdlib) { tcc_add_library_err(s1, "c"); @@ -1356,7 +1421,17 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) { tcc_add_library_err(s1, "pthread"); tcc_add_library_err(s1, "dl"); - tcc_add_support(s1, TCC_LIBBCHECK); + tcc_add_support(s1, "bcheck.o"); + } +#endif +#ifdef CONFIG_TCC_BACKTRACE + 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"); + if (s1->output_type != TCC_OUTPUT_MEMORY) + tcc_add_btstub(s1); } #endif tcc_add_support(s1, TCC_LIBTCC1); @@ -1364,8 +1439,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) if (s1->output_type != TCC_OUTPUT_MEMORY) tcc_add_crt(s1, "crtn.o"); } -#endif } +#endif /* add various standard linker symbols (must be done after the sections are filled (for example after allocating common @@ -1376,59 +1451,39 @@ static void tcc_add_linker_symbols(TCCState *s1) int i; Section *s; - set_elf_sym(symtab_section, - text_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - text_section->sh_num, "_etext"); - set_elf_sym(symtab_section, - data_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - data_section->sh_num, "_edata"); - set_elf_sym(symtab_section, - bss_section->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - bss_section->sh_num, "_end"); + set_global_sym(s1, "_etext", text_section, -1); + set_global_sym(s1, "_edata", data_section, -1); + set_global_sym(s1, "_end", bss_section, -1); #ifdef TCC_TARGET_RISCV64 /* XXX should be .sdata+0x800, not .data+0x800 */ - set_elf_sym(symtab_section, - 0x800, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - data_section->sh_num, "__global_pointer$"); + set_global_sym(s1, "__global_pointer$", data_section, 0x800); #endif /* horrible new standard ldscript defines */ add_init_array_defines(s1, ".preinit_array"); add_init_array_defines(s1, ".init_array"); add_init_array_defines(s1, ".fini_array"); - /* add start and stop symbols for sections whose name can be expressed in C */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; - if (s->sh_type == SHT_PROGBITS && - (s->sh_flags & SHF_ALLOC)) { + if ((s->sh_flags & SHF_ALLOC) + && (s->sh_type == SHT_PROGBITS + || s->sh_type == SHT_STRTAB)) { const char *p; - int ch; - /* check if section name can be expressed in C */ p = s->name; for(;;) { - ch = *p; - if (!ch) + int c = *p; + if (!c) break; - if (!isid(ch) && !isnum(ch)) + if (!isid(c) && !isnum(c)) goto next_sec; p++; } snprintf(buf, sizeof(buf), "__start_%s", s->name); - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, buf); + set_global_sym(s1, buf, s, 0); snprintf(buf, sizeof(buf), "__stop_%s", s->name); - set_elf_sym(symtab_section, - s->data_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - s->sh_num, buf); + set_global_sym(s1, buf, s, -1); } next_sec: ; } @@ -1699,8 +1754,8 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) !(s->sh_flags & SHF_ALLOC) && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && prepare_dynamic_rel(s1, s)) { - if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR) - textrel = 1; + if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) + textrel = 1; } else #endif if ((s1->do_debug && s->sh_type != SHT_RELX) || @@ -1814,9 +1869,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, if (s == interp) { if (k != 0) continue; - } else if (s->sh_type == SHT_DYNSYM || - s->sh_type == SHT_STRTAB || - s->sh_type == SHT_HASH) { + } else if ((s->sh_type == SHT_DYNSYM || + s->sh_type == SHT_STRTAB || + s->sh_type == SHT_HASH) + && !strstr(s->name, ".stab")) { if (k != 1) continue; } else if (s->sh_type == SHT_RELX) { @@ -2060,7 +2116,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, Section *s; ElfW(Ehdr) ehdr; ElfW(Shdr) shdr, *sh; - ElfW(Sym) *sym; file_type = s1->output_type; shnum = s1->nb_sections; @@ -2131,10 +2186,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); sort_syms(s1, symtab_section); - if (s1->dynsym) - for_each_elem(s1->dynsym, 0, sym, ElfW(Sym)) - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) - s1->dynsym->sh_info++; for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[sec_order[i]]; if (s->sh_type != SHT_NOBITS) { @@ -2842,12 +2893,6 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { Section *s = symtab_section; sym_index = find_elf_sym(s, p); -#ifdef TCC_TARGET_PE /* windows DLL's don't have UNDEF syms */ - if (sym_index == 0) { - s = s1->dynsymtab_section; - sym_index = find_elf_sym(s, p); - } -#endif if (!sym_index) continue; sym = &((ElfW(Sym) *)s->data)[sym_index]; diff --git a/tccgen.c b/tccgen.c index 0c427c8f..71d3d04d 100644 --- a/tccgen.c +++ b/tccgen.c @@ -103,7 +103,7 @@ ST_DATA struct switch_t { struct scope *scope; } *cur_switch; /* current switch */ -#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4 +#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 /*list of temporary local variables on the stack in current function. */ ST_DATA struct temp_local_variable { int location; //offset on stack. Svalue.c.i @@ -375,11 +375,10 @@ static BufferedFile* put_new_file(TCCState *s1) ST_FUNC void tcc_debug_line(TCCState *s1) { BufferedFile *f; - if (!s1->do_debug || !(f = put_new_file(s1))) - return; - if (last_line_num == f->line_num) - return; - if (text_section != cur_text_section) + if (!s1->do_debug + || cur_text_section != text_section + || !(f = put_new_file(s1)) + || last_line_num == f->line_num) return; if (func_ind != -1) { put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind); @@ -409,9 +408,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) { if (!s1->do_debug) return; -#if 0 // this seems to confuse gnu tools put_stabn(s1, N_FUN, 0, 0, size); -#endif } /* put alternative filename */ @@ -2592,7 +2589,6 @@ redo: vswap(); gen_op('-'); } - vtop[-1].r &= ~VT_MUSTBOUND; gen_bounded_ptr_add(); } else #endif @@ -3428,6 +3424,10 @@ ST_FUNC void vstore(void) /* destination */ vswap(); +#ifdef CONFIG_TCC_BCHECK + if (vtop->r & VT_MUSTBOUND) + gbound(); /* check would be wrong after gaddrof() */ +#endif vtop->type.t = VT_PTR; gaddrof(); @@ -3444,8 +3444,11 @@ ST_FUNC void vstore(void) vswap(); /* source */ - vtop->r &= ~VT_MUSTBOUND; vpushv(vtop - 2); +#ifdef CONFIG_TCC_BCHECK + if (vtop->r & VT_MUSTBOUND) + gbound(); +#endif vtop->type.t = VT_PTR; gaddrof(); /* type size */ @@ -3662,11 +3665,11 @@ redo: } case TOK_CONSTRUCTOR1: case TOK_CONSTRUCTOR2: - ad->constructor = 1; + ad->f.func_ctor = 1; break; case TOK_DESTRUCTOR1: case TOK_DESTRUCTOR2: - ad->destructor = 1; + ad->f.func_dtor = 1; break; case TOK_SECTION1: case TOK_SECTION2: @@ -4958,6 +4961,10 @@ ST_FUNC void unary(void) Sym *s; AttributeDef ad; + /* generate line number info */ + if (tcc_state->do_debug) + tcc_debug_line(tcc_state); + sizeof_caller = in_sizeof; in_sizeof = 0; type.ref = NULL; @@ -5522,7 +5529,7 @@ special_math_val: vtop->r |= VT_LVAL; #ifdef CONFIG_TCC_BCHECK /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL) + if (tcc_state->do_bounds_check) vtop->r |= VT_MUSTBOUND; #endif } @@ -5538,15 +5545,6 @@ special_math_val: Sym *sa; int nb_args, ret_nregs, ret_align, regsize, variadic; -#ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check && (vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) { - addr_t *bounds_ptr; - - bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t)); - bounds_ptr[0] = 1; /* marks alloca/vla used */ - bounds_ptr[1] = 0; - } -#endif /* function call */ if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { /* pointer test (no array accepted) */ @@ -6514,10 +6512,10 @@ again: } prev_scope(&o, is_expr); - - if (0 == local_scope && !nocode_wanted) + if (local_scope) + next(); + else if (!nocode_wanted) check_func_return(); - next(); } else if (t == TOK_RETURN) { b = (func_vt.t & VT_BTYPE) != VT_VOID; @@ -7582,16 +7580,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, gen_vla_sp_save(addr); cur_scope->vla.loc = addr; cur_scope->vla.num++; -#ifdef CONFIG_TCC_BCHECK - if (bcheck) { - addr_t *bounds_ptr; - - bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t)); - bounds_ptr[0] = 1; /* marks alloca/vla used */ - bounds_ptr[1] = 0; - } -#endif - } else if (has_init) { size_t oldreloc_offset = 0; if (sec && sec->reloc) @@ -7617,7 +7605,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, /* parse a function defined by symbol 'sym' and generate its code in 'cur_text_section' */ -static void gen_function(Sym *sym, AttributeDef *ad) +static void gen_function(Sym *sym) { /* Initialize VLA state */ struct scope f = { 0 }; @@ -7632,17 +7620,12 @@ static void gen_function(Sym *sym, AttributeDef *ad) } /* NOTE: we patch the symbol size later */ put_extern_sym(sym, cur_text_section, ind, 0); - - if (ad && ad->constructor) { - add_init_array (tcc_state, sym); - } - if (ad && ad->destructor) { - add_fini_array (tcc_state, sym); - } - + if (sym->type.ref->f.func_ctor) + add_array (tcc_state, ".init_array", sym->c); + if (sym->type.ref->f.func_dtor) + add_array (tcc_state, ".fini_array", sym->c); funcname = get_tok_str(sym->v, NULL); func_ind = ind; - /* put debug symbol */ tcc_debug_funcstart(tcc_state, sym); /* push a dummy symbol to enable local sym storage */ @@ -7675,6 +7658,8 @@ static void gen_function(Sym *sym, AttributeDef *ad) ind = 0; /* for safety */ nocode_wanted = 0x80000000; check_vstack(); + /* do this after funcend debug info */ + next(); } static void gen_inline_functions(TCCState *s) @@ -7698,7 +7683,7 @@ static void gen_inline_functions(TCCState *s) begin_macro(fn->func_str, 1); next(); cur_text_section = text_section; - gen_function(sym, NULL); + gen_function(sym); end_macro(); inline_generated = 1; @@ -7866,11 +7851,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) the compilation unit only if they are used */ if (sym->type.t & VT_INLINE) { struct InlineFunc *fn; - const char *filename; - - filename = file ? file->filename : ""; - fn = tcc_malloc(sizeof *fn + strlen(filename)); - strcpy(fn->filename, filename); + fn = tcc_malloc(sizeof *fn + strlen(file->filename)); + strcpy(fn->filename, file->filename); fn->sym = sym; skip_or_save_block(&fn->func_str); dynarray_add(&tcc_state->inline_fns, @@ -7880,7 +7862,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) cur_text_section = ad.section; if (!cur_text_section) cur_text_section = text_section; - gen_function(sym, &ad); + gen_function(sym); } break; } else { diff --git a/tccpe.c b/tccpe.c index dff6169b..a16411c7 100644 --- a/tccpe.c +++ b/tccpe.c @@ -239,8 +239,6 @@ typedef struct _IMAGE_BASE_RELOCATION { #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 -#define IMAGE_SCN_TYPE_NOLOAD 0x00000002 -#define IMAGE_SCN_LNK_REMOVE 0x00000800 #pragma pack(pop) @@ -299,6 +297,7 @@ enum { sec_other , sec_rsrc , sec_stab , + sec_stabstr , sec_reloc , sec_last }; @@ -318,12 +317,12 @@ static const DWORD pe_sec_flags[] = { #endif struct section_info { - int cls, ord; + int cls; char name[32]; DWORD sh_addr; DWORD sh_size; DWORD pe_flags; - unsigned char *data; + Section *sec; DWORD data_size; IMAGE_SECTION_HEADER ish; }; @@ -359,7 +358,7 @@ struct pe_info { int subsystem; DWORD section_align; DWORD file_align; - struct section_info *sec_info; + struct section_info **sec_info; int sec_count; struct pe_import_info **imp_info; int imp_count; @@ -432,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key) return -1; } -#if 0 -ST_FN DWORD umin(DWORD a, DWORD b) +static DWORD umin(DWORD a, DWORD b) { return a < b ? a : b; } -#endif static DWORD umax(DWORD a, DWORD b) { @@ -467,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz hdr->opthdr.DataDirectory[dir].Size = size; } -static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum) +struct pe_file { + FILE *op; + DWORD sum; + unsigned pos; +}; + +static int pe_fwrite(void *data, int len, struct pe_file *pf) { - if (psum) { - DWORD sum = *psum; - WORD *p = data; - int i; - for (i = len; i > 0; i -= 2) { - sum += (i >= 2) ? *p++ : *(BYTE*)p; - sum = (sum + (sum >> 16)) & 0xFFFF; - } - *psum = sum; + WORD *p = data; + DWORD sum; + int ret, i; + pf->pos += (ret = fwrite(data, 1, len, pf->op)); + sum = pf->sum; + for (i = len; i > 0; i -= 2) { + sum += (i >= 2) ? *p++ : *(BYTE*)p; + sum = (sum + (sum >> 16)) & 0xFFFF; } - return len == fwrite(data, 1, len, fp) ? 0 : -1; + pf->sum = sum; + return len == ret ? 0 : -1; } -static void pe_fpad(FILE *fp, DWORD new_pos) +static void pe_fpad(struct pe_file *pf, DWORD new_pos) { - DWORD pos = ftell(fp); - while (++pos <= new_pos) - fputc(0, fp); + char buf[256]; + int n, diff = new_pos - pf->pos; + memset(buf, 0, sizeof buf); + while (diff > 0) { + diff -= n = umin(diff, sizeof buf); + fwrite(buf, n, 1, pf->op); + } + pf->pos = new_pos; } /*----------------------------------------------------------------------------*/ @@ -598,14 +606,14 @@ static int pe_write(struct pe_info *pe) struct pe_header pe_header = pe_template; int i; - FILE *op; - DWORD file_offset, sum; + struct pe_file pf = {0}; + DWORD file_offset; struct section_info *si; IMAGE_SECTION_HEADER *psh; TCCState *s1 = pe->s1; - op = fopen(pe->filename, "wb"); - if (NULL == op) { + pf.op = fopen(pe->filename, "wb"); + if (NULL == pf.op) { tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); return -1; } @@ -624,7 +632,7 @@ static int pe_write(struct pe_info *pe) DWORD addr, size; const char *sh_name; - si = pe->sec_info + i; + si = pe->sec_info[i]; sh_name = si->name; addr = si->sh_addr - pe->imagebase; size = si->sh_size; @@ -663,20 +671,18 @@ static int pe_write(struct pe_info *pe) break; } - if (pe->thunk == pe->s1->sections[si->ord]) { - if (pe->imp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, - pe->imp_offs + addr, pe->imp_size); - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, - pe->iat_offs + addr, pe->iat_size); - } - if (pe->exp_size) { - pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, - pe->exp_offs + addr, pe->exp_size); - } + if (pe->imp_size) { + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, + pe->imp_offs, pe->imp_size); + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, + pe->iat_offs, pe->iat_size); + } + if (pe->exp_size) { + pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, + pe->exp_offs, pe->exp_size); } - strncpy((char*)psh->Name, sh_name, sizeof psh->Name); + memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name)); psh->Characteristics = si->pe_flags; psh->VirtualAddress = addr; @@ -707,25 +713,29 @@ static int pe_write(struct pe_info *pe) pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics; - sum = 0; - pe_fwrite(&pe_header, sizeof pe_header, op, &sum); + pe_fwrite(&pe_header, sizeof pe_header, &pf); for (i = 0; i < pe->sec_count; ++i) - pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum); - pe_fpad(op, pe->sizeofheaders); + pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf); + + file_offset = pe->sizeofheaders; for (i = 0; i < pe->sec_count; ++i) { - si = pe->sec_info + i; - psh = &si->ish; - if (si->data_size) { - pe_fwrite(si->data, si->data_size, op, &sum); - file_offset = psh->PointerToRawData + psh->SizeOfRawData; - pe_fpad(op, file_offset); + Section *s; + si = pe->sec_info[i]; + for (s = si->sec; s; s = s->prev) { + pe_fpad(&pf, file_offset); + pe_fwrite(s->data, s->data_offset, &pf); + if (s->prev) + file_offset += s->prev->sh_addr - s->sh_addr; } + file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData; + pe_fpad(&pf, file_offset); } - pe_header.opthdr.CheckSum = sum + file_offset; - fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); - pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL); - fclose (op); + pf.sum += file_offset; + fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); + pe_fwrite(&pf.sum, sizeof (DWORD), &pf); + + fclose (pf.op); #ifndef _WIN32 chmod(pe->filename, 0777); #endif @@ -796,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe) return; pe_align_section(pe->thunk, 16); - - pe->imp_offs = dll_ptr = pe->thunk->data_offset; pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); - pe->iat_offs = dll_ptr + pe->imp_size; pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); + dll_ptr = pe->thunk->data_offset; + thk_ptr = dll_ptr + pe->imp_size; + ent_ptr = thk_ptr + pe->iat_size; + pe->imp_offs = dll_ptr + rva_base; + pe->iat_offs = thk_ptr + rva_base; section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); - thk_ptr = pe->iat_offs; - ent_ptr = pe->iat_offs + pe->iat_size; - for (i = 0; i < pe->imp_count; ++i) { IMAGE_IMPORT_DESCRIPTOR *hdr; int k, n, dllindex; @@ -895,7 +904,7 @@ static void pe_build_exports(struct pe_info *pe) { ElfW(Sym) *sym; int sym_index, sym_end; - DWORD rva_base, func_o, name_o, ord_o, str_o; + DWORD rva_base, base_o, func_o, name_o, ord_o, str_o; IMAGE_EXPORT_DIRECTORY *hdr; int sym_count, ord; struct pe_sort_sym **sorted, *p; @@ -937,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe) pe_align_section(pe->thunk, 16); dllname = tcc_basename(pe->filename); - pe->exp_offs = pe->thunk->data_offset; - func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY); + base_o = pe->thunk->data_offset; + func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY); name_o = func_o + sym_count * sizeof (DWORD); ord_o = name_o + sym_count * sizeof (DWORD); str_o = ord_o + sym_count * sizeof(WORD); - hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs); + hdr = section_ptr_add(pe->thunk, str_o - base_o); hdr->Characteristics = 0; hdr->Base = 1; hdr->NumberOfFunctions = sym_count; @@ -985,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe) if (op) fprintf(op, "%s\n", name); } - pe->exp_size = pe->thunk->data_offset - pe->exp_offs; + + pe->exp_offs = base_o + rva_base; + pe->exp_size = pe->thunk->data_offset - base_o; dynarray_reset(&sorted, &sym_count); if (op) fclose(op); @@ -994,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe) /* ------------------------------------------------------------- */ static void pe_build_reloc (struct pe_info *pe) { - DWORD offset, block_ptr, addr; + DWORD offset, block_ptr, sh_addr, addr; int count, i; ElfW_Rel *rel, *rel_end; Section *s = NULL, *sr; + struct pe_reloc_header *hdr; - offset = addr = block_ptr = count = i = 0; + sh_addr = offset = block_ptr = count = i = 0; rel = rel_end = NULL; for(;;) { if (rel < rel_end) { int type = ELFW(R_TYPE)(rel->r_info); - addr = rel->r_offset + s->sh_addr; + addr = rel->r_offset + sh_addr; ++ rel; if (type != REL_TYPE_DIRECT) continue; @@ -1022,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe) } -- rel; - } else if (i < pe->sec_count) { - sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc; + } else if (s) { + sr = s->reloc; if (sr) { rel = (ElfW_Rel *)sr->data; rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); + sh_addr = s->sh_addr; } + s = s->prev; continue; - } - if (count) { - /* store the last block and ready for a new one */ - struct pe_reloc_header *hdr; - if (count & 1) /* align for DWORDS */ - section_ptr_add(pe->reloc, sizeof(WORD)), ++count; - hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); - hdr -> offset = offset - pe->imagebase; - hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); - count = 0; - } + } else if (i < pe->sec_count) { + s = pe->sec_info[i]->sec, ++i; + continue; - if (rel >= rel_end) + } else if (!count) break; + + /* fill the last block and ready for a new one */ + if (count & 1) /* align for DWORDS */ + section_ptr_add(pe->reloc, sizeof(WORD)), ++count; + hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); + hdr -> offset = offset - pe->imagebase; + hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); + count = 0; } } @@ -1072,13 +1086,14 @@ static int pe_section_class(Section *s) if (flags & SHF_WRITE) return sec_bss; } - return sec_other; } else { if (0 == strcmp(name, ".reloc")) return sec_reloc; - if (0 == memcmp(name, ".stab", 5)) - return sec_stab; } + if (0 == memcmp(name, ".stab", 5)) + return name[5] ? sec_stabstr : sec_stab; + if (flags & SHF_ALLOC) + return sec_other; return -1; } @@ -1092,47 +1107,62 @@ static int pe_assign_addresses (struct pe_info *pe) if (PE_DLL == pe->type) pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0); - // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); for (o = k = 0 ; k < sec_last; ++k) { for (i = 1; i < pe->s1->nb_sections; ++i) { s = pe->s1->sections[i]; - if (k == pe_section_class(s)) { - // printf("%s %d\n", s->name, k); - s->sh_addr = pe->imagebase; + if (k == pe_section_class(s)) section_order[o++] = i; - } } } - pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); + si = NULL; addr = pe->imagebase + 1; - for (i = 0; i < o; ++i) - { + for (i = 0; i < o; ++i) { k = section_order[i]; s = pe->s1->sections[k]; c = pe_section_class(s); - si = &pe->sec_info[pe->sec_count]; + + if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug) + continue; #ifdef PE_MERGE_DATA - if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { - /* append .bss to .data */ - s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1; - addr += s->data_offset; - si[-1].sh_size = addr - si[-1].sh_addr; - continue; - } + if (c == sec_bss) + c = sec_data; #endif - if (c == sec_stab && 0 == pe->s1->do_debug) + if (si && c == si->cls) { + /* merge with previous section */ + s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1; + } else { + si = NULL; + s->sh_addr = addr = pe_virtual_align(pe, addr); + } + + if (c == sec_data && NULL == pe->thunk) + pe->thunk = s; + + if (s == pe->thunk) { + pe_build_imports(pe); + pe_build_exports(pe); + } + if (s == pe->reloc) + pe_build_reloc (pe); + + if (0 == s->data_offset) continue; + if (si) + goto add_section; + + si = tcc_mallocz(sizeof *si); + dynarray_add(&pe->sec_info, &pe->sec_count, si); + strcpy(si->name, s->name); si->cls = c; - si->ord = k; - si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr); + si->sh_addr = addr; si->pe_flags = IMAGE_SCN_MEM_READ; if (s->sh_flags & SHF_EXECINSTR) @@ -1143,48 +1173,35 @@ static int pe_assign_addresses (struct pe_info *pe) si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA; if (s->sh_flags & SHF_WRITE) si->pe_flags |= IMAGE_SCN_MEM_WRITE; - if (0 == (s->sh_flags & SHF_ALLOC)) { + if (0 == (s->sh_flags & SHF_ALLOC)) si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE; - if (c == sec_stab) - si->pe_flags |= 0x802; //IMAGE_SCN_TYPE_NOLOAD|IMAGE_SCN_LNK_REMOVE + +add_section: + addr += s->data_offset; + si->sh_size = addr - si->sh_addr; + if (s->sh_type != SHT_NOBITS) { + Section **ps = &si->sec; + while (*ps) + ps = &(*ps)->prev; + *ps = s, s->prev = NULL; + si->data_size = si->sh_size; } - - if (c == sec_data && NULL == pe->thunk) - pe->thunk = s; - - if (s == pe->thunk) { - pe_build_imports(pe); - pe_build_exports(pe); - } - - if (c == sec_reloc) - pe_build_reloc (pe); - - if (s->data_offset) - { - if (s->sh_type != SHT_NOBITS) { - si->data = s->data; - si->data_size = s->data_offset; - } - - addr += s->data_offset; - si->sh_size = s->data_offset; - ++pe->sec_count; - } - //printf("%08x %05x %s %08x\n", si->sh_addr, si->sh_size, si->name, si->pe_flags); + //printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name); } + tcc_free(section_order); #if 0 for (i = 1; i < pe->s1->nb_sections; ++i) { Section *s = pe->s1->sections[i]; int type = s->sh_type; int flags = s->sh_flags; - printf("section %-16s %-10s %5x %s,%s,%s\n", + printf("section %-16s %-10s %08x %04x %s,%s,%s\n", s->name, type == SHT_PROGBITS ? "progbits" : type == SHT_NOBITS ? "nobits" : type == SHT_SYMTAB ? "symtab" : type == SHT_STRTAB ? "strtab" : type == SHT_RELX ? "rel" : "???", + s->sh_addr, s->data_offset, flags & SHF_ALLOC ? "alloc" : "", flags & SHF_WRITE ? "write" : "", @@ -1193,8 +1210,6 @@ static int pe_assign_addresses (struct pe_info *pe) } pe->s1->verbose = 2; #endif - - tcc_free(section_order); return 0; } @@ -1860,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) else if (TCC_OUTPUT_DLL == s1->output_type) { pe_type = PE_DLL; - /* need this for 'tccelf.c:relocate_section()' */ - s1->output_type = TCC_OUTPUT_EXE; } else { pe_type = PE_EXE; @@ -1881,24 +1894,34 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) if (!s1->leading_underscore || strchr(start_symbol, '@')) ++start_symbol; - /* grab the startup code from libtcc1 */ +#ifdef CONFIG_TCC_BACKTRACE + if (s1->do_backtrace) { +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) + tcc_add_support(s1, "bcheck.o"); +#endif + 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-dll.o"); + if (s1->output_type != TCC_OUTPUT_DLL) + tcc_add_support(s1, "bt-log.o"); + if (s1->output_type != TCC_OUTPUT_MEMORY) + tcc_add_btstub(s1); + } +#endif + + /* grab the startup code from libtcc1.a */ #ifdef TCC_IS_NATIVE if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) #endif - set_elf_sym(symtab_section, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, start_symbol); + set_global_sym(s1, start_symbol, NULL, 0); if (0 == s1->nostdlib) { static const char *libs[] = { "msvcrt", "kernel32", "", "user32", "gdi32", NULL }; const char **pp, *p; -#ifdef TCC_IS_NATIVE - if (s1->do_bounds_check) - tcc_add_support(s1, TCC_LIBBCHECK); -#endif tcc_add_support(s1, TCC_LIBTCC1); for (pp = libs; 0 != (p = *pp); ++pp) { if (*p) @@ -1907,6 +1930,10 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) break; } } + + /* need this for 'tccelf.c:relocate_section()' */ + if (TCC_OUTPUT_DLL == s1->output_type) + s1->output_type = TCC_OUTPUT_EXE; if (TCC_OUTPUT_MEMORY == s1->output_type) pe_type = PE_RUN; pe->type = pe_type; @@ -1970,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) pe.filename = filename; pe.s1 = s1; - tcc_add_runtime(s1); +#ifdef CONFIG_TCC_BCHECK + tcc_add_bcheck(s1); +#endif + tcc_add_pragma_libs(s1); pe_add_runtime(s1, &pe); resolve_common_syms(s1); pe_set_options(s1, &pe); @@ -1995,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) ret = -1; else ret = pe_write(&pe); - tcc_free(pe.sec_info); + dynarray_reset(&pe.sec_info, &pe.sec_count); } else { #ifdef TCC_IS_NATIVE pe.thunk = data_section; diff --git a/tccpp.c b/tccpp.c index f69d4e9a..e70c2bb2 100644 --- a/tccpp.c +++ b/tccpp.c @@ -109,9 +109,7 @@ ST_FUNC void expect(const char *msg) /* ------------------------------------------------------------------------- */ /* Custom allocator for tiny objects */ -#ifndef __BOUNDS_CHECKING_ON #define USE_TAL -#endif #ifndef USE_TAL #define tal_free(al, p) tcc_free(p) @@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_ tail_call: is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size); if ((!p || is_own) && size <= al->limit) { - if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) { + if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) { header = (tal_header_t *)al->p; header->size = adj_size; #ifdef TAL_DEBUG @@ -1958,7 +1956,11 @@ include_done: if (tok == TOK_STR) { if (file->true_filename == file->filename) file->true_filename = tcc_strdup(file->filename); - tcc_debug_putfile(s1, (char *)tokc.str.data); + /* prepend directory from real file */ + pstrcpy(buf, sizeof buf, file->true_filename); + *tcc_basename(buf) = 0; + pstrcat(buf, sizeof buf, (char *)tokc.str.data); + tcc_debug_putfile(s1, buf); } else if (parse_flags & PARSE_FLAG_ASM_FILE) break; else @@ -3529,9 +3531,6 @@ no_subst: /* return next token with macro substitution */ ST_FUNC void next(void) { - /* generate line number info */ - if (tcc_state->do_debug) - tcc_debug_line(tcc_state); redo: if (parse_flags & PARSE_FLAG_SPACES) next_nomacro_spc(); @@ -3607,6 +3606,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm) cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename); if (is_asm) cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n"); + if (s1->output_type == TCC_OUTPUT_MEMORY) + cstr_printf(&cstr, "#define __TCC_RUN__ 1\n"); if (s1->cmdline_incl.size) cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size); //printf("%s\n", (char*)cstr.data); @@ -3657,7 +3658,7 @@ ST_FUNC void tccpp_new(TCCState *s) cstr_realloc(&cstr_buf, STRING_MAX_SIZE); tok_str_new(&tokstr_buf); tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE); - + tok_ident = TOK_IDENT; p = tcc_keywords; while (*p) { diff --git a/tccrun.c b/tccrun.c index 494dd59f..f01c5a61 100644 --- a/tccrun.c +++ b/tccrun.c @@ -23,29 +23,38 @@ /* only native compiler supports -run */ #ifdef TCC_IS_NATIVE +#ifdef CONFIG_TCC_BACKTRACE +typedef struct rt_context +{ + /* --> tccelf.c:tcc_add_btstub wants those below in that order: */ + Stab_Sym *stab_sym, *stab_sym_end; + char *stab_str; + ElfW(Sym) *esym_start, *esym_end; + char *elf_str; + addr_t prog_base; + void *bounds_start; + struct rt_context *next; + /* <-- */ + int num_callers; + addr_t ip, fp, sp; + void *top_func; + jmp_buf jmp_buf; + char do_jmp; +} rt_context; + +static rt_context g_rtctxt; +static void set_exception_handler(void); +static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); +static void rt_exit(int code); +#endif /* CONFIG_TCC_BACKTRACE */ + +/* defined when included from lib/bt.c */ +#ifndef CONFIG_TCC_BACKTRACE_ONLY + #ifndef _WIN32 # include #endif -#ifdef CONFIG_TCC_BACKTRACE -static void set_exception_handler(void); -#ifdef _WIN32 -static DWORD s1_for_run_idx; -void set_s1_for_run(TCCState *s) -{ - if (!s1_for_run_idx) - s1_for_run_idx = TlsAlloc(); - TlsSetValue(s1_for_run_idx, s); -} -#define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx)) -#else -/* XXX: add tls support for linux */ -static TCCState *s1_for_run; -#define set_s1_for_run(s) (s1_for_run = s) -#define get_s1_for_run() s1_for_run -#endif -#endif - static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length); static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff); @@ -113,72 +122,73 @@ ST_FUNC void tcc_run_free(TCCState *s1) #endif } tcc_free(s1->runtime_mem); - if (get_s1_for_run() == s1) - set_s1_for_run(NULL); +} + +static void run_cdtors(TCCState *s1, const char *start, const char *end) +{ + void **a = tcc_get_symbol(s1, start); + void **b = tcc_get_symbol(s1, end); + while (a != b) + ((void(*)(void))*a++)(); } /* launch the compiled program with the given arguments */ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) { -/* PE target overwrites runtime_main */ -#ifndef TCC_TARGET_PE - typedef void (*init_array_func)(int, char **, char **); - typedef void (*fini_array_func)(void); - init_array_func *__init_array_start; - init_array_func *__init_array_end; - fini_array_func *__fini_array_start; - fini_array_func *__fini_array_end; + int (*prog_main)(int, char **), ret; +#ifdef CONFIG_TCC_BACKTRACE + rt_context *rc = &g_rtctxt; #endif - int i; - int ret; - int (*prog_main)(int, char **); s1->runtime_main = s1->nostdlib ? "_start" : "main"; if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main)) return 0; +#ifdef CONFIG_TCC_BACKTRACE + if (s1->do_debug) + tcc_add_symbol(s1, "exit", rt_exit); +#endif if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) return -1; prog_main = tcc_get_symbol_err(s1, s1->runtime_main); #ifdef CONFIG_TCC_BACKTRACE + memset(rc, 0, sizeof *rc); if (s1->do_debug) { + void *p; + rc->stab_sym = (Stab_Sym *)stab_section->data; + rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); + rc->stab_str = (char *)stab_section->link->data; + 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; + rc->top_func = tcc_get_symbol(s1, "main"); + rc->num_callers = s1->rt_num_callers; + rc->do_jmp = 1; + if ((p = tcc_get_symbol(s1, "__rt_error"))) + *(void**)p = _rt_error; +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) { + if ((p = tcc_get_symbol(s1, "__bound_init"))) + ((void(*)(void*))p)(bounds_section->data); + } +#endif set_exception_handler(); - s1->rt_prog_main = prog_main; - /* set global state pointer for exception handlers*/ - set_s1_for_run(s1); } #endif errno = 0; /* clean errno value */ - -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) - /* set error function */ - s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); + fflush(stdout); + fflush(stderr); + run_cdtors(s1, "__init_array_start", "__init_array_end"); +#ifdef CONFIG_TCC_BACKTRACE + if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf))) #endif - -#ifndef TCC_TARGET_PE - __init_array_start = tcc_get_symbol_err(s1, "__init_array_start"); - __init_array_end = tcc_get_symbol_err(s1, "__init_array_end"); - __fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start"); - __fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end"); - - if (__init_array_start && __init_array_end) { - i = 0; - while (&__init_array_start[i] != __init_array_end) - (*__init_array_start[i++])(argc, argv, environ); + { + ret = prog_main(argc, argv); } -#endif - - ret = (*prog_main)(argc, argv); - -#ifndef TCC_TARGET_PE - if (__fini_array_start && __fini_array_end) { - i = 0; - while (&__fini_array_end[i] != __fini_array_start) - (*__fini_array_end[--i])(); - } -#endif + run_cdtors(s1, "__fini_array_start", "__fini_array_end"); + if ((s1->dflag & 16) && ret) + fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp); return ret; } @@ -336,11 +346,10 @@ static void win64_del_function_table(void *p) } } #endif - +#endif //ndef CONFIG_TCC_BACKTRACE_ONLY /* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_BACKTRACE -#define INCLUDE_STACK_SIZE 32 static int rt_vprintf(const char *fmt, va_list ap) { int ret = vfprintf(stderr, fmt, ap); @@ -358,21 +367,22 @@ static int rt_printf(const char *fmt, ...) return r; } +#define INCLUDE_STACK_SIZE 32 + /* print the position in the source file of PC value 'pc' by reading the stabs debug information */ -static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) +static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, + const char *msg, const char *skip) { char func_name[128]; addr_t func_addr, last_pc, pc; const char *incl_files[INCLUDE_STACK_SIZE]; int incl_index, last_incl_index, len, last_line_num, i; const char *str, *p; + ElfW(Sym) *esym; + Stab_Sym *sym; - ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym; - Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym; - char *stab_str = NULL; - char *elf_str = NULL; - +next: func_name[0] = '\0'; func_addr = 0; incl_index = 0; @@ -380,19 +390,8 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) last_line_num = 1; last_incl_index = 0; - if (stab_section) { - stab_sym = (Stab_Sym *)stab_section->data; - stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); - stab_str = (char *) stab_section->link->data; - } - if (symtab_section) { - esym_start = (ElfW(Sym) *)(symtab_section->data); - esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); - elf_str = (char *) symtab_section->link->data; - } - - for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) { - str = stab_str + sym->n_strx; + for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) { + str = rc->stab_str + sym->n_strx; pc = sym->n_value; switch(sym->n_type) { @@ -406,16 +405,18 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) if (sym->n_strx == 0) /* end of function */ goto rel_pc; abs_pc: - if (sizeof pc == 8) + if (sizeof sym->n_value < PTR_SIZE) { /* Stab_Sym.n_value is only 32bits */ - pc |= wanted_pc & 0xffffffff00000000ULL; + //fprintf(stderr, "pc = %p %p %p\n", pc, rc->prog_base, wanted_pc), fflush(stderr); + pc += rc->prog_base; + } break; rel_pc: pc += func_addr; break; } - if (pc > wanted_pc && wanted_pc > last_pc) + if (pc >= wanted_pc && wanted_pc >= last_pc) goto found; switch(sym->n_type) { @@ -434,8 +435,6 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) last_pc = pc; last_line_num = sym->n_desc; last_incl_index = incl_index; - if (pc == wanted_pc) - goto found; break; /* include files */ case N_BINCL: @@ -468,31 +467,38 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) } } + func_name[0] = '\0'; + func_addr = 0; + last_incl_index = 0; + /* we try symtab symbols (no line number info) */ - for (esym = esym_start + 1; esym < esym_end; ++esym) { + for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) { int type = ELFW(ST_TYPE)(esym->st_info); if (type == STT_FUNC || type == STT_GNU_IFUNC) { if (wanted_pc >= esym->st_value && wanted_pc < esym->st_value + esym->st_size) { pstrcpy(func_name, sizeof(func_name), - elf_str + esym->st_name); + rc->elf_str + esym->st_name); func_addr = esym->st_value; - last_incl_index = 0; goto found; } } } - /* did not find any info: */ - rt_printf("%s %p ???", msg, (void*)wanted_pc); - return 0; - found: + if ((rc = rc->next)) + goto next; + +found: i = last_incl_index; - if (i > 0) - rt_printf("%s:%d: ", incl_files[--i], last_line_num); - rt_printf("%s %p", msg, (void*)wanted_pc); - if (func_name[0] != '\0') - rt_printf(" %s()", func_name); + if (i > 0) { + str = incl_files[--i]; + if (skip[0] && strstr(str, skip)) + return (addr_t)-1; + 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 (;;) { @@ -503,48 +509,79 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) } rt_printf(")"); } +#endif return func_addr; } -typedef struct rt_context { - addr_t ip, fp, sp, pc; -} rt_context; - static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level); +static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) +{ + rt_context *rc = &g_rtctxt; + addr_t pc = 0; + char skip[100]; + int i, level, ret, n; + const char *a, *b, *msg; + + if (fp) { + /* we're called from tcc_backtrace. */ + rc->fp = (addr_t)fp; + rc->ip = (addr_t)ip; + msg = ""; + } else { + /* we're called from signal/exception handler */ + msg = "RUNTIME ERROR: "; + } + + skip[0] = 0; + /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ + if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) { + memcpy(skip, a, b - a), skip[b - a] = 0; + fmt = b + 1; + } + + n = rc->num_callers ? rc->num_callers : 6; + for (i = level = 0; level < n; i++) { + ret = rt_get_caller_pc(&pc, rc, i); + a = "%s"; + if (ret != -1) { + pc = rt_printline(rc, pc, level ? "by" : "at", skip); + if (pc == (addr_t)-1) + continue; + a = ": %s"; + } + if (level == 0) { + rt_printf(a, msg); + rt_vprintf(fmt, ap); + } else if (ret == -1) + break; + rt_printf("\n"); + if (ret == -1 || (pc == (addr_t)rc->top_func && pc)) + break; + ++level; + } + + rc->ip = rc->fp = 0; + return 0; +} + /* emit a run time error at position 'pc' */ -static void rt_error(rt_context *rc, const char *fmt, ...) +static int rt_error(const char *fmt, ...) { va_list ap; - addr_t pc; - int i; - TCCState *s1; - - s1 = get_s1_for_run(); - if (*fmt == ' ') { - if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg) - fmt = *s1->rt_bound_error_msg; - else - ++fmt; - } - - rt_printf("Runtime error: "); + int ret; va_start(ap, fmt); - rt_vprintf(fmt, ap); + ret = _rt_error(0, 0, fmt, ap); va_end(ap); - rt_printf("\n"); + return ret; +} - if (!s1) - return; - - for(i=0; irt_num_callers; i++) { - if (rt_get_caller_pc(&pc, rc, i) < 0) - break; - pc = rt_printline(s1, pc, i ? "by" : "at"); - rt_printf("\n"); - if (pc == (addr_t)s1->rt_prog_main && pc) - break; - } +static void rt_exit(int code) +{ + rt_context *rc = &g_rtctxt; + if (rc->do_jmp) + longjmp(rc->jmp_buf, code ? code : 256); + exit(code); } /* ------------------------------------------------------------- */ @@ -621,36 +658,36 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc) /* signal handler for fatal errors */ static void sig_error(int signum, siginfo_t *siginf, void *puc) { - rt_context rc; + rt_context *rc = &g_rtctxt; + rt_getcontext(puc, rc); - rt_getcontext(puc, &rc); switch(signum) { case SIGFPE: switch(siginf->si_code) { case FPE_INTDIV: case FPE_FLTDIV: - rt_error(&rc, "division by zero"); + rt_error("division by zero"); break; default: - rt_error(&rc, "floating point exception"); + rt_error("floating point exception"); break; } break; case SIGBUS: case SIGSEGV: - rt_error(&rc, " dereferencing invalid pointer"); + rt_error("invalid memory access"); break; case SIGILL: - rt_error(&rc, "illegal instruction"); + rt_error("illegal instruction"); break; case SIGABRT: - rt_error(&rc, "abort() called"); + rt_error("abort() called"); break; default: - rt_error(&rc, "caught signal %d", signum); + rt_error("caught signal %d", signum); break; } - exit(255); + rt_exit(255); } #ifndef SA_SIGINFO @@ -664,7 +701,7 @@ static void set_exception_handler(void) /* install TCC signal handlers to print debug info on fatal runtime errors */ sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; -#ifdef SIGSTKSZ +#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; @@ -674,7 +711,7 @@ static void set_exception_handler(void) sigaction(SIGSEGV, &sigact, NULL); sigaction(SIGBUS, &sigact, NULL); sigaction(SIGABRT, &sigact, NULL); -#ifdef SIGSTKSZ +#if 0//def SIGSTKSZ /* This allows stack overflow to be reported instead of a SEGV */ { stack_t ss; @@ -689,32 +726,35 @@ static void set_exception_handler(void) } #else /* WIN32 */ + /* signal handler for fatal errors */ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) { - rt_context rc; + rt_context *rc = &g_rtctxt; unsigned code; + rt_getcontext(ex_info->ContextRecord, rc); - rt_getcontext(ex_info->ContextRecord, &rc); switch (code = ex_info->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: - rt_error(&rc, " access violation"); + rt_error("invalid memory access"); break; case EXCEPTION_STACK_OVERFLOW: - rt_error(&rc, "stack overflow"); + rt_error("stack overflow"); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: - rt_error(&rc, "division by zero"); + rt_error("division by zero"); break; case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: - rc.ip = *(addr_t*)rc.sp; - rt_error(&rc, "^breakpoint/single-step exception:"); + rc->ip = *(addr_t*)rc->sp; + rt_error("breakpoint/single-step exception:"); return EXCEPTION_CONTINUE_SEARCH; default: - rt_error(&rc, "caught exception %08x", code); + rt_error("caught exception %08x", code); break; } + if (rc->do_jmp) + rt_exit(255); return EXCEPTION_EXECUTE_HANDLER; } @@ -807,7 +847,6 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) #endif #endif /* CONFIG_TCC_BACKTRACE */ - /* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_STATIC diff --git a/tests/Makefile b/tests/Makefile index c4790606..1ddf68ef 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -73,6 +73,7 @@ endif RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) DISAS = objdump -d DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1) +Q = # >/dev/null 2>&1 all test : $(MAKE) clean-s @@ -88,7 +89,7 @@ hello-run: ../examples/ex1.c libtes%: libtcc_tes%$(EXESUF) @echo ------------ $@ ------------ - ./libtcc_tes$*$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) + ./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC) $(CC) -o $@ $^ $(CFLAGS) $(LIBS) @@ -105,22 +106,24 @@ test.ref: tcctest.c # auto test test1 test1b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) -run $< > test.out1 - @diff -u test.ref test.out1 && echo "Auto Test OK" + $(TCC) -w -run $< > test.out1 $Q + @diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK" # iterated test2 (compile tcc then compile tcctest.c !) test2 test2b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2 - @diff -u test.ref test.out2 && echo "Auto Test2 OK" + $(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2 $Q + @diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK" # iterated test3 (compile tcc then compile tcc then compile tcctest.c !) test3 test3b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3 - @diff -u test.ref test.out3 && echo "Auto Test3 OK" + $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3 $Q + @diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK" -test%b : TCCFLAGS += -b +AUTO_TEST = Auto Test +test%b : TCCFLAGS += -b -bt1 +test%b : AUTO_TEST = Auto Bound-Test # binary output test test4: tcctest.c test.ref @@ -129,21 +132,21 @@ test4: tcctest.c test.ref $(TCC) -c -o tcctest3.o $< $(TCC) -o tcctest3 tcctest3.o ./tcctest3 > test3.out - @if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi + @if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi # dynamic output $(TCC) -o tcctest1 $< ./tcctest1 > test1.out - @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi + @if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi # dynamic output + bound check $(TCC) -b -o tcctest4 $< ./tcctest4 > test4.out - @if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi + @if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi test4_static: tcctest.c test.ref # static output. $(TCC) -static -o tcctest2 $< ./tcctest2 > test2.out - @if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi + @if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi # use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them dlltest: @@ -164,32 +167,29 @@ memtest: @echo ------------ $@ ------------ $(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF) ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS) - ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c - + ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c # memory and bound check auto test -BOUNDS_OK = 1 4 8 10 14 16 18 +BOUNDS_OK = 1 4 8 10 14 16 BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17 btest: boundtest.c @echo ------------ $@ ------------ @for i in $(BOUNDS_OK); do \ - echo ; echo --- boundtest $$i ---; \ if $(TCC) -b -run $< $$i ; then \ - echo succeeded as expected; \ + echo "- Test $$i succeeded as expected" ; \ else\ - echo Failed positive test $$i ; exit 1 ; \ + echo "- Failed positive test $$i" ; exit 1 ; \ fi ;\ done ;\ for i in $(BOUNDS_FAIL); do \ - echo ; echo --- boundtest $$i ---; \ - if $(TCC) -b -run $< $$i ; then \ - echo Failed negative test $$i ; exit 1 ;\ + if $(TCC) -b -bt1 -run $< $$i ; then \ + echo "- Failed negative test $$i" ; exit 1 ;\ else\ - echo failed as expected; \ + echo "- Test $$i failed as expected" ; \ fi ;\ done ;\ - echo; echo Bound test OK + echo Bound test OK # speed test speedtest: ex2 ex3 diff --git a/tests/boundtest.c b/tests/boundtest.c index bd9ea5ba..9c135108 100644 --- a/tests/boundtest.c +++ b/tests/boundtest.c @@ -50,15 +50,12 @@ int test4(void) int i, sum = 0; int *tab4; - fprintf(stderr, "%s start\n", __FUNCTION__); - tab4 = malloc(20 * sizeof(int)); for(i=0;i<20;i++) { sum += tab4[i]; } free(tab4); - fprintf(stderr, "%s end\n", __FUNCTION__); return sum; } @@ -68,15 +65,12 @@ int test5(void) int i, sum = 0; int *tab4; - fprintf(stderr, "%s start\n", __FUNCTION__); - tab4 = malloc(20 * sizeof(int)); for(i=0;i<21;i++) { sum += tab4[i]; } free(tab4); - fprintf(stderr, "%s end\n", __FUNCTION__); return sum; } @@ -198,16 +192,12 @@ int test16() char *demo = "This is only a test."; char *p; - fprintf(stderr, "%s start\n", __FUNCTION__); - p = alloca(16); strcpy(p,"12345678901234"); - printf("alloca: p is %s\n", p); /* Test alloca embedded in a larger expression */ - printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) ); + printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) ); - fprintf(stderr, "%s end\n", __FUNCTION__); return 0; } @@ -217,211 +207,11 @@ int test17() char *demo = "This is only a test."; char *p; - fprintf(stderr, "%s start\n", __FUNCTION__); - p = alloca(16); strcpy(p,"12345678901234"); - printf("alloca: p is %s\n", p); /* Test alloca embedded in a larger expression */ - printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) ); - - fprintf(stderr, "%s end\n", __FUNCTION__); - return 0; -} - -#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort(); - -extern void __bound_never_fatal (int neverfatal); -extern const char *__bound_error_msg; - -static void init18(char *a, char *b) -{ - memset (a, 'a', 10); - a[3] = 0; - a[9] = 0; - memset (b, 'b', 10); - __bound_error_msg = ""; -} - -/* ok (catch all errors) */ -int test18() -{ - char pad1[10]; - char a[10]; - char pad2[10]; - char b[10]; - char pad3[10]; - - memset (pad1, 0, sizeof(pad1)); - memset (pad2, 0, sizeof(pad2)); - memset (pad3, 0, sizeof(pad3)); - - /* -2 in case TCC_BOUNDS_NEVER_FATAL is set */ - __bound_never_fatal (-2); - - /* memcpy */ - init18(a,b); - memcpy(&a[1],&b[0],10); - CHECK("memcpy dest"); - init18(a,b); - memcpy(&a[0],&b[1],10); - CHECK("memcpy src"); - init18(a,b); - memcpy(&a[0],&a[3],4); - CHECK("overlapping regions"); - init18(a,b); - memcpy(&a[3],&a[0],4); - CHECK("overlapping regions"); - - /* memcmp */ - init18(a,b); - memcmp(&b[1],&b[0],10); - CHECK("memcmp s1"); - init18(a,b); - memcmp(&b[0],&b[1],10); - CHECK("memcmp s2"); - - /* memmove */ - init18(a,b); - memmove(&b[1],&b[0],10); - CHECK("memmove dest"); - init18(a,b); - memmove(&b[0],&b[1],10); - CHECK("memmove src"); - - /* memset */ - init18(a,b); - memset(&b[1],'b',10); - CHECK("memset"); - - /* strlen */ - init18(a,b); - strlen(&b[0]); - CHECK("strlen"); - - /* strcpy */ - init18(a,b); - strcpy(&a[7], &a[0]); - CHECK("strcpy dest"); - init18(a,b); - strcpy(&a[0], &b[7]); - CHECK("strcpy src"); - init18(a,b); - strcpy(&a[0], &a[1]); - CHECK("overlapping regions"); - init18(a,b); - strcpy(&a[2], &a[0]); - CHECK("overlapping regions"); - - /* strncpy */ - init18(a,b); - strncpy(&a[7], &a[0], 10); - CHECK("strncpy dest"); - init18(a,b); - strncpy(&a[0], &b[7], 10); - CHECK("strncpy src"); - init18(a,b); - strncpy(&a[0], &a[1], 10); - CHECK("overlapping regions"); - strncpy(&a[2], &a[0], 10); - CHECK("overlapping regions"); - - /* strcmp */ - init18(a,b); - strcmp(&b[2], &b[0]); - CHECK("strcmp s1"); - init18(a,b); - strcmp(&b[0], &b[2]); - CHECK("strcmp s2"); - - /* strncmp */ - init18(a,b); - strncmp(&b[5], &b[0], 10); - CHECK("strncmp s1"); - init18(a,b); - strncmp(&b[0], &b[5], 10); - CHECK("strncmp s2"); - - /* strcat */ - init18(a,b); - strcat(&a[7], &a[0]); - CHECK("strcat dest"); - init18(a,b); - strcat(&a[0], &b[5]); - CHECK("strcat src"); - init18(a,b); - strcat(&a[0], &a[4]); - CHECK("overlapping regions"); - init18(a,b); - strcat(&a[3], &a[0]); - CHECK("overlapping regions"); - - /* strchr */ - init18(a,b); - strchr(&b[0], 'a'); - CHECK("strchr"); - - /* strdup */ - init18(a,b); - free(strdup(&b[0])); - CHECK("strdup"); - - __bound_never_fatal (2); - - /* memcpy */ - init18(a,b); - memcpy(&a[0],&b[0],10); - init18(a,b); - memcpy(&a[0],&a[3],3); - init18(a,b); - memcpy(&a[3],&a[0],3); - - /* memcmp */ - init18(a,b); - memcmp(&b[0],&b[0],10); - - /* memmove */ - init18(a,b); - memmove(&b[0],&b[5],5); - init18(a,b); - memmove(&b[5],&b[0],5); - - /* memset */ - init18(a,b); - memset(&b[0],'b',10); - - /* strlen */ - init18(a,b); - strlen (&a[0]); - - /* strcpy */ - init18(a,b); - strcpy (&a[0], &a[7]); - - /* strncpy */ - init18(a,b); - strncpy (&a[0], &a[7], 4); - - /* strcmp */ - init18(a,b); - strcmp (&a[0], &a[4]); - - /* strncmp */ - init18(a,b); - strncmp (&a[0], &a[4], 10); - - /* strcat */ - init18(a,b); - strcat (&a[0], &a[7]); - - /* strchr */ - init18(a,b); - strchr (&a[0], 0); - - /* strdup */ - init18(a,b); - free (strdup (&a[0])); + printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) ); return 0; } @@ -443,8 +233,7 @@ int (*table_test[])(void) = { test14, test15, test16, - test17, - test18, + test17 }; int main(int argc, char **argv) diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c index 6fe4100a..196a0bd5 100644 --- a/tests/libtcc_test_mt.c +++ b/tests/libtcc_test_mt.c @@ -203,14 +203,11 @@ TF_TYPE(thread_test_complex, vn) sprintf(b, "%d", F(n)); - argv[argc++] = "../tcc.c"; for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i]; #if 0 argv[argc++] = "-run"; - argv[argc++] = "../tcc.c"; for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i]; #endif - argv[argc++] = "-g"; argv[argc++] = "-DFIB"; argv[argc++] = "-run"; argv[argc++] = __FILE__; @@ -221,23 +218,24 @@ TF_TYPE(thread_test_complex, vn) sleep_ms(2); ret = tcc_add_file(s, argv[0]); sleep_ms(3); - if (ret >= 0) - tcc_run(s, argc, argv); + if (ret < 0) + exit(1); + tcc_run(s, argc, argv); tcc_delete(s); fflush(stdout); return 0; } -void time_tcc(int n) +void time_tcc(int n, const char *src) { TCCState *s; int ret; while (--n >= 0) { s = new_state(1); - ret = tcc_add_file(s, "../tcc.c"); + ret = tcc_add_file(s, src); tcc_delete(s); if (ret < 0) - break; + exit(1); } } @@ -260,6 +258,11 @@ int main(int argc, char **argv) g_argc = argc; g_argv = argv; + if (argc < 2) { + fprintf(stderr, "usage: libtcc_test_mt tcc.c \n"); + return 1; + } + #if 1 printf("----- libtest : mixed calls -------\n"), fflush(stdout); t = getclock_ms(); @@ -285,7 +288,7 @@ int main(int argc, char **argv) #if 1 printf("----- compilation of tcc -----------\n"), fflush(stdout); t = getclock_ms(); - time_tcc(10); + time_tcc(10, argv[1]); printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout); #endif return 0; diff --git a/tests/tcctest.c b/tests/tcctest.c index 4bf5d598..f911e90b 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1725,10 +1725,6 @@ void cast_test() printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a')); printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a')); -#ifdef __TINYC__ -# pragma comment(option, "-w") -#endif - /* from pointer to integer types */ printf("%d %d %ld %ld %lld %lld\n", (int)p, (unsigned int)p, @@ -1739,10 +1735,6 @@ void cast_test() printf("%p %p %p %p\n", (void *)a, (void *)b, (void *)c, (void *)d); -#ifdef __TINYC__ -# pragma comment(option, "-W") -#endif - /* int to int with sign set */ printf("0x%lx\n", (unsigned long)(int)ul); } @@ -3406,7 +3398,7 @@ void clobber_r12(void) } #endif -void test_high_clobbers(void) +void test_high_clobbers_really(void) { #if defined __x86_64__ && !defined _WIN64 register long val asm("r12"); @@ -3422,6 +3414,20 @@ void test_high_clobbers(void) #endif } +void test_high_clobbers(void) +{ +#if defined __x86_64__ && !defined _WIN64 + long x1, x2; + asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */ + test_high_clobbers_really(); + asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */ + asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */ + /* should be 0 but tcc doesn't save r12 automatically, which has + bad effects when gcc helds TCCState *s in r12 in tcc.c:main */ + //printf("r12-clobber-diff: %lx\n", x2 - x1); +#endif +} + static long cpu_number; void trace_console(long len, long len2) { diff --git a/tests/tests2/112_backtrace.c b/tests/tests2/112_backtrace.c new file mode 100644 index 00000000..cd38c3c8 --- /dev/null +++ b/tests/tests2/112_backtrace.c @@ -0,0 +1,165 @@ +#include + +/* ------------------------------------------------------- */ +#if defined test_backtrace_1 + +void f3() +{ + printf("* f3()\n"), fflush(stdout); + *(void**)0 = 0; +} +void f2() +{ + printf("* f2()\n"), fflush(stdout); + f3(); +} +void f1() +{ + printf("* f1()\n"), fflush(stdout); + f2(); +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_bcheck_1 + +struct s { int a,b,c,d,e; }; +struct s s[3]; +struct s *ps = s; +void f1() +{ + printf("* f1()\n"), fflush(stdout); + ps[3] = ps[2]; +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_tcc_backtrace_2 + +/* test custom backtrace and 'exit()' redirection */ +int tcc_backtrace(const char *fmt, ...); +void exit(int); + +void f2() +{ + printf("* f2()\n"); + printf("* exit f2\n"), fflush(stdout); + exit(34); +} +void f1() +{ + printf("* f1()\n"), fflush(stdout); + tcc_backtrace("Hello from %s!", "f1"); + f2(); +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_tcc_backtrace_3 + +/* this test should be run despite of the exit(34) above */ +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + return 1; +} + +/* ------------------------------------------------------- */ +#else +#include +#include +char *strdup(); +int main() +{ + char pad1[10]; + char a[10]; + char pad2[10]; + char b[10]; + char pad3[10]; + memset (pad1, 0, sizeof(pad1)); + memset (pad2, 0, sizeof(pad2)); + memset (pad3, 0, sizeof(pad3)); + + memset (a, 'a', 10); + a[3] = 0; + a[9] = 0; + memset (b, 'b', 10); + +#if defined test_bcheck_100 + memcpy(&a[1],&b[0],10); +#elif defined test_bcheck_101 + memcpy(&a[0],&b[1],10); +#elif defined test_bcheck_102 + memcpy(&a[0],&a[3],4); +#elif defined test_bcheck_103 + memcpy(&a[3],&a[0],4); +#elif defined test_bcheck_104 + memcmp(&b[1],&b[0],10); +#elif defined test_bcheck_105 + memcmp(&b[0],&b[1],10); +#elif defined test_bcheck_106 + memmove(&b[1],&b[0],10); +#elif defined test_bcheck_107 + memmove(&b[0],&b[1],10); +#elif defined test_bcheck_108 + memset(&b[1],'b',10); +#elif defined test_bcheck_109 + strlen(&b[0]); +#elif defined test_bcheck_110 + strcpy(&a[7], &a[0]); +#elif defined test_bcheck_111 + strcpy(&a[0], &b[7]); +#elif defined test_bcheck_112 + strcpy(&a[0], &a[1]); +#elif defined test_bcheck_113 + strcpy(&a[2], &a[0]); +#elif defined test_bcheck_114 + strncpy(&a[7], &a[0], 10); +#elif defined test_bcheck_115 + strncpy(&a[0], &b[7], 10); +#elif defined test_bcheck_116 + strncpy(&a[0], &a[1], 10); +#elif defined test_bcheck_117 + strncpy(&a[2], &a[0], 10); +#elif defined test_bcheck_118 + strcmp(&b[2], &b[0]); +#elif defined test_bcheck_119 + strcmp(&b[0], &b[2]); +#elif defined test_bcheck_120 + strncmp(&b[5], &b[0], 10); +#elif defined test_bcheck_121 + strncmp(&b[0], &b[5], 10); +#elif defined test_bcheck_122 + strcat(&a[7], &a[0]); +#elif defined test_bcheck_123 + strcat(&a[0], &b[5]); +#elif defined test_bcheck_124 + strcat(&a[0], &a[4]); +#elif defined test_bcheck_125 + strcat(&a[3], &a[0]); +#elif defined test_bcheck_126 + strchr(&b[0], 'a'); +#elif defined test_bcheck_127 + free(strdup(&b[0])); +#endif +} +/* ------------------------------------------------------- */ +#endif diff --git a/tests/tests2/112_backtrace.expect b/tests/tests2/112_backtrace.expect new file mode 100644 index 00000000..8bb1dd1f --- /dev/null +++ b/tests/tests2/112_backtrace.expect @@ -0,0 +1,164 @@ +[test_backtrace_1] +* main +* f1() +* f2() +* f3() +112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access +112_backtrace.c:14: by f2 +112_backtrace.c:19: by f1 +112_backtrace.c:24: by main +[returns 255] + +[test_bcheck_1] +* main +* f1() +112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region +112_backtrace.c:43: by main +112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x14 in memmove dest +112_backtrace.c:43: by main +[returns 255] + +[test_tcc_backtrace_2] +* main +* f1() +112_backtrace.c:64: at f1: Hello from f1! +112_backtrace.c:70: by main +* f2() +* exit f2 +[returns 34] + +[test_tcc_backtrace_3] +* main +[returns 1] + +[test_bcheck_100] +112_backtrace.c:107: at main: BCHECK: ........ is outside of the region +112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0xa in memcpy dest +[returns 255] + +[test_bcheck_101] +112_backtrace.c:109: at main: BCHECK: ........ is outside of the region +112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0xa in memcpy src +[returns 255] + +[test_bcheck_102] +112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy +[returns 255] + +[test_bcheck_103] +112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy +[returns 255] + +[test_bcheck_104] +112_backtrace.c:115: at main: BCHECK: ........ is outside of the region +112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s1 +[returns 255] + +[test_bcheck_105] +112_backtrace.c:117: at main: BCHECK: ........ is outside of the region +112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s2 +[returns 255] + +[test_bcheck_106] +112_backtrace.c:119: at main: BCHECK: ........ is outside of the region +112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0xa in memmove dest +[returns 255] + +[test_bcheck_107] +112_backtrace.c:121: at main: BCHECK: ........ is outside of the region +112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0xa in memmove src +[returns 255] + +[test_bcheck_108] +112_backtrace.c:123: at main: BCHECK: ........ is outside of the region +112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0xa in memset +[returns 255] + +[test_bcheck_109] +112_backtrace.c:125: at main: BCHECK: ........ is outside of the region +112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0xb in strlen +[returns 255] + +[test_bcheck_110] +112_backtrace.c:127: at main: BCHECK: ........ is outside of the region +112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy dest +[returns 255] + +[test_bcheck_111] +112_backtrace.c:129: at main: BCHECK: ........ is outside of the region +112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy src +[returns 255] + +[test_bcheck_112] +112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strcpy +[returns 255] + +[test_bcheck_113] +112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcpy +[returns 255] + +[test_bcheck_114] +112_backtrace.c:135: at main: BCHECK: ........ is outside of the region +112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy dest +[returns 255] + +[test_bcheck_115] +112_backtrace.c:137: at main: BCHECK: ........ is outside of the region +112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy src +[returns 255] + +[test_bcheck_116] +112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strncpy +[returns 255] + +[test_bcheck_117] +112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strncpy +[returns 255] + +[test_bcheck_118] +112_backtrace.c:143: at main: BCHECK: ........ is outside of the region +112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s1 +[returns 255] + +[test_bcheck_119] +112_backtrace.c:145: at main: BCHECK: ........ is outside of the region +112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s2 +[returns 255] + +[test_bcheck_120] +112_backtrace.c:147: at main: BCHECK: ........ is outside of the region +112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s1 +[returns 255] + +[test_bcheck_121] +112_backtrace.c:149: at main: BCHECK: ........ is outside of the region +112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s2 +[returns 255] + +[test_bcheck_122] +112_backtrace.c:151: at main: BCHECK: ........ is outside of the region +112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x6 in strcat dest +[returns 255] + +[test_bcheck_123] +112_backtrace.c:153: at main: BCHECK: ........ is outside of the region +112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x6 in strcat src +[returns 255] + +[test_bcheck_124] +112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x9), ........(0x6) in strcat +[returns 255] + +[test_bcheck_125] +112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcat +[returns 255] + +[test_bcheck_126] +112_backtrace.c:159: at main: BCHECK: ........ is outside of the region +112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0xb in strchr +[returns 255] + +[test_bcheck_127] +112_backtrace.c:161: at main: BCHECK: ........ is outside of the region +112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0xb in strdup +[returns 255] diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 4c86c189..a60686a7 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -20,6 +20,7 @@ 60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED' [test_63_local_enumerator_redefinition] +[returns 1] [test_61_undefined_enum] 60_errors_and_warnings.c:46: error: unknown type size diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index cec5b50f..a383bf46 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -24,6 +24,7 @@ ifeq (,$(filter i386,$(ARCH))) endif ifeq (,$(filter i386 x86_64,$(ARCH))) SKIP += 85_asm-outside-function.test + SKIP += 112_backtrace.test endif ifeq (-$(findstring gcc,$(CC))-,--) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) @@ -70,12 +71,11 @@ GEN-ALWAYS = # constructor/destructor 108_constructor.test: NORUN = true +112_backtrace.test: FLAGS += -dt -b +112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g' + # Filter source directory in warnings/errors (out-of-tree builds) -FILTER = 2>&1 | sed 's,$(SRC)/,,g' -# Filter some always-warning -ifeq (-$(findstring arm,$(ARCH))-,-arm-) -FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported' -endif +FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ; diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index ceb4411f..882299d1 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -138,7 +138,7 @@ copy>nul tcc-win32.txt doc @if errorlevel 1 goto :the_end :libtcc1.a -@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o +@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o .\tcc -m32 -c ../lib/libtcc1.c .\tcc -m32 -c lib/crt1.c .\tcc -m32 -c lib/crt1w.c @@ -147,7 +147,6 @@ copy>nul tcc-win32.txt doc .\tcc -m32 -c lib/dllcrt1.c .\tcc -m32 -c lib/dllmain.c .\tcc -m32 -c lib/chkstk.S -.\tcc -m32 -w -c ../lib/bcheck.c .\tcc -m32 -c ../lib/alloca86.S .\tcc -m32 -c ../lib/alloca86-bt.S .\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o @@ -160,11 +159,14 @@ copy>nul tcc-win32.txt doc .\tcc -m64 -c lib/dllcrt1.c .\tcc -m64 -c lib/dllmain.c .\tcc -m64 -c lib/chkstk.S -.\tcc -m64 -w -c ../lib/bcheck.c .\tcc -m64 -c ../lib/alloca86_64.S .\tcc -m64 -c ../lib/alloca86_64-bt.S .\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o @if errorlevel 1 goto :the_end +.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o +.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o +.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o +.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o :tcc-doc.html @if not (%DOC%)==(yes) goto :doc-done @@ -182,7 +184,7 @@ if not exist %INST% mkdir %INST% if not exist %BIN% mkdir %BIN% for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f @if not exist %INST%\lib mkdir %INST%\lib -for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f +for %%f in (lib\*.a lib\*.o lib\*.def) do @copy>nul %%f %INST%\%%f for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f :the_end diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c index 7f7e7980..abe31b9b 100644 --- a/win32/lib/crt1.c +++ b/win32/lib/crt1.c @@ -99,7 +99,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) #if defined __i386__ || defined __x86_64__ _controlfp(_PC_53, _MCW_PC); #endif - return do_main(__argc, __targv, _tenviron); + return _tmain(__argc, __targv, _tenviron); } // ============================================= diff --git a/x86_64-link.c b/x86_64-link.c index dcb2b90c..2dd4a50f 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -191,6 +191,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t if (s1->output_type == TCC_OUTPUT_DLL) { /* XXX: this logic may depend on TCC's codegen now TCC uses R_X86_64_32 even for a 64bit pointer */ + qrel->r_offset = rel->r_offset; qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); /* Use sign extension! */ qrel->r_addend = (int)read32le(ptr) + val;