mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-26 03:50:07 +08:00
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:
parent
7b9f19eaab
commit
a7cd016d71
54
.github/workflows/build.yml
vendored
54
.github/workflows/build.yml
vendored
@ -8,21 +8,21 @@ jobs:
|
||||
test-x86_64-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
run: ./configure && make && make test -k
|
||||
|
||||
test-x86_64-osx:
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
run: ./configure --config-codesign=no && make && make test -k
|
||||
|
||||
test-x86_64-win32:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -30,3 +30,51 @@ jobs:
|
||||
set MSYSTEM=MINGW64
|
||||
set CHERE_INVOKING=yes
|
||||
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
|
||||
|
3
Makefile
3
Makefile
@ -152,8 +152,7 @@ TCC_X += riscv64 arm64-osx
|
||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||
|
||||
# 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 += riscv64 arm64-osx
|
||||
LIBTCC1_X = $(filter-out c67,$(TCC_X))
|
||||
|
||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
|
||||
|
4
configure
vendored
4
configure
vendored
@ -478,6 +478,10 @@ if test "$cpu" = "arm"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dwarf"; then
|
||||
confvars="$confvars dwarf=$dwarf"
|
||||
fi
|
||||
|
||||
# a final configuration tuning
|
||||
if test "$cc_name" != "tcc"; then
|
||||
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"
|
||||
|
63
lib/bt-exe.c
63
lib/bt-exe.c
@ -5,61 +5,56 @@
|
||||
#define CONFIG_TCC_BACKTRACE_ONLY
|
||||
#define ONE_SOURCE 1
|
||||
#define pstrcpy tcc_pstrcpy
|
||||
#define TCC_SEM_IMPL 1
|
||||
#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
|
||||
# define __declspec(n)
|
||||
#endif
|
||||
|
||||
__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)) 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 */
|
||||
/* 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)
|
||||
__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)
|
||||
void __bt_exit(rt_context *p)
|
||||
{
|
||||
struct rt_context *rc, **pp;
|
||||
__attribute__((weak)) void __bound_exit_dll(void*);
|
||||
struct rt_context *rc = &g_rtctxt;
|
||||
|
||||
if (p->bounds_start) {
|
||||
__bound_exit_dll(p->bounds_start);
|
||||
__bound_checking_lock();
|
||||
}
|
||||
while (rc) {
|
||||
if (rc->next == p) {
|
||||
rc->next = rc->next->next;
|
||||
break;
|
||||
}
|
||||
rc = rc->next;
|
||||
}
|
||||
WAIT_SEM(&rt_sem);
|
||||
//fprintf(stderr, "__bt_exit %d %p\n", !!p->top_func, p);
|
||||
|
||||
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. */
|
||||
|
20
lib/bt-log.c
20
lib/bt-log.c
@ -4,8 +4,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
#undef __attribute__
|
||||
|
||||
#ifdef _WIN32
|
||||
# define DLL_EXPORT __declspec(dllexport)
|
||||
@ -19,16 +18,25 @@ int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
#pragma GCC diagnostic ignored "-Wframe-address"
|
||||
#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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
if (__rt_error) {
|
||||
void *fp = __builtin_frame_address(1);
|
||||
void *ip = __builtin_return_address(0);
|
||||
if (_rt_error) {
|
||||
rt_frame f;
|
||||
f.fp = __builtin_frame_address(1);
|
||||
f.ip = __builtin_return_address(0);
|
||||
va_start(ap, fmt);
|
||||
ret = __rt_error(fp, ip, fmt, ap);
|
||||
ret = _rt_error(&f, "", fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
const char *p, *nl = "\n";
|
||||
|
42
libtcc.c
42
libtcc.c
@ -60,6 +60,7 @@
|
||||
#endif
|
||||
#endif /* ONE_SOURCE */
|
||||
|
||||
#define TCC_SEM_IMPL 1
|
||||
#include "tcc.h"
|
||||
|
||||
/********************************************************/
|
||||
@ -110,7 +111,7 @@ static inline char *config_tccdir_w32(char *path)
|
||||
#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef TCC_IS_NATIVE
|
||||
static void tcc_add_systemdir(TCCState *s)
|
||||
{
|
||||
char buf[1000];
|
||||
@ -121,44 +122,6 @@ static void tcc_add_systemdir(TCCState *s)
|
||||
#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)
|
||||
{
|
||||
@ -1959,6 +1922,7 @@ dorun:
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
case TCC_OPTION_bt:
|
||||
s->rt_num_callers = atoi(optarg); /* zero = default (6) */
|
||||
goto enable_backtrace;
|
||||
enable_backtrace:
|
||||
s->do_backtrace = 1;
|
||||
s->do_debug = s->do_debug ? s->do_debug : 1;
|
||||
|
48
tcc.h
48
tcc.h
@ -1853,11 +1853,6 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
|
||||
#define dwarf_str_section s1->dwarf_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" */
|
||||
#ifdef TCC_TARGET_MACHO
|
||||
# define DEFAULT_DWARF_VERSION 2
|
||||
@ -1865,6 +1860,11 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
|
||||
# define DEFAULT_DWARF_VERSION 5
|
||||
#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
|
||||
# define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */
|
||||
#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_error use_tcc_error_noabort
|
||||
#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
|
||||
|
7
tccdbg.c
7
tccdbg.c
@ -416,12 +416,15 @@ ST_FUNC void tcc_debug_new(TCCState *s1)
|
||||
int shf = 0;
|
||||
if (!s1->dState)
|
||||
s1->dState = tcc_mallocz(sizeof *s1->dState);
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
/* include stab info with standalone backtrace support */
|
||||
if (s1->do_backtrace
|
||||
&& (s1->output_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL)))
|
||||
if (s1->do_debug && s1->output_type == TCC_OUTPUT_MEMORY)
|
||||
s1->do_backtrace = 1;
|
||||
if (s1->do_backtrace)
|
||||
shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX
|
||||
#endif
|
||||
|
||||
if (s1->dwarf) {
|
||||
s1->dwlo = s1->nb_sections;
|
||||
dwarf_info_section =
|
||||
|
61
tccelf.c
61
tccelf.c
@ -139,21 +139,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
|
||||
|
||||
tcc_free(s1->sym_attrs);
|
||||
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 */
|
||||
@ -1582,14 +1567,15 @@ static void put_ptr(TCCState *s1, Section *s, int offs)
|
||||
ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||
{
|
||||
Section *s;
|
||||
int n, o;
|
||||
int n, o, *p;
|
||||
CString cstr;
|
||||
const char *__rt_info = &"___rt_info"[!s1->leading_underscore];
|
||||
|
||||
s = data_section;
|
||||
/* Align to PTR_SIZE */
|
||||
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
|
||||
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) {
|
||||
put_ptr(s1, dwarf_line_section, 0);
|
||||
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->link, 0);
|
||||
}
|
||||
*(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf;
|
||||
|
||||
/* skip esym_start/esym_end/elf_str (not loaded) */
|
||||
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
|
||||
/* adjust for __PAGEZERO */
|
||||
if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE)
|
||||
write64le(data_section->data + data_section->data_offset - PTR_SIZE,
|
||||
(uint64_t)1 << 32);
|
||||
/* adjust for __PAGEZERO */
|
||||
if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE)
|
||||
write64le(data_section->data + data_section->data_offset - PTR_SIZE,
|
||||
(uint64_t)1 << 32);
|
||||
#endif
|
||||
n = 2 * PTR_SIZE;
|
||||
}
|
||||
n = 4 * PTR_SIZE;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
put_ptr(s1, bounds_section, 0);
|
||||
@ -1623,6 +1614,18 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||
}
|
||||
#endif
|
||||
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_printf(&cstr,
|
||||
"extern void __bt_init(),__bt_exit(),__bt_init_dll();"
|
||||
@ -1637,14 +1640,14 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||
#endif
|
||||
#endif
|
||||
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 */
|
||||
cstr_printf(&cstr,
|
||||
"__attribute__((destructor)) static void __bt_exit_rt(){"
|
||||
"__bt_exit(__rt_info);}");
|
||||
tcc_compile_string_no_debug(s1, cstr.data);
|
||||
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 */
|
||||
|
||||
@ -1777,8 +1780,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||
tcc_add_support(s1, "bt-exe.o");
|
||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||
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
|
||||
if (lpthread)
|
||||
|
3
tccpe.c
3
tccpe.c
@ -1963,8 +1963,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
tcc_add_support(s1, "bt-dll.o");
|
||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-log.o");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||
tcc_add_btstub(s1);
|
||||
tcc_add_btstub(s1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
405
tccrun.c
405
tccrun.c
@ -23,52 +23,69 @@
|
||||
/* only native compiler supports -run */
|
||||
#ifdef TCC_IS_NATIVE
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
typedef struct rt_context
|
||||
{
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
|
||||
union {
|
||||
struct {
|
||||
Stab_Sym *stab_sym, *stab_sym_end;
|
||||
char *stab_str;
|
||||
Stab_Sym *stab_sym;
|
||||
Stab_Sym *stab_sym_end;
|
||||
char *stab_str;
|
||||
};
|
||||
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, *esym_end;
|
||||
ElfW(Sym) *esym_start;
|
||||
ElfW(Sym) *esym_end;
|
||||
char *elf_str;
|
||||
|
||||
addr_t prog_base;
|
||||
void *bounds_start;
|
||||
struct rt_context *next;
|
||||
/* <-- */
|
||||
int num_callers;
|
||||
addr_t ip, fp, sp;
|
||||
void *top_func;
|
||||
#endif
|
||||
jmp_buf jb;
|
||||
int do_jmp;
|
||||
# define NR_AT_EXIT 32
|
||||
int nr_exit;
|
||||
void *exitfunc[NR_AT_EXIT];
|
||||
void *exitarg[NR_AT_EXIT];
|
||||
} rt_context;
|
||||
TCCState *s1;
|
||||
struct rt_context *next;
|
||||
|
||||
int num_callers;
|
||||
int dwarf;
|
||||
/* <-- */
|
||||
} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
|
||||
|
||||
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)
|
||||
{
|
||||
rt_context *rc = &g_rtctxt;
|
||||
if (rc->do_jmp)
|
||||
longjmp(rc->jb, code ? code : 256);
|
||||
if (rt_do_jmp)
|
||||
longjmp(rt_jb, code ? code : 256);
|
||||
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 */
|
||||
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
||||
|
||||
@ -84,22 +101,60 @@ static void *win64_add_function_table(TCCState *s1);
|
||||
static void win64_del_function_table(void *);
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
static void bt_link(TCCState *s1)
|
||||
{
|
||||
#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;
|
||||
int size;
|
||||
unsigned ptr_diff = 0;
|
||||
|
||||
size = tcc_relocate_ex(s1, NULL, 0);
|
||||
if (size < 0)
|
||||
return -1;
|
||||
|
||||
int ptr_diff = 0;
|
||||
#ifdef HAVE_SELINUX
|
||||
{
|
||||
/* Using mmap instead of malloc */
|
||||
void *prw;
|
||||
char tmpfname[] = "/tmp/.tccrunXXXXXX";
|
||||
@ -115,21 +170,68 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
|
||||
return tcc_error_noabort("tccrun: could not map memory");
|
||||
ptr_diff = (char*)prw - (char*)ptr; /* = size; */
|
||||
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
|
||||
}
|
||||
#else
|
||||
ptr = tcc_malloc(size);
|
||||
#endif
|
||||
s1->run_ptr = ptr;
|
||||
s1->run_size = size;
|
||||
tcc_relocate_ex(s1, ptr, ptr_diff);
|
||||
return 0;
|
||||
return ptr_diff;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* 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)
|
||||
{
|
||||
void *ptr = s1->run_ptr;
|
||||
unsigned size = s1->run_size;
|
||||
unsigned 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
|
||||
munmap(ptr, size * 2);
|
||||
#else
|
||||
@ -153,18 +255,16 @@ static void run_cdtors(TCCState *s1, const char *start, const char *end,
|
||||
|
||||
static void run_on_exit(int ret)
|
||||
{
|
||||
rt_context *rc = &g_rtctxt;
|
||||
int n = rc->nr_exit;
|
||||
int n = rt_nr_exit;
|
||||
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)
|
||||
{
|
||||
rt_context *rc = &g_rtctxt;
|
||||
if (rc->nr_exit < NR_AT_EXIT) {
|
||||
rc->exitfunc[rc->nr_exit] = function;
|
||||
rc->exitarg[rc->nr_exit++] = arg;
|
||||
if (rt_nr_exit < countof(rt_exitfunc)) {
|
||||
rt_exitfunc[rt_nr_exit] = function;
|
||||
rt_exitarg[rt_nr_exit++] = arg;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -179,7 +279,6 @@ static int rt_atexit(void *function)
|
||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
int (*prog_main)(int, char **, char **), ret;
|
||||
rt_context *rc = &g_rtctxt;
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
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)
|
||||
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 */
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
rt_do_jmp = 1;
|
||||
rt_nr_exit = 0;
|
||||
|
||||
/* These aren't C symbols, so don't need leading underscore handling. */
|
||||
run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
|
||||
ret = setjmp(rc->jb);
|
||||
ret = setjmp(rt_jb);
|
||||
if (0 == ret)
|
||||
ret = prog_main(argc, argv, envp);
|
||||
else if (256 == ret)
|
||||
@ -276,7 +332,7 @@ static void cleanup_symbols(TCCState *s1)
|
||||
/* reset symtab */
|
||||
s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
|
||||
init_symtab(s);
|
||||
/* re-add symbols except STB_LOCAL */
|
||||
/* add global symbols again */
|
||||
for (sym_index = 1; sym_index < end_sym; ++sym_index) {
|
||||
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||
const char *name = (char *)s->link->data + sym->st_name;
|
||||
@ -295,14 +351,10 @@ static void cleanup_sections(TCCState *s1)
|
||||
do {
|
||||
for (i = --f; i < p->nb_secs; i++) {
|
||||
Section *s = p->secs[i];
|
||||
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash
|
||||
|| 0 == memcmp(s->name, ".stab", 5)
|
||||
|| 0 == memcmp(s->name, ".debug_", 7)) {
|
||||
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
|
||||
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
|
||||
} else {
|
||||
free_section(s);
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
tcc_free(s), p->secs[i] = NULL;
|
||||
free_section(s), tcc_free(s), p->secs[i] = NULL;
|
||||
}
|
||||
}
|
||||
} while (++p, f);
|
||||
@ -335,8 +387,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
|
||||
resolve_common_syms(s1);
|
||||
build_got_entries(s1, 0);
|
||||
#endif
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = copy = 0;
|
||||
@ -349,6 +399,8 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
|
||||
#endif
|
||||
|
||||
redo:
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
|
||||
n = 0; addr = 0;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
@ -376,7 +428,6 @@ redo:
|
||||
if (s == s1->uw_pdata)
|
||||
s1->run_function_table = win64_add_function_table(s1);
|
||||
#endif
|
||||
free_section(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -423,11 +474,18 @@ redo:
|
||||
#endif
|
||||
if (protect_pages((void*)addr, n, f) < 0)
|
||||
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) {
|
||||
offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
|
||||
#ifndef HAVE_SELINUX
|
||||
offset += PAGESIZE; /* extra space to align malloc memory start */
|
||||
#endif
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (copy) {
|
||||
/* remove local symbols and free sections except symtab */
|
||||
cleanup_symbols(s1);
|
||||
@ -437,17 +495,7 @@ redo:
|
||||
|
||||
/* relocate symbols */
|
||||
relocate_syms(s1, s1->symtab, !(s1->nostdlib));
|
||||
if (s1->nb_errors)
|
||||
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;
|
||||
}
|
||||
|
||||
/* relocate sections */
|
||||
#ifdef TCC_TARGET_PE
|
||||
s1->pe_imagebase = mem;
|
||||
#else
|
||||
@ -578,6 +626,8 @@ next:
|
||||
last_pc = (addr_t)-1;
|
||||
last_line_num = 1;
|
||||
last_incl_index = 0;
|
||||
if (NULL == rc)
|
||||
goto found;
|
||||
|
||||
for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
|
||||
str = rc->stab_str + sym->n_strx;
|
||||
@ -658,14 +708,16 @@ next:
|
||||
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;
|
||||
}
|
||||
if ((rc = rc->next))
|
||||
goto next;
|
||||
rc = rc->next;
|
||||
goto next;
|
||||
|
||||
found:
|
||||
i = last_incl_index;
|
||||
if (i > 0) {
|
||||
@ -799,6 +851,11 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
||||
char *function;
|
||||
|
||||
next:
|
||||
filename = NULL;
|
||||
func_addr = 0;
|
||||
if (NULL == rc)
|
||||
goto found;
|
||||
|
||||
ln = rc->dwarf_line;
|
||||
while (ln < rc->dwarf_line_end) {
|
||||
dir_size = 0;
|
||||
@ -953,8 +1010,7 @@ check_pc:
|
||||
pc = dwarf_read_8(cp, end);
|
||||
#endif
|
||||
#if defined TCC_TARGET_MACHO
|
||||
if (rc->prog_base != (addr_t) -1)
|
||||
pc += rc->prog_base;
|
||||
pc += rc->prog_base;
|
||||
#endif
|
||||
opindex = 0;
|
||||
break;
|
||||
@ -1036,8 +1092,9 @@ next_line:
|
||||
function = rt_elfsym(rc, wanted_pc, &func_addr);
|
||||
if (function)
|
||||
goto found;
|
||||
if ((rc = rc->next))
|
||||
goto next;
|
||||
rc = rc->next;
|
||||
goto next;
|
||||
|
||||
found:
|
||||
if (filename) {
|
||||
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;
|
||||
char skip[100];
|
||||
int i, level, ret, n, one;
|
||||
const char *a, *b, *msg;
|
||||
|
||||
if (fp) {
|
||||
/* 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: ";
|
||||
}
|
||||
const char *a, *b;
|
||||
addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
|
||||
addr_t top_func = 0;
|
||||
|
||||
skip[0] = 0;
|
||||
/* 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')
|
||||
++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++) {
|
||||
ret = rt_get_caller_pc(&pc, rc, i);
|
||||
ret = rt_get_caller_pc(&pc, f, i);
|
||||
a = "%s";
|
||||
if (ret != -1) {
|
||||
if (rc->dwarf)
|
||||
pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
|
||||
else
|
||||
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
|
||||
pc = printline(rc, pc, level ? "by" : "at", skip);
|
||||
if (pc == (addr_t)-1)
|
||||
continue;
|
||||
a = ": %s";
|
||||
@ -1103,22 +1159,22 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
|
||||
if (one)
|
||||
break;
|
||||
rt_printf("\n");
|
||||
if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
|
||||
if (ret == -1 || (pc == top_func && pc))
|
||||
break;
|
||||
++level;
|
||||
}
|
||||
|
||||
rc->ip = rc->fp = 0;
|
||||
rt_post_sem();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
int ret;
|
||||
va_start(ap, fmt);
|
||||
ret = _rt_error(0, 0, fmt, ap);
|
||||
ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
@ -1135,7 +1191,7 @@ static int rt_error(const char *fmt, ...)
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
rc->ip = uc->Rip;
|
||||
@ -1228,33 +1284,33 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
|
||||
/* signal handler for fatal errors */
|
||||
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||
{
|
||||
rt_context *rc = &g_rtctxt;
|
||||
rt_getcontext(puc, rc);
|
||||
rt_frame f;
|
||||
rt_getcontext(puc, &f);
|
||||
|
||||
switch(signum) {
|
||||
case SIGFPE:
|
||||
switch(siginf->si_code) {
|
||||
case FPE_INTDIV:
|
||||
case FPE_FLTDIV:
|
||||
rt_error("division by zero");
|
||||
rt_error(&f, "division by zero");
|
||||
break;
|
||||
default:
|
||||
rt_error("floating point exception");
|
||||
rt_error(&f, "floating point exception");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SIGBUS:
|
||||
case SIGSEGV:
|
||||
rt_error("invalid memory access");
|
||||
rt_error(&f, "invalid memory access");
|
||||
break;
|
||||
case SIGILL:
|
||||
rt_error("illegal instruction");
|
||||
rt_error(&f, "illegal instruction");
|
||||
break;
|
||||
case SIGABRT:
|
||||
rt_error("abort() called");
|
||||
rt_error(&f, "abort() called");
|
||||
break;
|
||||
default:
|
||||
rt_error("caught signal %d", signum);
|
||||
rt_error(&f, "caught signal %d", signum);
|
||||
break;
|
||||
}
|
||||
rt_exit(255);
|
||||
@ -1301,30 +1357,31 @@ static void set_exception_handler(void)
|
||||
/* signal handler for fatal errors */
|
||||
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||
{
|
||||
rt_context *rc = &g_rtctxt;
|
||||
rt_frame f;
|
||||
unsigned code;
|
||||
rt_getcontext(ex_info->ContextRecord, rc);
|
||||
|
||||
rt_getcontext(ex_info->ContextRecord, &f);
|
||||
|
||||
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
rt_error("invalid memory access");
|
||||
rt_error(&f, "invalid memory access");
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
rt_error("stack overflow");
|
||||
rt_error(&f, "stack overflow");
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
rt_error("division by zero");
|
||||
rt_error(&f, "division by zero");
|
||||
break;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
rc->ip = *(addr_t*)rc->sp;
|
||||
rt_error("breakpoint/single-step exception:");
|
||||
f.ip = *(addr_t*)f.sp;
|
||||
rt_error(&f, "breakpoint/single-step exception:");
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
default:
|
||||
rt_error("caught exception %08x", code);
|
||||
rt_error(&f, "caught exception %08x", code);
|
||||
break;
|
||||
}
|
||||
if (rc->do_jmp)
|
||||
if (rt_do_jmp)
|
||||
rt_exit(255);
|
||||
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 */
|
||||
#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;
|
||||
if (level == 0) {
|
||||
@ -1364,7 +1421,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
}
|
||||
|
||||
#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 */
|
||||
#if !defined(__linux__) && \
|
||||
@ -1384,7 +1441,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
}
|
||||
|
||||
#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) {
|
||||
*paddr = rc->ip;
|
||||
@ -1398,7 +1455,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
}
|
||||
|
||||
#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) {
|
||||
*paddr = rc->ip;
|
||||
@ -1415,7 +1472,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
|
||||
#else
|
||||
#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;
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
||||
endif
|
||||
|
||||
all test :
|
||||
@echo ------------ version ------------
|
||||
@$(TCC_LOCAL) -v
|
||||
@$(MAKE) --no-print-directory -s clean
|
||||
@$(MAKE) --no-print-directory -s -r $(TESTS)
|
||||
|
||||
|
@ -10,7 +10,7 @@ set /p VERSION= < ..\VERSION
|
||||
set TCCDIR=
|
||||
set BINDIR=
|
||||
set DOC=no
|
||||
set EXES_ONLY=no
|
||||
set XCC=no
|
||||
goto :a0
|
||||
:a2
|
||||
shift
|
||||
@ -27,7 +27,7 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2
|
||||
if (%1)==(-i) set TCCDIR=%2&& goto :a2
|
||||
if (%1)==(-b) set BINDIR=%2&& goto :a2
|
||||
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
|
||||
:usage
|
||||
echo usage: build-tcc.bat [ options ... ]
|
||||
@ -39,7 +39,7 @@ echo -v "version" set tcc version
|
||||
echo -i tccdir install tcc into tccdir
|
||||
echo -b bindir but install tcc.exe and libtcc.dll into bindir
|
||||
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
|
||||
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
|
||||
@if errorlevel 1 goto :the_end
|
||||
%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%
|
||||
:compiler_done
|
||||
@if (%EXES_ONLY%)==(yes) goto :files_done
|
||||
|
Loading…
Reference in New Issue
Block a user