1
0
Fork 0

tccrun: review last changes

- LIBTCCAPI int tcc_set_backtrace_func(void *ud, ...)
  accept opaque user data pointer,
- tcc -vv -run... : show section info
- use memalign() to allocate runtime memory
- printline_/dwarf : pass output to parent function
- tccpe.c : fix -nostdlib -run
- --config-backtrace=no : make it work again
This commit is contained in:
grischka 2024-02-16 19:11:56 +01:00
parent c88b19966c
commit d2f8ceac7a
18 changed files with 404 additions and 321 deletions

View File

@ -386,13 +386,13 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2
IM = @echo "-> $2 : $1" ; IM = @echo "-> $2 : $1" ;
BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1) BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
B_O = runmain.o bt-exe.o bt-dll.o bcheck.o EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
# install progs & libs # install progs & libs
install-unx: install-unx:
$(call BINCHECK) $(call BINCHECK)
$(call IBw,$(PROGS) *-tcc,"$(bindir)") $(call IBw,$(PROGS) *-tcc,"$(bindir)")
$(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)") $(call IFw,$(LIBTCC1) $(EXTRA_O) $(LIBTCC1_U),"$(tccdir)")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)") $(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)") $(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
@ -419,7 +419,7 @@ install-win:
$(call BINCHECK) $(call BINCHECK)
$(call IBw,$(PROGS) *-tcc.exe libtcc.dll,"$(bindir)") $(call IBw,$(PROGS) *-tcc.exe libtcc.dll,"$(bindir)")
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib") $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
$(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib") $(call IFw,libtcc1.a $(EXTRA_O) $(LIBTCC1_W),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples") $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")

2
configure vendored
View File

@ -365,7 +365,7 @@ case $targetos in
default tcc_libpaths "{B}:{R}/lib:/system/lib${S}" default tcc_libpaths "{B}:{R}/lib:/system/lib${S}"
default tcc_crtprefix "{R}/lib" default tcc_crtprefix "{R}/lib"
default tcc_elfinterp "/system/bin/linker${S}" default tcc_elfinterp "/system/bin/linker${S}"
default tcc_switches "-Wl,-rpath=$sysroot/lib,-section-alignment=0x1000" default tcc_switches "-Wl,-rpath=$sysroot/lib"
;; ;;
WIN32) WIN32)
mingw32="yes" mingw32="yes"

View File

@ -40,7 +40,7 @@ endif
$(X)BT_O = bt-exe.o bt-log.o $(X)BT_O = bt-exe.o bt-log.o
$(X)B_O = $(BCHECK_O) bt-exe.o bt-log.o bt-dll.o $(X)B_O = $(BCHECK_O) bt-exe.o bt-log.o bt-dll.o
endif endif
$(X)BT_O += tcov.o $(X)BT_O += runmain.o tcov.o
DSO_O = dsohandle.o DSO_O = dsohandle.o
@ -67,8 +67,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
OBJ-arm-wince = $(ARM_O) $(WIN_O) OBJ-arm-wince = $(ARM_O) $(WIN_O)
OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O) OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T))) OBJ-extra = $(filter $(B_O) runmain.o,$(OBJ-$T))
OBJ-extra += runmain.o
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))

View File

@ -23,19 +23,19 @@ typedef struct rt_frame {
} rt_frame; } rt_frame;
__attribute__((weak)) __attribute__((weak))
int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap);
DLL_EXPORT int tcc_backtrace(const char *fmt, ...) DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
{ {
va_list ap; va_list ap;
int ret; int ret;
if (__rt_dump) { if (_tcc_backtrace) {
rt_frame f; rt_frame f;
f.fp = __builtin_frame_address(1); f.fp = __builtin_frame_address(1);
f.ip = __builtin_return_address(0); f.ip = __builtin_return_address(0);
va_start(ap, fmt); va_start(ap, fmt);
ret = __rt_dump(&f, NULL, fmt, ap); ret = _tcc_backtrace(&f, fmt, ap);
va_end(ap); va_end(ap);
} else { } else {
const char *p, *nl = "\n"; const char *p, *nl = "\n";

View File

@ -29,7 +29,7 @@ static void run_dtors(void)
static void *rt_exitfunc[32]; static void *rt_exitfunc[32];
static void *rt_exitarg[32]; static void *rt_exitarg[32];
int __rt_nr_exit; static int __rt_nr_exit;
void __run_on_exit(int ret) void __run_on_exit(int ret)
{ {
@ -59,16 +59,16 @@ typedef struct rt_frame {
void *ip, *fp, *sp; void *ip, *fp, *sp;
} rt_frame; } rt_frame;
void __rt_longjmp(rt_frame *, int); void __rt_exit(rt_frame *, int);
void exit(int code) void exit(int code)
{ {
rt_frame f; rt_frame f;
run_dtors(); run_dtors();
__run_on_exit(code); __run_on_exit(code);
f.fp = __builtin_frame_address(1); f.fp = 0;
f.ip = __builtin_return_address(0); f.ip = exit;
__rt_longjmp(&f, code); __rt_exit(&f, code);
} }
#ifndef _WIN32 #ifndef _WIN32
@ -77,7 +77,6 @@ int main(int, char**, char**);
int _runmain(int argc, char **argv, char **envp) int _runmain(int argc, char **argv, char **envp)
{ {
int ret; int ret;
__rt_nr_exit = 0;
run_ctors(argc, argv, envp); run_ctors(argc, argv, envp);
ret = main(argc, argv, envp); ret = main(argc, argv, envp);
run_dtors(); run_dtors();

View File

@ -229,7 +229,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
return ptr1; return ptr1;
} }
static void libc_free(void *ptr) ST_FUNC void libc_free(void *ptr)
{ {
free(ptr); free(ptr);
} }

View File

@ -104,12 +104,12 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
/* catch runtime exceptions (optionally limit backtraces at top_func), /* catch runtime exceptions (optionally limit backtraces at top_func),
when using tcc_set_options("-bt") and when not using tcc_run() */ when using tcc_set_options("-bt") and when not using tcc_run() */
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *longjmp, void *jmp_buf, void *top_func); LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, longjmp, jb, f)) #define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
/* set custom error printer for runtime exceptions */ /* custom error printer for runtime exceptions. Returning 0 stops backtrace */
typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func); typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*); LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
#ifdef __cplusplus #ifdef __cplusplus
} }

7
tcc.h
View File

@ -1003,7 +1003,9 @@ struct TCCState {
struct TCCState *next; struct TCCState *next;
struct rt_context *rc; /* pointer to backtrace info block */ struct rt_context *rc; /* pointer to backtrace info block */
void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */ void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */
void (*bt_func)(void *, const char*, int, const char*); TCCBtFunc *bt_func;
void *bt_data;
int run_tid;
#endif #endif
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
@ -1250,6 +1252,7 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#endif #endif
ST_FUNC void libc_free(void *ptr);
#define free(p) use_tcc_free(p) #define free(p) use_tcc_free(p)
#define malloc(s) use_tcc_malloc(s) #define malloc(s) use_tcc_malloc(s)
#define realloc(p, s) use_tcc_realloc(p, s) #define realloc(p, s) use_tcc_realloc(p, s)
@ -1982,7 +1985,7 @@ ST_FUNC void wait_sem(TCCSem *p)
sem_init(&p->sem, 0, 1), p->init = 1; sem_init(&p->sem, 0, 1), p->init = 1;
while (sem_wait(&p->sem) < 0 && errno == EINTR); while (sem_wait(&p->sem) < 0 && errno == EINTR);
} }
ST_INLN void post_sem(TCCSem *p) ST_FUNC void post_sem(TCCSem *p)
{ {
sem_post(&p->sem); sem_post(&p->sem);
} }

View File

@ -1606,7 +1606,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
(uint64_t)1 << 32); (uint64_t)1 << 32);
#endif #endif
} }
n = 4 * PTR_SIZE; n = 3 * PTR_SIZE;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) { if (s1->do_bounds_check) {
put_ptr(s1, bounds_section, 0); put_ptr(s1, bounds_section, 0);
@ -1617,9 +1617,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
p = section_ptr_add(s, 2 * sizeof (int)); p = section_ptr_add(s, 2 * sizeof (int));
p[0] = s1->rt_num_callers; p[0] = s1->rt_num_callers;
p[1] = s1->dwarf; p[1] = s1->dwarf;
// if (s->data_offset - o != 10*PTR_SIZE + 2*sizeof (int)) exit(99);
if (s->data_offset - o != 11 * PTR_SIZE + 2 * sizeof (int))
exit(99);
if (s1->output_type == TCC_OUTPUT_MEMORY) { if (s1->output_type == TCC_OUTPUT_MEMORY) {
set_global_sym(s1, __rt_info, s, o); set_global_sym(s1, __rt_info, s, o);
@ -1778,6 +1776,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
if (s1->do_backtrace) { if (s1->do_backtrace) {
if (s1->output_type & TCC_OUTPUT_EXE) if (s1->output_type & TCC_OUTPUT_EXE)
tcc_add_support(s1, "bt-exe.o"); tcc_add_support(s1, "bt-exe.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
tcc_add_btstub(s1); tcc_add_btstub(s1);
lpthread = 1; lpthread = 1;
} }

View File

@ -1943,7 +1943,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
pe_type = PE_EXE; pe_type = PE_EXE;
} }
if (TCC_OUTPUT_MEMORY == s1->output_type) if (TCC_OUTPUT_MEMORY == s1->output_type && !s1->nostdlib)
start_symbol = run_symbol; start_symbol = run_symbol;
} }
@ -1961,6 +1961,8 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
tcc_add_support(s1, "bt-exe.o"); tcc_add_support(s1, "bt-exe.o");
if (s1->output_type == TCC_OUTPUT_DLL) if (s1->output_type == TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-dll.o"); tcc_add_support(s1, "bt-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
tcc_add_btstub(s1); tcc_add_btstub(s1);
} }
#endif #endif

599
tccrun.c
View File

@ -24,6 +24,7 @@
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
/* runtime debug info block */
typedef struct rt_context typedef struct rt_context
{ {
/* tccelf.c:tcc_add_btstub() wants these in that order: */ /* tccelf.c:tcc_add_btstub() wants these in that order: */
@ -42,32 +43,33 @@ typedef struct rt_context
ElfW(Sym) *esym_start; ElfW(Sym) *esym_start;
ElfW(Sym) *esym_end; ElfW(Sym) *esym_end;
char *elf_str; char *elf_str;
// 6 // 6 * PTR_SIZE
addr_t prog_base; addr_t prog_base;
void *bounds_start; void *bounds_start;
void *top_func; void *top_func;
TCCState *s1;
struct rt_context *next; struct rt_context *next;
// 11 // 10 * PTR_SIZE
int num_callers; int num_callers;
int dwarf; int dwarf;
} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */ } rt_context;
/* linked list of rt_contexts */
static rt_context *g_rc;
static int signal_set;
static void set_exception_handler(void);
#endif /* def CONFIG_TCC_BACKTRACE */
typedef struct rt_frame { typedef struct rt_frame {
addr_t ip, fp, sp; addr_t ip, fp, sp;
} rt_frame; } rt_frame;
/* linked list of rt_contexts */
static rt_context *g_rc;
static TCCState *g_s1; static TCCState *g_s1;
/* semaphore to protect it */ /* semaphore to protect it */
TCC_SEM(static rt_sem); TCC_SEM(static rt_sem);
static int signal_set;
static void set_exception_handler(void);
static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); } static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
static void rt_post_sem(void) { POST_SEM(&rt_sem); } static void rt_post_sem(void) { POST_SEM(&rt_sem); }
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
#endif /* def CONFIG_TCC_BACKTRACE */ static void rt_exit(rt_frame *f, int code);
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* defined when included from lib/bt-exe.c */ /* defined when included from lib/bt-exe.c */
@ -79,73 +81,26 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
static int protect_pages(void *ptr, unsigned long length, int mode); static int protect_pages(void *ptr, unsigned long length, int mode);
static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff); static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); static void st_link(TCCState *s1);
static void rt_longjmp(rt_frame *f, int code); static void st_unlink(TCCState *s1);
#ifdef CONFIG_TCC_BACKTRACE
static int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap);
#endif
#ifdef _WIN64 #ifdef _WIN64
static void *win64_add_function_table(TCCState *s1); static void *win64_add_function_table(TCCState *s1);
static void win64_del_function_table(void *); static void win64_del_function_table(void *);
#endif #endif
static void bt_link(TCCState *s1) #ifdef __APPLE__
{ # define CONFIG_RUNMEM_ALIGNED 0
#ifdef CONFIG_TCC_BACKTRACE #else
rt_context *rc; # ifndef CONFIG_RUNMEM_ALIGNED
void *p; # define CONFIG_RUNMEM_ALIGNED 1
# endif
if (!s1->do_backtrace) # if CONFIG_RUNMEM_ALIGNED
return; # include <malloc.h> /* memalign() */
rc = tcc_get_symbol(s1, "__rt_info"); # endif
if (!rc)
return;
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
rc->elf_str = (char *)symtab_section->link->data;
if (PTR_SIZE == 8 && !s1->dwarf)
rc->prog_base &= 0xffffffff00000000ULL;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(void*,int))p)(rc->bounds_start, 1);
}
#endif #endif
rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc;
if (0 == signal_set)
set_exception_handler(), signal_set = 1;
#endif
}
static void bt_unlink(TCCState *s1)
{
#ifdef CONFIG_TCC_BACKTRACE
rt_context *rc, **pp;
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
if (rc->s1 == s1) {
*pp = rc->next;
break;
}
#endif
}
static void st_link(TCCState *s1)
{
rt_wait_sem();
s1->next = g_s1, g_s1 = s1;
bt_link(s1);
rt_post_sem();
}
static void st_unlink(TCCState *s1)
{
TCCState *s2, **pp;
rt_wait_sem();
bt_unlink(s1);
for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next)
if (s2 == s1) {
*pp = s2->next;
break;
}
rt_post_sem();
}
#if !_WIN32 && !__APPLE__ #if !_WIN32 && !__APPLE__
//#define HAVE_SELINUX 1 //#define HAVE_SELINUX 1
@ -172,7 +127,15 @@ static int rt_mem(TCCState *s1, int size)
ptr_diff = (char*)prw - (char*)ptr; /* = size; */ ptr_diff = (char*)prw - (char*)ptr; /* = size; */
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff); //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
#else #else
ptr = tcc_malloc(size); # if !CONFIG_RUNMEM_ALIGNED
ptr = tcc_malloc(size += PAGESIZE);
# elif _WIN32
ptr = _aligned_malloc(size, PAGESIZE);
# else
ptr = memalign(PAGESIZE, size);
# endif
if (NULL == ptr)
return tcc_error_noabort("tccrun: could not allocate memory");
#endif #endif
s1->run_ptr = ptr; s1->run_ptr = ptr;
s1->run_size = size; s1->run_size = size;
@ -189,12 +152,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
if (s1->run_ptr) if (s1->run_ptr)
exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported")); exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
if (s1->do_backtrace) if (s1->do_backtrace)
tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */ tcc_add_symbol(s1, "_tcc_backtrace", _tcc_backtrace); /* for bt-log.c */
#endif #endif
size = tcc_relocate_ex(s1, NULL, 0); size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0) if (size < 0)
return -1; return -1;
@ -236,31 +197,24 @@ ST_FUNC void tcc_run_free(TCCState *s1)
#else #else
/* unprotect memory to make it usable for malloc again */ /* unprotect memory to make it usable for malloc again */
protect_pages(ptr, size, 2 /*rw*/); protect_pages(ptr, size, 2 /*rw*/);
#ifdef _WIN64 # ifdef _WIN64
win64_del_function_table(s1->run_function_table); win64_del_function_table(s1->run_function_table);
#endif # endif
# if !CONFIG_RUNMEM_ALIGNED
tcc_free(ptr); tcc_free(ptr);
# elif _WIN32
_aligned_free(ptr);
# else
libc_free(ptr);
# endif
#endif #endif
} }
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func)
{
s1->run_lj = p_longjmp;
s1->run_jb = p_jmp_buf;
if (func && s1->rc)
s1->rc->top_func = func;
return p_jmp_buf;
}
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func)
{
s1->bt_func = func;
}
/* launch the compiled program with the given arguments */ /* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{ {
int (*prog_main)(int, char **, char **), ret; int (*prog_main)(int, char **, char **), ret;
const char *top_sym;
jmp_buf main_jb; jmp_buf main_jb;
#if defined(__APPLE__) || defined(__FreeBSD__) #if defined(__APPLE__) || defined(__FreeBSD__)
@ -276,20 +230,25 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1)) if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1))
return 0; return 0;
tcc_add_support(s1, "runmain.o"); tcc_add_symbol(s1, "__rt_exit", rt_exit);
tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp); if (s1->nostdlib) {
s1->run_main = (s1->nostdlib ? "_start" : "_runmain"); s1->run_main = top_sym = "_start";
} else {
tcc_add_support(s1, "runmain.o");
s1->run_main = "_runmain";
top_sym = "main";
}
if (tcc_relocate(s1) < 0) if (tcc_relocate(s1) < 0)
return -1; return 1;
prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1); prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
if ((addr_t)-1 == (addr_t)prog_main) if ((addr_t)-1 == (addr_t)prog_main)
return -1; return 1;
errno = 0; /* clean errno value */ errno = 0; /* clean errno value */
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main")); ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym));
if (0 == ret) if (0 == ret)
ret = prog_main(argc, argv, envp); ret = prog_main(argc, argv, envp);
else if (256 == ret) else if (256 == ret)
@ -344,8 +303,6 @@ static void cleanup_sections(TCCState *s1)
# define CONFIG_RUNMEM_RO 1 # define CONFIG_RUNMEM_RO 1
#endif #endif
#define DEBUG_RUNMEN 0
/* relocate code. Return -1 on error, required size if ptr is NULL, /* relocate code. Return -1 on error, required size if ptr is NULL,
otherwise copy code into buffer passed by the caller */ otherwise copy code into buffer passed by the caller */
static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
@ -367,16 +324,17 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
offset = copy = 0; offset = copy = 0;
mem = (addr_t)ptr; mem = (addr_t)ptr;
#if DEBUG_RUNMEN
if (mem)
fprintf(stderr, "X: <base> %p len %5x\n",
ptr, s1->run_size);
#endif
redo: redo:
if (s1->verbose == 2 && copy) {
printf(&"-----------------------------------------------------\n"[PTR_SIZE*2 - 8]);
if (1 == copy)
printf("memory %p len %05x\n", ptr, s1->run_size);
}
if (s1->nb_errors) if (s1->nb_errors)
return -1; return -1;
if (copy == 2)
return 0;
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
n = 0; addr = 0; n = 0; addr = 0;
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
@ -389,7 +347,9 @@ redo:
length = s->data_offset; length = s->data_offset;
if (copy) { /* final step: copy section data to memory */ if (copy) { /* final step: copy section data to memory */
void *ptr; if (s1->verbose == 2)
printf("%d: %-16s %p len %05x align %04x\n",
k, s->name, (void*)s->sh_addr, length, s->sh_addralign);
if (addr == 0) if (addr == 0)
addr = s->sh_addr; addr = s->sh_addr;
n = (s->sh_addr - addr) + length; n = (s->sh_addr - addr) + length;
@ -407,28 +367,25 @@ redo:
continue; continue;
} }
align = s->sh_addralign - 1; align = s->sh_addralign;
if (++n == 1) { if (++n == 1) {
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
/* To avoid that x86 processors would reload cached instructions /* To avoid that x86 processors would reload cached instructions
each time when data is written in the near, we need to make each time when data is written in the near, we need to make
sure that code and data do not share the same 64 byte unit */ sure that code and data do not share the same 64 byte unit */
if (align < 63) if (align < 64)
align = 63; align = 64;
#endif #endif
/* start new page for different permissions */ /* start new page for different permissions */
if (CONFIG_RUNMEM_RO || k < 2) if (CONFIG_RUNMEM_RO || k < 2)
align = PAGESIZE - 1; align = PAGESIZE;
} }
s->sh_addralign = align;
addr = k ? mem + ptr_diff : mem; addr = k ? mem + ptr_diff : mem;
offset += -(addr + offset) & align; offset += -(addr + offset) & (align - 1);
s->sh_addr = mem ? addr + offset : 0; s->sh_addr = mem ? addr + offset : 0;
offset += length; offset += length;
#if DEBUG_RUNMEN
if (mem)
fprintf(stderr, "%d: %-16s %p len %5x align %04x\n",
k, s->name, (void*)s->sh_addr, length, align + 1);
#endif
} }
if (copy) { /* set permissions */ if (copy) { /* set permissions */
if (n == 0) /* no data */ if (n == 0) /* no data */
@ -443,30 +400,25 @@ redo:
continue; continue;
f = 3; /* change only SHF_EXECINSTR to rwx */ f = 3; /* change only SHF_EXECINSTR to rwx */
} }
#if DEBUG_RUNMEN n = (n + PAGESIZE-1) & ~(PAGESIZE-1);
fprintf(stderr, "protect %3s %p len %5x\n", if (s1->verbose == 2) {
&"rx\0r \0rw\0rwx"[f*3], printf("protect %3s %p len %05x\n",
(void*)addr, (unsigned)((n + PAGESIZE-1) & ~(PAGESIZE-1))); &"rx\0r \0rw\0rwx"[f*3], (void*)addr, (unsigned)n);
#endif }
if (protect_pages((void*)addr, n, f) < 0) if (protect_pages((void*)addr, n, f) < 0)
return tcc_error_noabort( return tcc_error_noabort(
"mprotect failed (did you mean to configure --with-selinux?)"); "mprotect failed (did you mean to configure --with-selinux?)");
} }
} }
if (0 == mem) { if (0 == mem)
offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1); return (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
#ifndef HAVE_SELINUX
offset += PAGESIZE; /* extra space to align malloc memory start */
#endif
return offset;
}
if (copy) { if (++copy == 2) {
/* remove local symbols and free sections except symtab */ /* remove local symbols and free sections except symtab */
cleanup_symbols(s1); cleanup_symbols(s1);
cleanup_sections(s1); cleanup_sections(s1);
return 0; goto redo;
} }
/* relocate symbols */ /* relocate symbols */
@ -478,7 +430,6 @@ redo:
relocate_plt(s1); relocate_plt(s1);
#endif #endif
relocate_sections(s1); relocate_sections(s1);
copy = 1;
goto redo; goto redo;
} }
@ -546,6 +497,152 @@ static void win64_del_function_table(void *p)
} }
#endif #endif
static void bt_link(TCCState *s1)
{
#ifdef CONFIG_TCC_BACKTRACE
rt_context *rc;
void *p;
if (!s1->do_backtrace)
return;
rc = tcc_get_symbol(s1, "__rt_info");
if (!rc)
return;
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
rc->elf_str = (char *)symtab_section->link->data;
if (PTR_SIZE == 8 && !s1->dwarf)
rc->prog_base &= 0xffffffff00000000ULL;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(void*,int))p)(rc->bounds_start, 1);
}
#endif
rc->next = g_rc, g_rc = rc, s1->rc = rc;
if (0 == signal_set)
set_exception_handler(), signal_set = 1;
#endif
}
static void st_link(TCCState *s1)
{
rt_wait_sem();
s1->next = g_s1, g_s1 = s1;
bt_link(s1);
rt_post_sem();
}
/* remove 'el' from 'list' */
static void ptr_unlink(void *list, void *e, unsigned next)
{
void **pp, **nn, *p;
for (pp = list; !!(p = *pp); pp = nn) {
nn = (void*)((char*)p + next); /* nn = &p->next; */
if (p == e) {
*pp = *nn;
break;
}
}
}
static void st_unlink(TCCState *s1)
{
rt_wait_sem();
#ifdef CONFIG_TCC_BACKTRACE
ptr_unlink(&g_rc, s1->rc, offsetof(rt_context, next));
#endif
ptr_unlink(&g_s1, s1, offsetof(TCCState, next));
rt_post_sem();
}
#ifdef _WIN32
# define GETTID() GetCurrentThreadId()
#elif defined __linux__
# define GETTID() gettid()
#elif 0
# define GETTID() 1234 // threads not supported
#endif
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_jmp_buf, void *func, void *p_longjmp)
{
#ifdef GETTID
int tid = GETTID();
TCCState *s;
rt_wait_sem();
for (s = g_s1; s; s = s->next)
if (s->run_tid == tid)
s->run_tid = -1;
s1->run_tid = (int)tid;
rt_post_sem();
#endif
s1->run_lj = p_longjmp;
s1->run_jb = p_jmp_buf;
#ifdef CONFIG_TCC_BACKTRACE
if (s1->rc)
s1->rc->top_func = func;
#endif
return p_jmp_buf;
}
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void *data, TCCBtFunc *func)
{
s1->bt_func = func;
s1->bt_data = data;
}
static TCCState *rt_find_state(rt_frame *f)
{
#ifdef GETTID
int tid = GETTID();
TCCState *s;
for (s = g_s1; s; s = s->next)
if (s->run_tid == tid)
break;
return s;
#else
TCCState *s;
int level;
addr_t pc;
s = g_s1;
if (NULL == s || NULL == s->next) {
/* play it safe in the simple case when there is only one state */
return s;
}
for (level = 0; level < 8; ++level) {
if (rt_get_caller_pc(&pc, f, level) < 0)
break;
for (s = g_s1; s; s = s->next) {
if (pc >= (addr_t)s->run_ptr
&& pc < (addr_t)s->run_ptr + s->run_size)
return s;
}
}
return NULL;
#endif
}
static void rt_exit(rt_frame *f, int code)
{
TCCState *s;
rt_wait_sem();
s = rt_find_state(f);
rt_post_sem();
if (s && s->run_lj) {
if (code == 0)
code = 256;
((void(*)(void*,int))s->run_lj)(s->run_jb, code);
}
exit(code);
}
/* ------------------------------------------------------------- */
#else // if defined CONFIG_TCC_BACKTRACE_ONLY
static void rt_exit(rt_frame *f, int code)
{
exit(code);
}
#endif //ndef CONFIG_TCC_BACKTRACE_ONLY #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
@ -582,11 +679,17 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr)
return NULL; return NULL;
} }
typedef struct bt_info
{
char file[100];
int line;
char func[100];
addr_t func_pc;
} bt_info;
/* print the position in the source file of PC value 'pc' by reading /* print the position in the source file of PC value 'pc' by reading
the stabs debug information */ the stabs debug information */
static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, bt_info *bi)
rt_context** prc, const char *msg, const char *skip)
{ {
char func_name[128]; char func_name[128];
addr_t func_addr, last_pc, pc; addr_t func_addr, last_pc, pc;
@ -595,15 +698,12 @@ static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
const char *str, *p; const char *str, *p;
Stab_Sym *sym; Stab_Sym *sym;
next:
func_name[0] = '\0'; func_name[0] = '\0';
func_addr = 0; func_addr = 0;
incl_index = 0; incl_index = 0;
last_pc = (addr_t)-1; last_pc = (addr_t)-1;
last_line_num = 1; last_line_num = 1;
last_incl_index = 0; last_incl_index = 0;
if (NULL == rc)
goto found;
for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) { for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
str = rc->stab_str + sym->n_strx; str = rc->stab_str + sym->n_strx;
@ -680,50 +780,15 @@ next:
break; break;
} }
} }
last_incl_index = 0, func_name[0] = 0, func_addr = 0;
func_name[0] = '\0';
func_addr = 0;
last_incl_index = 0;
/* we try symtab symbols (no line number info) */
p = rt_elfsym(rc, wanted_pc, &func_addr);
if (p) {
pstrcpy(func_name, sizeof func_name, p);
goto found;
}
rc = rc->next;
goto next;
found: found:
i = last_incl_index; i = last_incl_index;
str = NULL;
if (i > 0) { if (i > 0) {
str = incl_files[--i]; pstrcpy(bi->file, sizeof bi->file, incl_files[--i]);
if (skip[0] && strstr(str, skip)) bi->line = last_line_num;
return (addr_t)-1;
} }
if (rc && rc->s1 && rc->s1->bt_func) { pstrcpy(bi->func, sizeof bi->func, func_name);
rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL); bi->func_pc = func_addr;
} else {
if (str)
rt_printf("%s:%d: ", str, last_line_num);
else
rt_printf("%08llx : ", (long long)wanted_pc);
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
}
#if 0
if (--i >= 0) {
rt_printf(" (included from ");
for (;;) {
rt_printf("%s", incl_files[i]);
if (--i < 0)
break;
rt_printf(", ");
}
rt_printf(")");
}
#endif
*prc = rc;
return func_addr; return func_addr;
} }
@ -793,8 +858,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
return retval; return retval;
} }
static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, bt_info *bi)
rt_context** prc, const char *msg, const char *skip)
{ {
unsigned char *ln; unsigned char *ln;
unsigned char *cp; unsigned char *cp;
@ -834,12 +898,10 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
char *filename; char *filename;
char *function; char *function;
next:
filename = NULL; filename = NULL;
function = NULL;
func_addr = 0; func_addr = 0;
line = 0; line = 0;
if (NULL == rc)
goto found;
ln = rc->dwarf_line; ln = rc->dwarf_line;
while (ln < rc->dwarf_line_end) { while (ln < rc->dwarf_line_end) {
@ -1070,44 +1132,28 @@ check_pc:
next_line: next_line:
ln = end; ln = end;
} }
filename = function = NULL, func_addr = 0;
filename = NULL;
func_addr = 0;
/* we try symtab symbols (no line number info) */
function = rt_elfsym(rc, wanted_pc, &func_addr);
if (function)
goto found;
rc = rc->next;
goto next;
found: found:
if (rc && rc->s1 && rc->s1->bt_func) { if (filename)
rc->s1->bt_func((void*)wanted_pc, filename, line, function); pstrcpy(bi->file, sizeof bi->file, filename), bi->line = line;
} else { if (function)
if (filename) { pstrcpy(bi->func, sizeof bi->func, function);
if (skip[0] && strstr(filename, skip)) bi->func_pc = func_addr;
return (addr_t)-1;
rt_printf("%s:%d: ", filename, line);
}
else
rt_printf("0x%08llx : ", (long long)wanted_pc);
rt_printf("%s %s", msg, function ? function : "???");
}
*prc = rc;
return (addr_t)func_addr; return (addr_t)func_addr;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifndef CONFIG_TCC_BACKTRACE_ONLY #ifndef CONFIG_TCC_BACKTRACE_ONLY
static static
#endif #endif
int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap)
{ {
rt_context *rc, *rd; rt_context *rc, *rc2;
addr_t pc = 0; addr_t pc;
char skip[100]; char skip[40], msg[200];
int i, level, ret, n, one; int i, level, ret, n, one;
const char *a, *b; const char *a, *b;
addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*); bt_info bi;
addr_t (*getinfo)(rt_context*, addr_t, bt_info*);
skip[0] = 0; skip[0] = 0;
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */ /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
@ -1119,41 +1165,73 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap)
/* hack for bcheck.c:dprintf(): one level, no newline */ /* hack for bcheck.c:dprintf(): one level, no newline */
if (fmt[0] == '\001') if (fmt[0] == '\001')
++fmt, one = 1; ++fmt, one = 1;
vsnprintf(msg, sizeof msg, fmt, ap);
rt_wait_sem(); rt_wait_sem();
rc = g_rc; rc = g_rc;
printline = rt_printline, n = 6; getinfo = rt_printline, n = 6;
if (rc) { if (rc) {
if (rc->dwarf) if (rc->dwarf)
printline = rt_printline_dwarf; getinfo = rt_printline_dwarf;
if (rc->num_callers) if (rc->num_callers)
n = rc->num_callers; n = rc->num_callers;
} }
for (i = level = 0; level < n; i++) { for (i = level = 0; level < n; i++) {
ret = rt_get_caller_pc(&pc, f, i); ret = rt_get_caller_pc(&pc, f, i);
if (ret != -1) { if (ret == -1)
pc = printline(rc, pc, &rd, level ? "by" : "at", skip); break;
if (pc == (addr_t)-1) memset(&bi, 0, sizeof bi);
continue; for (rc2 = rc; rc2; rc2 = rc2->next) {
} if (getinfo(rc2, pc, &bi))
if (level == 0) {
if (rd && rd->s1 && rd->s1->bt_func)
break; break;
if (ret != -1) /* we try symtab symbols (no line number info) */
rt_printf(": "); if (!!(a = rt_elfsym(rc2, pc, &bi.func_pc))) {
if (msg) pstrcpy(bi.func, sizeof bi.func, a);
rt_printf("%s: ", msg); break;
rt_vprintf(fmt, ap); }
} else if (ret == -1) }
break; //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc);
if (one) if (skip[0] && strstr(bi.file, skip))
break; continue;
#ifndef CONFIG_TCC_BACKTRACE_ONLY
{
TCCState *s = rt_find_state(f);
if (s && s->bt_func) {
ret = s->bt_func(
s->bt_data,
(void*)pc,
bi.file[0] ? bi.file : NULL,
bi.line,
bi.func[0] ? bi.func : NULL,
level == 0 ? msg : NULL
);
if (ret == 0)
break;
goto check_break;
}
}
#endif
if (bi.file[0]) {
rt_printf("%s:%d", bi.file, bi.line);
} else {
rt_printf("0x%08llx", (long long)pc);
}
rt_printf(": %s %s", level ? "by" : "at", bi.func[0] ? bi.func : "???");
if (level == 0) {
rt_printf(": %s", msg);
if (one)
break;
}
rt_printf("\n"); rt_printf("\n");
if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc))
check_break:
if (rc2
&& bi.func_pc
&& bi.func_pc == (addr_t)rc2->top_func)
break; break;
++level; ++level;
} }
rt_post_sem(); rt_post_sem();
return 0; return 0;
} }
@ -1161,49 +1239,14 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap)
/* emit a run time error at position 'pc' */ /* emit a run time error at position 'pc' */
static int rt_error(rt_frame *f, const char *fmt, ...) static int rt_error(rt_frame *f, const char *fmt, ...)
{ {
va_list ap; va_list ap; char msg[200]; int ret;
int ret;
va_start(ap, fmt); va_start(ap, fmt);
ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap); snprintf(msg, sizeof msg, "RUNTIME ERROR: %s", fmt);
ret = _tcc_backtrace(f, msg, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
static TCCState *rt_find_state(rt_frame *f)
{
TCCState *s;
int level;
addr_t pc;
rt_wait_sem();
for (s = g_s1; s; s = s->next) {
if (0 == s->run_lj)
continue;
for (level = 0; level < 8; ++level) {
if (rt_get_caller_pc(&pc, f, level) < 0)
break;
if (pc >= (addr_t)s->run_ptr
&& pc < (addr_t)s->run_ptr + s->run_size)
goto found;
}
}
found:
rt_post_sem();
//fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr);
return s;
}
static void rt_longjmp(rt_frame *f, int code)
{
TCCState *s = rt_find_state(f);
if (s && s->run_lj) {
if (code == 0)
code = 256;
((void(*)(void*,int))s->run_lj)(s->run_jb, code);
}
exit(code);
}
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifndef _WIN32 #ifndef _WIN32
@ -1338,8 +1381,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
rt_error(&f, "caught signal %d", signum); rt_error(&f, "caught signal %d", signum);
break; break;
} }
set_exception_handler(); {
rt_longjmp(&f, 255); sigset_t s;
sigemptyset(&s);
sigaddset(&s, signum);
sigprocmask(SIG_UNBLOCK, &s, NULL);
}
rt_exit(&f, 255);
} }
#ifndef SA_SIGINFO #ifndef SA_SIGINFO
@ -1353,12 +1401,11 @@ static void set_exception_handler(void)
/* install TCC signal handlers to print debug info on fatal /* install TCC signal handlers to print debug info on fatal
runtime errors */ runtime errors */
sigemptyset (&sigact.sa_mask); sigemptyset (&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER; sigact.sa_flags = SA_SIGINFO; //| SA_RESETHAND;
#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
sigact.sa_flags |= SA_ONSTACK; sigact.sa_flags |= SA_ONSTACK;
#endif #endif
sigact.sa_sigaction = sig_error; sigact.sa_sigaction = sig_error;
sigemptyset(&sigact.sa_mask);
sigaction(SIGFPE, &sigact, NULL); sigaction(SIGFPE, &sigact, NULL);
sigaction(SIGILL, &sigact, NULL); sigaction(SIGILL, &sigact, NULL);
sigaction(SIGSEGV, &sigact, NULL); sigaction(SIGSEGV, &sigact, NULL);
@ -1406,7 +1453,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
rt_error(&f, "caught exception %08x", code); rt_error(&f, "caught exception %08x", code);
break; break;
} }
rt_longjmp(&f, 255); rt_exit(&f, 255);
return EXCEPTION_EXECUTE_HANDLER; return EXCEPTION_EXECUTE_HANDLER;
} }
@ -1506,6 +1553,14 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
} }
#endif #endif
#else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level)
{
if (level)
return -1;
*paddr = f->ip;
return 0;
}
#endif /* CONFIG_TCC_BACKTRACE */ #endif /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC #ifdef CONFIG_TCC_STATIC

View File

@ -26,7 +26,9 @@ TESTS = \
# test4_static -- Not all relocation types are implemented yet. # test4_static -- Not all relocation types are implemented yet.
# asmtest / asmtest2 -- minor differences with gcc # asmtest / asmtest2 -- minor differences with gcc
ifneq ($(CONFIG_bcheck),no) ifeq ($(CONFIG_backtrace),no)
TESTS := $(filter-out libtest_mt, $(TESTS))
else ifneq ($(CONFIG_bcheck),no)
TESTS += btest test1b tccb TESTS += btest test1b tccb
endif endif
ifeq ($(CONFIG_dll),no) ifeq ($(CONFIG_dll),no)

View File

@ -83,11 +83,13 @@ PROG(my_program)
" return add(fib(n-1),fib(n-2));\n" " return add(fib(n-1),fib(n-2));\n"
"}\n" "}\n"
"\n" "\n"
"void bar(void) { *(void**)0 = 0; }\n"
"\n"
"int foo(int n)\n" "int foo(int n)\n"
"{\n" "{\n"
" if (n >= N_CRASH && n < N_CRASH + 3)\n"
" *(void**)0 = 0;\n"
" printf(\" %d\", fib(n));\n" " printf(\" %d\", fib(n));\n"
" if (n >= N_CRASH && n < N_CRASH + 8)\n"
" bar();\n"
" return 0;\n" " return 0;\n"
"# warning is this the correct file:line...\n" "# warning is this the correct file:line...\n"
"}\n"; "}\n";
@ -113,9 +115,27 @@ void parse_args(TCCState *s)
} }
} }
void bt_func(void *pc, const char *file, int line, const char *func) int backtrace_func(
void *ud,
void *pc,
const char *file,
int line,
const char *func,
const char *msg)
{ {
printf(" *** at %s:%d in '%s'\n", file, line, func); #if 0
printf("\n *** %p %s %s:%d in '%s'",
pc,
msg ? "at" : "by",
file ? file : "?",
line,
func ? func : "?");
return 1; // want more backtrace levels
#else
//printf(" [%d]", *(int*)ud);
printf("!");
return 0; // cancel backtrace
#endif
} }
TCCState *new_state(int w) TCCState *new_state(int w)
@ -132,9 +152,8 @@ TCCState *new_state(int w)
if (w & 2) { if (w & 2) {
tcc_set_options(s, "-bt"); tcc_set_options(s, "-bt");
tcc_define_symbol(s, "N_CRASH", str(M/2)); tcc_define_symbol(s, "N_CRASH", str(M/2));
tcc_set_backtrace_func(s, bt_func);
} else } else
tcc_define_symbol(s, "N_CRASH", "99"); tcc_define_symbol(s, "N_CRASH", "-1000");
tcc_set_output_type(s, TCC_OUTPUT_MEMORY); tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
return s; return s;
} }
@ -171,8 +190,7 @@ int state_test(int w)
if (c < M) if (c < M)
funcs[c] = reloc_state(s[c], "foo"); funcs[c] = reloc_state(s[c], "foo");
if (d < M && funcs[d]) { if (d < M && funcs[d]) {
if ((w & 2) && d == 8) tcc_set_backtrace_func(s[d], &d, backtrace_func);
printf("\n");
if (0 == tcc_setjmp(s[d], jb, funcs[d])) if (0 == tcc_setjmp(s[d], jb, funcs[d]))
funcs[d](F(d)); funcs[d](F(d));
} }
@ -189,15 +207,19 @@ TF_TYPE(thread_test_simple, vn)
int (*func)(int); int (*func)(int);
int ret; int ret;
int n = (size_t)vn; int n = (size_t)vn;
jmp_buf jb;
s = new_state(0); s = new_state(0); /* '2' for exceptions */
sleep_ms(1); sleep_ms(1);
ret = tcc_compile_string(s, my_program); ret = tcc_compile_string(s, my_program);
sleep_ms(1); sleep_ms(1);
if (ret >= 0) { if (ret >= 0) {
func = reloc_state(s, "foo"); func = reloc_state(s, "foo");
if (func) tcc_set_backtrace_func(s, &n, backtrace_func);
func(F(n)); if (func) {
if (0 == tcc_setjmp(s, jb, func))
func(F(n));
}
} }
tcc_delete(s); tcc_delete(s);
return 0; return 0;
@ -281,18 +303,20 @@ int main(int argc, char **argv)
printf("\n (%u ms)\n", getclock_ms() - t); printf("\n (%u ms)\n", getclock_ms() - t);
#endif #endif
#if 1 #if 1
printf("producing some exceptions\n "), fflush(stdout); printf("producing some exceptions (!)\n "), fflush(stdout);
t = getclock_ms(); t = getclock_ms();
state_test(2); state_test(2);
printf("\n (%u ms)\n", getclock_ms() - t); printf("\n (%u ms)\n", getclock_ms() - t);
#endif #endif
#if 1 #if 1
//{ int i; for (i = 0; i < 100; ++i) { printf("(%d) ", i);
printf("running fib in threads\n "), fflush(stdout); printf("running fib in threads\n "), fflush(stdout);
t = getclock_ms(); t = getclock_ms();
for (n = 0; n < M; ++n) for (n = 0; n < M; ++n)
create_thread(thread_test_simple, n); create_thread(thread_test_simple, n);
wait_threads(n); wait_threads(n);
printf("\n (%u ms)\n", getclock_ms() - t); printf("\n (%u ms)\n", getclock_ms() - t);
//}}
#endif #endif
#if 1 #if 1
printf("running tcc.c in threads to run fib\n "), fflush(stdout); printf("running tcc.c in threads to run fib\n "), fflush(stdout);

View File

@ -3889,7 +3889,7 @@ static void builtin_test_bits(unsigned long long x, int cnt[])
if ((unsigned long) x) cnt[7] += __builtin_ctzl(x); if ((unsigned long) x) cnt[7] += __builtin_ctzl(x);
if ((unsigned long long) x) cnt[8] += __builtin_ctzll(x); if ((unsigned long long) x) cnt[8] += __builtin_ctzll(x);
#if CC_NAME != CC_clang || GCC_MAJOR >= 11 #if GCC_MAJOR >= 6 && (CC_NAME != CC_clang || GCC_MAJOR >= 11)
/* Apple clang 10 does not have __builtin_clrsb[l[l]] */ /* Apple clang 10 does not have __builtin_clrsb[l[l]] */
cnt[9] += __builtin_clrsb(x); cnt[9] += __builtin_clrsb(x);
cnt[10] += __builtin_clrsbl(x); cnt[10] += __builtin_clrsbl(x);

View File

@ -202,4 +202,5 @@ exit /B %ERRORLEVEL%
.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o .\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o
.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o .\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o
.\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o .\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o
.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o
exit /B %ERRORLEVEL% exit /B %ERRORLEVEL%

View File

@ -62,8 +62,8 @@ extern "C" {
void *__cdecl malloc(size_t _Size); void *__cdecl malloc(size_t _Size);
void *__cdecl realloc(void *_Memory,size_t _NewSize); void *__cdecl realloc(void *_Memory,size_t _NewSize);
_CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size);
/* _CRTIMP void __cdecl _aligned_free(void *_Memory); _CRTIMP void __cdecl _aligned_free(void *_Memory);
_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment);
_CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset);
_CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment);
_CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment);

View File

@ -403,8 +403,8 @@ extern "C" {
void *__cdecl malloc(size_t _Size); void *__cdecl malloc(size_t _Size);
void *__cdecl realloc(void *_Memory,size_t _NewSize); void *__cdecl realloc(void *_Memory,size_t _NewSize);
_CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size);
//_CRTIMP void __cdecl _aligned_free(void *_Memory); _CRTIMP void __cdecl _aligned_free(void *_Memory);
//_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment);
_CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset);
_CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment);
_CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment);

View File

@ -70,7 +70,6 @@ void _tstart(void)
// ============================================= // =============================================
// for 'tcc -run ,,,' // for 'tcc -run ,,,'
__attribute__((weak)) extern int __rt_nr_exit;
__attribute__((weak)) extern int __run_on_exit(); __attribute__((weak)) extern int __run_on_exit();
int _runtmain(int argc, /* as tcc passed in */ char **argv) int _runtmain(int argc, /* as tcc passed in */ char **argv)
@ -92,7 +91,6 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
#if defined __i386__ || defined __x86_64__ #if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC); _controlfp(_PC_53, _MCW_PC);
#endif #endif
__rt_nr_exit = 0;
run_ctors(__argc, __targv, _tenviron); run_ctors(__argc, __targv, _tenviron);
ret = _tmain(__argc, __targv, _tenviron); ret = _tmain(__argc, __targv, _tenviron);
run_dtors(); run_dtors();