diff --git a/lib/bcheck.c b/lib/bcheck.c index 94fec6f5..1f974b2e 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -270,6 +270,7 @@ DLL_EXPORT void FASTCALL __bound_local_delete(void *p1); void __bound_init(size_t *, int); void __bound_main_arg(int argc, char **argv, char **envp); void __bound_exit(void); +void __bound_exit_dll(size_t *); #if !defined(_WIN32) void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd, off_t offset); @@ -1255,6 +1256,25 @@ void __attribute__((destructor)) __bound_exit(void) } } +void __bound_exit_dll(size_t *p) +{ + dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__); + + if (p) { + while (p[0] != 0) { + tree = splay_delete(p[0], tree); +#if BOUND_DEBUG + if (print_calls) { + dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n", + __FILE__, __FUNCTION__, + (void *) p[0], (unsigned long) p[1]); + } +#endif + p += 2; + } + } +} + #if HAVE_PTHREAD_CREATE typedef struct { void *(*start_routine) (void *); diff --git a/lib/bt-dll.c b/lib/bt-dll.c index 3389bd72..ea8efaee 100644 --- a/lib/bt-dll.c +++ b/lib/bt-dll.c @@ -6,6 +6,8 @@ #define REDIR_ALL \ REDIR(__bt_init) \ + REDIR(__bt_exit) \ + REDIR(__bound_exit_dll) \ REDIR(tcc_backtrace) \ \ REDIR(__bound_ptr_add) \ diff --git a/lib/bt-exe.c b/lib/bt-exe.c index 980d097a..b3bf2e67 100644 --- a/lib/bt-exe.c +++ b/lib/bt-exe.c @@ -30,11 +30,27 @@ void __bt_init(rt_context *p, int num_callers) __rt_error = _rt_error; set_exception_handler(); } else { - p->num_callers = -1; p->next = rc->next, rc->next = p; } } +__declspec(dllexport) +void __bt_exit(rt_context *p) +{ + __attribute__((weak)) void __bound_exit_dll(void*); + struct rt_context *rc = &g_rtctxt; + + if (__bound_exit_dll && p->bounds_start) + __bound_exit_dll(p->bounds_start); + while (rc) { + if (rc->next == p) { + rc->next = rc->next->next; + break; + } + rc = rc->next; + } +} + /* copy a string and truncate it. */ ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) { diff --git a/tccdbg.c b/tccdbg.c index c1904ea6..8ee37901 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -541,7 +541,7 @@ static void dwarf_file(TCCState *s1) filename = strrchr(file->filename, '/'); if (filename == NULL) { - for (i = 1; i < dwarf_line.filename_size; i++) + for (i = 0; i < dwarf_line.filename_size; i++) if (dwarf_line.filename_table[i].dir_entry == 0 && strcmp(dwarf_line.filename_table[i].name, file->filename) == 0) { @@ -685,6 +685,7 @@ ST_FUNC void tcc_debug_start(TCCState *s1) if (s1->dwarf) { int start_abbrev; unsigned char *ptr; + char *undo; /* dwarf_abbrev */ start_abbrev = dwarf_abbrev_section->data_offset; @@ -775,18 +776,32 @@ ST_FUNC void tcc_debug_start(TCCState *s1) dwarf_data1(dwarf_line_section, DWARF_OPCODE_BASE); ptr = section_ptr_add(dwarf_line_section, sizeof(dwarf_line_opcodes)); memcpy(ptr, dwarf_line_opcodes, sizeof(dwarf_line_opcodes)); - dwarf_line.dir_size = 1; - dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *)); + undo = strrchr(filename, '/'); + if (undo) + *undo = 0; + dwarf_line.dir_size = 1 + (undo != NULL); + dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *) * + dwarf_line.dir_size); dwarf_line.dir_table[0] = tcc_strdup(buf); - /* line state machine starts with file 1 instead of 0 */ + if (undo) + dwarf_line.dir_table[1] = tcc_strdup(filename); dwarf_line.filename_size = 2; dwarf_line.filename_table = (struct dwarf_filename_struct *) tcc_malloc(2*sizeof (struct dwarf_filename_struct)); dwarf_line.filename_table[0].dir_entry = 0; - dwarf_line.filename_table[0].name = tcc_strdup(filename); - dwarf_line.filename_table[1].dir_entry = 0; - dwarf_line.filename_table[1].name = tcc_strdup(filename); + if (undo) { + dwarf_line.filename_table[0].name = tcc_strdup(filename); + dwarf_line.filename_table[1].dir_entry = 1; + dwarf_line.filename_table[1].name = tcc_strdup(undo + 1); + *undo = '/'; + dwarf_line.filename_table[0].name = tcc_strdup(filename); + } + else { + dwarf_line.filename_table[0].name = tcc_strdup(filename); + dwarf_line.filename_table[1].dir_entry = 0; + dwarf_line.filename_table[1].name = tcc_strdup(filename); + } dwarf_line.line_size = dwarf_line.line_max_size = 0; dwarf_line.line_data = NULL; dwarf_line.cur_file = 1; @@ -1020,7 +1035,8 @@ ST_FUNC void tcc_debug_bincl(TCCState *s1) } if (strcmp(filename, "")) { for (j = 0; j < dwarf_line.filename_size; j++) - if (strcmp (dwarf_line.filename_table[j].name, filename) == 0) + if (dwarf_line.filename_table[j].dir_entry == i && + strcmp (dwarf_line.filename_table[j].name, filename) == 0) break; if (j == dwarf_line.filename_size) { dwarf_line.filename_table = @@ -1428,32 +1444,25 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) i = 0; while (e->next) { e = e->next; + dwarf_data1(dwarf_info_section, + e->type.t & VT_BITFIELD ? DWARF_ABBREV_MEMBER_BF + : DWARF_ABBREV_MEMBER); + dwarf_strp(dwarf_info_section, + (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM + ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + pos_type[i++] = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); if (e->type.t & VT_BITFIELD) { int pos = e->c * 8 + BIT_POS(e->type.t); int size = BIT_SIZE(e->type.t); - dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER_BF); - dwarf_strp(dwarf_info_section, - (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - pos_type[i++] = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); dwarf_uleb128(dwarf_info_section, size); dwarf_uleb128(dwarf_info_section, pos); } - else { - dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER); - dwarf_strp(dwarf_info_section, - (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); - dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); - dwarf_uleb128(dwarf_info_section, file->line_num); - pos_type[i++] = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); + else dwarf_uleb128(dwarf_info_section, e->c); - } } dwarf_data1(dwarf_info_section, 0); write32le(dwarf_info_section->data + pos_sib, @@ -1785,12 +1794,13 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym) dwarf_info.func = sym; dwarf_info.line = file->line_num; if (s1->do_backtrace) { - int i; + int i, len; dwarf_line_op(s1, 0); // extended dwarf_uleb128_op(s1, strlen(funcname) + 2); dwarf_line_op(s1, DW_LNE_hi_user - 1); - for (i = 0; i < strlen(funcname) + 1; i++) + len = strlen(funcname) + 1; + for (i = 0; i < len; i++) dwarf_line_op(s1, funcname[i]); } } diff --git a/tccelf.c b/tccelf.c index 3f44a1cc..7035b7c2 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1389,15 +1389,14 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) put_ptr(s1, dwarf_line_str_section, 0); else put_ptr(s1, dwarf_str_section, 0); - put_ptr(s1, text_section, 0); } else { put_ptr(s1, stab_section, 0); put_ptr(s1, stab_section, -1); put_ptr(s1, stab_section->link, 0); - section_ptr_add(s, PTR_SIZE); } + *(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf; /* skip esym_start/esym_end/elf_str (not loaded) */ section_ptr_add(s, 3 * PTR_SIZE); /* prog_base : local nameless symbol with offset 0 at SHN_ABS */ @@ -1412,7 +1411,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) section_ptr_add(s, n); cstr_new(&cstr); cstr_printf(&cstr, - "extern void __bt_init(),__bt_init_dll();" + "extern void __bt_init(),__bt_exit(),__bt_init_dll();" "static void *__rt_info[];" "__attribute__((constructor)) static void __bt_init_rt(){"); #ifdef TCC_TARGET_PE @@ -1425,6 +1424,10 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) #endif cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); + /* In case dlcose is called by application */ + cstr_printf(&cstr, + "__attribute__((destructor)) static void __bt_exit_rt(){" + "__bt_exit(__rt_info);}"); tcc_compile_string_no_debug(s1, cstr.data); cstr_free(&cstr); set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o); diff --git a/tccrun.c b/tccrun.c index 42d38827..8741a582 100644 --- a/tccrun.c +++ b/tccrun.c @@ -34,9 +34,9 @@ typedef struct rt_context }; struct { unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str; - addr_t dwarf_text; }; }; + addr_t dwarf; ElfW(Sym) *esym_start, *esym_end; char *elf_str; addr_t prog_base; @@ -182,15 +182,14 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset; if (dwarf_line_str_section) rc->dwarf_line_str = dwarf_line_str_section->data; - rc->dwarf_text = text_section->sh_addr; } else { rc->stab_sym = (Stab_Sym *)stab_section->data; rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); rc->stab_str = (char *)stab_section->link->data; - rc->dwarf_text = 0; } + rc->dwarf = s1->dwarf; rc->esym_start = (ElfW(Sym) *)(symtab_section->data); rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); rc->elf_str = (char *)symtab_section->link->data; @@ -666,7 +665,9 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, unsigned char *ln; unsigned char *cp; unsigned char *end; - unsigned int size; + unsigned char *opcode_length; + unsigned long long size; + unsigned int length; unsigned char version; unsigned int min_insn_length; unsigned int max_ops_per_insn; @@ -678,7 +679,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, unsigned int i; unsigned int j; unsigned int len; - unsigned int value; + unsigned long long value; struct { unsigned int type; unsigned int form; @@ -695,13 +696,11 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, addr_t last_pc; addr_t pc; addr_t func_addr; - addr_t offset_dll; int line; char *filename; char *function; next: - offset_dll = 0; ln = rc->dwarf_line; while (ln < rc->dwarf_line_end) { dir_size = 0; @@ -712,13 +711,18 @@ next: line = 1; filename = NULL; function = NULL; + length = 4; size = dwarf_read_4(ln, rc->dwarf_line_end); + if (size == 0xffffffffu) // dwarf 64 + length = 8, size = dwarf_read_8(ln, rc->dwarf_line_end); end = ln + size; + if (end < ln || end > rc->dwarf_line_end) + break; version = dwarf_read_2(ln, end); if (version >= 5) - ln += 6; // address size, segment selector, prologue Length + ln += length + 2; // address size, segment selector, prologue Length else - ln += 4; // prologue Length + ln += length; // prologue Length min_insn_length = dwarf_read_1(ln, end); if (version >= 4) max_ops_per_insn = dwarf_read_1(ln, end); @@ -729,8 +733,9 @@ next: line_base |= line_base >= 0x80 ? ~0xff : 0; line_range = dwarf_read_1(ln, end); opcode_base = dwarf_read_1(ln, end); + opcode_length = ln; + ln += opcode_base - 1; opindex = 0; - ln += 12; if (version >= 5) { col = dwarf_read_1(ln, end); for (i = 0; i < col; i++) { @@ -744,11 +749,13 @@ next: if (entry_format[j].form != DW_FORM_line_strp) goto next_line; #if 0 - value = dwarf_read_4(ln, end); + value = length == 4 ? dwarf_read_4(ln, end) + : dwarf_read_8(ln, end); if (i < DIR_TABLE_SIZE) dirs[i] = (char *)rc->dwarf_line_str + value; #else - dwarf_read_4(ln, end); + length == 4 ? dwarf_read_4(ln, end) + : dwarf_read_8(ln, end); #endif } else @@ -766,7 +773,8 @@ next: if (entry_format[j].type == DW_LNCT_path) { if (entry_format[j].form != DW_FORM_line_strp) goto next_line; - value = dwarf_read_4(ln, end); + value = length == 4 ? dwarf_read_4(ln, end) + : dwarf_read_8(ln, end); if (i < FILE_TABLE_SIZE) filename_table[i].name = (char *)rc->dwarf_line_str + value; @@ -813,108 +821,8 @@ next: filename = filename_table[0].name; while (ln < end) { last_pc = pc; - switch (dwarf_read_1(ln, end)) { - case 0: - len = dwarf_read_uleb128(&ln, end); - cp = ln; - ln += len; - if (len == 0) - goto next_line; - switch (dwarf_read_1(cp, end)) { - case DW_LNE_end_sequence: - goto next_line; - case DW_LNE_set_address: -#if PTR_SIZE == 4 - pc = dwarf_read_4(cp, end); -#else - pc = dwarf_read_8(cp, end); -#endif - if (rc->num_callers < 0) { - /* dll */ - if (!offset_dll) - offset_dll = pc; - pc = rc->dwarf_text + (pc - offset_dll); - } - opindex = 0; - break; - case DW_LNE_define_file: /* deprecated */ - if (++filename_size < FILE_TABLE_SIZE) { - filename_table[filename_size - 1].name = (char *)ln - 1; - while (dwarf_read_1(ln, end)) {} - filename_table[filename_size - 1].dir_entry = - dwarf_read_uleb128(&ln, end); - } - else { - while (dwarf_read_1(ln, end)) {} - dwarf_read_uleb128(&ln, end); - } - dwarf_read_uleb128(&ln, end); // time - dwarf_read_uleb128(&ln, end); // size - break; - case DW_LNE_hi_user - 1: - function = (char *)cp; - func_addr = pc; - break; - default: - break; - } - break; - case DW_LNS_copy: - break; - case DW_LNS_advance_pc: - if (max_ops_per_insn == 1) - pc += dwarf_read_uleb128(&ln, end) * min_insn_length; - else { - unsigned long long off = dwarf_read_uleb128(&ln, end); - - pc += (opindex + off) / max_ops_per_insn * - min_insn_length; - opindex = (opindex + off) % max_ops_per_insn; - } - i = 0; - goto check_pc; - case DW_LNS_advance_line: - line += dwarf_read_sleb128(&ln, end); - break; - case DW_LNS_set_file: - i = dwarf_read_uleb128(&ln, end); - if (i < FILE_TABLE_SIZE && i < filename_size) - filename = filename_table[i].name; - break; - case DW_LNS_set_column: - dwarf_read_uleb128(&ln, end); - break; - case DW_LNS_negate_stmt: - break; - case DW_LNS_set_basic_block: - break; - case DW_LNS_const_add_pc: - if (max_ops_per_insn == 1) - pc += ((255 - opcode_base) / line_range) * min_insn_length; - else { - unsigned int off = (255 - opcode_base) / line_range; - - pc += ((opindex + off) / max_ops_per_insn) * - min_insn_length; - opindex = (opindex + off) % max_ops_per_insn; - } - i = 0; - goto check_pc; - case DW_LNS_fixed_advance_pc: - i = dwarf_read_2(ln, end); - pc += i; - opindex = 0; - i = 0; - goto check_pc; - case DW_LNS_set_prologue_end: - break; - case DW_LNS_set_epilogue_begin: - break; - case DW_LNS_set_isa: - dwarf_read_uleb128(&ln, end); - break; - default: - i = ln[-1]; + i = dwarf_read_1(ln, end); + if (i >= opcode_base) { if (max_ops_per_insn == 1) pc += ((i - opcode_base) / line_range) * min_insn_length; else { @@ -928,7 +836,91 @@ check_pc: if (pc >= wanted_pc && wanted_pc >= last_pc) goto found; line += i; - break; + } + else { + switch (i) { + case 0: + len = dwarf_read_uleb128(&ln, end); + cp = ln; + ln += len; + if (len == 0) + goto next_line; + switch (dwarf_read_1(cp, end)) { + case DW_LNE_end_sequence: + break; + case DW_LNE_set_address: +#if PTR_SIZE == 4 + pc = dwarf_read_4(cp, end); +#else + pc = dwarf_read_8(cp, end); +#endif + opindex = 0; + break; + case DW_LNE_define_file: /* deprecated */ + if (++filename_size < FILE_TABLE_SIZE) { + filename_table[filename_size - 1].name = (char *)ln - 1; + while (dwarf_read_1(ln, end)) {} + filename_table[filename_size - 1].dir_entry = + dwarf_read_uleb128(&ln, end); + } + else { + while (dwarf_read_1(ln, end)) {} + dwarf_read_uleb128(&ln, end); + } + dwarf_read_uleb128(&ln, end); // time + dwarf_read_uleb128(&ln, end); // size + break; + case DW_LNE_hi_user - 1: + function = (char *)cp; + func_addr = pc; + break; + default: + break; + } + break; + case DW_LNS_advance_pc: + if (max_ops_per_insn == 1) + pc += dwarf_read_uleb128(&ln, end) * min_insn_length; + else { + unsigned long long off = dwarf_read_uleb128(&ln, end); + + pc += (opindex + off) / max_ops_per_insn * + min_insn_length; + opindex = (opindex + off) % max_ops_per_insn; + } + i = 0; + goto check_pc; + case DW_LNS_advance_line: + line += dwarf_read_sleb128(&ln, end); + break; + case DW_LNS_set_file: + i = dwarf_read_uleb128(&ln, end); + if (i < FILE_TABLE_SIZE && i < filename_size) + filename = filename_table[i].name; + break; + case DW_LNS_const_add_pc: + if (max_ops_per_insn == 1) + pc += ((255 - opcode_base) / line_range) * min_insn_length; + else { + unsigned int off = (255 - opcode_base) / line_range; + + pc += ((opindex + off) / max_ops_per_insn) * + min_insn_length; + opindex = (opindex + off) % max_ops_per_insn; + } + i = 0; + goto check_pc; + case DW_LNS_fixed_advance_pc: + i = dwarf_read_2(ln, end); + pc += i; + opindex = 0; + i = 0; + goto check_pc; + default: + for (j = 0; j < opcode_length[i - 1]; j++) + dwarf_read_uleb128 (&ln, end); + break; + } } } next_line: @@ -988,7 +980,7 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) ret = rt_get_caller_pc(&pc, rc, i); a = "%s"; if (ret != -1) { - if ((addr_t)rc->dwarf_text) + if (rc->dwarf) pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip); else pc = rt_printline(rc, pc, level ? "by" : "at", skip);