tccrun.c: better stab debug support

* a major revision of the rt_printline() feature in
  tccrun.c to report file:linenumber more correctly.

* minor changes to the stab info produced by the
  compiler in tccgen.c

However stab addresses are limited to 32 bits.  I added
a work around:

    if (sizeof pc == 8)
        pc |= wanted_pc & 0xffffffff00000000ULL;

However GDB has problems with that too.
This commit is contained in:
grischka 2019-12-14 12:36:12 +01:00
parent 56db092ab7
commit 65f74a4df0
5 changed files with 385 additions and 388 deletions

5
tcc.h
View File

@ -1370,12 +1370,14 @@ ST_DATA int global_expr; /* true if compound literals must be allocated globall
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA const char *funcname;
ST_DATA int g_debug;
ST_FUNC void tcc_debug_start(TCCState *s1);
ST_FUNC void tcc_debug_end(TCCState *s1);
ST_FUNC void tcc_debug_bincl(TCCState *s1);
ST_FUNC void tcc_debug_eincl(TCCState *s1);
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename);
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
ST_FUNC void tcc_debug_line(TCCState *s1);
@ -1489,7 +1491,6 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, i
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
ST_FUNC void put_stabd(TCCState *s1, int type, int other, int desc);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);

View File

@ -92,6 +92,7 @@ ST_FUNC void tccelf_stab_new(TCCState *s)
TCCState *s1 = s;
stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
stab_section->sh_entsize = sizeof(Stab_Sym);
stab_section->sh_addralign = 4;
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0);
put_elf_str(stab_section->link, "");
/* put first entry */
@ -811,11 +812,6 @@ ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
put_stabs(s1, NULL, type, other, desc, value);
}
ST_FUNC void put_stabd(TCCState *s1, int type, int other, int desc)
{
put_stabs(s1, NULL, type, other, desc, 0);
}
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
{
int n;
@ -2489,6 +2485,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
ElfW(Shdr) *shdr, *sh;
int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed;
char *strsec, *strtab;
int stab_index, stabstr_index;
int *old_to_new_syms;
char *sh_name, *name;
SectionMergeInfo *sm_table, *sm;
@ -2496,11 +2493,6 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
ElfW_Rel *rel;
Section *s;
int stab_index;
int stabstr_index;
stab_index = stabstr_index = 0;
lseek(fd, file_offset, SEEK_SET);
if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL)
goto fail1;
@ -2526,6 +2518,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
strtab = NULL;
nb_syms = 0;
seencompressed = 0;
stab_index = stabstr_index = 0;
for(i = 1; i < ehdr.e_shnum; i++) {
sh = &shdr[i];
if (sh->sh_type == SHT_SYMTAB) {
@ -2588,9 +2582,14 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
it. */
sm_table[i].link_once = 1;
goto next;
} else {
goto found;
}
if (stab_section) {
if (s == stab_section)
stab_index = i;
if (s == stab_section->link)
stabstr_index = i;
}
goto found;
}
}
/* not found: create new section */
@ -2605,26 +2604,11 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
tcc_error_noabort("invalid section type");
goto fail;
}
/* align start of section */
offset = s->data_offset;
if (0 == strcmp(sh_name, ".stab")) {
stab_index = i;
goto no_align;
}
if (0 == strcmp(sh_name, ".stabstr")) {
stabstr_index = i;
goto no_align;
}
size = sh->sh_addralign - 1;
offset = (offset + size) & ~size;
s->data_offset += -s->data_offset & (sh->sh_addralign - 1);
if (sh->sh_addralign > s->sh_addralign)
s->sh_addralign = sh->sh_addralign;
s->data_offset = offset;
no_align:
sm_table[i].offset = offset;
sm_table[i].offset = s->data_offset;
sm_table[i].s = s;
/* concatenate sections */
size = sh->sh_size;
@ -2669,7 +2653,6 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
s1->sections[s->sh_info]->reloc = s;
}
}
sm = sm_table;
/* resolve symbols */
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
@ -2729,7 +2712,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
goto invalid_reloc;
sym_index = old_to_new_syms[sym_index];
/* ignore link_once in rel section. */
if (!sym_index && !sm->link_once
if (!sym_index && !sm_table[sh->sh_info].link_once
#ifdef TCC_TARGET_ARM
&& type != R_ARM_V4BX
#elif defined TCC_TARGET_RISCV64

View File

@ -75,7 +75,7 @@ ST_DATA int global_expr; /* true if compound literals must be allocated globall
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
static int last_line_num, new_file, func_ind; /* debug info control */
ST_DATA const char *funcname;
ST_DATA int g_debug;
@ -219,8 +219,10 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
text_section->data_offset, text_section, section_sym);
put_stabs_r(s1, file->prev->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
last_ind = 0;
last_line_num = 0;
new_file = last_line_num = 0;
func_ind = -1;
/* we're currently 'including' the <command line> */
tcc_debug_bincl(s1);
}
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
@ -237,40 +239,52 @@ ST_FUNC void tcc_debug_end(TCCState *s1)
return;
put_stabs_r(s1, NULL, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
}
static BufferedFile* put_new_file(TCCState *s1)
{
BufferedFile *f = file;
/* use upper file if from inline ":asm:" */
if (f->filename[0] == ':')
f = f->prev;
if (f && new_file) {
put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym);
new_file = last_line_num = 0;
}
return f;
}
/* generate line number info */
ST_FUNC void tcc_debug_line(TCCState *s1)
{
if (!s1->do_debug)
BufferedFile *f;
if (!s1->do_debug || !(f = put_new_file(s1)))
return;
if (ind && ((last_line_num != file->line_num || last_ind != ind))) {
put_stabn(s1, N_SLINE, 0, file->line_num, ind - func_ind);
last_ind = ind;
last_line_num = file->line_num;
if (last_line_num == f->line_num)
return;
if (text_section != cur_text_section)
return;
if (func_ind != -1) {
put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind);
} else {
/* from tcc_assemble */
put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym);
}
last_line_num = f->line_num;
}
/* put function symbol */
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
{
char buf[512];
if (!s1->do_debug)
BufferedFile *f;
if (!s1->do_debug || !(f = put_new_file(s1)))
return;
/* stabs info */
/* XXX: we put here a dummy type */
snprintf(buf, sizeof(buf), "%s:%c1",
funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
put_stabs_r(s1, buf, N_FUN, 0, file->line_num, 0,
cur_text_section, sym->c);
/* //gr gdb wants a line at the function */
put_stabn(s1, N_SLINE, 0, file->line_num, 0);
last_ind = 0;
last_line_num = 0;
put_stabs_r(s1, buf, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c);
tcc_debug_line(s1);
}
/* put function size */
@ -278,7 +292,36 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{
if (!s1->do_debug)
return;
#if 0 // this seems to confuse gnu tools
put_stabn(s1, N_FUN, 0, 0, size);
#endif
}
/* put alternative filename */
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename)
{
if (0 == strcmp(file->filename, filename))
return;
pstrcpy(file->filename, sizeof(file->filename), filename);
new_file = 1;
}
/* begin of #include */
ST_FUNC void tcc_debug_bincl(TCCState *s1)
{
if (!s1->do_debug)
return;
put_stabs(s1, file->filename, N_BINCL, 0, 0, 0);
new_file = 1;
}
/* end of #include */
ST_FUNC void tcc_debug_eincl(TCCState *s1)
{
if (!s1->do_debug)
return;
put_stabn(s1, N_EINCL, 0, 0, 0);
new_file = 1;
}
/* ------------------------------------------------------------------------- */
@ -7708,8 +7751,7 @@ static void gen_inline_functions(TCCState *s)
/* the function was used or forced (and then not internal):
generate its code and convert it to a normal function */
fn->sym = NULL;
if (file)
pstrcpy(file->filename, sizeof file->filename, fn->filename);
tcc_debug_putfile(s, fn->filename);
begin_macro(fn->func_str, 1);
next();
cur_text_section = text_section;

19
tccpp.c
View File

@ -1862,8 +1862,7 @@ ST_FUNC void preprocess(int is_bof)
tcc_strdup(buf1));
}
/* add include file debug info */
if (s1->do_debug)
put_stabs(tcc_state, file->filename, N_BINCL, 0, 0, 0);
tcc_debug_bincl(tcc_state);
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
ch = file->buf_ptr[0];
goto the_end;
@ -1961,7 +1960,7 @@ include_done:
if (tok == TOK_STR) {
if (file->true_filename == file->filename)
file->true_filename = tcc_strdup(file->filename);
pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
tcc_debug_putfile(s1, (char *)tokc.str.data);
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
break;
else
@ -1971,8 +1970,6 @@ include_done:
if (file->fd > 0)
total_lines += file->line_num - n;
file->line_num = n;
if (s1->do_debug)
put_stabs(tcc_state, file->filename, N_BINCL, 0, 0, 0);
break;
case TOK_ERROR:
case TOK_WARNING:
@ -2629,9 +2626,7 @@ static inline void next_nomacro1(void)
}
/* add end of include file debug info */
if (tcc_state->do_debug && strcmp (file->filename, "<command line>") != 0) {
put_stabd(tcc_state, N_EINCL, 0, 0);
}
tcc_debug_eincl(tcc_state);
/* pop include stack */
tcc_close();
s1->include_stack_ptr--;
@ -3611,14 +3606,14 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
set_idnum('.', is_asm ? IS_ID : 0);
cstr_new(&cstr);
if (is_asm)
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
if (s1->cmdline_defs.size)
cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size);
//printf("%s\n", (char*)s1->cmdline_defs.data);
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
if (is_asm)
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
if (s1->cmdline_incl.size)
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
//printf("%s\n", (char*)cstr.data);
*s1->include_stack_ptr++ = file;
tcc_open_bf(s1, "<command line>", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size);

620
tccrun.c
View File

@ -28,19 +28,7 @@
#endif
#ifdef CONFIG_TCC_BACKTRACE
# ifndef _WIN32
# include <signal.h>
# ifndef __OpenBSD__
# include <sys/ucontext.h>
# endif
# else
# define ucontext_t CONTEXT
# endif
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
static void rt_error(ucontext_t *uc, const char *fmt, ...);
static void set_exception_handler(void);
#ifdef _WIN32
static DWORD s1_for_run_idx;
void set_s1_for_run(TCCState *s)
@ -337,212 +325,314 @@ static void win64_del_function_table(void *p)
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
#define INCLUDE_STACK_SIZE 32
static int rt_vprintf(const char *fmt, va_list ap)
{
int ret = vfprintf(stderr, fmt, ap);
fflush(stderr);
return ret;
}
static int rt_printf(const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = rt_vprintf(fmt, ap);
va_end(ap);
return r;
}
/* print the position in the source file of PC value 'pc' by reading
the stabs debug information */
static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
{
char func_name[128], last_func_name[128];
char func_name[128];
addr_t func_addr, last_pc, pc;
const char *incl_files[INCLUDE_STACK_SIZE];
int incl_index, len, last_line_num, i;
int incl_index, last_incl_index, len, last_line_num, i;
const char *str, *p;
Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
int stab_len = 0;
ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
char *stab_str = NULL;
if (stab_section) {
stab_len = stab_section->data_offset;
stab_sym = (Stab_Sym *)stab_section->data;
stab_str = (char *) stab_section->link->data;
}
char *elf_str = NULL;
func_name[0] = '\0';
func_addr = 0;
incl_index = 0;
last_func_name[0] = '\0';
last_pc = (addr_t)-1;
last_line_num = 1;
last_incl_index = 0;
if (!stab_sym)
goto no_stabs;
if (stab_section) {
stab_sym = (Stab_Sym *)stab_section->data;
stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
stab_str = (char *) stab_section->link->data;
}
if (symtab_section) {
esym_start = (ElfW(Sym) *)(symtab_section->data);
esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
elf_str = symtab_section->link->data;
}
stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
str = stab_str + sym->n_strx;
pc = sym->n_value;
switch(sym->n_type) {
case N_SLINE:
if (func_addr)
goto rel_pc;
case N_SO:
case N_SOL:
goto abs_pc;
case N_FUN:
if (sym->n_strx == 0) /* end of function */
goto rel_pc;
abs_pc:
if (sizeof pc == 8)
/* Stab_Sym.n_value is only 32bits */
pc |= wanted_pc & 0xffffffff00000000ULL;
break;
rel_pc:
pc += func_addr;
break;
}
if (pc > wanted_pc && wanted_pc > last_pc)
goto found;
switch(sym->n_type) {
/* function start or end */
case N_FUN:
if (sym->n_strx == 0) {
/* we test if between last line and end of function */
pc = sym->n_value + func_addr;
if (wanted_pc >= last_pc && wanted_pc < pc)
goto found;
func_name[0] = '\0';
func_addr = 0;
} else {
str = stab_str + sym->n_strx;
p = strchr(str, ':');
if (!p) {
pstrcpy(func_name, sizeof(func_name), str);
} else {
len = p - str;
if (len > sizeof(func_name) - 1)
len = sizeof(func_name) - 1;
memcpy(func_name, str, len);
func_name[len] = '\0';
}
func_addr = sym->n_value;
}
if (sym->n_strx == 0)
goto reset_func;
p = strchr(str, ':');
if (0 == p || (len = p - str + 1, len > sizeof func_name))
len = sizeof func_name;
pstrcpy(func_name, len, str);
func_addr = pc;
break;
/* line number info */
case N_SLINE:
pc = sym->n_value + func_addr;
if (wanted_pc >= last_pc && wanted_pc < pc)
goto found;
last_pc = pc;
last_line_num = sym->n_desc;
/* XXX: slow! */
strcpy(last_func_name, func_name);
last_incl_index = incl_index;
if (pc == wanted_pc)
goto found;
break;
/* include files */
case N_BINCL:
str = stab_str + sym->n_strx;
add_incl:
if (incl_index < INCLUDE_STACK_SIZE) {
if (incl_index < INCLUDE_STACK_SIZE)
incl_files[incl_index++] = str;
}
break;
case N_EINCL:
if (incl_index > 1)
incl_index--;
break;
/* start/end of translation unit */
case N_SO:
if (sym->n_strx == 0) {
incl_index = 0; /* end of translation unit */
} else {
str = stab_str + sym->n_strx;
incl_index = 0;
if (sym->n_strx) {
/* do not add path */
len = strlen(str);
if (len > 0 && str[len - 1] != '/')
goto add_incl;
incl_files[incl_index++] = str;
}
reset_func:
func_name[0] = '\0';
func_addr = 0;
last_pc = (addr_t)-1;
break;
/* alternative file name (from #line or #include directives) */
case N_SOL:
if (incl_index)
incl_files[incl_index-1] = str;
break;
}
}
no_stabs:
/* second pass: we try symtab symbols (no line number info) */
incl_index = 0;
if (symtab_section)
{
ElfW(Sym) *sym, *sym_end;
int type;
sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
for(sym = (ElfW(Sym) *)symtab_section->data + 1;
sym < sym_end;
sym++) {
type = ELFW(ST_TYPE)(sym->st_info);
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
if (wanted_pc >= sym->st_value &&
wanted_pc < sym->st_value + sym->st_size) {
pstrcpy(last_func_name, sizeof(last_func_name),
(char *) symtab_section->link->data + sym->st_name);
func_addr = sym->st_value;
goto found;
}
/* we try symtab symbols (no line number info) */
for (esym = esym_start + 1; esym < esym_end; ++esym) {
int type = ELFW(ST_TYPE)(esym->st_info);
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
if (wanted_pc >= esym->st_value &&
wanted_pc < esym->st_value + esym->st_size) {
pstrcpy(func_name, sizeof(func_name),
elf_str + esym->st_name);
func_addr = esym->st_value;
last_incl_index = 0;
goto found;
}
}
}
/* did not find any info: */
fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
fflush(stderr);
rt_printf("%s %p ???", msg, (void*)wanted_pc);
return 0;
found:
i = incl_index;
i = last_incl_index;
if (i > 0)
fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
if (last_func_name[0] != '\0')
fprintf(stderr, " %s()", last_func_name);
rt_printf("%s:%d: ", incl_files[--i], last_line_num);
rt_printf("%s %p", msg, (void*)wanted_pc);
if (func_name[0] != '\0')
rt_printf(" %s()", func_name);
if (--i >= 0) {
fprintf(stderr, " (included from ");
rt_printf(" (included from ");
for (;;) {
fprintf(stderr, "%s", incl_files[i]);
rt_printf("%s", incl_files[i]);
if (--i < 0)
break;
fprintf(stderr, ", ");
rt_printf(", ");
}
fprintf(stderr, ")");
rt_printf(")");
}
fprintf(stderr, "\n");
fflush(stderr);
return func_addr;
}
typedef struct rt_context {
addr_t ip, fp, sp, pc;
} rt_context;
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
/* emit a run time error at position 'pc' */
static void rt_error(ucontext_t *uc, const char *fmt, ...)
static void rt_error(rt_context *rc, const char *fmt, ...)
{
va_list ap;
addr_t pc;
int i;
TCCState *s1 = get_s1_for_run();
TCCState *s1;
fprintf(stderr, "Runtime error: ");
s1 = get_s1_for_run();
if (*fmt == ' ') {
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
fmt = *s1->rt_bound_error_msg;
else
++fmt;
}
rt_printf("Runtime error: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
rt_vprintf(fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
rt_printf("\n");
if (!s1)
return;
for(i=0;i<s1->rt_num_callers;i++) {
if (rt_get_caller_pc(&pc, uc, i) < 0)
for(i=0; i<s1->rt_num_callers; i++) {
if (rt_get_caller_pc(&pc, rc, i) < 0)
break;
pc = rt_printline(s1, pc, i ? "by" : "at");
rt_printf("\n");
if (pc == (addr_t)s1->rt_prog_main && pc)
break;
}
}
/* ------------------------------------------------------------- */
#ifndef _WIN32
#ifndef _WIN32
# include <signal.h>
# ifndef __OpenBSD__
# include <sys/ucontext.h>
# endif
#else
# define ucontext_t CONTEXT
#endif
/* translate from ucontext_t* to internal rt_context * */
static void rt_getcontext(ucontext_t *uc, rt_context *rc)
{
#if defined _WIN64
rc->ip = uc->Rip;
rc->fp = uc->Rbp;
rc->sp = uc->Rsp;
#elif defined _WIN32
rc->ip = uc->Eip;
rc->fp = uc->Ebp;
rc->sp = uc->Esp;
#elif defined __i386__
# if defined(__APPLE__)
rc->ip = uc->uc_mcontext->__ss.__eip;
rc->fp = uc->uc_mcontext->__ss.__ebp;
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
rc->ip = uc->uc_mcontext.mc_eip;
rc->fp = uc->uc_mcontext.mc_ebp;
# elif defined(__dietlibc__)
rc->ip = uc->uc_mcontext.eip;
rc->fp = uc->uc_mcontext.ebp;
# elif defined(__NetBSD__)
rc->ip = uc->uc_mcontext.__gregs[_REG_EIP];
rc->fp = uc->uc_mcontext.__gregs[_REG_EBP];
# elif defined(__OpenBSD__)
rc->ip = uc->sc_eip;
rc->fp = uc->sc_ebp;
# elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
rc->ip = uc->uc_mcontext.gregs[EIP];
rc->fp = uc->uc_mcontext.gregs[EBP];
# else
rc->ip = uc->uc_mcontext.gregs[REG_EIP];
rc->fp = uc->uc_mcontext.gregs[REG_EBP];
# endif
#elif defined(__x86_64__)
# if defined(__APPLE__)
rc->ip = uc->uc_mcontext->__ss.__rip;
rc->fp = uc->uc_mcontext->__ss.__rbp;
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
rc->ip = uc->uc_mcontext.mc_rip;
rc->fp = uc->uc_mcontext.mc_rbp;
# elif defined(__NetBSD__)
rc->ip = uc->uc_mcontext.__gregs[_REG_RIP];
rc->fp = uc->uc_mcontext.__gregs[_REG_RBP];
# else
rc->ip = uc->uc_mcontext.gregs[REG_RIP];
rc->fp = uc->uc_mcontext.gregs[REG_RBP];
# endif
#elif defined(__arm__)
rc->ip = uc->uc_mcontext.arm_pc;
rc->fp = uc->uc_mcontext.arm_fp;
rc->sp = uc->uc_mcontext.arm_sp;
#elif defined(__aarch64__)
rc->ip = uc->uc_mcontext.pc;
rc->fp = (addr_t *)uc->uc_mcontext.regs[29];
#endif
}
/* ------------------------------------------------------------- */
#ifndef _WIN32
/* signal handler for fatal errors */
static void sig_error(int signum, siginfo_t *siginf, void *puc)
{
ucontext_t *uc = puc;
TCCState *s1;
rt_context rc;
rt_getcontext(puc, &rc);
switch(signum) {
case SIGFPE:
switch(siginf->si_code) {
case FPE_INTDIV:
case FPE_FLTDIV:
rt_error(uc, "division by zero");
rt_error(&rc, "division by zero");
break;
default:
rt_error(uc, "floating point exception");
rt_error(&rc, "floating point exception");
break;
}
break;
case SIGBUS:
case SIGSEGV:
s1 = get_s1_for_run();
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
rt_error(uc, *s1->rt_bound_error_msg);
else
rt_error(uc, "dereferencing invalid pointer");
rt_error(&rc, " dereferencing invalid pointer");
break;
case SIGILL:
rt_error(uc, "illegal instruction");
rt_error(&rc, "illegal instruction");
break;
case SIGABRT:
rt_error(uc, "abort() called");
rt_error(&rc, "abort() called");
break;
default:
rt_error(uc, "caught signal %d", signum);
rt_error(&rc, "caught signal %d", signum);
break;
}
exit(255);
@ -568,202 +658,31 @@ static void set_exception_handler(void)
sigaction(SIGABRT, &sigact, NULL);
}
/* ------------------------------------------------------------- */
#ifdef __i386__
/* fix for glibc 2.1 */
#ifndef REG_EIP
#define REG_EIP EIP
#define REG_EBP EBP
#endif
/* return the PC at frame level 'level'. Return negative if not found */
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
addr_t fp;
int i;
if (level == 0) {
#if defined(__APPLE__)
*paddr = uc->uc_mcontext->__ss.__eip;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
*paddr = uc->uc_mcontext.mc_eip;
#elif defined(__dietlibc__)
*paddr = uc->uc_mcontext.eip;
#elif defined(__NetBSD__)
*paddr = uc->uc_mcontext.__gregs[_REG_EIP];
#elif defined(__OpenBSD__)
*paddr = uc->sc_eip;
#else
*paddr = uc->uc_mcontext.gregs[REG_EIP];
#endif
return 0;
} else {
#if defined(__APPLE__)
fp = uc->uc_mcontext->__ss.__ebp;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
fp = uc->uc_mcontext.mc_ebp;
#elif defined(__dietlibc__)
fp = uc->uc_mcontext.ebp;
#elif defined(__NetBSD__)
fp = uc->uc_mcontext.__gregs[_REG_EBP];
#elif defined(__OpenBSD__)
*paddr = uc->sc_ebp;
#else
fp = uc->uc_mcontext.gregs[REG_EBP];
#endif
for(i=1;i<level;i++) {
/* XXX: check address validity with program info */
if (fp <= 0x1000 || fp >= 0xc0000000)
return -1;
fp = ((addr_t *)fp)[0];
}
*paddr = ((addr_t *)fp)[1];
return 0;
}
}
/* ------------------------------------------------------------- */
#elif defined(__x86_64__)
/* return the PC at frame level 'level'. Return negative if not found */
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
addr_t fp;
int i;
if (level == 0) {
/* XXX: only support linux */
#if defined(__APPLE__)
*paddr = uc->uc_mcontext->__ss.__rip;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
*paddr = uc->uc_mcontext.mc_rip;
#elif defined(__NetBSD__)
*paddr = uc->uc_mcontext.__gregs[_REG_RIP];
#else
*paddr = uc->uc_mcontext.gregs[REG_RIP];
#endif
return 0;
} else {
#if defined(__APPLE__)
fp = uc->uc_mcontext->__ss.__rbp;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
fp = uc->uc_mcontext.mc_rbp;
#elif defined(__NetBSD__)
fp = uc->uc_mcontext.__gregs[_REG_RBP];
#else
fp = uc->uc_mcontext.gregs[REG_RBP];
#endif
for(i=1;i<level;i++) {
/* XXX: check address validity with program info */
if (fp <= 0x1000)
return -1;
fp = ((addr_t *)fp)[0];
}
*paddr = ((addr_t *)fp)[1];
return 0;
}
}
/* ------------------------------------------------------------- */
#elif defined(__arm__)
/* return the PC at frame level 'level'. Return negative if not found */
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
addr_t fp, sp;
int i;
if (level == 0) {
/* XXX: only supports linux */
#if defined(__linux__)
*paddr = uc->uc_mcontext.arm_pc;
#else
return -1;
#endif
return 0;
} else {
#if defined(__linux__)
fp = uc->uc_mcontext.arm_fp;
sp = uc->uc_mcontext.arm_sp;
if (sp < 0x1000)
sp = 0x1000;
#else
return -1;
#endif
/* XXX: specific to tinycc stack frames */
if (fp < sp + 12 || fp & 3)
return -1;
for(i = 1; i < level; i++) {
sp = ((addr_t *)fp)[-2];
if (sp < fp || sp - fp > 16 || sp & 3)
return -1;
fp = ((addr_t *)fp)[-3];
if (fp <= sp || fp - sp < 12 || fp & 3)
return -1;
}
/* XXX: check address validity with program info */
*paddr = ((addr_t *)fp)[-1];
return 0;
}
}
/* ------------------------------------------------------------- */
#elif defined(__aarch64__)
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
if (level < 0)
return -1;
else if (level == 0) {
*paddr = uc->uc_mcontext.pc;
return 0;
}
else {
addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
int i;
for (i = 1; i < level; i++)
fp = (addr_t *)fp[0];
*paddr = fp[1];
return 0;
}
}
/* ------------------------------------------------------------- */
#else
#warning add arch specific rt_get_caller_pc()
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
return -1;
}
#endif /* !__i386__ */
/* ------------------------------------------------------------- */
#else /* WIN32 */
/* signal handler for fatal errors */
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
CONTEXT *uc = ex_info->ContextRecord;
TCCState *s1;
switch (er->ExceptionCode) {
rt_context rc;
unsigned code;
rt_getcontext(ex_info->ContextRecord, &rc);
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
s1 = get_s1_for_run();
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
rt_error(uc, *s1->rt_bound_error_msg);
else
rt_error(uc, "access violation");
rt_error(&rc, " access violation");
break;
case EXCEPTION_STACK_OVERFLOW:
rt_error(uc, "stack overflow");
rt_error(&rc, "stack overflow");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
rt_error(uc, "division by zero");
rt_error(&rc, "division by zero");
break;
case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP:
rc.ip = *(addr_t*)rc.sp;
rt_error(&rc, "^breakpoint/single-step exception:");
return EXCEPTION_CONTINUE_SEARCH;
default:
rt_error(uc, "exception caught");
rt_error(&rc, "caught exception %08x", code);
break;
}
return EXCEPTION_EXECUTE_HANDLER;
@ -775,33 +694,90 @@ static void set_exception_handler(void)
SetUnhandledExceptionFilter(cpu_exception_handler);
}
/* return the PC at frame level 'level'. Return non zero if not found */
static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
{
addr_t fp, pc;
int i;
#ifdef _WIN64
pc = uc->Rip;
fp = uc->Rbp;
#else
pc = uc->Eip;
fp = uc->Ebp;
#endif
if (level > 0) {
for(i=1;i<level;i++) {
/* XXX: check address validity with program info */
if (fp <= 0x1000 || fp >= 0xc0000000)
return -1;
fp = ((addr_t*)fp)[0];
}
pc = ((addr_t*)fp)[1];
/* ------------------------------------------------------------- */
/* 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)
{
addr_t ip, fp;
if (level == 0) {
ip = rc->ip;
} else {
ip = 0;
fp = rc->fp;
while (--level) {
/* XXX: check address validity with program info */
if (fp <= 0x1000)
break;
fp = ((addr_t *)fp)[0];
}
if (fp > 0x1000)
ip = ((addr_t *)fp)[1];
}
*paddr = pc;
if (ip <= 0x1000)
return -1;
*paddr = ip;
return 0;
}
#endif /* _WIN32 */
#elif defined(__arm__)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
/* XXX: only supports linux */
#if !defined(__linux__)
return -1;
#else
if (level == 0) {
*paddr = rc->ip;
} else {
addr_t fp = rc->fp;
addr_t sp = rc->sp;
if (sp < 0x1000)
sp = 0x1000;
/* XXX: specific to tinycc stack frames */
if (fp < sp + 12 || fp & 3)
return -1;
while (--level) {
sp = ((addr_t *)fp)[-2];
if (sp < fp || sp - fp > 16 || sp & 3)
return -1;
fp = ((addr_t *)fp)[-3];
if (fp <= sp || fp - sp < 12 || fp & 3)
return -1;
}
/* XXX: check address validity with program info */
*paddr = ((addr_t *)fp)[-1];
}
return 0;
#endif
}
#elif defined(__aarch64__)
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
if (level == 0) {
*paddr = rc->ip;
} else {
addr_t *fp = rc->fp;
while (--level)
fp = (addr_t *)fp[0];
*paddr = fp[1];
}
return 0;
}
#else
#warning add arch specific rt_get_caller_pc()
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
return -1;
}
#endif
#endif /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC