1
0
Fork 0

tccrun: 'tcc_relocate()' twice no longer supported

- abort with notice when tcc_relocate() is called with the
  former two-step method
- support backtrace & bcheck not only with tcc_run() but also
  for directly called functions from tcc_get_symbol(); enable
  witn 'tcc_set_options("-bt/-b");'
- move struct rt_context and debug sections into compiled code
  for TCC_OUTPUT_MEMORY also
- protect access (g_rc) with semaphore
Also:
- add armv7/aarch4/riscv64 github tests (qemu emulated)
- win32/build-tcc.bat: build cross compiler only with -x
This commit is contained in:
grischka 2024-02-11 13:13:13 +01:00
parent 7b9f19eaab
commit a7cd016d71
13 changed files with 420 additions and 299 deletions

View File

@ -8,21 +8,21 @@ jobs:
test-x86_64-linux: test-x86_64-linux:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc
run: ./configure && make && make test -k run: ./configure && make && make test -k
test-x86_64-osx: test-x86_64-osx:
runs-on: macos-11 runs-on: macos-11
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc
run: ./configure --config-codesign=no && make && make test -k run: ./configure --config-codesign=no && make && make test -k
test-x86_64-win32: test-x86_64-win32:
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc
shell: cmd shell: cmd
run: | run: |
@ -30,3 +30,51 @@ jobs:
set MSYSTEM=MINGW64 set MSYSTEM=MINGW64
set CHERE_INVOKING=yes set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
test-armv7-linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
with:
arch: armv7
distro: ubuntu20.04
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -q -y gcc make
run: |
echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
./configure && make && make test -k
test-aarch64-linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
with:
arch: aarch64
distro: ubuntu20.04
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -q -y gcc make
run: |
echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
./configure && make && make test -k
test-riscv64-linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
with:
arch: riscv64
distro: ubuntu20.04
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -q -y gcc make
run: |
echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
./configure && make && make test -k

View File

@ -152,8 +152,7 @@ TCC_X += riscv64 arm64-osx
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi # TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
# cross libtcc1.a targets to build # cross libtcc1.a targets to build
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince LIBTCC1_X = $(filter-out c67,$(TCC_X))
LIBTCC1_X += riscv64 arm64-osx
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF)) PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a) LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)

4
configure vendored
View File

@ -478,6 +478,10 @@ if test "$cpu" = "arm"; then
fi fi
fi fi
if test -n "$dwarf"; then
confvars="$confvars dwarf=$dwarf"
fi
# a final configuration tuning # a final configuration tuning
if test "$cc_name" != "tcc"; then if test "$cc_name" != "tcc"; then
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing" OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"

View File

@ -5,61 +5,56 @@
#define CONFIG_TCC_BACKTRACE_ONLY #define CONFIG_TCC_BACKTRACE_ONLY
#define ONE_SOURCE 1 #define ONE_SOURCE 1
#define pstrcpy tcc_pstrcpy #define pstrcpy tcc_pstrcpy
#define TCC_SEM_IMPL 1
#include "../tccrun.c" #include "../tccrun.c"
int (*__rt_error)(void*, void*, const char *, va_list);
__attribute__((weak)) void __bound_checking_lock(void);
__attribute__((weak)) void __bound_checking_unlock(void);
#ifndef _WIN32 #ifndef _WIN32
# define __declspec(n) # define __declspec(n)
#endif #endif
__declspec(dllexport) __declspec(dllexport)
void __bt_init(rt_context *p, int num_callers) void __bt_init(rt_context *p, int is_exe)
{ {
__attribute__((weak)) int main(); __attribute__((weak)) int main();
__attribute__((weak)) void __bound_init(void*, int); __attribute__((weak)) void __bound_init(void*, int);
struct rt_context *rc = &g_rtctxt;
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr); WAIT_SEM(&rt_sem);
//fprintf(stderr, "__bt_init %d %p %p %p\n", is_exe, p, p->stab_sym, p->bounds_start), fflush(stderr);
/* call __bound_init here due to redirection of sigaction */ /* call __bound_init here due to redirection of sigaction */
/* needed to add global symbols */ /* needed to add global symbols */
if (p->bounds_start) {
__bound_init(p->bounds_start, -1);
__bound_checking_lock();
}
if (num_callers) {
memcpy(rc, p, offsetof(rt_context, next));
rc->num_callers = num_callers - 1;
rc->top_func = main;
__rt_error = _rt_error;
set_exception_handler();
} else {
p->next = rc->next, rc->next = p;
}
if (p->bounds_start) if (p->bounds_start)
__bound_checking_unlock(); __bound_init(p->bounds_start, -1);
/* add to chain */
p->next = g_rc, g_rc = p;
if (is_exe) {
/* we are the executable (not a dll) */
p->top_func = main;
set_exception_handler();
}
POST_SEM(&rt_sem);
} }
__declspec(dllexport) __declspec(dllexport)
void __bt_exit(rt_context *p) void __bt_exit(rt_context *p)
{ {
struct rt_context *rc, **pp;
__attribute__((weak)) void __bound_exit_dll(void*); __attribute__((weak)) void __bound_exit_dll(void*);
struct rt_context *rc = &g_rtctxt;
if (p->bounds_start) { WAIT_SEM(&rt_sem);
__bound_exit_dll(p->bounds_start); //fprintf(stderr, "__bt_exit %d %p\n", !!p->top_func, p);
__bound_checking_lock();
}
while (rc) {
if (rc->next == p) {
rc->next = rc->next->next;
break;
}
rc = rc->next;
}
if (p->bounds_start) if (p->bounds_start)
__bound_checking_unlock(); __bound_exit_dll(p->bounds_start);
/* remove from chain */
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
if (rc == p) {
*pp = rc->next;
break;
}
POST_SEM(&rt_sem);
} }
/* copy a string and truncate it. */ /* copy a string and truncate it. */

View File

@ -4,8 +4,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#undef __attribute__
int (*__rt_error)(void*, void*, const char *, va_list);
#ifdef _WIN32 #ifdef _WIN32
# define DLL_EXPORT __declspec(dllexport) # define DLL_EXPORT __declspec(dllexport)
@ -19,16 +18,25 @@ int (*__rt_error)(void*, void*, const char *, va_list);
#pragma GCC diagnostic ignored "-Wframe-address" #pragma GCC diagnostic ignored "-Wframe-address"
#endif #endif
typedef struct rt_frame
{
void *ip, *fp, *sp;
} rt_frame;
__attribute__((weak))
int _rt_error(rt_frame *f, const char *msg, 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_error) { if (_rt_error) {
void *fp = __builtin_frame_address(1); rt_frame f;
void *ip = __builtin_return_address(0); f.fp = __builtin_frame_address(1);
f.ip = __builtin_return_address(0);
va_start(ap, fmt); va_start(ap, fmt);
ret = __rt_error(fp, ip, fmt, ap); ret = _rt_error(&f, "", fmt, ap);
va_end(ap); va_end(ap);
} else { } else {
const char *p, *nl = "\n"; const char *p, *nl = "\n";

View File

@ -60,6 +60,7 @@
#endif #endif
#endif /* ONE_SOURCE */ #endif /* ONE_SOURCE */
#define TCC_SEM_IMPL 1
#include "tcc.h" #include "tcc.h"
/********************************************************/ /********************************************************/
@ -110,7 +111,7 @@ static inline char *config_tccdir_w32(char *path)
#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH)) #define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))
#endif #endif
#ifdef TCC_TARGET_PE #ifdef TCC_IS_NATIVE
static void tcc_add_systemdir(TCCState *s) static void tcc_add_systemdir(TCCState *s)
{ {
char buf[1000]; char buf[1000];
@ -121,44 +122,6 @@ static void tcc_add_systemdir(TCCState *s)
#endif #endif
/********************************************************/ /********************************************************/
#if CONFIG_TCC_SEMLOCK
#if defined _WIN32
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
InitializeCriticalSection(&p->cr), p->init = 1;
EnterCriticalSection(&p->cr);
}
ST_FUNC void post_sem(TCCSem *p)
{
LeaveCriticalSection(&p->cr);
}
#elif defined __APPLE__
/* Half-compatible MacOS doesn't have non-shared (process local)
semaphores. Use the dispatch framework for lightweight locks. */
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
p->sem = dispatch_semaphore_create(1), p->init = 1;
dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER);
}
ST_FUNC void post_sem(TCCSem *p)
{
dispatch_semaphore_signal(p->sem);
}
#else
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
sem_init(&p->sem, 0, 1), p->init = 1;
while (sem_wait(&p->sem) < 0 && errno == EINTR);
}
ST_FUNC void post_sem(TCCSem *p)
{
sem_post(&p->sem);
}
#endif
#endif
PUB_FUNC void tcc_enter_state(TCCState *s1) PUB_FUNC void tcc_enter_state(TCCState *s1)
{ {
@ -1959,6 +1922,7 @@ dorun:
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt: case TCC_OPTION_bt:
s->rt_num_callers = atoi(optarg); /* zero = default (6) */ s->rt_num_callers = atoi(optarg); /* zero = default (6) */
goto enable_backtrace;
enable_backtrace: enable_backtrace:
s->do_backtrace = 1; s->do_backtrace = 1;
s->do_debug = s->do_debug ? s->do_debug : 1; s->do_debug = s->do_debug ? s->do_debug : 1;

48
tcc.h
View File

@ -1853,11 +1853,6 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
#define dwarf_str_section s1->dwarf_str_section #define dwarf_str_section s1->dwarf_str_section
#define dwarf_line_str_section s1->dwarf_line_str_section #define dwarf_line_str_section s1->dwarf_line_str_section
/* default dwarf version for "-g". use 0 to emit stab debug infos */
#ifndef DWARF_VERSION
# define DWARF_VERSION 0
#endif
/* default dwarf version for "-gdwarf" */ /* default dwarf version for "-gdwarf" */
#ifdef TCC_TARGET_MACHO #ifdef TCC_TARGET_MACHO
# define DEFAULT_DWARF_VERSION 2 # define DEFAULT_DWARF_VERSION 2
@ -1865,6 +1860,11 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
# define DEFAULT_DWARF_VERSION 5 # define DEFAULT_DWARF_VERSION 5
#endif #endif
/* default dwarf version for "-g". use 0 to emit stab debug infos */
#ifndef DWARF_VERSION
# define DWARF_VERSION 0 //DEFAULT_DWARF_VERSION
#endif
#if defined TCC_TARGET_PE #if defined TCC_TARGET_PE
# define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */ # define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */
#elif defined TCC_TARGET_X86_64 #elif defined TCC_TARGET_X86_64
@ -1946,3 +1946,41 @@ PUB_FUNC void tcc_exit_state(TCCState *s1);
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn) # define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
# define _tcc_error use_tcc_error_noabort # define _tcc_error use_tcc_error_noabort
#endif #endif
#if CONFIG_TCC_SEMLOCK && TCC_SEM_IMPL
#undef TCC_SEM_IMPL
#if defined _WIN32
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
InitializeCriticalSection(&p->cr), p->init = 1;
EnterCriticalSection(&p->cr);
}
ST_FUNC void post_sem(TCCSem *p)
{
LeaveCriticalSection(&p->cr);
}
#elif defined __APPLE__
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
p->sem = dispatch_semaphore_create(1), p->init = 1;
dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER);
}
ST_FUNC void post_sem(TCCSem *p)
{
dispatch_semaphore_signal(p->sem);
}
#else
ST_FUNC void wait_sem(TCCSem *p)
{
if (!p->init)
sem_init(&p->sem, 0, 1), p->init = 1;
while (sem_wait(&p->sem) < 0 && errno == EINTR);
}
ST_INLN void post_sem(TCCSem *p)
{
sem_post(&p->sem);
}
#endif
#endif

View File

@ -416,12 +416,15 @@ ST_FUNC void tcc_debug_new(TCCState *s1)
int shf = 0; int shf = 0;
if (!s1->dState) if (!s1->dState)
s1->dState = tcc_mallocz(sizeof *s1->dState); s1->dState = tcc_mallocz(sizeof *s1->dState);
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
/* include stab info with standalone backtrace support */ /* include stab info with standalone backtrace support */
if (s1->do_backtrace if (s1->do_debug && s1->output_type == TCC_OUTPUT_MEMORY)
&& (s1->output_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL))) s1->do_backtrace = 1;
if (s1->do_backtrace)
shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX
#endif #endif
if (s1->dwarf) { if (s1->dwarf) {
s1->dwlo = s1->nb_sections; s1->dwlo = s1->nb_sections;
dwarf_info_section = dwarf_info_section =

View File

@ -139,21 +139,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
tcc_free(s1->sym_attrs); tcc_free(s1->sym_attrs);
symtab_section = NULL; /* for tccrun.c:rt_printline() */ symtab_section = NULL; /* for tccrun.c:rt_printline() */
/* free any loaded DLLs */
#ifdef TCC_IS_NATIVE
for ( i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *ref = s1->loaded_dlls[i];
if ( ref->handle )
# ifdef _WIN32
FreeLibrary((HMODULE)ref->handle);
# else
dlclose(ref->handle);
# endif
}
#endif
/* free loaded dlls array */
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
} }
/* save section data state */ /* save section data state */
@ -1582,14 +1567,15 @@ static void put_ptr(TCCState *s1, Section *s, int offs)
ST_FUNC void tcc_add_btstub(TCCState *s1) ST_FUNC void tcc_add_btstub(TCCState *s1)
{ {
Section *s; Section *s;
int n, o; int n, o, *p;
CString cstr; CString cstr;
const char *__rt_info = &"___rt_info"[!s1->leading_underscore];
s = data_section; s = data_section;
/* Align to PTR_SIZE */ /* Align to PTR_SIZE */
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1)); section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
o = s->data_offset; o = s->data_offset;
/* create (part of) a struct rt_context (see tccrun.c) */ /* create a struct rt_context (see tccrun.c) */
if (s1->dwarf) { if (s1->dwarf) {
put_ptr(s1, dwarf_line_section, 0); put_ptr(s1, dwarf_line_section, 0);
put_ptr(s1, dwarf_line_section, -1); put_ptr(s1, dwarf_line_section, -1);
@ -1604,18 +1590,23 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
put_ptr(s1, stab_section, -1); put_ptr(s1, stab_section, -1);
put_ptr(s1, stab_section->link, 0); put_ptr(s1, stab_section->link, 0);
} }
*(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf;
/* skip esym_start/esym_end/elf_str (not loaded) */ /* skip esym_start/esym_end/elf_str (not loaded) */
section_ptr_add(s, 3 * PTR_SIZE); section_ptr_add(s, 3 * PTR_SIZE);
/* prog_base : local nameless symbol with offset 0 at SHN_ABS */
put_ptr(s1, NULL, 0); if (s1->output_type == TCC_OUTPUT_MEMORY && 0 == s1->dwarf) {
put_ptr(s1, text_section, 0);
} else {
/* prog_base : local nameless symbol with offset 0 at SHN_ABS */
put_ptr(s1, NULL, 0);
#if defined TCC_TARGET_MACHO #if defined TCC_TARGET_MACHO
/* adjust for __PAGEZERO */ /* adjust for __PAGEZERO */
if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE) if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE)
write64le(data_section->data + data_section->data_offset - PTR_SIZE, write64le(data_section->data + data_section->data_offset - PTR_SIZE,
(uint64_t)1 << 32); (uint64_t)1 << 32);
#endif #endif
n = 2 * PTR_SIZE; }
n = 4 * 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);
@ -1623,6 +1614,18 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
} }
#endif #endif
section_ptr_add(s, n); section_ptr_add(s, n);
p = section_ptr_add(s, 2 * sizeof (int));
p[0] = s1->rt_num_callers;
p[1] = s1->dwarf;
if (s->data_offset - o != 11 * PTR_SIZE + 2 * sizeof (int))
exit(99);
if (s1->output_type == TCC_OUTPUT_MEMORY) {
set_global_sym(s1, __rt_info, s, o);
return;
}
cstr_new(&cstr); cstr_new(&cstr);
cstr_printf(&cstr, cstr_printf(&cstr,
"extern void __bt_init(),__bt_exit(),__bt_init_dll();" "extern void __bt_init(),__bt_exit(),__bt_init_dll();"
@ -1637,14 +1640,14 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
#endif #endif
#endif #endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); s1->output_type != TCC_OUTPUT_DLL);
/* In case dlcose is called by application */ /* In case dlcose is called by application */
cstr_printf(&cstr, cstr_printf(&cstr,
"__attribute__((destructor)) static void __bt_exit_rt(){" "__attribute__((destructor)) static void __bt_exit_rt(){"
"__bt_exit(__rt_info);}"); "__bt_exit(__rt_info);}");
tcc_compile_string_no_debug(s1, cstr.data); tcc_compile_string_no_debug(s1, cstr.data);
cstr_free(&cstr); cstr_free(&cstr);
set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o); set_local_sym(s1, __rt_info, s, o);
} }
#endif /* def CONFIG_TCC_BACKTRACE */ #endif /* def CONFIG_TCC_BACKTRACE */
@ -1777,8 +1780,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
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-log.o"); tcc_add_support(s1, "bt-log.o");
if (s1->output_type != TCC_OUTPUT_MEMORY) tcc_add_btstub(s1);
tcc_add_btstub(s1); lpthread = 1;
} }
#endif #endif
if (lpthread) if (lpthread)

View File

@ -1963,8 +1963,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
tcc_add_support(s1, "bt-dll.o"); tcc_add_support(s1, "bt-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL) if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o"); tcc_add_support(s1, "bt-log.o");
if (s1->output_type != TCC_OUTPUT_MEMORY) tcc_add_btstub(s1);
tcc_add_btstub(s1);
} }
#endif #endif

405
tccrun.c
View File

@ -23,52 +23,69 @@
/* only native compiler supports -run */ /* only native compiler supports -run */
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_BACKTRACE
typedef struct rt_context typedef struct rt_context
{ {
#ifdef CONFIG_TCC_BACKTRACE
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */ /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
union { union {
struct { struct {
Stab_Sym *stab_sym, *stab_sym_end; Stab_Sym *stab_sym;
char *stab_str; Stab_Sym *stab_sym_end;
char *stab_str;
}; };
struct { struct {
unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str; unsigned char *dwarf_line;
unsigned char *dwarf_line_end;
unsigned char *dwarf_line_str;
}; };
}; };
addr_t dwarf; ElfW(Sym) *esym_start;
ElfW(Sym) *esym_start, *esym_end; ElfW(Sym) *esym_end;
char *elf_str; char *elf_str;
addr_t prog_base; addr_t prog_base;
void *bounds_start; void *bounds_start;
struct rt_context *next;
/* <-- */
int num_callers;
addr_t ip, fp, sp;
void *top_func; void *top_func;
#endif TCCState *s1;
jmp_buf jb; struct rt_context *next;
int do_jmp;
# define NR_AT_EXIT 32 int num_callers;
int nr_exit; int dwarf;
void *exitfunc[NR_AT_EXIT]; /* <-- */
void *exitarg[NR_AT_EXIT]; } rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
} rt_context;
typedef struct rt_frame
{
addr_t ip, fp, sp;
} rt_frame;
/* linked list of rt_contexts */
static rt_context *g_rc;
/* semaphore to protect it */
TCC_SEM(static rt_sem);
static int signal_set;
static void set_exception_handler(void);
int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
void rt_post_sem(void) { POST_SEM(&rt_sem); }
#endif /* def CONFIG_TCC_BACKTRACE */
/* handle exit/atexit for tcc_run() -- thread-unsafe */
static jmp_buf rt_jb;
static int rt_do_jmp;
static int rt_nr_exit;
static void *rt_exitfunc[32];
static void *rt_exitarg[32];
static rt_context g_rtctxt;
static void rt_exit(int code) static void rt_exit(int code)
{ {
rt_context *rc = &g_rtctxt; if (rt_do_jmp)
if (rc->do_jmp) longjmp(rt_jb, code ? code : 256);
longjmp(rc->jb, code ? code : 256);
exit(code); exit(code);
} }
#ifdef CONFIG_TCC_BACKTRACE /* ------------------------------------------------------------- */
static void set_exception_handler(void);
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
#endif /* CONFIG_TCC_BACKTRACE */
/* defined when included from lib/bt-exe.c */ /* defined when included from lib/bt-exe.c */
#ifndef CONFIG_TCC_BACKTRACE_ONLY #ifndef CONFIG_TCC_BACKTRACE_ONLY
@ -84,22 +101,60 @@ 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)
/* Do all relocations (needed before using tcc_get_symbol()) {
Returns -1 on error. */ #ifdef CONFIG_TCC_BACKTRACE
rt_context *rc;
void *p;
LIBTCCAPI int tcc_relocate(TCCState *s1) if (!s1->do_backtrace)
return;
rc = tcc_get_symbol(s1, "__rt_info");
if (!rc)
return;
rt_wait_sem();
rc->next = g_rc, g_rc = rc, rc->s1 = s1;
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
rc->elf_str = (char *)symtab_section->link->data;
rc->top_func = tcc_get_symbol(s1, "main");
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
rt_post_sem();
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;
rt_wait_sem();
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
if (rc->s1 == s1) {
*pp = rc->next;
break;
}
rt_post_sem();
#endif
}
#if !_WIN32 && !__APPLE__
//#define HAVE_SELINUX 1
#endif
static int rt_mem(TCCState *s1, int size)
{ {
void *ptr; void *ptr;
int size; int ptr_diff = 0;
unsigned ptr_diff = 0;
size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0)
return -1;
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
{
/* Using mmap instead of malloc */ /* Using mmap instead of malloc */
void *prw; void *prw;
char tmpfname[] = "/tmp/.tccrunXXXXXX"; char tmpfname[] = "/tmp/.tccrunXXXXXX";
@ -115,21 +170,68 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
return tcc_error_noabort("tccrun: could not map memory"); return tcc_error_noabort("tccrun: could not map memory");
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); ptr = tcc_malloc(size);
#endif #endif
s1->run_ptr = ptr; s1->run_ptr = ptr;
s1->run_size = size; s1->run_size = size;
tcc_relocate_ex(s1, ptr, ptr_diff); return ptr_diff;
return 0; }
/* ------------------------------------------------------------- */
/* Do all relocations (needed before using tcc_get_symbol())
Returns -1 on error. */
LIBTCCAPI int tcc_relocate(TCCState *s1)
{
int size, ret, ptr_diff;
if (s1->run_ptr)
exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
#ifdef CONFIG_TCC_BACKTRACE
/* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error"))
tcc_add_symbol(s1, "_rt_error", _rt_error);
#endif
size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0)
return -1;
ptr_diff = rt_mem(s1, size);
if (ptr_diff < 0)
return -1;
ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
if (ret == 0)
bt_link(s1);
return ret;
} }
ST_FUNC void tcc_run_free(TCCState *s1) ST_FUNC void tcc_run_free(TCCState *s1)
{ {
void *ptr = s1->run_ptr; unsigned size;
unsigned size = s1->run_size; void *ptr;
int i;
/* free any loaded DLLs */
for ( i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *ref = s1->loaded_dlls[i];
if ( ref->handle )
#ifdef _WIN32
FreeLibrary((HMODULE)ref->handle);
#else
dlclose(ref->handle);
#endif
}
/* free loaded dlls array */
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
/* unmap or unprotect and free memory */
ptr = s1->run_ptr;
if (NULL == ptr)
return;
bt_unlink(s1);
size = s1->run_size;
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
munmap(ptr, size * 2); munmap(ptr, size * 2);
#else #else
@ -153,18 +255,16 @@ static void run_cdtors(TCCState *s1, const char *start, const char *end,
static void run_on_exit(int ret) static void run_on_exit(int ret)
{ {
rt_context *rc = &g_rtctxt; int n = rt_nr_exit;
int n = rc->nr_exit;
while (n) while (n)
--n, ((void(*)(int,void*))rc->exitfunc[n])(ret, rc->exitarg[n]); --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
} }
static int rt_on_exit(void *function, void *arg) static int rt_on_exit(void *function, void *arg)
{ {
rt_context *rc = &g_rtctxt; if (rt_nr_exit < countof(rt_exitfunc)) {
if (rc->nr_exit < NR_AT_EXIT) { rt_exitfunc[rt_nr_exit] = function;
rc->exitfunc[rc->nr_exit] = function; rt_exitarg[rt_nr_exit++] = arg;
rc->exitarg[rc->nr_exit++] = arg;
return 0; return 0;
} }
return 1; return 1;
@ -179,7 +279,6 @@ static int rt_atexit(void *function)
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;
rt_context *rc = &g_rtctxt;
#if defined(__APPLE__) || defined(__FreeBSD__) #if defined(__APPLE__) || defined(__FreeBSD__)
char **envp = NULL; char **envp = NULL;
@ -204,58 +303,15 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
if ((addr_t)-1 == (addr_t)prog_main) if ((addr_t)-1 == (addr_t)prog_main)
return -1; return -1;
memset(rc, 0, sizeof *rc);
rc->do_jmp = 1;
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_debug) {
void *p;
if (s1->dwarf) {
rc->dwarf_line = dwarf_line_section->data;
rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset;
if (dwarf_line_str_section)
rc->dwarf_line_str = dwarf_line_str_section->data;
}
else
{
rc->stab_sym = (Stab_Sym *)stab_section->data;
rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
rc->stab_str = (char *)stab_section->link->data;
}
rc->dwarf = s1->dwarf;
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
rc->prog_base = text_section->sh_addr & 0xffffffff00000000ULL;
#if defined TCC_TARGET_MACHO
if (s1->dwarf)
rc->prog_base = (addr_t) -1;
#else
#endif
#endif
rc->top_func = tcc_get_symbol(s1, "main");
rc->num_callers = s1->rt_num_callers;
if ((p = tcc_get_symbol(s1, "__rt_error")))
*(void**)p = _rt_error;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
rc->bounds_start = (void*)bounds_section->sh_addr;
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(void*,int))p)(rc->bounds_start, 1);
}
#endif
set_exception_handler();
}
#endif
errno = 0; /* clean errno value */ errno = 0; /* clean errno value */
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
rt_do_jmp = 1;
rt_nr_exit = 0;
/* These aren't C symbols, so don't need leading underscore handling. */ /* These aren't C symbols, so don't need leading underscore handling. */
run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp); run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
ret = setjmp(rc->jb); ret = setjmp(rt_jb);
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)
@ -276,7 +332,7 @@ static void cleanup_symbols(TCCState *s1)
/* reset symtab */ /* reset symtab */
s->data_offset = s->link->data_offset = s->hash->data_offset = 0; s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
init_symtab(s); init_symtab(s);
/* re-add symbols except STB_LOCAL */ /* add global symbols again */
for (sym_index = 1; sym_index < end_sym; ++sym_index) { for (sym_index = 1; sym_index < end_sym; ++sym_index) {
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index]; ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
const char *name = (char *)s->link->data + sym->st_name; const char *name = (char *)s->link->data + sym->st_name;
@ -295,14 +351,10 @@ static void cleanup_sections(TCCState *s1)
do { do {
for (i = --f; i < p->nb_secs; i++) { for (i = --f; i < p->nb_secs; i++) {
Section *s = p->secs[i]; Section *s = p->secs[i];
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
|| 0 == memcmp(s->name, ".stab", 5)
|| 0 == memcmp(s->name, ".debug_", 7)) {
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset); s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
} else { } else {
free_section(s); free_section(s), tcc_free(s), p->secs[i] = NULL;
if (0 == (s->sh_flags & SHF_ALLOC))
tcc_free(s), p->secs[i] = NULL;
} }
} }
} while (++p, f); } while (++p, f);
@ -335,8 +387,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
resolve_common_syms(s1); resolve_common_syms(s1);
build_got_entries(s1, 0); build_got_entries(s1, 0);
#endif #endif
if (s1->nb_errors)
return -1;
} }
offset = copy = 0; offset = copy = 0;
@ -349,6 +399,8 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
#endif #endif
redo: redo:
if (s1->nb_errors)
return -1;
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++) {
@ -376,7 +428,6 @@ redo:
if (s == s1->uw_pdata) if (s == s1->uw_pdata)
s1->run_function_table = win64_add_function_table(s1); s1->run_function_table = win64_add_function_table(s1);
#endif #endif
free_section(s);
continue; continue;
} }
@ -423,11 +474,18 @@ redo:
#endif #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 " "mprotect failed (did you mean to configure --with-selinux?)");
"(did you mean to configure --with-selinux?)");
} }
} }
if (0 == mem) {
offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
#ifndef HAVE_SELINUX
offset += PAGESIZE; /* extra space to align malloc memory start */
#endif
return offset;
}
if (copy) { if (copy) {
/* remove local symbols and free sections except symtab */ /* remove local symbols and free sections except symtab */
cleanup_symbols(s1); cleanup_symbols(s1);
@ -437,17 +495,7 @@ redo:
/* relocate symbols */ /* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib)); relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors) /* relocate sections */
return -1;
if (0 == mem) {
offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
#ifndef HAVE_SELINUX
offset += PAGESIZE; /* extra space to align malloc memory start */
#endif
return offset;
}
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
s1->pe_imagebase = mem; s1->pe_imagebase = mem;
#else #else
@ -578,6 +626,8 @@ next:
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;
@ -658,14 +708,16 @@ next:
func_name[0] = '\0'; func_name[0] = '\0';
func_addr = 0; func_addr = 0;
last_incl_index = 0; last_incl_index = 0;
/* we try symtab symbols (no line number info) */ /* we try symtab symbols (no line number info) */
p = rt_elfsym(rc, wanted_pc, &func_addr); p = rt_elfsym(rc, wanted_pc, &func_addr);
if (p) { if (p) {
pstrcpy(func_name, sizeof func_name, p); pstrcpy(func_name, sizeof func_name, p);
goto found; goto found;
} }
if ((rc = rc->next)) rc = rc->next;
goto next; goto next;
found: found:
i = last_incl_index; i = last_incl_index;
if (i > 0) { if (i > 0) {
@ -799,6 +851,11 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
char *function; char *function;
next: next:
filename = NULL;
func_addr = 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) {
dir_size = 0; dir_size = 0;
@ -953,8 +1010,7 @@ check_pc:
pc = dwarf_read_8(cp, end); pc = dwarf_read_8(cp, end);
#endif #endif
#if defined TCC_TARGET_MACHO #if defined TCC_TARGET_MACHO
if (rc->prog_base != (addr_t) -1) pc += rc->prog_base;
pc += rc->prog_base;
#endif #endif
opindex = 0; opindex = 0;
break; break;
@ -1036,8 +1092,9 @@ next_line:
function = rt_elfsym(rc, wanted_pc, &func_addr); function = rt_elfsym(rc, wanted_pc, &func_addr);
if (function) if (function)
goto found; goto found;
if ((rc = rc->next)) rc = rc->next;
goto next; goto next;
found: found:
if (filename) { if (filename) {
if (skip[0] && strstr(filename, skip)) if (skip[0] && strstr(filename, skip))
@ -1051,25 +1108,17 @@ found:
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level); static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)
{ {
rt_context *rc = &g_rtctxt; rt_context *rc;
addr_t pc = 0; addr_t pc = 0;
char skip[100]; char skip[100];
int i, level, ret, n, one; int i, level, ret, n, one;
const char *a, *b, *msg; const char *a, *b;
addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
if (fp) { addr_t top_func = 0;
/* we're called from tcc_backtrace. */
rc->fp = (addr_t)fp;
rc->ip = (addr_t)ip;
msg = "";
} else {
/* we're called from signal/exception handler */
msg = "RUNTIME ERROR: ";
}
skip[0] = 0; 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' */
@ -1082,15 +1131,22 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
if (fmt[0] == '\001') if (fmt[0] == '\001')
++fmt, one = 1; ++fmt, one = 1;
n = rc->num_callers ? rc->num_callers : 6; rt_wait_sem();
rc = g_rc;
printline = rt_printline, n = 6;
if (rc) {
if (rc->dwarf)
printline = rt_printline_dwarf;
if (rc->num_callers)
n = rc->num_callers;
top_func = (addr_t)rc->top_func;
}
for (i = level = 0; level < n; i++) { for (i = level = 0; level < n; i++) {
ret = rt_get_caller_pc(&pc, rc, i); ret = rt_get_caller_pc(&pc, f, i);
a = "%s"; a = "%s";
if (ret != -1) { if (ret != -1) {
if (rc->dwarf) pc = printline(rc, pc, level ? "by" : "at", skip);
pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
else
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
if (pc == (addr_t)-1) if (pc == (addr_t)-1)
continue; continue;
a = ": %s"; a = ": %s";
@ -1103,22 +1159,22 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
if (one) if (one)
break; break;
rt_printf("\n"); rt_printf("\n");
if (ret == -1 || (pc == (addr_t)rc->top_func && pc)) if (ret == -1 || (pc == top_func && pc))
break; break;
++level; ++level;
} }
rc->ip = rc->fp = 0; rt_post_sem();
return 0; return 0;
} }
/* emit a run time error at position 'pc' */ /* emit a run time error at position 'pc' */
static int rt_error(const char *fmt, ...) static int rt_error(rt_frame *f, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int ret; int ret;
va_start(ap, fmt); va_start(ap, fmt);
ret = _rt_error(0, 0, fmt, ap); ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
@ -1135,7 +1191,7 @@ static int rt_error(const char *fmt, ...)
#endif #endif
/* translate from ucontext_t* to internal rt_context * */ /* translate from ucontext_t* to internal rt_context * */
static void rt_getcontext(ucontext_t *uc, rt_context *rc) static void rt_getcontext(ucontext_t *uc, rt_frame *rc)
{ {
#if defined _WIN64 #if defined _WIN64
rc->ip = uc->Rip; rc->ip = uc->Rip;
@ -1228,33 +1284,33 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
/* signal handler for fatal errors */ /* signal handler for fatal errors */
static void sig_error(int signum, siginfo_t *siginf, void *puc) static void sig_error(int signum, siginfo_t *siginf, void *puc)
{ {
rt_context *rc = &g_rtctxt; rt_frame f;
rt_getcontext(puc, rc); rt_getcontext(puc, &f);
switch(signum) { switch(signum) {
case SIGFPE: case SIGFPE:
switch(siginf->si_code) { switch(siginf->si_code) {
case FPE_INTDIV: case FPE_INTDIV:
case FPE_FLTDIV: case FPE_FLTDIV:
rt_error("division by zero"); rt_error(&f, "division by zero");
break; break;
default: default:
rt_error("floating point exception"); rt_error(&f, "floating point exception");
break; break;
} }
break; break;
case SIGBUS: case SIGBUS:
case SIGSEGV: case SIGSEGV:
rt_error("invalid memory access"); rt_error(&f, "invalid memory access");
break; break;
case SIGILL: case SIGILL:
rt_error("illegal instruction"); rt_error(&f, "illegal instruction");
break; break;
case SIGABRT: case SIGABRT:
rt_error("abort() called"); rt_error(&f, "abort() called");
break; break;
default: default:
rt_error("caught signal %d", signum); rt_error(&f, "caught signal %d", signum);
break; break;
} }
rt_exit(255); rt_exit(255);
@ -1301,30 +1357,31 @@ static void set_exception_handler(void)
/* signal handler for fatal errors */ /* signal handler for fatal errors */
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{ {
rt_context *rc = &g_rtctxt; rt_frame f;
unsigned code; unsigned code;
rt_getcontext(ex_info->ContextRecord, rc);
rt_getcontext(ex_info->ContextRecord, &f);
switch (code = ex_info->ExceptionRecord->ExceptionCode) { switch (code = ex_info->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_ACCESS_VIOLATION:
rt_error("invalid memory access"); rt_error(&f, "invalid memory access");
break; break;
case EXCEPTION_STACK_OVERFLOW: case EXCEPTION_STACK_OVERFLOW:
rt_error("stack overflow"); rt_error(&f, "stack overflow");
break; break;
case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_DIVIDE_BY_ZERO:
rt_error("division by zero"); rt_error(&f, "division by zero");
break; break;
case EXCEPTION_BREAKPOINT: case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP: case EXCEPTION_SINGLE_STEP:
rc->ip = *(addr_t*)rc->sp; f.ip = *(addr_t*)f.sp;
rt_error("breakpoint/single-step exception:"); rt_error(&f, "breakpoint/single-step exception:");
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
default: default:
rt_error("caught exception %08x", code); rt_error(&f, "caught exception %08x", code);
break; break;
} }
if (rc->do_jmp) if (rt_do_jmp)
rt_exit(255); rt_exit(255);
return EXCEPTION_EXECUTE_HANDLER; return EXCEPTION_EXECUTE_HANDLER;
} }
@ -1340,7 +1397,7 @@ static void set_exception_handler(void)
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* return the PC at frame level 'level'. Return negative if not found */ /* return the PC at frame level 'level'. Return negative if not found */
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{ {
addr_t ip, fp; addr_t ip, fp;
if (level == 0) { if (level == 0) {
@ -1364,7 +1421,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
} }
#elif defined(__arm__) #elif defined(__arm__)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{ {
/* XXX: only supports linux/bsd */ /* XXX: only supports linux/bsd */
#if !defined(__linux__) && \ #if !defined(__linux__) && \
@ -1384,7 +1441,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{ {
if (level == 0) { if (level == 0) {
*paddr = rc->ip; *paddr = rc->ip;
@ -1398,7 +1455,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
} }
#elif defined(__riscv) #elif defined(__riscv)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{ {
if (level == 0) { if (level == 0) {
*paddr = rc->ip; *paddr = rc->ip;
@ -1415,7 +1472,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
#else #else
#warning add arch specific rt_get_caller_pc() #warning add arch specific rt_get_caller_pc()
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{ {
return -1; return -1;
} }

View File

@ -76,6 +76,8 @@ DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
endif endif
all test : all test :
@echo ------------ version ------------
@$(TCC_LOCAL) -v
@$(MAKE) --no-print-directory -s clean @$(MAKE) --no-print-directory -s clean
@$(MAKE) --no-print-directory -s -r $(TESTS) @$(MAKE) --no-print-directory -s -r $(TESTS)

View File

@ -10,7 +10,7 @@ set /p VERSION= < ..\VERSION
set TCCDIR= set TCCDIR=
set BINDIR= set BINDIR=
set DOC=no set DOC=no
set EXES_ONLY=no set XCC=no
goto :a0 goto :a0
:a2 :a2
shift shift
@ -27,7 +27,7 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2
if (%1)==(-i) set TCCDIR=%2&& goto :a2 if (%1)==(-i) set TCCDIR=%2&& goto :a2
if (%1)==(-b) set BINDIR=%2&& goto :a2 if (%1)==(-b) set BINDIR=%2&& goto :a2
if (%1)==(-d) set DOC=yes&& goto :a3 if (%1)==(-d) set DOC=yes&& goto :a3
if (%1)==(-x) set EXES_ONLY=yes&& goto :a3 if (%1)==(-x) set XCC=yes&& goto :a3
if (%1)==() goto :p1 if (%1)==() goto :p1
:usage :usage
echo usage: build-tcc.bat [ options ... ] echo usage: build-tcc.bat [ options ... ]
@ -39,7 +39,7 @@ echo -v "version" set tcc version
echo -i tccdir install tcc into tccdir echo -i tccdir install tcc into tccdir
echo -b bindir but install tcc.exe and libtcc.dll into bindir echo -b bindir but install tcc.exe and libtcc.dll into bindir
echo -d create tcc-doc.html too (needs makeinfo) echo -d create tcc-doc.html too (needs makeinfo)
echo -x just create the executables echo -x build the cross compiler too
echo -clean delete all previously produced files and directories echo -clean delete all previously produced files and directories
exit /B 1 exit /B 1
@ -144,6 +144,7 @@ for %%f in (*tcc.exe *tcc.dll) do @del %%f
%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL %CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL
@if errorlevel 1 goto :the_end @if errorlevel 1 goto :the_end
%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0" %CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
if not _%XCC%_==_yes_ goto :compiler_done
%CC% -o %PX%-tcc.exe ..\tcc.c %DX% %CC% -o %PX%-tcc.exe ..\tcc.c %DX%
:compiler_done :compiler_done
@if (%EXES_ONLY%)==(yes) goto :files_done @if (%EXES_ONLY%)==(yes) goto :files_done