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