History

tccrun: exit() via rt_longjmp()

- 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)

grischka committed 2 years ago

Commit c88b1991 parent 8d8d75c16 files · +384 −199Browse files

Unified · Split

16 files
  1. .github/workflows/build.yml +6 −0
  2. Makefile +23 −5
  3. lib/Makefile +2 −1
  4. lib/bt-exe.c +6 −6
  5. lib/bt-log.c +4 −5
  6. lib/runmain.c +87 −0
  7. libtcc.h +11 −0
  8. tcc.h +4 −0
  9. tccelf.c +0 −2
  10. tccpe.c +0 −2
  11. tccrun.c +167 −145
  12. tests/Makefile +14 −14
  13. tests/libtcc_test_mt.c +34 −8
  14. tests/tests2/128_run_atexit.c +5 −0
  15. tests/tests2/128_run_atexit.expect +2 −0
  16. win32/lib/crt1.c +19 −11
.github/workflows/build.yml+6−0
@@ -7,6 +7,7 @@ on: · 6 unmodified lines
7jobs:7jobs:
8 test-x86_64-linux:8 test-x86_64-linux:
9 runs-on: ubuntu-20.049 runs-on: ubuntu-20.04
10 timeout-minutes: 2
10 steps:11 steps:
11 - uses: actions/checkout@v412 - uses: actions/checkout@v4
12 - name: make & test tcc13 - 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-1117 runs-on: macos-11
18 timeout-minutes: 2
17 steps:19 steps:
18 - uses: actions/checkout@v420 - uses: actions/checkout@v4
19 - name: make & test tcc21 - 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-201925 runs-on: windows-2019
26 timeout-minutes: 4
24 steps:27 steps:
25 - uses: actions/checkout@v428 - uses: actions/checkout@v4
26 - name: make & test tcc29 - 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.0438 runs-on: ubuntu-20.04
39 timeout-minutes: 6
36 steps:40 steps:
37 - uses: actions/checkout@v441 - uses: actions/checkout@v4
38 - uses: uraimo/run-on-arch-action@v242 - 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.0455 runs-on: ubuntu-20.04
56 timeout-minutes: 6
52 steps:57 steps:
53 - uses: actions/checkout@v458 - uses: actions/checkout@v4
54 - uses: uraimo/run-on-arch-action@v259 - 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.0472 runs-on: ubuntu-20.04
73 timeout-minutes: 6
68 steps:74 steps:
69 - uses: actions/checkout@v475 - uses: actions/checkout@v4
70 - uses: uraimo/run-on-arch-action@v276 - uses: uraimo/run-on-arch-action@v2
Makefile+23−5
@@ -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.def31 LIBTCCDEF = libtcc.def
32 -LTCC = $(bindir)/libtcc.dll
33 else
34 -LTCC = -ltcc -L$(libdir)
32 endif35 endif
33 ifneq ($(CONFIG_debug),yes)36 ifneq ($(CONFIG_debug),yes)
34 LDFLAGS += -s37 LDFLAGS += -s
@@ -70,6 +73,7 @@ else · 35 unmodified lines
70 endif73 endif
71 export MACOSX_DEPLOYMENT_TARGET := 10.674 export MACOSX_DEPLOYMENT_TARGET := 10.6
72 endif75 endif
76 -LTCC = -ltcc
73endif77endif
74 78
75# run local version of tcc with local libraries and includes79# run local version of tcc with local libraries and includes
@@ -79,6 +83,15 @@ TCCFLAGS = $(TCCFLAGS$(CFG)) · 3 unmodified lines
79TCC_LOCAL = $(TOP)/tcc$(EXESUF)83TCC_LOCAL = $(TOP)/tcc$(EXESUF)
80TCC = $(TCC_LOCAL) $(TCCFLAGS)84TCC = $(TCC_LOCAL) $(TCCFLAGS)
81 85
86# run tests with the installed tcc instead
87ifdef TESTINSTALL
88 TCC_LOCAL = $(bindir)/tcc
89 TCCFLAGS-unx = -I..
90 TCCFLAGS-win = -I.. -B$(bindir)
91 LIBTCC =
92 LIBS += $(-LTCC)
93endif
94
82CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE95CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
83LIBS_P = $(LIBS)96LIBS_P = $(LIBS)
84LDFLAGS_P = $(LDFLAGS)97LDFLAGS_P = $(LDFLAGS)
@@ -373,7 +386,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2 · 288 unmodified lines
373IM = @echo "-> $2 : $1" ;386IM = @echo "-> $2 : $1" ;
374BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)387BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
375 388
376B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o389B_O = runmain.o bt-exe.o bt-dll.o bcheck.o
377 390
378# install progs & libs391# install progs & libs
379install-unx:392install-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)")
416ifneq "$(wildcard $(LIBTCC1_U))" ""429ifneq "$(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 windows434# uninstall on windows
422uninstall-win:435uninstall-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 install440# the msys-git shell works to configure && make except it does not have install
428ifeq ($(OS),Windows_NT)441ifeq ($(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$*
474tcc_c$(EXESUF): $($T_FILES)487tcc_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
490test-install: tccdefs_.h
491 @$(MAKE) -C tests TESTINSTALL=yes #_all
476 492
477clean:493clean:
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:"
lib/Makefile+2−1
@@ -67,7 +67,8 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) · 66 unmodified lines
67OBJ-arm-wince = $(ARM_O) $(WIN_O)67OBJ-arm-wince = $(ARM_O) $(WIN_O)
68OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)68OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
69 69
70OBJ-extra = $(filter $(B_O),$(OBJ-$T))70OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T)))
71OBJ-extra += runmain.o
71OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))72OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
72 73
73ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))74ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
lib/bt-exe.c+6−6
@@ -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. */
lib/bt-log.c+4−5
@@ -18,25 +18,24 @@ · 17 unmodified lines
18#pragma GCC diagnostic ignored "-Wframe-address"18#pragma GCC diagnostic ignored "-Wframe-address"
19#endif19#endif
20 20
21typedef struct rt_frame21typedef 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))
27int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);26int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
28 27
29DLL_EXPORT int tcc_backtrace(const char *fmt, ...)28DLL_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";
lib/runmain.c+87−0
@@ -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
11extern void (*_(_init_array_start)[]) (int argc, char **argv, char **envp);
12extern void (*_(_init_array_end)[]) (int argc, char **argv, char **envp);
13static 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
21extern void (*_(_fini_array_start)[]) (void);
22extern void (*_(_fini_array_end)[]) (void);
23static 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
30static void *rt_exitfunc[32];
31static void *rt_exitarg[32];
32int __rt_nr_exit;
33
34void __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
41int 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
53int atexit(void (*function)(void))
54{
55 return on_exit(function, 0);
56}
57
58typedef struct rt_frame {
59 void *ip, *fp, *sp;
60} rt_frame;
61
62void __rt_longjmp(rt_frame *, int);
63
64void 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
75int main(int, char**, char**);
76
77int _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
libtcc.h+11−0
@@ -100,6 +100,17 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); · 99 unmodified lines
100LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,100LIBTCCAPI 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() */
107LIBTCCAPI 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 */
111typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func);
112LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*);
113
103#ifdef __cplusplus114#ifdef __cplusplus
104}115}
105#endif116#endif
tcc.h+4−0
@@ -1000,6 +1000,10 @@ struct TCCState { · 999 unmodified lines
1000#ifdef _WIN641000#ifdef _WIN64
1001 void *run_function_table; /* unwind data */1001 void *run_function_table; /* unwind data */
1002#endif1002#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#endif1007#endif
1004 1008
1005#ifdef CONFIG_TCC_BACKTRACE1009#ifdef CONFIG_TCC_BACKTRACE
tccelf.c+0−2
@@ -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 }
tccpe.c+0−2
@@ -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#endif1966#endif
tccrun.c+167−145
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#ifdef CONFIG_TCC_BACKTRACE26#ifdef CONFIG_TCC_BACKTRACE
27typedef struct rt_context27typedef 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
57typedef struct rt_frame56typedef 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 */
63static rt_context *g_rc;61static rt_context *g_rc;
62static TCCState *g_s1;
64/* semaphore to protect it */63/* semaphore to protect it */
65TCC_SEM(static rt_sem);64TCC_SEM(static rt_sem);
66static int signal_set;65static int signal_set;
67static void set_exception_handler(void);66static void set_exception_handler(void);
68 67static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
69#ifdef _WIN3268static void rt_post_sem(void) { POST_SEM(&rt_sem); }
70#define ATTR_WEAK69static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
71#else
72#define ATTR_WEAK __attribute__((weak))
73#endif
74int ATTR_WEAK _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
75void ATTR_WEAK rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
76void 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 */
81static jmp_buf rt_jb;
82static int rt_do_jmp;
83static int rt_nr_exit;
84static void *rt_exitfunc[32];
85static void *rt_exitarg[32];
86
87static 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_ONLY74#ifndef CONFIG_TCC_BACKTRACE_ONLY
@@ -101,7 +79,8 @@ static void rt_exit(int code) · 4 unmodified lines
101 79
102static int protect_pages(void *ptr, unsigned long length, int mode);80static int protect_pages(void *ptr, unsigned long length, int mode);
103static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);81static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
104 82static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
83static void rt_longjmp(rt_frame *f, int code);
105#ifdef _WIN6484#ifdef _WIN64
106static void *win64_add_function_table(TCCState *s1);85static void *win64_add_function_table(TCCState *s1);
107static void win64_del_function_table(void *);86static 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_BCHECK105#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#endif110#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#endif114#endif
@@ -142,16 +118,35 @@ static void bt_unlink(TCCState *s1) · 3 unmodified lines
142{118{
143#ifdef CONFIG_TCC_BACKTRACE119#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#endif126#endif
153}127}
154 128
129static 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
137static 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 1151//#define HAVE_SELINUX 1
157#endif152#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_BACKTRACE193#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#endif196#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_SELINUX234#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#endif243#endif
251}244}
252 245
253static void run_cdtors(TCCState *s1, const char *start, const char *end,246LIBTCCAPI 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
262static void run_on_exit(int ret)255LIBTCCAPI 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
269static 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
279static 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 */
285LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)261LIBTCCAPI 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#endif273#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_PE359#ifdef TCC_TARGET_PE
390 pe_output_file(s1, NULL);360 pe_output_file(s1, NULL);
391#else361#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 reading586/* print the position in the source file of PC value 'pc' by reading
617 the stabs debug information */587 the stabs debug information */
618static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,588static 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
727found:697found:
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 } else705 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 0714#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#endif725#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
818static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,796static 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
859next:837next:
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
1104found:1083found:
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 else1096 *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
1117static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);1101static
1118 1102#endif
1119int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)1103int __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
1172static 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 }
1190found:
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
1196static 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 _WIN321209#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_SIGINFO1345#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 fatal1353 /* 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) linuxes1357#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#endif1359#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__)
1406static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)1424static 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)
1430static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)1445static 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}
tests/Makefile+14−14
@@ -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-dir21 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 gcc27# asmtest / asmtest2 -- minor differences with gcc
28 28
29ifneq ($(CONFIG_bcheck),no)29ifneq ($(CONFIG_bcheck),no)
30 TESTS += btest test1b30 TESTS += btest test1b tccb
31 ifndef CONFIG_WIN32
32 TESTS += tccb
33 endif
34endif31endif
35ifeq ($(CONFIG_dll),no)32ifeq ($(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) -v80 @$(TCC_LOCAL) -v
84 @$(MAKE) --no-print-directory -s clean81 @$(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
87hello-exe: ../examples/ex1.c86hello-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 OK201 echo Bound-Test OK
203 202
204tccb:203tccb:
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 test211# speed test
212speedtest: ex2 ex3212speedtest: ex2 ex3
tests/libtcc_test_mt.c+34−8
@@ -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
116void 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
113TCCState *new_state(int w)121TCCState *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 */
142int state_test(void)157int 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 1277#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#endif288#endif
263#if 1289#if 1
tests/tests2/128_run_atexit.c+5−0
@@ -4,6 +4,11 @@ int atexit(void (*function)(void)); · 3 unmodified lines
4int on_exit(void (*function)(int, void *), void *arg);4int on_exit(void (*function)(int, void *), void *arg);
5void exit(int status);5void exit(int status);
6 6
7void __attribute((constructor)) startup5(void)
8{
9 printf ("startup5\n");
10}
11
7void cleanup1(void)12void cleanup1(void)
8{13{
9 printf ("cleanup1\n");14 printf ("cleanup1\n");
tests/tests2/128_run_atexit.expect+2−0
@@ -1,4 +1,5 @@
1[test_128_return]1[test_128_return]
2startup5
2cleanup53cleanup5
31 cleanup441 cleanup4
41 cleanup351 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]
11startup5
10cleanup512cleanup5
112 cleanup4132 cleanup4
122 cleanup3142 cleanup3
win32/lib/crt1.c+19−11
@@ -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
40static 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 */
50int _dowildcard;41int _dowildcard;
51 42
@@ -56,6 +47,8 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex) · 4 unmodified lines
56 47
57void _tstart(void)48void _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 type54 // Sets the current application type
@@ -68,11 +61,21 @@ void _tstart(void) · 6 unmodified lines
68#endif61#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
74int _runtmain(int argc, /* as tcc passed in */ char **argv)76int _runtmain(int argc, /* as tcc passed in */ char **argv)
75{77{
78 int ret;
76#ifdef UNICODE79#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#endif94#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// =============================================

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t