- new LIBTCC API tcc_setjmp() to allow longjmps & signals from compiled code back to libtcc per TCCState - new LIBTCC API tcc_set_backtrace_func() to handle backtrace output - move c/dtor/atexit stuff to runtime (lib/runmain.c) - move bt-log.o into libtcc1.a - add timeouts to github action (beware, it did happen to hang infinitely in the signal handler at some point)
Unified · Split
| @@ -7,6 +7,7 @@ on: · 6 unmodified lines | ||
| 7 | 7 | jobs: |
| 8 | 8 | test-x86_64-linux: |
| 9 | 9 | runs-on: ubuntu-20.04 |
| 10 | + timeout-minutes: 2 | |
| 10 | 11 | steps: |
| 11 | 12 | - uses: actions/checkout@v4 |
| 12 | 13 | - name: make & test tcc |
| @@ -14,6 +15,7 @@ jobs: · 1 unmodified line | ||
| 14 | 15 | |
| 15 | 16 | test-x86_64-osx: |
| 16 | 17 | runs-on: macos-11 |
| 18 | + timeout-minutes: 2 | |
| 17 | 19 | steps: |
| 18 | 20 | - uses: actions/checkout@v4 |
| 19 | 21 | - name: make & test tcc |
| @@ -21,6 +23,7 @@ jobs: · 1 unmodified line | ||
| 21 | 23 | |
| 22 | 24 | test-x86_64-win32: |
| 23 | 25 | runs-on: windows-2019 |
| 26 | + timeout-minutes: 4 | |
| 24 | 27 | steps: |
| 25 | 28 | - uses: actions/checkout@v4 |
| 26 | 29 | - name: make & test tcc |
| @@ -33,6 +36,7 @@ jobs: · 6 unmodified lines | ||
| 33 | 36 | |
| 34 | 37 | test-armv7-linux: |
| 35 | 38 | runs-on: ubuntu-20.04 |
| 39 | + timeout-minutes: 6 | |
| 36 | 40 | steps: |
| 37 | 41 | - uses: actions/checkout@v4 |
| 38 | 42 | - uses: uraimo/run-on-arch-action@v2 |
| @@ -49,6 +53,7 @@ jobs: · 10 unmodified lines | ||
| 49 | 53 | |
| 50 | 54 | test-aarch64-linux: |
| 51 | 55 | runs-on: ubuntu-20.04 |
| 56 | + timeout-minutes: 6 | |
| 52 | 57 | steps: |
| 53 | 58 | - uses: actions/checkout@v4 |
| 54 | 59 | - uses: uraimo/run-on-arch-action@v2 |
| @@ -65,6 +70,7 @@ jobs: · 10 unmodified lines | ||
| 65 | 70 | |
| 66 | 71 | test-riscv64-linux: |
| 67 | 72 | runs-on: ubuntu-20.04 |
| 73 | + timeout-minutes: 6 | |
| 68 | 74 | steps: |
| 69 | 75 | - uses: actions/checkout@v4 |
| 70 | 76 | - uses: uraimo/run-on-arch-action@v2 |
| @@ -29,6 +29,9 @@ ifdef CONFIG_WIN32 · 28 unmodified lines | ||
| 29 | 29 | ifneq ($(CONFIG_static),yes) |
| 30 | 30 | LIBTCC = libtcc$(DLLSUF) |
| 31 | 31 | LIBTCCDEF = libtcc.def |
| 32 | + -LTCC = $(bindir)/libtcc.dll | |
| 33 | + else | |
| 34 | + -LTCC = -ltcc -L$(libdir) | |
| 32 | 35 | endif |
| 33 | 36 | ifneq ($(CONFIG_debug),yes) |
| 34 | 37 | LDFLAGS += -s |
| @@ -70,6 +73,7 @@ else · 35 unmodified lines | ||
| 70 | 73 | endif |
| 71 | 74 | export MACOSX_DEPLOYMENT_TARGET := 10.6 |
| 72 | 75 | endif |
| 76 | + -LTCC = -ltcc | |
| 73 | 77 | endif |
| 74 | 78 | |
| 75 | 79 | # run local version of tcc with local libraries and includes |
| @@ -79,6 +83,15 @@ TCCFLAGS = $(TCCFLAGS$(CFG)) · 3 unmodified lines | ||
| 79 | 83 | TCC_LOCAL = $(TOP)/tcc$(EXESUF) |
| 80 | 84 | TCC = $(TCC_LOCAL) $(TCCFLAGS) |
| 81 | 85 | |
| 86 | +# run tests with the installed tcc instead | |
| 87 | +ifdef TESTINSTALL | |
| 88 | + TCC_LOCAL = $(bindir)/tcc | |
| 89 | + TCCFLAGS-unx = -I.. | |
| 90 | + TCCFLAGS-win = -I.. -B$(bindir) | |
| 91 | + LIBTCC = | |
| 92 | + LIBS += $(-LTCC) | |
| 93 | +endif | |
| 94 | + | |
| 82 | 95 | CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE |
| 83 | 96 | LIBS_P = $(LIBS) |
| 84 | 97 | LDFLAGS_P = $(LDFLAGS) |
| @@ -373,7 +386,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2 · 288 unmodified lines | ||
| 373 | 386 | IM = @echo "-> $2 : $1" ; |
| 374 | 387 | BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1) |
| 375 | 388 | |
| 376 | −B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o | |
| 389 | +B_O = runmain.o bt-exe.o bt-dll.o bcheck.o | |
| 377 | 390 | |
| 378 | 391 | # install progs & libs |
| 379 | 392 | install-unx: |
| @@ -411,7 +424,7 @@ install-win: · 31 unmodified lines | ||
| 411 | 424 | $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include") |
| 412 | 425 | $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples") |
| 413 | 426 | $(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples") |
| 414 | − $(call IFw,$(TOPSRC)/libtcc.h libtcc.def,"$(libdir)") | |
| 427 | + $(call IFw,$(TOPSRC)/libtcc.h libtcc.def libtcc.a,"$(libdir)") | |
| 415 | 428 | $(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)") |
| 416 | 429 | ifneq "$(wildcard $(LIBTCC1_U))" "" |
| 417 | 430 | $(call IFw,$(LIBTCC1_U),"$(tccdir)/lib") |
| @@ -420,9 +433,9 @@ endif · 2 unmodified lines | ||
| 420 | 433 | |
| 421 | 434 | # uninstall on windows |
| 422 | 435 | uninstall-win: |
| 423 | − @rm -fv $(addprefix "$(bindir)/", libtcc*.dll $(PROGS) *-tcc.exe) | |
| 424 | − @rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P/*") | |
| 425 | − @rm -frv $(addprefix "$(tccdir)/", doc examples include lib libtcc) | |
| 436 | + @rm -fv $(foreach P,libtcc*.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P) | |
| 437 | + @rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P/*) | |
| 438 | + @rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P) | |
| 426 | 439 | |
| 427 | 440 | # the msys-git shell works to configure && make except it does not have install |
| 428 | 441 | ifeq ($(OS),Windows_NT) |
| @@ -473,6 +486,9 @@ tcov-tes% : tcc_c$(EXESUF) · 44 unmodified lines | ||
| 473 | 486 | @$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$* |
| 474 | 487 | tcc_c$(EXESUF): $($T_FILES) |
| 475 | 488 | $S$(TCC) tcc.c -o $@ -ftest-coverage $(DEFINES) $(LIBS) |
| 489 | +# test the installed tcc instead | |
| 490 | +test-install: tccdefs_.h | |
| 491 | + @$(MAKE) -C tests TESTINSTALL=yes #_all | |
| 476 | 492 | |
| 477 | 493 | clean: |
| 478 | 494 | @rm -f tcc$(EXESUF) tcc_c$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) |
| @@ -506,6 +522,8 @@ help: · 27 unmodified lines | ||
| 506 | 522 | @echo " run all/single test(s) from tests/pp" |
| 507 | 523 | @echo "make tcov-test / tcov-tests2... / tcov-testspp..." |
| 508 | 524 | @echo " run tests as above with code coverage. After test(s) see tcc_c$(EXESUF).tcov" |
| 525 | + @echo "make test-install" | |
| 526 | + @echo " run tests with the installed tcc" | |
| 509 | 527 | @echo "Other supported make targets:" |
| 510 | 528 | @echo " install install-strip doc clean tags ETAGS tar distclean help" |
| 511 | 529 | @echo "Custom configuration:" |
| @@ -67,7 +67,8 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) · 66 unmodified lines | ||
| 67 | 67 | OBJ-arm-wince = $(ARM_O) $(WIN_O) |
| 68 | 68 | OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O) |
| 69 | 69 | |
| 70 | −OBJ-extra = $(filter $(B_O),$(OBJ-$T)) | |
| 70 | +OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T))) | |
| 71 | +OBJ-extra += runmain.o | |
| 71 | 72 | OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) |
| 72 | 73 | |
| 73 | 74 | ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) |
| @@ -26,14 +26,14 @@ void __bt_init(rt_context *p, int is_exe) · 25 unmodified lines | ||
| 26 | 26 | __bound_init(p->bounds_start, -1); |
| 27 | 27 | |
| 28 | 28 | /* add to chain */ |
| 29 | − WAIT_SEM(&rt_sem); | |
| 29 | + rt_wait_sem(); | |
| 30 | 30 | p->next = g_rc, g_rc = p; |
| 31 | − if (is_exe) | |
| 31 | + rt_post_sem(); | |
| 32 | + if (is_exe) { | |
| 32 | 33 | /* we are the executable (not a dll) */ |
| 33 | 34 | p->top_func = main; |
| 34 | − POST_SEM(&rt_sem); | |
| 35 | − if (is_exe) | |
| 36 | 35 | set_exception_handler(); |
| 36 | + } | |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | __declspec(dllexport) |
| @@ -48,13 +48,13 @@ void __bt_exit(rt_context *p) · 8 unmodified lines | ||
| 48 | 48 | __bound_exit_dll(p->bounds_start); |
| 49 | 49 | |
| 50 | 50 | /* remove from chain */ |
| 51 | − WAIT_SEM(&rt_sem); | |
| 51 | + rt_wait_sem(); | |
| 52 | 52 | for (pp = &g_rc; rc = *pp, rc; pp = &rc->next) |
| 53 | 53 | if (rc == p) { |
| 54 | 54 | *pp = rc->next; |
| 55 | 55 | break; |
| 56 | 56 | } |
| 57 | − POST_SEM(&rt_sem); | |
| 57 | + rt_post_sem(); | |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | /* copy a string and truncate it. */ |
| @@ -18,25 +18,24 @@ · 17 unmodified lines | ||
| 18 | 18 | #pragma GCC diagnostic ignored "-Wframe-address" |
| 19 | 19 | #endif |
| 20 | 20 | |
| 21 | −typedef struct rt_frame | |
| 22 | −{ | |
| 21 | +typedef struct rt_frame { | |
| 23 | 22 | void *ip, *fp, *sp; |
| 24 | 23 | } rt_frame; |
| 25 | 24 | |
| 26 | 25 | __attribute__((weak)) |
| 27 | −int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap); | |
| 26 | +int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); | |
| 28 | 27 | |
| 29 | 28 | DLL_EXPORT int tcc_backtrace(const char *fmt, ...) |
| 30 | 29 | { |
| 31 | 30 | va_list ap; |
| 32 | 31 | int ret; |
| 33 | 32 | |
| 34 | − if (_rt_error) { | |
| 33 | + if (__rt_dump) { | |
| 35 | 34 | rt_frame f; |
| 36 | 35 | f.fp = __builtin_frame_address(1); |
| 37 | 36 | f.ip = __builtin_return_address(0); |
| 38 | 37 | va_start(ap, fmt); |
| 39 | − ret = _rt_error(&f, "", fmt, ap); | |
| 38 | + ret = __rt_dump(&f, NULL, fmt, ap); | |
| 40 | 39 | va_end(ap); |
| 41 | 40 | } else { |
| 42 | 41 | const char *p, *nl = "\n"; |
| @@ -0,0 +1,87 @@ | ||
| 1 | +/* ------------------------------------------------------------- */ | |
| 2 | +/* support for tcc_run() */ | |
| 3 | + | |
| 4 | +#ifdef __leading_underscore | |
| 5 | +# define _(s) s | |
| 6 | +#else | |
| 7 | +# define _(s) _##s | |
| 8 | +#endif | |
| 9 | + | |
| 10 | +#ifndef _WIN32 | |
| 11 | +extern void (*_(_init_array_start)[]) (int argc, char **argv, char **envp); | |
| 12 | +extern void (*_(_init_array_end)[]) (int argc, char **argv, char **envp); | |
| 13 | +static void run_ctors(int argc, char **argv, char **env) | |
| 14 | +{ | |
| 15 | + int i = 0; | |
| 16 | + while (&_(_init_array_start)[i] != _(_init_array_end)) | |
| 17 | + (*_(_init_array_start)[i++])(argc, argv, env); | |
| 18 | +} | |
| 19 | +#endif | |
| 20 | + | |
| 21 | +extern void (*_(_fini_array_start)[]) (void); | |
| 22 | +extern void (*_(_fini_array_end)[]) (void); | |
| 23 | +static void run_dtors(void) | |
| 24 | +{ | |
| 25 | + int i = 0; | |
| 26 | + while (&_(_fini_array_end)[i] != _(_fini_array_start)) | |
| 27 | + (*_(_fini_array_end)[--i])(); | |
| 28 | +} | |
| 29 | + | |
| 30 | +static void *rt_exitfunc[32]; | |
| 31 | +static void *rt_exitarg[32]; | |
| 32 | +int __rt_nr_exit; | |
| 33 | + | |
| 34 | +void __run_on_exit(int ret) | |
| 35 | +{ | |
| 36 | + int n = __rt_nr_exit; | |
| 37 | + while (n) | |
| 38 | + --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]); | |
| 39 | +} | |
| 40 | + | |
| 41 | +int on_exit(void *function, void *arg) | |
| 42 | +{ | |
| 43 | + int n = __rt_nr_exit; | |
| 44 | + if (n < 32) { | |
| 45 | + rt_exitfunc[n] = function; | |
| 46 | + rt_exitarg[n] = arg; | |
| 47 | + __rt_nr_exit = n + 1; | |
| 48 | + return 0; | |
| 49 | + } | |
| 50 | + return 1; | |
| 51 | +} | |
| 52 | + | |
| 53 | +int atexit(void (*function)(void)) | |
| 54 | +{ | |
| 55 | + return on_exit(function, 0); | |
| 56 | +} | |
| 57 | + | |
| 58 | +typedef struct rt_frame { | |
| 59 | + void *ip, *fp, *sp; | |
| 60 | +} rt_frame; | |
| 61 | + | |
| 62 | +void __rt_longjmp(rt_frame *, int); | |
| 63 | + | |
| 64 | +void exit(int code) | |
| 65 | +{ | |
| 66 | + rt_frame f; | |
| 67 | + run_dtors(); | |
| 68 | + __run_on_exit(code); | |
| 69 | + f.fp = __builtin_frame_address(1); | |
| 70 | + f.ip = __builtin_return_address(0); | |
| 71 | + __rt_longjmp(&f, code); | |
| 72 | +} | |
| 73 | + | |
| 74 | +#ifndef _WIN32 | |
| 75 | +int main(int, char**, char**); | |
| 76 | + | |
| 77 | +int _runmain(int argc, char **argv, char **envp) | |
| 78 | +{ | |
| 79 | + int ret; | |
| 80 | + __rt_nr_exit = 0; | |
| 81 | + run_ctors(argc, argv, envp); | |
| 82 | + ret = main(argc, argv, envp); | |
| 83 | + run_dtors(); | |
| 84 | + __run_on_exit(ret); | |
| 85 | + return ret; | |
| 86 | +} | |
| 87 | +#endif | |
| @@ -100,6 +100,17 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); · 99 unmodified lines | ||
| 100 | 100 | LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, |
| 101 | 101 | void (*symbol_cb)(void *ctx, const char *name, const void *val)); |
| 102 | 102 | |
| 103 | +/* experimental/advanced section (see libtcc_test_mt.c for an example) */ | |
| 104 | + | |
| 105 | +/* catch runtime exceptions (optionally limit backtraces at top_func), | |
| 106 | + when using tcc_set_options("-bt") and when not using tcc_run() */ | |
| 107 | +LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *longjmp, void *jmp_buf, void *top_func); | |
| 108 | +#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, longjmp, jb, f)) | |
| 109 | + | |
| 110 | +/* set custom error printer for runtime exceptions */ | |
| 111 | +typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func); | |
| 112 | +LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*); | |
| 113 | + | |
| 103 | 114 | #ifdef __cplusplus |
| 104 | 115 | } |
| 105 | 116 | #endif |
| @@ -1000,6 +1000,10 @@ struct TCCState { · 999 unmodified lines | ||
| 1000 | 1000 | #ifdef _WIN64 |
| 1001 | 1001 | void *run_function_table; /* unwind data */ |
| 1002 | 1002 | #endif |
| 1003 | + struct TCCState *next; | |
| 1004 | + struct rt_context *rc; /* pointer to backtrace info block */ | |
| 1005 | + void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */ | |
| 1006 | + void (*bt_func)(void *, const char*, int, const char*); | |
| 1003 | 1007 | #endif |
| 1004 | 1008 | |
| 1005 | 1009 | #ifdef CONFIG_TCC_BACKTRACE |
| @@ -1778,8 +1778,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 1777 unmodified lines | ||
| 1778 | 1778 | if (s1->do_backtrace) { |
| 1779 | 1779 | if (s1->output_type & TCC_OUTPUT_EXE) |
| 1780 | 1780 | tcc_add_support(s1, "bt-exe.o"); |
| 1781 | − if (s1->output_type != TCC_OUTPUT_DLL) | |
| 1782 | − tcc_add_support(s1, "bt-log.o"); | |
| 1783 | 1781 | tcc_add_btstub(s1); |
| 1784 | 1782 | lpthread = 1; |
| 1785 | 1783 | } |
| @@ -1961,8 +1961,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 1960 unmodified lines | ||
| 1961 | 1961 | tcc_add_support(s1, "bt-exe.o"); |
| 1962 | 1962 | if (s1->output_type == TCC_OUTPUT_DLL) |
| 1963 | 1963 | tcc_add_support(s1, "bt-dll.o"); |
| 1964 | − if (s1->output_type != TCC_OUTPUT_DLL) | |
| 1965 | − tcc_add_support(s1, "bt-log.o"); | |
| 1966 | 1964 | tcc_add_btstub(s1); |
| 1967 | 1965 | } |
| 1968 | 1966 | #endif |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #ifdef CONFIG_TCC_BACKTRACE |
| 27 | 27 | typedef struct rt_context |
| 28 | 28 | { |
| 29 | − /* --> tccelf.c:tcc_add_btstub wants those below in that order: */ | |
| 29 | + /* tccelf.c:tcc_add_btstub() wants these in that order: */ | |
| 30 | 30 | union { |
| 31 | 31 | struct { |
| 32 | 32 | Stab_Sym *stab_sym; |
| @@ -42,55 +42,33 @@ typedef struct rt_context · 9 unmodified lines | ||
| 42 | 42 | ElfW(Sym) *esym_start; |
| 43 | 43 | ElfW(Sym) *esym_end; |
| 44 | 44 | char *elf_str; |
| 45 | − | |
| 45 | + // 6 | |
| 46 | 46 | addr_t prog_base; |
| 47 | 47 | void *bounds_start; |
| 48 | 48 | void *top_func; |
| 49 | 49 | TCCState *s1; |
| 50 | 50 | struct rt_context *next; |
| 51 | − | |
| 51 | + // 11 | |
| 52 | 52 | int num_callers; |
| 53 | 53 | int dwarf; |
| 54 | − /* <-- */ | |
| 55 | 54 | } rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */ |
| 56 | 55 | |
| 57 | −typedef struct rt_frame | |
| 58 | −{ | |
| 56 | +typedef struct rt_frame { | |
| 59 | 57 | addr_t ip, fp, sp; |
| 60 | 58 | } rt_frame; |
| 61 | 59 | |
| 62 | 60 | /* linked list of rt_contexts */ |
| 63 | 61 | static rt_context *g_rc; |
| 62 | +static TCCState *g_s1; | |
| 64 | 63 | /* semaphore to protect it */ |
| 65 | 64 | TCC_SEM(static rt_sem); |
| 66 | 65 | static int signal_set; |
| 67 | 66 | static void set_exception_handler(void); |
| 68 | − | |
| 69 | −#ifdef _WIN32 | |
| 70 | −#define ATTR_WEAK | |
| 71 | −#else | |
| 72 | −#define ATTR_WEAK __attribute__((weak)) | |
| 73 | −#endif | |
| 74 | −int ATTR_WEAK _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap); | |
| 75 | −void ATTR_WEAK rt_wait_sem(void) { WAIT_SEM(&rt_sem); } | |
| 76 | −void ATTR_WEAK rt_post_sem(void) { POST_SEM(&rt_sem); } | |
| 77 | −#undef ATTR_WEAK | |
| 67 | +static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); } | |
| 68 | +static void rt_post_sem(void) { POST_SEM(&rt_sem); } | |
| 69 | +static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); | |
| 78 | 70 | #endif /* def CONFIG_TCC_BACKTRACE */ |
| 79 | 71 | |
| 80 | −/* handle exit/atexit for tcc_run() -- thread-unsafe */ | |
| 81 | −static jmp_buf rt_jb; | |
| 82 | −static int rt_do_jmp; | |
| 83 | −static int rt_nr_exit; | |
| 84 | −static void *rt_exitfunc[32]; | |
| 85 | −static void *rt_exitarg[32]; | |
| 86 | − | |
| 87 | −static void rt_exit(int code) | |
| 88 | −{ | |
| 89 | − if (rt_do_jmp) | |
| 90 | − longjmp(rt_jb, code ? code : 256); | |
| 91 | − exit(code); | |
| 92 | −} | |
| 93 | − | |
| 94 | 72 | /* ------------------------------------------------------------- */ |
| 95 | 73 | /* defined when included from lib/bt-exe.c */ |
| 96 | 74 | #ifndef CONFIG_TCC_BACKTRACE_ONLY |
| @@ -101,7 +79,8 @@ static void rt_exit(int code) · 4 unmodified lines | ||
| 101 | 79 | |
| 102 | 80 | static int protect_pages(void *ptr, unsigned long length, int mode); |
| 103 | 81 | static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff); |
| 104 | − | |
| 82 | +static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); | |
| 83 | +static void rt_longjmp(rt_frame *f, int code); | |
| 105 | 84 | #ifdef _WIN64 |
| 106 | 85 | static void *win64_add_function_table(TCCState *s1); |
| 107 | 86 | static void win64_del_function_table(void *); |
| @@ -118,12 +97,9 @@ static void bt_link(TCCState *s1) · 10 unmodified lines | ||
| 118 | 97 | rc = tcc_get_symbol(s1, "__rt_info"); |
| 119 | 98 | if (!rc) |
| 120 | 99 | return; |
| 121 | − rt_wait_sem(); | |
| 122 | − rc->next = g_rc, g_rc = rc, rc->s1 = s1; | |
| 123 | 100 | rc->esym_start = (ElfW(Sym) *)(symtab_section->data); |
| 124 | 101 | rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); |
| 125 | 102 | rc->elf_str = (char *)symtab_section->link->data; |
| 126 | − rc->top_func = tcc_get_symbol(s1, "main"); | |
| 127 | 103 | if (PTR_SIZE == 8 && !s1->dwarf) |
| 128 | 104 | rc->prog_base &= 0xffffffff00000000ULL; |
| 129 | 105 | #ifdef CONFIG_TCC_BCHECK |
| @@ -132,7 +108,7 @@ static void bt_link(TCCState *s1) · 2 unmodified lines | ||
| 132 | 108 | ((void(*)(void*,int))p)(rc->bounds_start, 1); |
| 133 | 109 | } |
| 134 | 110 | #endif |
| 135 | − rt_post_sem(); | |
| 111 | + rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc; | |
| 136 | 112 | if (0 == signal_set) |
| 137 | 113 | set_exception_handler(), signal_set = 1; |
| 138 | 114 | #endif |
| @@ -142,16 +118,35 @@ static void bt_unlink(TCCState *s1) · 3 unmodified lines | ||
| 142 | 118 | { |
| 143 | 119 | #ifdef CONFIG_TCC_BACKTRACE |
| 144 | 120 | rt_context *rc, **pp; |
| 145 | − rt_wait_sem(); | |
| 146 | 121 | for (pp = &g_rc; rc = *pp, rc; pp = &rc->next) |
| 147 | 122 | if (rc->s1 == s1) { |
| 148 | 123 | *pp = rc->next; |
| 149 | 124 | break; |
| 150 | 125 | } |
| 151 | − rt_post_sem(); | |
| 152 | 126 | #endif |
| 153 | 127 | } |
| 154 | 128 | |
| 129 | +static void st_link(TCCState *s1) | |
| 130 | +{ | |
| 131 | + rt_wait_sem(); | |
| 132 | + s1->next = g_s1, g_s1 = s1; | |
| 133 | + bt_link(s1); | |
| 134 | + rt_post_sem(); | |
| 135 | +} | |
| 136 | + | |
| 137 | +static void st_unlink(TCCState *s1) | |
| 138 | +{ | |
| 139 | + TCCState *s2, **pp; | |
| 140 | + rt_wait_sem(); | |
| 141 | + bt_unlink(s1); | |
| 142 | + for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next) | |
| 143 | + if (s2 == s1) { | |
| 144 | + *pp = s2->next; | |
| 145 | + break; | |
| 146 | + } | |
| 147 | + rt_post_sem(); | |
| 148 | +} | |
| 149 | + | |
| 155 | 150 | #if !_WIN32 && !__APPLE__ |
| 156 | 151 | //#define HAVE_SELINUX 1 |
| 157 | 152 | #endif |
| @@ -196,9 +191,8 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) · 38 unmodified lines | ||
| 196 | 191 | exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported")); |
| 197 | 192 | |
| 198 | 193 | #ifdef CONFIG_TCC_BACKTRACE |
| 199 | − /* for bt-log.c (but not when 'tcc -bt -run tcc.c') */ | |
| 200 | − if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error")) | |
| 201 | − tcc_add_symbol(s1, "_rt_error", _rt_error); | |
| 194 | + if (s1->do_backtrace) | |
| 195 | + tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */ | |
| 202 | 196 | #endif |
| 203 | 197 | |
| 204 | 198 | size = tcc_relocate_ex(s1, NULL, 0); |
| @@ -209,7 +203,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) · 4 unmodified lines | ||
| 209 | 203 | return -1; |
| 210 | 204 | ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff); |
| 211 | 205 | if (ret == 0) |
| 212 | − bt_link(s1); | |
| 206 | + st_link(s1); | |
| 213 | 207 | return ret; |
| 214 | 208 | } |
| 215 | 209 | |
| @@ -231,12 +225,11 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 15 unmodified lines | ||
| 231 | 225 | } |
| 232 | 226 | /* free loaded dlls array */ |
| 233 | 227 | dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); |
| 234 | − | |
| 235 | 228 | /* unmap or unprotect and free memory */ |
| 236 | 229 | ptr = s1->run_ptr; |
| 237 | 230 | if (NULL == ptr) |
| 238 | 231 | return; |
| 239 | − bt_unlink(s1); | |
| 232 | + st_unlink(s1); | |
| 240 | 233 | size = s1->run_size; |
| 241 | 234 | #ifdef HAVE_SELINUX |
| 242 | 235 | munmap(ptr, size * 2); |
| @@ -250,41 +243,25 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 7 unmodified lines | ||
| 250 | 243 | #endif |
| 251 | 244 | } |
| 252 | 245 | |
| 253 | −static void run_cdtors(TCCState *s1, const char *start, const char *end, | |
| 254 | − int argc, char **argv, char **envp) | |
| 246 | +LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func) | |
| 255 | 247 | { |
| 256 | − void **a = (void **)get_sym_addr(s1, start, 0, 0); | |
| 257 | − void **b = (void **)get_sym_addr(s1, end, 0, 0); | |
| 258 | − while (a != b) | |
| 259 | − ((void(*)(int, char **, char **))*a++)(argc, argv, envp); | |
| 248 | + s1->run_lj = p_longjmp; | |
| 249 | + s1->run_jb = p_jmp_buf; | |
| 250 | + if (func && s1->rc) | |
| 251 | + s1->rc->top_func = func; | |
| 252 | + return p_jmp_buf; | |
| 260 | 253 | } |
| 261 | 254 | |
| 262 | −static void run_on_exit(int ret) | |
| 255 | +LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func) | |
| 263 | 256 | { |
| 264 | − int n = rt_nr_exit; | |
| 265 | − while (n) | |
| 266 | − --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]); | |
| 267 | −} | |
| 268 | − | |
| 269 | −static int rt_on_exit(void *function, void *arg) | |
| 270 | −{ | |
| 271 | − if (rt_nr_exit < countof(rt_exitfunc)) { | |
| 272 | − rt_exitfunc[rt_nr_exit] = function; | |
| 273 | − rt_exitarg[rt_nr_exit++] = arg; | |
| 274 | − return 0; | |
| 275 | − } | |
| 276 | − return 1; | |
| 277 | −} | |
| 278 | − | |
| 279 | −static int rt_atexit(void *function) | |
| 280 | −{ | |
| 281 | − return rt_on_exit(function, NULL); | |
| 257 | + s1->bt_func = func; | |
| 282 | 258 | } |
| 283 | 259 | |
| 284 | 260 | /* launch the compiled program with the given arguments */ |
| 285 | 261 | LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) |
| 286 | 262 | { |
| 287 | 263 | int (*prog_main)(int, char **, char **), ret; |
| 264 | + jmp_buf main_jb; | |
| 288 | 265 | |
| 289 | 266 | #if defined(__APPLE__) || defined(__FreeBSD__) |
| 290 | 267 | char **envp = NULL; |
| @@ -295,35 +272,29 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 4 unmodified lines | ||
| 295 | 272 | char **envp = environ; |
| 296 | 273 | #endif |
| 297 | 274 | |
| 298 | − s1->run_main = s1->nostdlib ? "_start" : "main"; | |
| 299 | − if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1)) | |
| 275 | + /* tcc -dt -run ... nothing to do if no main() */ | |
| 276 | + if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1)) | |
| 300 | 277 | return 0; |
| 301 | 278 | |
| 302 | − tcc_add_symbol(s1, "exit", rt_exit); | |
| 303 | − tcc_add_symbol(s1, "atexit", rt_atexit); | |
| 304 | − tcc_add_symbol(s1, "on_exit", rt_on_exit); | |
| 279 | + tcc_add_support(s1, "runmain.o"); | |
| 280 | + tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp); | |
| 281 | + s1->run_main = (s1->nostdlib ? "_start" : "_runmain"); | |
| 305 | 282 | if (tcc_relocate(s1) < 0) |
| 306 | 283 | return -1; |
| 307 | 284 | |
| 308 | 285 | prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1); |
| 309 | 286 | if ((addr_t)-1 == (addr_t)prog_main) |
| 310 | 287 | return -1; |
| 311 | − | |
| 312 | 288 | errno = 0; /* clean errno value */ |
| 313 | 289 | fflush(stdout); |
| 314 | 290 | fflush(stderr); |
| 315 | − rt_do_jmp = 1; | |
| 316 | − rt_nr_exit = 0; | |
| 317 | 291 | |
| 318 | − /* These aren't C symbols, so don't need leading underscore handling. */ | |
| 319 | − run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp); | |
| 320 | − ret = setjmp(rt_jb); | |
| 292 | + ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main")); | |
| 321 | 293 | if (0 == ret) |
| 322 | 294 | ret = prog_main(argc, argv, envp); |
| 323 | 295 | else if (256 == ret) |
| 324 | 296 | ret = 0; |
| 325 | − run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL); | |
| 326 | − run_on_exit(ret); | |
| 297 | + | |
| 327 | 298 | if (s1->dflag & 16 && ret) /* tcc -dt -run ... */ |
| 328 | 299 | fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp); |
| 329 | 300 | return ret; |
| @@ -385,7 +356,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) · 55 unmodified lines | ||
| 385 | 356 | addr_t mem, addr; |
| 386 | 357 | |
| 387 | 358 | if (NULL == ptr) { |
| 388 | − s1->nb_errors = 0; | |
| 389 | 359 | #ifdef TCC_TARGET_PE |
| 390 | 360 | pe_output_file(s1, NULL); |
| 391 | 361 | #else |
| @@ -616,7 +586,7 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr) · 224 unmodified lines | ||
| 616 | 586 | /* print the position in the source file of PC value 'pc' by reading |
| 617 | 587 | the stabs debug information */ |
| 618 | 588 | static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, |
| 619 | − const char *msg, const char *skip) | |
| 589 | + rt_context** prc, const char *msg, const char *skip) | |
| 620 | 590 | { |
| 621 | 591 | char func_name[128]; |
| 622 | 592 | addr_t func_addr, last_pc, pc; |
| @@ -726,14 +696,21 @@ next: · 103 unmodified lines | ||
| 726 | 696 | |
| 727 | 697 | found: |
| 728 | 698 | i = last_incl_index; |
| 699 | + str = NULL; | |
| 729 | 700 | if (i > 0) { |
| 730 | 701 | str = incl_files[--i]; |
| 731 | 702 | if (skip[0] && strstr(str, skip)) |
| 732 | 703 | return (addr_t)-1; |
| 733 | − rt_printf("%s:%d: ", str, last_line_num); | |
| 734 | − } else | |
| 735 | − rt_printf("%08llx : ", (long long)wanted_pc); | |
| 736 | − rt_printf("%s %s", msg, func_name[0] ? func_name : "???"); | |
| 704 | + } | |
| 705 | + if (rc && rc->s1 && rc->s1->bt_func) { | |
| 706 | + rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL); | |
| 707 | + } else { | |
| 708 | + if (str) | |
| 709 | + rt_printf("%s:%d: ", str, last_line_num); | |
| 710 | + else | |
| 711 | + rt_printf("%08llx : ", (long long)wanted_pc); | |
| 712 | + rt_printf("%s %s", msg, func_name[0] ? func_name : "???"); | |
| 713 | + } | |
| 737 | 714 | #if 0 |
| 738 | 715 | if (--i >= 0) { |
| 739 | 716 | rt_printf(" (included from "); |
| @@ -746,6 +723,7 @@ found: · 6 unmodified lines | ||
| 746 | 723 | rt_printf(")"); |
| 747 | 724 | } |
| 748 | 725 | #endif |
| 726 | + *prc = rc; | |
| 749 | 727 | return func_addr; |
| 750 | 728 | } |
| 751 | 729 | |
| @@ -816,7 +794,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) · 64 unmodified lines | ||
| 816 | 794 | } |
| 817 | 795 | |
| 818 | 796 | static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, |
| 819 | − const char *msg, const char *skip) | |
| 797 | + rt_context** prc, const char *msg, const char *skip) | |
| 820 | 798 | { |
| 821 | 799 | unsigned char *ln; |
| 822 | 800 | unsigned char *cp; |
| @@ -859,6 +837,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, · 36 unmodified lines | ||
| 859 | 837 | next: |
| 860 | 838 | filename = NULL; |
| 861 | 839 | func_addr = 0; |
| 840 | + line = 0; | |
| 862 | 841 | if (NULL == rc) |
| 863 | 842 | goto found; |
| 864 | 843 | |
| @@ -1102,29 +1081,33 @@ next_line: · 237 unmodified lines | ||
| 1102 | 1081 | goto next; |
| 1103 | 1082 | |
| 1104 | 1083 | found: |
| 1105 | − if (filename) { | |
| 1106 | − if (skip[0] && strstr(filename, skip)) | |
| 1107 | − return (addr_t)-1; | |
| 1108 | − rt_printf("%s:%d: ", filename, line); | |
| 1084 | + if (rc && rc->s1 && rc->s1->bt_func) { | |
| 1085 | + rc->s1->bt_func((void*)wanted_pc, filename, line, function); | |
| 1086 | + } else { | |
| 1087 | + if (filename) { | |
| 1088 | + if (skip[0] && strstr(filename, skip)) | |
| 1089 | + return (addr_t)-1; | |
| 1090 | + rt_printf("%s:%d: ", filename, line); | |
| 1091 | + } | |
| 1092 | + else | |
| 1093 | + rt_printf("0x%08llx : ", (long long)wanted_pc); | |
| 1094 | + rt_printf("%s %s", msg, function ? function : "???"); | |
| 1109 | 1095 | } |
| 1110 | − else | |
| 1111 | − rt_printf("0x%08llx : ", (long long)wanted_pc); | |
| 1112 | − rt_printf("%s %s", msg, function ? function : "???"); | |
| 1096 | + *prc = rc; | |
| 1113 | 1097 | return (addr_t)func_addr; |
| 1114 | 1098 | } |
| 1115 | 1099 | /* ------------------------------------------------------------- */ |
| 1116 | − | |
| 1117 | −static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); | |
| 1118 | − | |
| 1119 | −int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap) | |
| 1100 | +#ifndef CONFIG_TCC_BACKTRACE_ONLY | |
| 1101 | +static | |
| 1102 | +#endif | |
| 1103 | +int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) | |
| 1120 | 1104 | { |
| 1121 | − rt_context *rc; | |
| 1105 | + rt_context *rc, *rd; | |
| 1122 | 1106 | addr_t pc = 0; |
| 1123 | 1107 | char skip[100]; |
| 1124 | 1108 | int i, level, ret, n, one; |
| 1125 | 1109 | const char *a, *b; |
| 1126 | − addr_t (*printline)(rt_context*, addr_t, const char*, const char*); | |
| 1127 | − addr_t top_func = 0; | |
| 1110 | + addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*); | |
| 1128 | 1111 | |
| 1129 | 1112 | skip[0] = 0; |
| 1130 | 1113 | /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ |
| @@ -1145,27 +1128,28 @@ int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap) · 14 unmodified lines | ||
| 1145 | 1128 | printline = rt_printline_dwarf; |
| 1146 | 1129 | if (rc->num_callers) |
| 1147 | 1130 | n = rc->num_callers; |
| 1148 | − top_func = (addr_t)rc->top_func; | |
| 1149 | 1131 | } |
| 1150 | − | |
| 1151 | 1132 | for (i = level = 0; level < n; i++) { |
| 1152 | 1133 | ret = rt_get_caller_pc(&pc, f, i); |
| 1153 | − a = "%s"; | |
| 1154 | 1134 | if (ret != -1) { |
| 1155 | − pc = printline(rc, pc, level ? "by" : "at", skip); | |
| 1135 | + pc = printline(rc, pc, &rd, level ? "by" : "at", skip); | |
| 1156 | 1136 | if (pc == (addr_t)-1) |
| 1157 | 1137 | continue; |
| 1158 | − a = ": %s"; | |
| 1159 | 1138 | } |
| 1160 | 1139 | if (level == 0) { |
| 1161 | − rt_printf(a, msg); | |
| 1140 | + if (rd && rd->s1 && rd->s1->bt_func) | |
| 1141 | + break; | |
| 1142 | + if (ret != -1) | |
| 1143 | + rt_printf(": "); | |
| 1144 | + if (msg) | |
| 1145 | + rt_printf("%s: ", msg); | |
| 1162 | 1146 | rt_vprintf(fmt, ap); |
| 1163 | 1147 | } else if (ret == -1) |
| 1164 | 1148 | break; |
| 1165 | 1149 | if (one) |
| 1166 | 1150 | break; |
| 1167 | 1151 | rt_printf("\n"); |
| 1168 | − if (ret == -1 || (pc == top_func && pc)) | |
| 1152 | + if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc)) | |
| 1169 | 1153 | break; |
| 1170 | 1154 | ++level; |
| 1171 | 1155 | } |
| @@ -1180,11 +1164,46 @@ static int rt_error(rt_frame *f, const char *fmt, ...) · 8 unmodified lines | ||
| 1180 | 1164 | va_list ap; |
| 1181 | 1165 | int ret; |
| 1182 | 1166 | va_start(ap, fmt); |
| 1183 | − ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap); | |
| 1167 | + ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap); | |
| 1184 | 1168 | va_end(ap); |
| 1185 | 1169 | return ret; |
| 1186 | 1170 | } |
| 1187 | 1171 | |
| 1172 | +static TCCState *rt_find_state(rt_frame *f) | |
| 1173 | +{ | |
| 1174 | + TCCState *s; | |
| 1175 | + int level; | |
| 1176 | + addr_t pc; | |
| 1177 | + | |
| 1178 | + rt_wait_sem(); | |
| 1179 | + for (s = g_s1; s; s = s->next) { | |
| 1180 | + if (0 == s->run_lj) | |
| 1181 | + continue; | |
| 1182 | + for (level = 0; level < 8; ++level) { | |
| 1183 | + if (rt_get_caller_pc(&pc, f, level) < 0) | |
| 1184 | + break; | |
| 1185 | + if (pc >= (addr_t)s->run_ptr | |
| 1186 | + && pc < (addr_t)s->run_ptr + s->run_size) | |
| 1187 | + goto found; | |
| 1188 | + } | |
| 1189 | + } | |
| 1190 | +found: | |
| 1191 | + rt_post_sem(); | |
| 1192 | + //fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr); | |
| 1193 | + return s; | |
| 1194 | +} | |
| 1195 | + | |
| 1196 | +static void rt_longjmp(rt_frame *f, int code) | |
| 1197 | +{ | |
| 1198 | + TCCState *s = rt_find_state(f); | |
| 1199 | + if (s && s->run_lj) { | |
| 1200 | + if (code == 0) | |
| 1201 | + code = 256; | |
| 1202 | + ((void(*)(void*,int))s->run_lj)(s->run_jb, code); | |
| 1203 | + } | |
| 1204 | + exit(code); | |
| 1205 | +} | |
| 1206 | + | |
| 1188 | 1207 | /* ------------------------------------------------------------- */ |
| 1189 | 1208 | |
| 1190 | 1209 | #ifndef _WIN32 |
| @@ -1319,7 +1338,8 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) · 128 unmodified lines | ||
| 1319 | 1338 | rt_error(&f, "caught signal %d", signum); |
| 1320 | 1339 | break; |
| 1321 | 1340 | } |
| 1322 | − rt_exit(255); | |
| 1341 | + set_exception_handler(); | |
| 1342 | + rt_longjmp(&f, 255); | |
| 1323 | 1343 | } |
| 1324 | 1344 | |
| 1325 | 1345 | #ifndef SA_SIGINFO |
| @@ -1333,7 +1353,7 @@ static void set_exception_handler(void) · 7 unmodified lines | ||
| 1333 | 1353 | /* install TCC signal handlers to print debug info on fatal |
| 1334 | 1354 | runtime errors */ |
| 1335 | 1355 | sigemptyset (&sigact.sa_mask); |
| 1336 | − sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; | |
| 1356 | + sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER; | |
| 1337 | 1357 | #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes |
| 1338 | 1358 | sigact.sa_flags |= SA_ONSTACK; |
| 1339 | 1359 | #endif |
| @@ -1365,7 +1385,6 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) · 25 unmodified lines | ||
| 1365 | 1385 | { |
| 1366 | 1386 | rt_frame f; |
| 1367 | 1387 | unsigned code; |
| 1368 | − | |
| 1369 | 1388 | rt_getcontext(ex_info->ContextRecord, &f); |
| 1370 | 1389 | |
| 1371 | 1390 | switch (code = ex_info->ExceptionRecord->ExceptionCode) { |
| @@ -1387,8 +1406,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) · 15 unmodified lines | ||
| 1387 | 1406 | rt_error(&f, "caught exception %08x", code); |
| 1388 | 1407 | break; |
| 1389 | 1408 | } |
| 1390 | − if (rt_do_jmp) | |
| 1391 | − rt_exit(255); | |
| 1409 | + rt_longjmp(&f, 255); | |
| 1392 | 1410 | return EXCEPTION_EXECUTE_HANDLER; |
| 1393 | 1411 | } |
| 1394 | 1412 | |
| @@ -1405,45 +1423,41 @@ static void set_exception_handler(void) · 10 unmodified lines | ||
| 1405 | 1423 | #if defined(__i386__) || defined(__x86_64__) |
| 1406 | 1424 | static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) |
| 1407 | 1425 | { |
| 1408 | − addr_t ip, fp; | |
| 1409 | 1426 | if (level == 0) { |
| 1410 | − ip = rc->ip; | |
| 1427 | + *paddr = rc->ip; | |
| 1411 | 1428 | } else { |
| 1412 | − ip = 0; | |
| 1413 | − fp = rc->fp; | |
| 1414 | − while (--level) { | |
| 1415 | − /* XXX: check address validity with program info */ | |
| 1416 | − if (fp <= 0x1000) | |
| 1429 | + addr_t fp = rc->fp; | |
| 1430 | + while (1) { | |
| 1431 | + if (fp < 0x1000) | |
| 1432 | + return -1; | |
| 1433 | + if (0 == --level) | |
| 1417 | 1434 | break; |
| 1435 | + /* XXX: check address validity with program info */ | |
| 1418 | 1436 | fp = ((addr_t *)fp)[0]; |
| 1419 | 1437 | } |
| 1420 | − if (fp > 0x1000) | |
| 1421 | − ip = ((addr_t *)fp)[1]; | |
| 1438 | + *paddr = ((addr_t *)fp)[1]; | |
| 1422 | 1439 | } |
| 1423 | − if (ip <= 0x1000) | |
| 1424 | − return -1; | |
| 1425 | − *paddr = ip; | |
| 1426 | 1440 | return 0; |
| 1427 | 1441 | } |
| 1428 | 1442 | |
| 1429 | −#elif defined(__arm__) | |
| 1443 | +/* XXX: only supports linux/bsd */ | |
| 1444 | +#elif defined(__arm__) && !defined(_WIN32) | |
| 1430 | 1445 | static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) |
| 1431 | 1446 | { |
| 1432 | − /* XXX: only supports linux/bsd */ | |
| 1433 | −#if !defined(__linux__) && \ | |
| 1434 | − !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) | |
| 1435 | − return -1; | |
| 1436 | −#else | |
| 1437 | 1447 | if (level == 0) { |
| 1438 | 1448 | *paddr = rc->ip; |
| 1439 | 1449 | } else { |
| 1440 | 1450 | addr_t fp = rc->fp; |
| 1441 | − while (--level) | |
| 1451 | + while (1) { | |
| 1452 | + if (fp < 0x1000) | |
| 1453 | + return -1; | |
| 1454 | + if (0 == --level) | |
| 1455 | + break; | |
| 1442 | 1456 | fp = ((addr_t *)fp)[0]; |
| 1457 | + } | |
| 1443 | 1458 | *paddr = ((addr_t *)fp)[2]; |
| 1444 | 1459 | } |
| 1445 | 1460 | return 0; |
| 1446 | −#endif | |
| 1447 | 1461 | } |
| 1448 | 1462 | |
| 1449 | 1463 | #elif defined(__aarch64__) |
| @@ -1452,10 +1466,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) · 2 unmodified lines | ||
| 1452 | 1466 | if (level == 0) { |
| 1453 | 1467 | *paddr = rc->ip; |
| 1454 | 1468 | } else { |
| 1455 | − addr_t *fp = (addr_t*)rc->fp; | |
| 1456 | − while (--level) | |
| 1457 | − fp = (addr_t *)fp[0]; | |
| 1458 | − *paddr = fp[1]; | |
| 1469 | + addr_t fp = rc->fp; | |
| 1470 | + while (1) { | |
| 1471 | + if (fp < 0x1000) | |
| 1472 | + return -1; | |
| 1473 | + if (0 == --level) | |
| 1474 | + break; | |
| 1475 | + fp = ((addr_t *)fp)[0]; | |
| 1476 | + } | |
| 1477 | + *paddr = ((addr_t *)fp)[1]; | |
| 1459 | 1478 | } |
| 1460 | 1479 | return 0; |
| 1461 | 1480 | } |
| @@ -1466,12 +1485,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) · 4 unmodified lines | ||
| 1466 | 1485 | if (level == 0) { |
| 1467 | 1486 | *paddr = rc->ip; |
| 1468 | 1487 | } else { |
| 1469 | − addr_t *fp = (addr_t*)rc->fp; | |
| 1470 | − while (--level && fp >= (addr_t*)0x1000) | |
| 1471 | − fp = (addr_t *)fp[-2]; | |
| 1472 | − if (fp < (addr_t*)0x1000) | |
| 1473 | − return -1; | |
| 1474 | − *paddr = fp[-1]; | |
| 1488 | + addr_t fp = rc->fp; | |
| 1489 | + while (1) { | |
| 1490 | + if (fp < 0x1000) | |
| 1491 | + return -1; | |
| 1492 | + if (0 == --level) | |
| 1493 | + break; | |
| 1494 | + fp = ((addr_t *)fp)[-2]; | |
| 1495 | + } | |
| 1496 | + *paddr = ((addr_t *)fp)[-1]; | |
| 1475 | 1497 | } |
| 1476 | 1498 | return 0; |
| 1477 | 1499 | } |
| @@ -14,23 +14,20 @@ TESTS = \ · 13 unmodified lines | ||
| 14 | 14 | libtest \ |
| 15 | 15 | libtest_mt \ |
| 16 | 16 | test3 \ |
| 17 | − memtest \ | |
| 18 | − dlltest \ | |
| 19 | 17 | abitest \ |
| 20 | 18 | asm-c-connect-test \ |
| 21 | 19 | vla_test-run \ |
| 22 | − cross-test \ | |
| 23 | 20 | tests2-dir \ |
| 24 | − pp-dir | |
| 21 | + pp-dir \ | |
| 22 | + memtest \ | |
| 23 | + dlltest \ | |
| 24 | + cross-test | |
| 25 | 25 | |
| 26 | 26 | # test4_static -- Not all relocation types are implemented yet. |
| 27 | 27 | # asmtest / asmtest2 -- minor differences with gcc |
| 28 | 28 | |
| 29 | 29 | ifneq ($(CONFIG_bcheck),no) |
| 30 | − TESTS += btest test1b | |
| 31 | − ifndef CONFIG_WIN32 | |
| 32 | − TESTS += tccb | |
| 33 | − endif | |
| 30 | + TESTS += btest test1b tccb | |
| 34 | 31 | endif |
| 35 | 32 | ifeq ($(CONFIG_dll),no) |
| 36 | 33 | TESTS := $(filter-out dlltest, $(TESTS)) |
| @@ -82,7 +79,9 @@ all test : · 45 unmodified lines | ||
| 82 | 79 | @echo ------------ version ------------ |
| 83 | 80 | @$(TCC_LOCAL) -v |
| 84 | 81 | @$(MAKE) --no-print-directory -s clean |
| 85 | − @$(MAKE) --no-print-directory -s -r $(TESTS) | |
| 82 | + @$(MAKE) --no-print-directory -s -r _all | |
| 83 | + | |
| 84 | +_all : $(TESTS) | |
| 86 | 85 | |
| 87 | 86 | hello-exe: ../examples/ex1.c |
| 88 | 87 | @echo ------------ $@ ------------ |
| @@ -199,14 +198,15 @@ btest: boundtest.c · 110 unmodified lines | ||
| 199 | 198 | echo "Test $$i failed as expected" ; \ |
| 200 | 199 | fi ;\ |
| 201 | 200 | done ;\ |
| 202 | − echo Bound test OK | |
| 201 | + echo Bound-Test OK | |
| 203 | 202 | |
| 204 | 203 | tccb: |
| 205 | 204 | @echo ------------ $@ ------------ |
| 206 | − $(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF) | |
| 207 | − mv v1-tcc$(EXESUF) v2-tcc$(EXESUF) | |
| 208 | − ./v2-tcc$(EXESUF) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF) | |
| 209 | − cmp -s v1-tcc$(EXESUF) v2-tcc$(EXESUF) && echo "Bound-Test tcc OK" | |
| 205 | + $(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe | |
| 206 | + mv tccb1.exe tccb2.exe | |
| 207 | + ./tccb2.exe -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe | |
| 208 | + cmp -s tccb1.exe tccb2.exe && echo "Exe Bound-Rest OK" | |
| 209 | + | |
| 210 | 210 | |
| 211 | 211 | # speed test |
| 212 | 212 | speedtest: ex2 ex3 |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <stdlib.h> |
| 7 | 7 | #include <stdio.h> |
| 8 | 8 | #include <string.h> |
| 9 | +#include <setjmp.h> | |
| 9 | 10 | #include "libtcc.h" |
| 10 | 11 | |
| 11 | 12 | #define M 20 /* number of states */ |
| @@ -84,6 +85,8 @@ PROG(my_program) · 72 unmodified lines | ||
| 84 | 85 | "\n" |
| 85 | 86 | "int foo(int n)\n" |
| 86 | 87 | "{\n" |
| 88 | +" if (n >= N_CRASH && n < N_CRASH + 3)\n" | |
| 89 | +" *(void**)0 = 0;\n" | |
| 87 | 90 | " printf(\" %d\", fib(n));\n" |
| 88 | 91 | " return 0;\n" |
| 89 | 92 | "# warning is this the correct file:line...\n" |
| @@ -110,6 +113,11 @@ void parse_args(TCCState *s) · 20 unmodified lines | ||
| 110 | 113 | } |
| 111 | 114 | } |
| 112 | 115 | |
| 116 | +void bt_func(void *pc, const char *file, int line, const char *func) | |
| 117 | +{ | |
| 118 | + printf(" *** at %s:%d in '%s'\n", file, line, func); | |
| 119 | +} | |
| 120 | + | |
| 113 | 121 | TCCState *new_state(int w) |
| 114 | 122 | { |
| 115 | 123 | TCCState *s = tcc_new(); |
| @@ -119,7 +127,14 @@ TCCState *new_state(int w) · 3 unmodified lines | ||
| 119 | 127 | } |
| 120 | 128 | tcc_set_error_func(s, stdout, handle_error); |
| 121 | 129 | parse_args(s); |
| 122 | − if (!w) tcc_set_options(s, "-w"); | |
| 130 | + if (0 == (w & 1)) | |
| 131 | + tcc_set_options(s, "-w"); | |
| 132 | + if (w & 2) { | |
| 133 | + tcc_set_options(s, "-bt"); | |
| 134 | + tcc_define_symbol(s, "N_CRASH", str(M/2)); | |
| 135 | + tcc_set_backtrace_func(s, bt_func); | |
| 136 | + } else | |
| 137 | + tcc_define_symbol(s, "N_CRASH", "99"); | |
| 123 | 138 | tcc_set_output_type(s, TCC_OUTPUT_MEMORY); |
| 124 | 139 | return s; |
| 125 | 140 | } |
| @@ -139,23 +154,28 @@ void *reloc_state(TCCState *s, const char *entry) · 13 unmodified lines | ||
| 139 | 154 | } |
| 140 | 155 | |
| 141 | 156 | /* work with several states at the same time */ |
| 142 | −int state_test(void) | |
| 157 | +int state_test(int w) | |
| 143 | 158 | { |
| 144 | 159 | TCCState *s[M]; |
| 145 | − int (*func[M])(int); | |
| 160 | + int (*funcs[M])(int); | |
| 146 | 161 | int n; |
| 162 | + jmp_buf jb; | |
| 147 | 163 | |
| 148 | 164 | for (n = 0; n < M + 4; ++n) { |
| 149 | 165 | unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4; |
| 150 | 166 | if (a < M) |
| 151 | − s[a] = new_state(0); | |
| 167 | + s[a] = new_state(w); | |
| 152 | 168 | if (b < M) |
| 153 | 169 | if (tcc_compile_string(s[b], my_program) == -1) |
| 154 | 170 | break; |
| 155 | 171 | if (c < M) |
| 156 | − func[c] = reloc_state(s[c], "foo"); | |
| 157 | − if (d < M && func[d]) | |
| 158 | − func[d](F(d)); | |
| 172 | + funcs[c] = reloc_state(s[c], "foo"); | |
| 173 | + if (d < M && funcs[d]) { | |
| 174 | + if ((w & 2) && d == 8) | |
| 175 | + printf("\n"); | |
| 176 | + if (0 == tcc_setjmp(s[d], jb, funcs[d])) | |
| 177 | + funcs[d](F(d)); | |
| 178 | + } | |
| 159 | 179 | if (e < M) |
| 160 | 180 | tcc_delete(s[e]); |
| 161 | 181 | } |
| @@ -257,7 +277,13 @@ int main(int argc, char **argv) · 95 unmodified lines | ||
| 257 | 277 | #if 1 |
| 258 | 278 | printf("running fib with mixed calls\n "), fflush(stdout); |
| 259 | 279 | t = getclock_ms(); |
| 260 | − state_test(); | |
| 280 | + state_test(0); | |
| 281 | + printf("\n (%u ms)\n", getclock_ms() - t); | |
| 282 | +#endif | |
| 283 | +#if 1 | |
| 284 | + printf("producing some exceptions\n "), fflush(stdout); | |
| 285 | + t = getclock_ms(); | |
| 286 | + state_test(2); | |
| 261 | 287 | printf("\n (%u ms)\n", getclock_ms() - t); |
| 262 | 288 | #endif |
| 263 | 289 | #if 1 |
| @@ -4,6 +4,11 @@ int atexit(void (*function)(void)); · 3 unmodified lines | ||
| 4 | 4 | int on_exit(void (*function)(int, void *), void *arg); |
| 5 | 5 | void exit(int status); |
| 6 | 6 | |
| 7 | +void __attribute((constructor)) startup5(void) | |
| 8 | +{ | |
| 9 | + printf ("startup5\n"); | |
| 10 | +} | |
| 11 | + | |
| 7 | 12 | void cleanup1(void) |
| 8 | 13 | { |
| 9 | 14 | printf ("cleanup1\n"); |
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | [test_128_return] |
| 2 | +startup5 | |
| 2 | 3 | cleanup5 |
| 3 | 4 | 1 cleanup4 |
| 4 | 5 | 1 cleanup3 |
| @@ -7,6 +8,7 @@ cleanup1 · 2 unmodified lines | ||
| 7 | 8 | [returns 1] |
| 8 | 9 | |
| 9 | 10 | [test_128_exit] |
| 11 | +startup5 | |
| 10 | 12 | cleanup5 |
| 11 | 13 | 2 cleanup4 |
| 12 | 14 | 2 cleanup3 |
| @@ -37,15 +37,6 @@ extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]); · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | #include "crtinit.c" |
| 39 | 39 | |
| 40 | −static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[]) | |
| 41 | −{ | |
| 42 | − int retval; | |
| 43 | − run_ctors(argc, argv, env); | |
| 44 | − retval = _tmain(__argc, __targv, _tenviron); | |
| 45 | − run_dtors(); | |
| 46 | − return retval; | |
| 47 | −} | |
| 48 | − | |
| 49 | 40 | /* Allow command-line globbing with "int _dowildcard = 1;" in the user source */ |
| 50 | 41 | int _dowildcard; |
| 51 | 42 | |
| @@ -56,6 +47,8 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex) · 4 unmodified lines | ||
| 56 | 47 | |
| 57 | 48 | void _tstart(void) |
| 58 | 49 | { |
| 50 | + int ret; | |
| 51 | + | |
| 59 | 52 | _startupinfo start_info = {0}; |
| 60 | 53 | SetUnhandledExceptionFilter(catch_sig); |
| 61 | 54 | // Sets the current application type |
| @@ -68,11 +61,21 @@ void _tstart(void) · 6 unmodified lines | ||
| 68 | 61 | #endif |
| 69 | 62 | |
| 70 | 63 | __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info); |
| 71 | − exit(do_main(__argc, __targv, _tenviron)); | |
| 64 | + run_ctors(__argc, __targv, _tenviron); | |
| 65 | + ret = _tmain(__argc, __targv, _tenviron); | |
| 66 | + run_dtors(); | |
| 67 | + exit(ret); | |
| 72 | 68 | } |
| 73 | 69 | |
| 70 | +// ============================================= | |
| 71 | +// for 'tcc -run ,,,' | |
| 72 | + | |
| 73 | +__attribute__((weak)) extern int __rt_nr_exit; | |
| 74 | +__attribute__((weak)) extern int __run_on_exit(); | |
| 75 | + | |
| 74 | 76 | int _runtmain(int argc, /* as tcc passed in */ char **argv) |
| 75 | 77 | { |
| 78 | + int ret; | |
| 76 | 79 | #ifdef UNICODE |
| 77 | 80 | _startupinfo start_info = {0}; |
| 78 | 81 | |
| @@ -89,7 +92,12 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) · 10 unmodified lines | ||
| 89 | 92 | #if defined __i386__ || defined __x86_64__ |
| 90 | 93 | _controlfp(_PC_53, _MCW_PC); |
| 91 | 94 | #endif |
| 92 | − return _tmain(__argc, __targv, _tenviron); | |
| 95 | + __rt_nr_exit = 0; | |
| 96 | + run_ctors(__argc, __targv, _tenviron); | |
| 97 | + ret = _tmain(__argc, __targv, _tenviron); | |
| 98 | + run_dtors(); | |
| 99 | + __run_on_exit(ret); | |
| 100 | + return ret; | |
| 93 | 101 | } |
| 94 | 102 | |
| 95 | 103 | // ============================================= |