From 65f74a4df094996903a86463d09f3f126fcc790f Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 14 Dec 2019 12:36:12 +0100 Subject: [PATCH] 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. --- tcc.h | 5 +- tccelf.c | 45 ++-- tccgen.c | 84 ++++++-- tccpp.c | 19 +- tccrun.c | 620 ++++++++++++++++++++++++++----------------------------- 5 files changed, 385 insertions(+), 388 deletions(-) diff --git a/tcc.h b/tcc.h index 13579894..30f7eb94 100644 --- a/tcc.h +++ b/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); diff --git a/tccelf.c b/tccelf.c index f5f55b1c..9d7391c0 100644 --- a/tccelf.c +++ b/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 diff --git a/tccgen.c b/tccgen.c index 01473fff..1d1fe8a3 100644 --- a/tccgen.c +++ b/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 */ + 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; diff --git a/tccpp.c b/tccpp.c index 5f66cce1..accdcdc0 100644 --- a/tccpp.c +++ b/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, "") != 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, "", cstr.size); memcpy(file->buffer, cstr.data, cstr.size); diff --git a/tccrun.c b/tccrun.c index a733e9ae..b76f9fa8 100644 --- a/tccrun.c +++ b/tccrun.c @@ -28,19 +28,7 @@ #endif #ifdef CONFIG_TCC_BACKTRACE -# ifndef _WIN32 -# include -# ifndef __OpenBSD__ -# include -# 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;irt_num_callers;i++) { - if (rt_get_caller_pc(&pc, uc, i) < 0) + for(i=0; irt_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 +# ifndef __OpenBSD__ +# include +# 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= 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;iuc_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= 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