mirror of
https://github.com/frida/tinycc
synced 2025-02-12 13:24:02 +03:00
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:
parent
56db092ab7
commit
65f74a4df0
5
tcc.h
5
tcc.h
@ -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);
|
||||
|
45
tccelf.c
45
tccelf.c
@ -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
|
||||
|
84
tccgen.c
84
tccgen.c
@ -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
19
tccpp.c
@ -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
620
tccrun.c
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user