From 62096265ed62eb07144bed0dd9c038e03abdf30f Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Wed, 30 Nov 2022 21:49:07 +0100 Subject: [PATCH] Add debug support to macos lldb now works with this push. In tccmacho.c add S_ATTR_DEBUG to all debug sections. Add __DWARF section and rearange struct skinfo. In tccdbg.c The first filename in dwarf_line can not be used. Also had to fix structure/union/lexical_block/subroutine to allow empty childs. dwarfdump --verify complained about this. --- tccdbg.c | 104 ++++++++++++++++++++++++++++++++++++----------------- tccmacho.c | 60 ++++++++++++++++++------------- 2 files changed, 107 insertions(+), 57 deletions(-) diff --git a/tccdbg.c b/tccdbg.c index 9b2b527e..170bc8c3 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -111,12 +111,16 @@ static const struct { #define DWARF_ABBREV_MEMBER 14 #define DWARF_ABBREV_MEMBER_BF 15 #define DWARF_ABBREV_STRUCTURE_TYPE 16 -#define DWARF_ABBREV_UNION_TYPE 17 -#define DWARF_ABBREV_SUBPROGRAM_EXTERNAL 18 -#define DWARF_ABBREV_SUBPROGRAM_STATIC 19 -#define DWARF_ABBREV_LEXICAL_BLOCK 20 -#define DWARF_ABBREV_SUBROUTINE_TYPE 21 -#define DWARF_ABBREV_FORMAL_PARAMETER2 22 +#define DWARF_ABBREV_STRUCTURE_EMPTY_TYPE 17 +#define DWARF_ABBREV_UNION_TYPE 18 +#define DWARF_ABBREV_UNION_EMPTY_TYPE 19 +#define DWARF_ABBREV_SUBPROGRAM_EXTERNAL 20 +#define DWARF_ABBREV_SUBPROGRAM_STATIC 21 +#define DWARF_ABBREV_LEXICAL_BLOCK 22 +#define DWARF_ABBREV_LEXICAL_EMPTY_BLOCK 23 +#define DWARF_ABBREV_SUBROUTINE_TYPE 24 +#define DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE 25 +#define DWARF_ABBREV_FORMAL_PARAMETER2 26 /* all entries should have been generated with dwarf_uleb128 except has_children. All values are currently below 128 so this currently @@ -222,6 +226,12 @@ static const unsigned char dwarf_abbrev_init[] = { DW_AT_decl_line, DW_FORM_udata, DW_AT_sibling, DW_FORM_ref4, 0, 0, + DWARF_ABBREV_STRUCTURE_EMPTY_TYPE, DW_TAG_structure_type, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_byte_size, DW_FORM_udata, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + 0, 0, DWARF_ABBREV_UNION_TYPE, DW_TAG_union_type, 1, DW_AT_name, DW_FORM_strp, DW_AT_byte_size, DW_FORM_udata, @@ -229,6 +239,12 @@ static const unsigned char dwarf_abbrev_init[] = { DW_AT_decl_line, DW_FORM_udata, DW_AT_sibling, DW_FORM_ref4, 0, 0, + DWARF_ABBREV_UNION_EMPTY_TYPE, DW_TAG_union_type, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_byte_size, DW_FORM_udata, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + 0, 0, DWARF_ABBREV_SUBPROGRAM_EXTERNAL, DW_TAG_subprogram, 1, DW_AT_external, DW_FORM_flag, DW_AT_name, DW_FORM_strp, @@ -264,12 +280,23 @@ static const unsigned char dwarf_abbrev_init[] = { DW_AT_high_pc, DW_FORM_data4, #else DW_AT_high_pc, DW_FORM_data8, +#endif + 0, 0, + DWARF_ABBREV_LEXICAL_EMPTY_BLOCK, DW_TAG_lexical_block, 0, + DW_AT_low_pc, DW_FORM_addr, +#if PTR_SIZE == 4 + DW_AT_high_pc, DW_FORM_data4, +#else + DW_AT_high_pc, DW_FORM_data8, #endif 0, 0, DWARF_ABBREV_SUBROUTINE_TYPE, DW_TAG_subroutine_type, 1, DW_AT_type, DW_FORM_ref4, DW_AT_sibling, DW_FORM_ref4, 0, 0, + DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE, DW_TAG_subroutine_type, 0, + DW_AT_type, DW_FORM_ref4, + 0, 0, DWARF_ABBREV_FORMAL_PARAMETER2, DW_TAG_formal_parameter, 0, DW_AT_type, DW_FORM_ref4, 0, 0, @@ -546,7 +573,7 @@ static void dwarf_file(TCCState *s1) filename = strrchr(file->filename, '/'); if (filename == NULL) { - for (i = 0; i < dwarf_line.filename_size; i++) + for (i = 1; 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) { @@ -789,11 +816,9 @@ ST_FUNC void tcc_debug_start(TCCState *s1) tcc_malloc(2*sizeof (struct dwarf_filename_struct)); dwarf_line.filename_table[0].dir_entry = 0; if (undo) { - dwarf_line.filename_table[0].name = tcc_strdup(filename); + dwarf_line.filename_table[0].name = tcc_strdup(undo + 1); 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); @@ -849,17 +874,14 @@ ST_FUNC void tcc_debug_end(TCCState *s1) int pos = dwarf_info_section->data_offset; dwarf_data1(dwarf_info_section, - IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_TYPE - : DWARF_ABBREV_STRUCTURE_TYPE); + IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_EMPTY_TYPE + : DWARF_ABBREV_STRUCTURE_EMPTY_TYPE); dwarf_strp(dwarf_info_section, (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); dwarf_uleb128(dwarf_info_section, 0); dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); dwarf_uleb128(dwarf_info_section, file->line_num); - j = dwarf_info_section->data_offset + 5 - dwarf_info.start; - dwarf_data4(dwarf_info_section, j); - dwarf_data1(dwarf_info_section, 0); for (j = 0; j < debug_anon_hash[i].n_debug_type; j++) write32le(dwarf_info_section->data + debug_anon_hash[i].debug_type[j], @@ -1032,7 +1054,7 @@ ST_FUNC void tcc_debug_bincl(TCCState *s1) *undo = '/'; } if (strcmp(filename, "")) { - for (j = 0; j < dwarf_line.filename_size; j++) + for (j = 1; j < dwarf_line.filename_size; j++) if (dwarf_line.filename_table[j].dir_entry == i && strcmp (dwarf_line.filename_table[j].name, filename) == 0) break; @@ -1417,7 +1439,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) t = t->type.ref; debug_type = tcc_debug_find(s1, t, 1); if (debug_type == -1) { - int pos_sib, i, *pos_type; + int pos_sib = 0, i, *pos_type; debug_type = tcc_debug_add(s1, t, 1); e = t; @@ -1428,16 +1450,21 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) } pos_type = (int *) tcc_malloc(i * sizeof(int)); dwarf_data1(dwarf_info_section, - IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_TYPE - : DWARF_ABBREV_STRUCTURE_TYPE); + IS_UNION (t->type.t) + ? t->next ? DWARF_ABBREV_UNION_TYPE + : DWARF_ABBREV_UNION_EMPTY_TYPE + : t->next ? DWARF_ABBREV_STRUCTURE_TYPE + : DWARF_ABBREV_STRUCTURE_EMPTY_TYPE); dwarf_strp(dwarf_info_section, (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); dwarf_uleb128(dwarf_info_section, t->c); dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); dwarf_uleb128(dwarf_info_section, file->line_num); - pos_sib = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); + if (t->next) { + pos_sib = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + } e = t; i = 0; while (e->next) { @@ -1462,9 +1489,11 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) else dwarf_uleb128(dwarf_info_section, e->c); } - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + pos_sib, - dwarf_info_section->data_offset - dwarf_info.start); + if (t->next) { + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + pos_sib, + dwarf_info_section->data_offset - dwarf_info.start); + } e = t; i = 0; while (e->next) { @@ -1602,14 +1631,16 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) dwarf_info_section->data_offset - dwarf_info.start); } else if (type == VT_FUNC) { - int sib_pos, *pos_type; + int sib_pos = 0, *pos_type; Sym *f; i = dwarf_info_section->data_offset; debug_type = tcc_get_dwarf_info(s1, t->type.ref); if (retval == debug_type) retval = i; - dwarf_data1(dwarf_info_section, DWARF_ABBREV_SUBROUTINE_TYPE); + dwarf_data1(dwarf_info_section, + t->type.ref->next ? DWARF_ABBREV_SUBROUTINE_TYPE + : DWARF_ABBREV_SUBROUTINE_EMPTY_TYPE); if (last_pos != -1) { tcc_debug_check_anon(s1, e, last_pos); write32le(dwarf_info_section->data + last_pos, @@ -1618,8 +1649,10 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) last_pos = dwarf_info_section->data_offset; e = t->type.ref; dwarf_data4(dwarf_info_section, 0); - sib_pos = dwarf_info_section->data_offset; - dwarf_data4(dwarf_info_section, 0); + if (t->type.ref->next) { + sib_pos = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + } f = t->type.ref; i = 0; while (f->next) { @@ -1635,9 +1668,11 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s) pos_type[i++] = dwarf_info_section->data_offset; dwarf_data4(dwarf_info_section, 0); } - dwarf_data1(dwarf_info_section, 0); - write32le(dwarf_info_section->data + sib_pos, - dwarf_info_section->data_offset - dwarf_info.start); + if (t->type.ref->next) { + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + sib_pos, + dwarf_info_section->data_offset - dwarf_info.start); + } f = t->type.ref; i = 0; while (f->next) { @@ -1710,7 +1745,9 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur) tcc_free (s->str); } tcc_free (cur->sym); - dwarf_data1(dwarf_info_section, DWARF_ABBREV_LEXICAL_BLOCK); + dwarf_data1(dwarf_info_section, + cur->child ? DWARF_ABBREV_LEXICAL_BLOCK + : DWARF_ABBREV_LEXICAL_EMPTY_BLOCK); dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); #if PTR_SIZE == 4 dwarf_data4(dwarf_info_section, func_ind + cur->start); @@ -1720,7 +1757,8 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur) dwarf_data8(dwarf_info_section, cur->end - cur->start); #endif tcc_debug_finish (s1, cur->child); - dwarf_data1(dwarf_info_section, 0); + if (cur->child) + dwarf_data1(dwarf_info_section, 0); } else { diff --git a/tccmacho.c b/tccmacho.c index 6527ec22..b122204d 100644 --- a/tccmacho.c +++ b/tccmacho.c @@ -228,6 +228,8 @@ struct dyld_chained_ptr_64_bind #define S_ATTR_PURE_INSTRUCTIONS 0x80000000 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 +#define S_ATTR_DEBUG 0x02000000 + typedef uint32_t lc_str; @@ -372,18 +374,18 @@ enum skind { sk_ro_data, sk_uw_info, sk_nl_ptr, // non-lazy pointers, aka GOT - sk_la_ptr, // lazy pointers - sk_init, - sk_fini, - sk_rw_data, - sk_stab, - sk_stab_str, sk_debug_info, sk_debug_abbrev, sk_debug_line, sk_debug_aranges, sk_debug_str, sk_debug_line_str, + sk_stab, + sk_stab_str, + sk_la_ptr, // lazy pointers + sk_init, + sk_fini, + sk_rw_data, sk_bss, sk_linkedit, sk_last @@ -407,7 +409,7 @@ struct nlist_64 { struct macho { struct mach_header_64 mh; - int seg2lc[5], nseg; + int seg2lc[6], nseg; struct load_command **lc; struct entry_point_command *ep; int nlc; @@ -1202,20 +1204,20 @@ const struct { /*[sk_ro_data] =*/ { 2, S_REGULAR, "__rodata" }, /*[sk_uw_info] =*/ { 0 }, /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, - /*[sk_la_ptr] =*/ { 3, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" }, - /*[sk_init] =*/ { 3, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, - /*[sk_fini] =*/ { 3, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, - /*[sk_rw_data] =*/ { 3, S_REGULAR, "__data" }, - /*[sk_stab] =*/ { 3, S_REGULAR, "__stab" }, - /*[sk_stab_str] =*/ { 3, S_REGULAR, "__stab_str" }, - /*[sk_debug_info] =*/ { 3, S_REGULAR, "__debug_info" }, - /*[sk_debug_abbrev] =*/ { 3, S_REGULAR, "__debug_abbrev" }, - /*[sk_debug_line] =*/ { 3, S_REGULAR, "__debug_line" }, - /*[sk_debug_aranges] =*/ { 3, S_REGULAR, "__debug_aranges" }, - /*[sk_debug_str] =*/ { 3, S_REGULAR, "__debug_str" }, - /*[sk_debug_line_str] =*/ { 3, S_REGULAR, "__debug_line_str" }, - /*[sk_bss] =*/ { 3, S_ZEROFILL, "__bss" }, - /*[sk_linkedit] =*/ { 4, S_REGULAR, NULL }, + /*[sk_debug_info] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_info" }, + /*[sk_debug_abbrev] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_abbrev" }, + /*[sk_debug_line] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line" }, + /*[sk_debug_aranges] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_aranges" }, + /*[sk_debug_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_str" }, + /*[sk_debug_line_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line_str" }, + /*[sk_stab] =*/ { 4, S_REGULAR, "__stab" }, + /*[sk_stab_str] =*/ { 4, S_REGULAR, "__stab_str" }, + /*[sk_la_ptr] =*/ { 4, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" }, + /*[sk_init] =*/ { 4, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, + /*[sk_fini] =*/ { 4, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, + /*[sk_rw_data] =*/ { 4, S_REGULAR, "__data" }, + /*[sk_bss] =*/ { 4, S_ZEROFILL, "__bss" }, + /*[sk_linkedit] =*/ { 5, S_REGULAR, NULL }, }; #ifdef CONFIG_NEW_MACHO @@ -1285,7 +1287,7 @@ static void bind_rebase(TCCState *s1, struct macho *mo) *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; - strcpy(ptr, name); + strcpy((char *)ptr, name); ptr += strlen(name) + 1; *ptr++ = BIND_OPCODE_DO_BIND; *ptr = BIND_OPCODE_DONE; @@ -1316,7 +1318,7 @@ static void bind_rebase(TCCState *s1, struct macho *mo) *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; - strcpy(ptr, name); + strcpy((char *)ptr, name); ptr += strlen(name) + 1; *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; set_segment_and_offset(mo, s->sh_addr, ptr, @@ -1582,6 +1584,11 @@ static void collect_sections(TCCState *s1, struct macho *mo) seg->initprot = 3; // rw- seg->flags = SG_READ_ONLY; + seg = add_segment(mo, "__DWARF"); + seg->vmaddr = -1; + seg->maxprot = 7; // rwx + seg->initprot = 3; // rw- + seg = add_segment(mo, "__DATA"); seg->vmaddr = -1; seg->maxprot = 3; // rw- @@ -1592,6 +1599,10 @@ static void collect_sections(TCCState *s1, struct macho *mo) seg->maxprot = 1; // r-- seg->initprot = 1; // r-- + /* trick to avoid __DWARF vmaddr = -1 */ + if (dwarf_info_section == NULL) + dwarf_info_section = new_section(s1, ".debug_info", SHT_PROGBITS, 0); + #ifdef CONFIG_NEW_MACHO chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS, sizeof(struct linkedit_data_command)); @@ -1638,7 +1649,8 @@ static void collect_sections(TCCState *s1, struct macho *mo) type = s->sh_type; flags = s->sh_flags; sk = sk_unknown; - if (flags & SHF_ALLOC) { + /* debug sections have sometimes no SHF_ALLOC */ + if ((flags & SHF_ALLOC) || !strncmp(s->name, ".debug_", 7)) { switch (type) { default: sk = sk_unknown; break; case SHT_INIT_ARRAY: sk = sk_init; break;