From 322c4dc2756cedf21de7ff5fccc2573175a4b6d6 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Sat, 9 Nov 2024 08:04:45 +0100 Subject: [PATCH 1/3] Add support for backtrace() This requires adding .eh_frame and .eh_frame_hdr sections. There are 3 new functions to setup the sections: tcc_eh_frame_start: create cie in .eh_frame tcc_debug_frame_end: add fde in .eh_frame for every function tcc_eh_frame_hdr: create .eh_frame_hdr The PT_GNU_EH_FRAME header is created. The dwarf read functions are moved from tccrun.c to tcc.h The backtrace() function is not supported on all targets. windows, apple, bsd and arm are disabled. arm uses its own sections .ARM.extab and .ARM.exidx. --- arm64-link.c | 2 +- riscv64-link.c | 15 ++- tcc.h | 57 ++++++++++ tccdbg.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++- tccelf.c | 17 +++ tccgen.c | 1 + tccrun.c | 49 -------- 7 files changed, 388 insertions(+), 53 deletions(-) diff --git a/arm64-link.c b/arm64-link.c index 9cd8989b1..cfdd95ea0 100644 --- a/arm64-link.c +++ b/arm64-link.c @@ -218,7 +218,7 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, break; } } - write32le(ptr, val - addr); + add32le(ptr, val - addr); return; case R_AARCH64_MOVW_UABS_G0_NC: write32le(ptr, ((read32le(ptr) & 0xffe0001f) | diff --git a/riscv64-link.c b/riscv64-link.c index f10e7c038..5cdbe2f76 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -352,8 +352,21 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, case R_RISCV_SUB6: *ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f); return; - case R_RISCV_32_PCREL: + if (s1->output_type & TCC_OUTPUT_DYN) { + /* DLL relocation */ + esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; + if (esym_index) { + qrel->r_offset = rel->r_offset; + qrel->r_info = ELFW(R_INFO)(esym_index, R_RISCV_32_PCREL); + /* Use sign extension! */ + qrel->r_addend = (int)read32le(ptr) + rel->r_addend; + qrel++; + break; + } + } + add32le(ptr, val - addr); + return; case R_RISCV_COPY: /* XXX */ return; diff --git a/tcc.h b/tcc.h index 7bae6affe..ef02e4d2a 100644 --- a/tcc.h +++ b/tcc.h @@ -925,6 +925,10 @@ struct TCCState { Section *dynsym; /* got & plt handling */ Section *got, *plt; + /* exception handling */ + Section *eh_frame_section; + Section *eh_frame_hdr_section; + unsigned long eh_start; /* debug sections */ Section *stab_section; Section *dwarf_info_section; @@ -1673,6 +1677,53 @@ static inline void write64le(unsigned char *p, uint64_t x) { static inline void add64le(unsigned char *p, int64_t x) { write64le(p, read64le(p) + x); } +#define DWARF_MAX_128 ((8 * sizeof (int64_t) + 6) / 7) +#define dwarf_read_1(ln,end) \ + ((ln) < (end) ? *(ln)++ : 0) +#define dwarf_read_2(ln,end) \ + ((ln) + 1 < (end) ? (ln) += 2, read16le((ln) - 2) : 0) +#define dwarf_read_4(ln,end) \ + ((ln) + 3 < (end) ? (ln) += 4, read32le((ln) - 4) : 0) +#define dwarf_read_8(ln,end) \ + ((ln) + 7 < (end) ? (ln) += 8, read64le((ln) - 8) : 0) +static inline uint64_t +dwarf_read_uleb128(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + uint64_t retval = 0; + int i; + + for (i = 0; i < DWARF_MAX_128; i++) { + uint64_t byte = dwarf_read_1(cp, end); + + retval |= (byte & 0x7f) << (i * 7); + if ((byte & 0x80) == 0) + break; + } + *ln = cp; + return retval; +} +static inline int64_t +dwarf_read_sleb128(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + int64_t retval = 0; + int i; + + for (i = 0; i < DWARF_MAX_128; i++) { + uint64_t byte = dwarf_read_1(cp, end); + + retval |= (byte & 0x7f) << (i * 7); + if ((byte & 0x80) == 0) { + if ((byte & 0x40) && (i + 1) * 7 < 64) + retval |= -1LL << ((i + 1) * 7); + break; + } + } + *ln = cp; + return retval; +} + /* ------------ i386-gen.c ------------ */ #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM @@ -1818,6 +1869,10 @@ ST_FUNC int gen_makedeps(TCCState *s, const char *target, const char *filename); /* ------------ tccdbg.c ------------ */ +ST_FUNC void tcc_eh_frame_start(TCCState *s1); +ST_FUNC void tcc_eh_frame_end(TCCState *s1); +ST_FUNC void tcc_eh_frame_hdr(TCCState *s1, int final); + ST_FUNC void tcc_debug_new(TCCState *s); ST_FUNC void tcc_debug_start(TCCState *s1); @@ -1846,6 +1901,8 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1); #define stab_section s1->stab_section #define stabstr_section stab_section->link #define tcov_section s1->tcov_section +#define eh_frame_section s1->eh_frame_section +#define eh_frame_hdr_section s1->eh_frame_hdr_section #define dwarf_info_section s1->dwarf_info_section #define dwarf_abbrev_section s1->dwarf_abbrev_section #define dwarf_line_section s1->dwarf_line_section diff --git a/tccdbg.c b/tccdbg.c index 15d54b475..4176fd636 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -71,7 +71,7 @@ static const struct { { VT_BOOL, 1, DW_ATE_boolean, "bool:t26=r26;0;255;" }, #if LONG_SIZE == 4 { VT_VOID, 1, DW_ATE_unsigned_char, "void:t27=27" }, -#else +#else /* bitfields use these */ { VT_LONG | VT_INT, 8, DW_ATE_signed, "long int:t27=r27;-9223372036854775808;9223372036854775807;" }, { VT_LONG | VT_INT | VT_UNSIGNED, 8, DW_ATE_unsigned, "long unsigned int:t28=r28;0;01777777777777777777777;" }, @@ -407,6 +407,8 @@ struct _tccdbg { #define dwarf_info s1->dState->dwarf_info #define tcov_data s1->dState->tcov_data +#define FDE_ENCODING (DW_EH_PE_udata4 | DW_EH_PE_signed | DW_EH_PE_pcrel) + /* ------------------------------------------------------------------------- */ static void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value); @@ -611,7 +613,7 @@ static void dwarf_file(TCCState *s1) } if (i == dwarf_line.dir_size) { dwarf_line.dir_size++; - dwarf_line.dir_table = + dwarf_line.dir_table = (char **) tcc_realloc(dwarf_line.dir_table, dwarf_line.dir_size * sizeof (char *)); @@ -710,6 +712,299 @@ static void dwarf_sleb128_op (TCCState *s1, long long value) } while (more); } +ST_FUNC void tcc_eh_frame_start(TCCState *s1) +{ +#if !(defined _WIN32 || defined __APPLE__ || defined TCC_TARGET_ARM || \ + defined TARGETOS_BSD) + eh_frame_section = new_section(s1, ".eh_frame", SHT_PROGBITS, SHF_ALLOC); + + s1->eh_start = eh_frame_section->data_offset; + dwarf_data4(eh_frame_section, 0); // length + dwarf_data4(eh_frame_section, 0); // CIE ID + dwarf_data1(eh_frame_section, 1); // Version + dwarf_data1(eh_frame_section, 'z'); // Augmentation String + dwarf_data1(eh_frame_section, 'R'); + dwarf_data1(eh_frame_section, 0); +#if defined TCC_TARGET_I386 + dwarf_uleb128(eh_frame_section, 1); // code_alignment_factor + dwarf_sleb128(eh_frame_section, -4); // data_alignment_factor + dwarf_uleb128(eh_frame_section, 8); // return address column + dwarf_uleb128(eh_frame_section, 1); // Augmentation len + dwarf_data1(eh_frame_section, FDE_ENCODING); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 4); // r4 (esp) + dwarf_uleb128(eh_frame_section, 4); // ofs 4 + dwarf_data1(eh_frame_section, DW_CFA_offset + 8); // r8 (eip) + dwarf_uleb128(eh_frame_section, 1); // cfa-4 +#elif defined TCC_TARGET_X86_64 + dwarf_uleb128(eh_frame_section, 1); // code_alignment_factor + dwarf_sleb128(eh_frame_section, -8); // data_alignment_factor + dwarf_uleb128(eh_frame_section, 16); // return address column + dwarf_uleb128(eh_frame_section, 1); // Augmentation len + dwarf_data1(eh_frame_section, FDE_ENCODING); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 7); // r7 (rsp) + dwarf_uleb128(eh_frame_section, 8); // ofs 8 + dwarf_data1(eh_frame_section, DW_CFA_offset + 16); // r16 (rip) + dwarf_uleb128(eh_frame_section, 1); // cfa-8 +#elif defined TCC_TARGET_ARM + /* TODO: arm must be compiled with: -funwind-tables */ + /* arm also uses .ARM.extab and .ARM.exidx sections */ + dwarf_uleb128(eh_frame_section, 2); // code_alignment_factor + dwarf_sleb128(eh_frame_section, -4); // data_alignment_factor + dwarf_uleb128(eh_frame_section, 14); // return address column + dwarf_uleb128(eh_frame_section, 1); // Augmentation len + dwarf_data1(eh_frame_section, FDE_ENCODING); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 13); // r13 (sp) + dwarf_uleb128(eh_frame_section, 0); // ofs 0 +#elif defined TCC_TARGET_ARM64 + dwarf_uleb128(eh_frame_section, 4); // code_alignment_factor + dwarf_sleb128(eh_frame_section, -8); // data_alignment_factor + dwarf_uleb128(eh_frame_section, 30); // return address column + dwarf_uleb128(eh_frame_section, 1); // Augmentation len + dwarf_data1(eh_frame_section, FDE_ENCODING); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 31); // x31 (sp) + dwarf_uleb128(eh_frame_section, 0); // ofs 0 +#elif defined TCC_TARGET_RISCV64 + eh_frame_section->data[s1->eh_start + 8] = 3; // version = 3 + dwarf_uleb128(eh_frame_section, 1); // code_alignment_factor + dwarf_sleb128(eh_frame_section, -4); // data_alignment_factor + dwarf_uleb128(eh_frame_section, 1); // return address column + dwarf_uleb128(eh_frame_section, 1); // Augmentation len + dwarf_data1(eh_frame_section, FDE_ENCODING); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 2); // r2 (sp) + dwarf_uleb128(eh_frame_section, 0); // ofs 0 +#endif + while ((eh_frame_section->data_offset - s1->eh_start) & 3) + dwarf_data1(eh_frame_section, DW_CFA_nop); + write32le(eh_frame_section->data + s1->eh_start, // length + eh_frame_section->data_offset - s1->eh_start - 4); +#endif +} + +static void tcc_debug_frame_end(TCCState *s1, int size) +{ + int eh_section_sym; + unsigned long fde_start; + + if (!eh_frame_section) + return; + eh_section_sym = dwarf_get_section_sym(text_section); + fde_start = eh_frame_section->data_offset; + dwarf_data4(eh_frame_section, 0); // length + dwarf_data4(eh_frame_section, + fde_start - s1->eh_start + 4); // CIE Pointer +#if TCC_TARGET_I386 + dwarf_reloc(eh_frame_section, eh_section_sym, R_386_PC32); +#elif defined TCC_TARGET_X86_64 + dwarf_reloc(eh_frame_section, eh_section_sym, R_X86_64_PC32); +#elif defined TCC_TARGET_ARM + dwarf_reloc(eh_frame_section, eh_section_sym, R_ARM_REL32); +#elif defined TCC_TARGET_ARM64 + dwarf_reloc(eh_frame_section, eh_section_sym, R_AARCH64_PREL32); +#elif defined TCC_TARGET_RISCV64 + dwarf_reloc(eh_frame_section, eh_section_sym, R_RISCV_32_PCREL); +#endif + dwarf_data4(eh_frame_section, func_ind); // PC Begin + dwarf_data4(eh_frame_section, size); // PC Range + dwarf_data1(eh_frame_section, 0); // Augmentation Length +#if TCC_TARGET_I386 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 1); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 8); + dwarf_data1(eh_frame_section, DW_CFA_offset + 5); // r5 (ebp) + dwarf_uleb128(eh_frame_section, 2); // cfa-8 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 2); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_register); + dwarf_uleb128(eh_frame_section, 5); // r5 (ebp) + dwarf_data1(eh_frame_section, DW_CFA_advance_loc4); + dwarf_data4(eh_frame_section, size - 5); + dwarf_data1(eh_frame_section, DW_CFA_restore + 5); // r5 (ebp) + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 4); // r4 (esp) + dwarf_uleb128(eh_frame_section, 4); // ofs 4 +#elif defined TCC_TARGET_X86_64 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 1); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 16); + dwarf_data1(eh_frame_section, DW_CFA_offset + 6); // r6 (rbp) + dwarf_uleb128(eh_frame_section, 2); // cfa-16 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 3); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_register); + dwarf_uleb128(eh_frame_section, 6); // r6 (rbp) + dwarf_data1(eh_frame_section, DW_CFA_advance_loc4); + dwarf_data4(eh_frame_section, size - 5); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 7); // r7 (rsp) + dwarf_uleb128(eh_frame_section, 8); // ofs 8 +#elif defined TCC_TARGET_ARM + /* TODO */ + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 2); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 8); + dwarf_data1(eh_frame_section, DW_CFA_offset + 14); // r14 (lr) + dwarf_uleb128(eh_frame_section, 1); + dwarf_data1(eh_frame_section, DW_CFA_offset + 11); // r11 (fp) + dwarf_uleb128(eh_frame_section, 2); + dwarf_data1(eh_frame_section, DW_CFA_advance_loc4); + dwarf_data4(eh_frame_section, size / 2 - 5); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_register); + dwarf_uleb128(eh_frame_section, 11); // r11 (fp) +#elif defined TCC_TARGET_ARM64 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 1); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 224); + dwarf_data1(eh_frame_section, DW_CFA_offset + 29); // x29 (fp) + dwarf_uleb128(eh_frame_section, 28); // cfa-224 + dwarf_data1(eh_frame_section, DW_CFA_offset + 30); // x30 (lr) + dwarf_uleb128(eh_frame_section, 27); // cfa-216 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 3); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 224 + ((-loc + 15) & ~15)); + dwarf_data1(eh_frame_section, DW_CFA_advance_loc4); + dwarf_data4(eh_frame_section, size / 4 - 5); + dwarf_data1(eh_frame_section, DW_CFA_restore + 30); // x30 (lr) + dwarf_data1(eh_frame_section, DW_CFA_restore + 29); // x29 (fp) + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 0); +#elif defined TCC_TARGET_RISCV64 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 4); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 16); // ofs 16 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 8); + dwarf_data1(eh_frame_section, DW_CFA_offset + 1); // r1 (ra, lr) + dwarf_uleb128(eh_frame_section, 2); // cfa-8 + dwarf_data1(eh_frame_section, DW_CFA_offset + 8); // r8 (s0, fp) + dwarf_uleb128(eh_frame_section, 4); // cfa-16 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 8); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 8); // r8 (s0, fp) + dwarf_uleb128(eh_frame_section, 0); // ofs 0 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc4); + while (size >= 4 && + read32le(cur_text_section->data + func_ind + size - 4) != 0x00008067) + size -= 4; + dwarf_data4(eh_frame_section, size - 36); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa); + dwarf_uleb128(eh_frame_section, 2); // r2 (r2, sp) + dwarf_uleb128(eh_frame_section, 16); // ofs 16 + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 4); + dwarf_data1(eh_frame_section, DW_CFA_restore + 1); // r1 (lr) + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 4); + dwarf_data1(eh_frame_section, DW_CFA_restore + 8); // r8 (s0, fp) + dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 4); + dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); + dwarf_uleb128(eh_frame_section, 0); // ofs 0 +#endif + while ((eh_frame_section->data_offset - fde_start) & 3) + dwarf_data1(eh_frame_section, DW_CFA_nop); + write32le(eh_frame_section->data + fde_start, // length + eh_frame_section->data_offset - fde_start - 4); +} + +ST_FUNC void tcc_eh_frame_end(TCCState *s1) +{ + if (!eh_frame_section) + return; + dwarf_data4(eh_frame_section, 0); +} + +struct eh_search_table { + uint32_t pc_offset; + uint32_t fde_offset; +}; + +static int sort_eh_table(const void *a, const void *b) +{ + uint32_t pc1 = ((const struct eh_search_table *)a)->pc_offset; + uint32_t pc2 = ((const struct eh_search_table *)b)->pc_offset; + + return pc1 < pc2 ? -1 : pc1 > pc2 ? 1 : 0; +} + +ST_FUNC void tcc_eh_frame_hdr(TCCState *s1, int final) +{ + int count = 0, offset; + unsigned long count_offset, tab_offset; + unsigned char *ln, *end; + unsigned int last_cie_offset = 0xffffffff; + + if (!eh_frame_section || !eh_frame_section->data_offset) + return; + if (final && !eh_frame_hdr_section) + return; + if (final == 0) + eh_frame_hdr_section = + new_section(s1, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC); + eh_frame_hdr_section->data_offset = 0; + dwarf_data1(eh_frame_hdr_section, 1); // Version + // Pointer Encoding Format + dwarf_data1(eh_frame_hdr_section, DW_EH_PE_sdata4 | DW_EH_PE_pcrel); + // Count Encoding Format + dwarf_data1(eh_frame_hdr_section, DW_EH_PE_udata4 | DW_EH_PE_absptr); + // Table Encoding Format + dwarf_data1(eh_frame_hdr_section, DW_EH_PE_sdata4 | DW_EH_PE_datarel); + offset = eh_frame_section->sh_addr - + eh_frame_hdr_section->sh_addr - + eh_frame_hdr_section->data_offset; + dwarf_data4(eh_frame_hdr_section, offset); // eh_frame_ptr + // Count + count_offset = eh_frame_hdr_section->data_offset; + dwarf_data4(eh_frame_hdr_section, 0); + tab_offset = eh_frame_hdr_section->data_offset; + ln = eh_frame_section->data; + end = eh_frame_section->data + eh_frame_section->data_offset; + while (ln < end) { + unsigned char *fde = ln, *rd = ln; + unsigned int cie_offset, version, length = dwarf_read_4(rd, end); + unsigned int pc_offset, fde_offset; + + if (length == 0) + goto next; + cie_offset = dwarf_read_4(rd, end); + if (cie_offset == 0) + goto next; + if (cie_offset != last_cie_offset) { + unsigned char *cie = rd - cie_offset + 4; + + if (cie < eh_frame_section->data) + goto next; + version = dwarf_read_1(cie, end); + if ((version == 1 || version == 3) && + dwarf_read_1(cie, end) == 'z' && // Augmentation String + dwarf_read_1(cie, end) == 'R' && + dwarf_read_1(cie, end) == 0) { + dwarf_read_uleb128(&cie, end); // code_alignment_factor + dwarf_read_sleb128(&cie, end); // data_alignment_factor + dwarf_read_1(cie, end); // return address column + if (dwarf_read_uleb128(&cie, end) == 1 && + dwarf_read_1(cie, end) == FDE_ENCODING) { + last_cie_offset = cie_offset; + } + else + goto next; + } + else + goto next; + } + count++; + fde_offset = eh_frame_section->sh_addr + + (fde - eh_frame_section->data) - + eh_frame_hdr_section->sh_addr; + pc_offset = dwarf_read_4(rd, end) + fde_offset + 8; + dwarf_data4(eh_frame_hdr_section, pc_offset); + dwarf_data4(eh_frame_hdr_section, fde_offset); +next: + ln += length + 4; + } + add32le(eh_frame_hdr_section->data + count_offset, count); + qsort(eh_frame_hdr_section->data + tab_offset, count, + sizeof(struct eh_search_table), sort_eh_table); +} + /* start of translation unit info */ ST_FUNC void tcc_debug_start(TCCState *s1) { @@ -1875,6 +2170,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) /* lldb does not like function end and next function start at same pc */ int min_instr_len; + tcc_debug_frame_end(s1, size); if (!s1->do_debug) return; min_instr_len = dwarf_line.last_pc == ind ? 0 : DWARF_MIN_INSTR_LEN; diff --git a/tccelf.c b/tccelf.c index 498cd2785..50f365eb7 100644 --- a/tccelf.c +++ b/tccelf.c @@ -95,6 +95,8 @@ ST_FUNC void tccelf_new(TCCState *s) tcc_debug_new(s); } + tcc_eh_frame_start(s); + #ifdef CONFIG_TCC_BCHECK if (s->do_bounds_check) { /* if bound checking, then add corresponding sections */ @@ -2271,6 +2273,8 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) ++phnum; if (d->dynamic) ++phnum; + if (eh_frame_hdr_section) + ++phnum; if (d->roinf) ++phnum; d->phnum = phnum; @@ -2391,6 +2395,12 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) fill_phdr(++ph, PT_NOTE, d->note); if (d->dynamic) fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W; + if (eh_frame_hdr_section) { + add32le(eh_frame_hdr_section->data + 4, + eh_frame_section->sh_offset - + eh_frame_hdr_section->sh_offset - 4); + fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section); + } if (d->roinf) fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W; if (d->interp) @@ -2859,6 +2869,10 @@ static int elf_output_file(TCCState *s1, const char *filename) /* shared library case: simply export all global symbols */ export_global_syms(s1); } + + /* fill with initial data */ + tcc_eh_frame_hdr(s1, 0); + dyninf.gnu_hash = create_gnu_hash(s1); } else { build_got_entries(s1, 0); @@ -2943,6 +2957,9 @@ static int elf_output_file(TCCState *s1, const char *filename) reorder_sections(s1, sec_order); + /* fill with final data */ + tcc_eh_frame_hdr(s1, 1); + /* Create the ELF file with name 'filename' */ ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr); the_end: diff --git a/tccgen.c b/tccgen.c index 1cf933044..9cb699bba 100644 --- a/tccgen.c +++ b/tccgen.c @@ -402,6 +402,7 @@ ST_FUNC int tccgen_compile(TCCState *s1) gen_inline_functions(s1); check_vstack(); /* end of translation unit info */ + tcc_eh_frame_end(s1); tcc_debug_end(s1); tcc_tcov_end(s1); return 0; diff --git a/tccrun.c b/tccrun.c index b0cb4dba9..61cd4717f 100644 --- a/tccrun.c +++ b/tccrun.c @@ -760,19 +760,9 @@ static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, bt_info *bi) /* ------------------------------------------------------------- */ /* rt_printline - dwarf version */ -#define MAX_128 ((8 * sizeof (long long) + 6) / 7) - #define DIR_TABLE_SIZE (64) #define FILE_TABLE_SIZE (512) -#define dwarf_read_1(ln,end) \ - ((ln) < (end) ? *(ln)++ : 0) -#define dwarf_read_2(ln,end) \ - ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0) -#define dwarf_read_4(ln,end) \ - ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0) -#define dwarf_read_8(ln,end) \ - ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0) #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \ switch (entry_format[j].form) { \ case DW_FORM_data1: (ln) += 1; break; \ @@ -784,45 +774,6 @@ static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, bt_info *bi) default: goto next_line; \ } -static unsigned long long -dwarf_read_uleb128(unsigned char **ln, unsigned char *end) -{ - unsigned char *cp = *ln; - unsigned long long retval = 0; - int i; - - for (i = 0; i < MAX_128; i++) { - unsigned long long byte = dwarf_read_1(cp, end); - - retval |= (byte & 0x7f) << (i * 7); - if ((byte & 0x80) == 0) - break; - } - *ln = cp; - return retval; -} - -static long long -dwarf_read_sleb128(unsigned char **ln, unsigned char *end) -{ - unsigned char *cp = *ln; - long long retval = 0; - int i; - - for (i = 0; i < MAX_128; i++) { - unsigned long long byte = dwarf_read_1(cp, end); - - retval |= (byte & 0x7f) << (i * 7); - if ((byte & 0x80) == 0) { - if ((byte & 0x40) && (i + 1) * 7 < 64) - retval |= -1LL << ((i + 1) * 7); - break; - } - } - *ln = cp; - return retval; -} - static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, bt_info *bi) { unsigned char *ln; From 233e22f23d52b8c4faa4736c517c59868d842ab4 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Sat, 9 Nov 2024 08:24:58 +0100 Subject: [PATCH 2/3] Fix compile problem on windows --- tccdbg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tccdbg.c b/tccdbg.c index 4176fd636..f82d6bbe1 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -797,7 +797,7 @@ static void tcc_debug_frame_end(TCCState *s1, int size) dwarf_data4(eh_frame_section, 0); // length dwarf_data4(eh_frame_section, fde_start - s1->eh_start + 4); // CIE Pointer -#if TCC_TARGET_I386 +#if defined TCC_TARGET_I386 dwarf_reloc(eh_frame_section, eh_section_sym, R_386_PC32); #elif defined TCC_TARGET_X86_64 dwarf_reloc(eh_frame_section, eh_section_sym, R_X86_64_PC32); @@ -811,7 +811,7 @@ static void tcc_debug_frame_end(TCCState *s1, int size) dwarf_data4(eh_frame_section, func_ind); // PC Begin dwarf_data4(eh_frame_section, size); // PC Range dwarf_data1(eh_frame_section, 0); // Augmentation Length -#if TCC_TARGET_I386 +#if defined TCC_TARGET_I386 dwarf_data1(eh_frame_section, DW_CFA_advance_loc + 1); dwarf_data1(eh_frame_section, DW_CFA_def_cfa_offset); dwarf_uleb128(eh_frame_section, 8); From f0cd0fbe1b0b0465c87f9507299b468a0b208cf7 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Sat, 9 Nov 2024 08:34:10 +0100 Subject: [PATCH 3/3] Print bound region when bound checking error occurs --- lib/bcheck.c | 16 +++++++++------- tests/tests2/126_bound_global.expect | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/bcheck.c b/lib/bcheck.c index f609a2282..2b78aa659 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -559,7 +559,9 @@ void * __bound_ptr_add(void *p, size_t offset) if (tree->is_invalid || addr + offset > tree->size) { POST_SEM (); if (print_warn_ptr_add) - bound_warning("%p is outside of the region", p + offset); + bound_warning("%p is outside of the region (0x%lx..0x%lx)", + p + offset, (long)tree->start, + (long)(tree->start + tree->size - 1)); if (never_fatal <= 0) return INVALID_POINTER; /* return an invalid pointer */ return p + offset; @@ -605,7 +607,9 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \ if (addr <= tree->size) { \ if (tree->is_invalid || addr + offset + dsize > tree->size) { \ POST_SEM (); \ - bound_warning("%p is outside of the region", p + offset); \ + bound_warning("%p is outside of the region (0x%lx..0x%lx)", \ + p + offset, (long)tree->start, \ + (long)(tree->start + tree->size - 1)); \ if (never_fatal <= 0) \ return INVALID_POINTER; /* return an invalid pointer */ \ return p + offset; \ @@ -1105,11 +1109,9 @@ void __bound_init(size_t *p, int mode) while (p[0] != 0) { tree = splay_insert(p[0], p[1], tree); #if BOUND_DEBUG - if (print_calls) { - dprintf(stderr, "%s, %s(): static var %p 0x%lx\n", - __FILE__, __FUNCTION__, - (void *) p[0], (unsigned long) p[1]); - } + dprintf(stderr, "%s, %s(): static var %p 0x%lx\n", + __FILE__, __FUNCTION__, + (void *) p[0], (unsigned long) p[1]); #endif p += 2; } diff --git a/tests/tests2/126_bound_global.expect b/tests/tests2/126_bound_global.expect index fcdea9002..969c20aa1 100644 --- a/tests/tests2/126_bound_global.expect +++ b/tests/tests2/126_bound_global.expect @@ -1,2 +1,2 @@ -126_bound_global.c:11: at main: BCHECK: ........ is outside of the region +126_bound_global.c:11: at main: BCHECK: ........ is outside of the region (..................) 126_bound_global.c:11: at main: RUNTIME ERROR: invalid memory access