mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-22 11:23:27 +08:00
tccrun.c: standalone backtraces with -bt[N] or -b
This makes it possible to get backtraces with executables
(including DLLs/SOs) like we had it already with -g -run.
Option -b includes -bt, and -bt includes -g.
- new file lib/bt-exe.c: used to link rt_printline and the
exception handler from tccrun.c into executables/DLLs.
- new file lib/bt-log.c: provides a function that may be
called from user code to print out a backtrace with a
message (currently for i386/x86_64 only):
int (*tcc_backtrace)(const char *fmt, ...);
As an extra hack, if 'fmt' is prefixed like "^file.c^..."
then the backtrace will skip calls from within 'file.c'.
- new file lib/bt-dll.c: used on win32 to link the backtrace
and bcheck functions with the main module at runtime
- bcheck.c: now uses the tcc_backtrace function from above
- tccgen.c: minor cleanups
- tccelf.c: stab sections get SHF_ALLOC for easy access.
Also in relocate_section(): 64bit relocations for stabs
in DLLs cannot work. To find DLL addresses, the DLL base
is added manually in tccrun.c via rc.prog_base instead.
- tccpe.c: there are some changes to allow merging sections,
used to merge .finit_array into .data in the first place.
- tccpp.c: tcc -run now #defines __TCC_RUN__
also: refactor a line in tal_realloc that was incompatible
with bcheck
- tcctest.c: fixed a problem with r12 which tcc cannot preserve
as well as gcc does.
- tests2/112_backtrace.c: test the feature and the bcheck test18
that previously was in boundtest.c
This commit is contained in:
22
lib/Makefile
22
lib/Makefile
@@ -13,7 +13,7 @@ XCC = $(XTCC)
|
||||
XAR = $(XTCC) -ar
|
||||
XFLAGS-unx = -B$(TOPSRC)
|
||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
||||
XFLAGS = $(XFLAGS$(XCFG))
|
||||
XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
|
||||
XCFG = $(or $(findstring -win,$T),-unx)
|
||||
|
||||
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
||||
@@ -27,6 +27,8 @@ endif
|
||||
|
||||
# only for native compiler
|
||||
$(X)BCHECK_O = bcheck.o
|
||||
$(X)BT_O = bt-exe.o bt-log.o
|
||||
$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
||||
|
||||
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
|
||||
BCHECK_O =
|
||||
@@ -38,18 +40,18 @@ ifdef CONFIG_OSX
|
||||
XFLAGS += -D_ANSI_SOURCE
|
||||
endif
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
||||
ARM64_O = lib-arm64.o
|
||||
RISCV64_O = lib-arm64.o
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
|
||||
ARM64_O = lib-arm64.o $(BT_O)
|
||||
RISCV64_O = lib-arm64.o $(BT_O)
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
|
||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
||||
OBJ-arm = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
||||
@@ -60,7 +62,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
||||
|
||||
OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
|
||||
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
|
||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||
|
||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
||||
@@ -80,8 +82,10 @@ $(TOP)/%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(TOP)/bcheck.o : XFLAGS += -g
|
||||
$(TOP)/bt-exe.o : $(TOP)/tccrun.c
|
||||
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
||||
clean :
|
||||
rm -f *.a *.o $(ALL)
|
||||
|
||||
161
lib/bcheck.c
161
lib/bcheck.c
@@ -49,6 +49,12 @@
|
||||
#endif
|
||||
#define FASTCALL __attribute__((regparm(3)))
|
||||
|
||||
#ifdef _WIN32
|
||||
# define DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define DLL_EXPORT
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__DragonFly__) \
|
||||
@@ -162,16 +168,16 @@ void splay_printtree(Tree * t, int d);
|
||||
/* external interface */
|
||||
void __bound_checking (int no_check);
|
||||
void __bound_never_fatal (int no_check);
|
||||
void * __bound_ptr_add(void *p, size_t offset);
|
||||
void * __bound_ptr_indir1(void *p, size_t offset);
|
||||
void * __bound_ptr_indir2(void *p, size_t offset);
|
||||
void * __bound_ptr_indir4(void *p, size_t offset);
|
||||
void * __bound_ptr_indir8(void *p, size_t offset);
|
||||
void * __bound_ptr_indir12(void *p, size_t offset);
|
||||
void * __bound_ptr_indir16(void *p, size_t offset);
|
||||
void FASTCALL __bound_local_new(void *p1);
|
||||
void FASTCALL __bound_local_delete(void *p1);
|
||||
void __bound_init(void);
|
||||
DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
|
||||
DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
|
||||
DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
|
||||
void __bound_init(size_t *);
|
||||
void __bound_main_arg(char **p);
|
||||
void __bound_exit(void);
|
||||
#if !defined(_WIN32)
|
||||
@@ -179,35 +185,32 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
|
||||
off_t offset);
|
||||
int __bound_munmap (void *start, size_t size);
|
||||
#endif
|
||||
void __bound_new_region(void *p, size_t size);
|
||||
void *__bound_memcpy(void *dst, const void *src, size_t size);
|
||||
int __bound_memcmp(const void *s1, const void *s2, size_t size);
|
||||
void *__bound_memmove(void *dst, const void *src, size_t size);
|
||||
void *__bound_memset(void *dst, int c, size_t size);
|
||||
int __bound_strlen(const char *s);
|
||||
char *__bound_strcpy(char *dst, const char *src);
|
||||
char *__bound_strncpy(char *dst, const char *src, size_t n);
|
||||
int __bound_strcmp(const char *s1, const char *s2);
|
||||
int __bound_strncmp(const char *s1, const char *s2, size_t n);
|
||||
char *__bound_strcat(char *dest, const char *src);
|
||||
char *__bound_strchr(const char *string, int ch);
|
||||
char *__bound_strdup(const char *s);
|
||||
DLL_EXPORT void __bound_new_region(void *p, size_t size);
|
||||
DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
|
||||
DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
|
||||
DLL_EXPORT int __bound_strlen(const char *s);
|
||||
DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
|
||||
DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
|
||||
DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
|
||||
DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
|
||||
DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
|
||||
DLL_EXPORT char *__bound_strchr(const char *string, int ch);
|
||||
DLL_EXPORT char *__bound_strdup(const char *s);
|
||||
|
||||
#if !MALLOC_REDIR
|
||||
void *__bound_malloc(size_t size, const void *caller);
|
||||
void *__bound_memalign(size_t size, size_t align, const void *caller);
|
||||
void __bound_free(void *ptr, const void *caller);
|
||||
void *__bound_realloc(void *ptr, size_t size, const void *caller);
|
||||
void *__bound_calloc(size_t nmemb, size_t size);
|
||||
DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
|
||||
DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
|
||||
DLL_EXPORT void __bound_free(void *ptr, const void *caller);
|
||||
DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
|
||||
DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
|
||||
#endif
|
||||
|
||||
#define FREE_REUSE_SIZE (100)
|
||||
static unsigned int free_reuse_index;
|
||||
static void *free_reuse_list[FREE_REUSE_SIZE];
|
||||
|
||||
/* error message, just for TCC */
|
||||
const char *__bound_error_msg;
|
||||
|
||||
static Tree *tree = NULL;
|
||||
#define TREE_REUSE (1)
|
||||
#if TREE_REUSE
|
||||
@@ -296,14 +299,18 @@ void __bound_never_fatal (int neverfatal)
|
||||
fetch_and_add (&never_fatal, neverfatal);
|
||||
}
|
||||
|
||||
int tcc_backtrace(const char *fmt, ...);
|
||||
|
||||
/* print a bound error message */
|
||||
static void bound_error(const char *error)
|
||||
{
|
||||
__bound_error_msg = error;
|
||||
fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error);
|
||||
if (never_fatal == 0)
|
||||
*(void **)0 = 0; /* force a runtime error */
|
||||
}
|
||||
#define bound_warning(...) \
|
||||
tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__)
|
||||
|
||||
#define bound_error(...) \
|
||||
do { \
|
||||
bound_warning(__VA_ARGS__); \
|
||||
if (never_fatal == 0) \
|
||||
exit(255); \
|
||||
} while (0)
|
||||
|
||||
static void bound_alloc_error(const char *s)
|
||||
{
|
||||
@@ -317,20 +324,6 @@ static void bound_not_found_warning(const char *file, const char *function,
|
||||
dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
|
||||
}
|
||||
|
||||
static void bound_ptr_add_warning(const char *file, const char *function,
|
||||
void *ptr)
|
||||
{
|
||||
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
|
||||
exec, file, function, ptr);
|
||||
}
|
||||
|
||||
static void bound_ptr_indir_error(const char *file, const char *function,
|
||||
void *ptr)
|
||||
{
|
||||
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
|
||||
exec, file, function, ptr);
|
||||
}
|
||||
|
||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||
the end of a region in this case */
|
||||
void * __bound_ptr_add(void *p, size_t offset)
|
||||
@@ -360,8 +353,7 @@ void * __bound_ptr_add(void *p, size_t offset)
|
||||
if (addr <= tree->size) {
|
||||
if (tree->is_invalid || addr + offset > tree->size) {
|
||||
POST_SEM ();
|
||||
if (print_warn_ptr_add)
|
||||
bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset);
|
||||
bound_warning("%p is outside of the region", p + offset);
|
||||
if (never_fatal <= 0)
|
||||
return INVALID_POINTER; /* return an invalid pointer */
|
||||
return p + offset;
|
||||
@@ -407,8 +399,7 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
||||
if (addr <= tree->size) { \
|
||||
if (tree->is_invalid || addr + offset + dsize > tree->size) { \
|
||||
POST_SEM (); \
|
||||
bound_ptr_indir_error (__FILE__, __FUNCTION__, \
|
||||
p + offset); \
|
||||
bound_warning("%p is outside of the region", p + offset); \
|
||||
if (never_fatal <= 0) \
|
||||
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||
return p + offset; \
|
||||
@@ -460,8 +451,7 @@ void FASTCALL __bound_local_new(void *p1)
|
||||
WAIT_SEM ();
|
||||
while ((addr = p[0])) {
|
||||
INCR_COUNT(bound_local_new_count);
|
||||
if (addr != 1)
|
||||
tree = splay_insert(addr + fp, p[1], tree);
|
||||
tree = splay_insert(addr + fp, p[1], tree);
|
||||
p += 2;
|
||||
}
|
||||
POST_SEM ();
|
||||
@@ -498,7 +488,10 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
WAIT_SEM ();
|
||||
while ((addr = p[0])) {
|
||||
INCR_COUNT(bound_local_delete_count);
|
||||
if (addr == 1) {
|
||||
tree = splay_delete(addr + fp, tree);
|
||||
p += 2;
|
||||
}
|
||||
{
|
||||
alloca_list_type *last = NULL;
|
||||
alloca_list_type *cur = alloca_list;
|
||||
|
||||
@@ -518,11 +511,8 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
tree = splay_delete(addr + fp, tree);
|
||||
p += 2;
|
||||
}
|
||||
|
||||
POST_SEM ();
|
||||
while (free_list) {
|
||||
alloca_list_type *next = free_list->next;
|
||||
@@ -607,14 +597,14 @@ void __bound_new_region(void *p, size_t size)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
void __attribute__((constructor)) __bound_init(void)
|
||||
void __bound_init(size_t *p)
|
||||
{
|
||||
extern size_t __bounds_start[];
|
||||
size_t *p;
|
||||
|
||||
if (inited)
|
||||
return;
|
||||
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
if (inited) {
|
||||
WAIT_SEM();
|
||||
goto add_bounds;
|
||||
}
|
||||
inited = 1;
|
||||
|
||||
print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
|
||||
@@ -623,8 +613,6 @@ void __attribute__((constructor)) __bound_init(void)
|
||||
print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
|
||||
never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
|
||||
|
||||
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
INIT_SEM ();
|
||||
|
||||
#if MALLOC_REDIR
|
||||
@@ -724,27 +712,26 @@ void __attribute__((constructor)) __bound_init(void)
|
||||
tree = splay_insert((size_t) (&errno), sizeof (int), tree);
|
||||
#endif
|
||||
|
||||
add_bounds:
|
||||
if (!p)
|
||||
goto no_bounds;
|
||||
|
||||
/* add all static bound check values */
|
||||
p = __bounds_start;
|
||||
while (p[0] != 0) {
|
||||
tree = splay_insert(p[0], p[1], tree);
|
||||
p += 2;
|
||||
}
|
||||
POST_SEM ();
|
||||
#if BOUND_DEBUG
|
||||
if (print_calls) {
|
||||
p = __bounds_start;
|
||||
while (p[0] != 0) {
|
||||
if (print_calls) {
|
||||
dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
|
||||
__FILE__, __FUNCTION__,
|
||||
(void *) p[0], (unsigned long) p[1]);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p += 2;
|
||||
}
|
||||
no_bounds:
|
||||
|
||||
POST_SEM ();
|
||||
no_checking = 0;
|
||||
|
||||
dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
@@ -931,7 +918,7 @@ void *__bound_malloc(size_t size, const void *caller)
|
||||
#if MALLOC_REDIR
|
||||
/* This will catch the first dlsym call from __bound_init */
|
||||
if (malloc_redir == NULL) {
|
||||
__bound_init ();
|
||||
__bound_init (0);
|
||||
if (malloc_redir == NULL) {
|
||||
ptr = &initial_pool[pool_index];
|
||||
pool_index = (pool_index + size + 15) & ~15;
|
||||
@@ -1113,7 +1100,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
#if MALLOC_REDIR
|
||||
/* This will catch the first dlsym call from __bound_init */
|
||||
if (malloc_redir == NULL) {
|
||||
__bound_init ();
|
||||
__bound_init (0);
|
||||
if (malloc_redir == NULL) {
|
||||
ptr = &initial_pool[pool_index];
|
||||
pool_index = (pool_index + size + 15) & ~15;
|
||||
@@ -1190,10 +1177,8 @@ static void __bound_check(const void *p, size_t size, const char *function)
|
||||
{
|
||||
if (no_checking == 0 && size != 0 &&
|
||||
__bound_ptr_add((void *)p, size) == INVALID_POINTER) {
|
||||
static char line[100];
|
||||
sprintf(line, "invalid pointer %p, size 0x%lx in %s",
|
||||
bound_error("invalid pointer %p, size 0x%lx in %s",
|
||||
p, (unsigned long)size, function);
|
||||
bound_error(line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1207,10 +1192,8 @@ static int check_overlap (const void *p1, size_t n1,
|
||||
if (no_checking == 0 && n1 != 0 && n2 !=0 &&
|
||||
((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
|
||||
(p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
|
||||
static char line[100];
|
||||
sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s",
|
||||
bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
|
||||
p1, (unsigned long)n1, p2, (unsigned long)n2, function);
|
||||
bound_error(line);
|
||||
return never_fatal < 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
67
lib/bt-dll.c
Normal file
67
lib/bt-dll.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ------------------------------------------------------------- */
|
||||
/* stubs for calling bcheck functions from a dll. */
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define REDIR_ALL \
|
||||
REDIR(__bt_init) \
|
||||
REDIR(tcc_backtrace) \
|
||||
\
|
||||
REDIR(__bound_ptr_add) \
|
||||
REDIR(__bound_ptr_indir1) \
|
||||
REDIR(__bound_ptr_indir2) \
|
||||
REDIR(__bound_ptr_indir4) \
|
||||
REDIR(__bound_ptr_indir8) \
|
||||
REDIR(__bound_ptr_indir12) \
|
||||
REDIR(__bound_ptr_indir16) \
|
||||
REDIR(__bound_local_new) \
|
||||
REDIR(__bound_local_delete) \
|
||||
REDIR(__bound_new_region) \
|
||||
\
|
||||
REDIR(__bound_free) \
|
||||
REDIR(__bound_malloc) \
|
||||
REDIR(__bound_realloc) \
|
||||
REDIR(__bound_memcpy) \
|
||||
REDIR(__bound_memcmp) \
|
||||
REDIR(__bound_memmove) \
|
||||
REDIR(__bound_memset) \
|
||||
REDIR(__bound_strlen) \
|
||||
REDIR(__bound_strcpy) \
|
||||
REDIR(__bound_strncpy) \
|
||||
REDIR(__bound_strcmp) \
|
||||
REDIR(__bound_strncmp) \
|
||||
REDIR(__bound_strcat) \
|
||||
REDIR(__bound_strchr) \
|
||||
REDIR(__bound_strdup)
|
||||
|
||||
#define REDIR(s) void *s;
|
||||
static struct { REDIR_ALL } all_ptrs;
|
||||
#undef REDIR
|
||||
#define REDIR(s) #s"\0"
|
||||
static const char all_names[] = REDIR_ALL;
|
||||
#undef REDIR
|
||||
#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
|
||||
static void all_jmps() { REDIR_ALL }
|
||||
#undef REDIR
|
||||
|
||||
void __bt_init_dll(int bcheck)
|
||||
{
|
||||
const char *s = all_names;
|
||||
void **p = (void**)&all_ptrs;
|
||||
do {
|
||||
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
|
||||
if (NULL == *p) {
|
||||
char buf[100];
|
||||
sprintf(buf,
|
||||
"Error: function '%s()' not found in executable. "
|
||||
"(Need -bt or -b for linking the exe.)", s);
|
||||
if (GetStdHandle(STD_ERROR_HANDLE))
|
||||
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
|
||||
else
|
||||
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
|
||||
ExitProcess(1);
|
||||
}
|
||||
s = strchr(s,'\0') + 1, ++p;
|
||||
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
|
||||
}
|
||||
43
lib/bt-exe.c
Normal file
43
lib/bt-exe.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ------------------------------------------------------------- */
|
||||
/* for linking rt_printline and the signal/exception handler
|
||||
from tccrun.c into executables. */
|
||||
|
||||
#define CONFIG_TCC_BACKTRACE_ONLY
|
||||
#include "../tccrun.c"
|
||||
|
||||
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
|
||||
#ifndef _WIN32
|
||||
# define __declspec(n)
|
||||
#endif
|
||||
|
||||
__declspec(dllexport)
|
||||
void __bt_init(rt_context *p, int num_callers)
|
||||
{
|
||||
__attribute__((weak)) int main();
|
||||
__attribute__((weak)) void __bound_init(void*);
|
||||
struct rt_context *rc = &g_rtctxt;
|
||||
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
|
||||
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 (__bound_init && p->bounds_start)
|
||||
__bound_init(p->bounds_start);
|
||||
}
|
||||
|
||||
/* copy a string and truncate it. */
|
||||
static char *pstrcpy(char *buf, size_t buf_size, const char *s)
|
||||
{
|
||||
int l = strlen(s);
|
||||
if (l >= buf_size)
|
||||
l = buf_size - 1;
|
||||
memcpy(buf, s, l);
|
||||
buf[l] = 0;
|
||||
return buf;
|
||||
}
|
||||
36
lib/bt-log.c
Normal file
36
lib/bt-log.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/* ------------------------------------------------------------- */
|
||||
/* function to get a stack backtrace on demand with a message */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
|
||||
#ifdef _WIN32
|
||||
# define DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define DLL_EXPORT
|
||||
#endif
|
||||
|
||||
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);
|
||||
va_start(ap, fmt);
|
||||
ret = __rt_error(fp, ip, fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
const char *p;
|
||||
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
|
||||
fmt = p + 1;
|
||||
va_start(ap, fmt);
|
||||
ret = vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n"), fflush(stderr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user