diff --git a/.gitignore b/.gitignore index e517e41d8129ad5ba99d374dc6c11ab7013c1eb8..452f7d2d99d50bef9448f2e4c216db88a427c4df 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,14 @@ vendor Cargo.lock *.rto +# readelf/objdump +*.asm +*.elf +*.w +*.wi +*.s +*.x + # vscode .vscode/* !.vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d9794492565ab223c197b86d43b250103cc07fcc..07eb98958d679f8ad09a9f8e451de2430915f94b 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -22,6 +22,7 @@ { "name": "elfmerge", "includePath": [ + "/usr/src/debug/libdwarf-0.7.0-1.oe2309.aarch64/src/lib/libdwarf/", ], "defines": [], }, diff --git a/src/elfmerge/elf_link_common.c b/src/elfmerge/elf_link_common.c index c6b9373a4f118d4664fa62276dde9ca0609781b3..d6bccb5f4e344154d5440f9722781464464f9cee 100644 --- a/src/elfmerge/elf_link_common.c +++ b/src/elfmerge/elf_link_common.c @@ -703,15 +703,45 @@ unsigned long get_new_addr_by_old_addr_ok(elf_link_t *elf_link, elf_file_t *src_ return 0; } +static unsigned long _get_new_elf_offset(elf_link_t *elf_link, elf_file_t *src_ef, + unsigned long offset) +{ + int len = elf_link->sec_mapping_arr->len; + elf_sec_mapping_t *sec_rels = elf_link->sec_mapping_arr->data; + elf_sec_mapping_t *sec_rel = NULL; + bool found = false; + + for (int i = 0; i < len; i++) { + sec_rel = &sec_rels[i]; + if (sec_rel->src_ef != src_ef) { + continue; + } + // .bss overlaps with areas behind + if (sec_rel->src_sec->sh_type == SHT_NOBITS) { + continue; + } + if (offset < sec_rel->src_sec->sh_offset || + offset >= sec_rel->src_sec->sh_offset + sec_rel->src_sec->sh_size) { + continue; + } + found = true; + break; + } + + if (!found) + return NOT_FOUND; + return offset - sec_rel->src_sec->sh_offset + sec_rel->dst_file_offset; +} + unsigned long get_new_offset_by_old_offset(elf_link_t *elf_link, elf_file_t *src_ef, unsigned long offset) { // addr != offset after .rodata segment, .tdata is not eq Elf64_Phdr *p = src_ef->data_Phdr; - if (offset >= p->p_offset) { - si_panic("error: %s offset %lx\n", src_ef->file_name, offset); + if (offset < p->p_offset) { + return get_new_addr_by_old_addr(elf_link, src_ef, offset); } - return get_new_addr_by_old_addr(elf_link, src_ef, offset); + return _get_new_elf_offset(elf_link, src_ef, offset); } static unsigned long get_ifunc_new_addr(elf_link_t *elf_link, elf_file_t *ef, Elf64_Sym *sym, const char *sym_name); diff --git a/src/elfmerge/elf_link_elf.c b/src/elfmerge/elf_link_elf.c index a39fa1253bf4028fc58b9f44e34e07da49b87e21..778f55e1e44de85503bc3f11f587c6077fadeb95 100644 --- a/src/elfmerge/elf_link_elf.c +++ b/src/elfmerge/elf_link_elf.c @@ -1316,6 +1316,11 @@ static void modify_elf_header(elf_link_t *elf_link) #include #include +#include +#include +#include +#include +#include struct dwarf_unit_header { @@ -1355,7 +1360,7 @@ void modify_debug_info_abbrev_offset(elf_link_t *elf_link) { elf_file_t *ef; uint32_t da_offset = 0; - void *di_base = elf_find_section_ptr_by_name(&elf_link->out_ef, ".debug_info"); + void *di_base = elf_find_section_ptr_by_name(get_out_ef(elf_link), ".debug_info"); uint32_t cu_offset = 0; foreach_infile(elf_link, ef) { @@ -1379,9 +1384,280 @@ void modify_debug_info_abbrev_offset(elf_link_t *elf_link) } } +Dwarf_Debug dwarf_init(const char *path) +{ + static char true_pathbuf[FILENAME_MAX]; + Dwarf_Debug dbg = 0; + int res; + + res = dwarf_init_path( + path, true_pathbuf, + FILENAME_MAX, DW_GROUPNUMBER_ANY, NULL, + NULL, &dbg, NULL + ); + + if (res != DW_DLV_OK) + return NULL; + + return dbg; +} + +int dwarf_get_first_die_of_next_cu(Dwarf_Debug dbg, Dwarf_Die* first_die) +{ + int ret; + // Dwarf_Error error; + ret = dwarf_next_cu_header_d(dbg, true, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + /* no next cu */ + if (ret == DW_DLV_NO_ENTRY) + return ret; + + if (ret != DW_DLV_OK) { + si_panic("dwarf_next_cu_header_d ERROR, ret: %d\n", ret); + return ret; + } + // else printf("OK\n"); + + ret = dwarf_siblingof_b(dbg, NULL, true, first_die, NULL); + /* + * if there is no entry, dwarf_siblingof_b will return DW_DLV_NO_ENTRY, + * but now we just ignore this condition for quick dev. + */ + if (ret != DW_DLV_OK) { + si_panic("dwarf_siblingof_b ERROR %d\n", ret); + return ret; + } + return ret; +} + +struct dwarf_bias_info { + uint64_t text; + uint64_t debug_str; + uint64_t debug_line_str; +}; + +int dwarf_modify_di_abbrev(Dwarf_Die die, void *di_ptr, struct dwarf_bias_info *bias_info) +{ + Dwarf_Debug dbg = die->di_cu_context->cc_dbg; + Dwarf_Byte_Ptr die_info_end = + _dwarf_calculate_info_section_end_ptr(die->di_cu_context); + void *abbrev_ptr = die->di_debug_ptr; + Dwarf_Error error; + + Dwarf_Unsigned unused = 0; + Dwarf_Unsigned len; + int ret = dwarf_decode_leb128( + abbrev_ptr, &len, &unused, (char *)die_info_end + ); + if (ret != DW_DLV_OK) + return ret; + abbrev_ptr += len; + void *di_base = dbg->de_debug_info.dss_data; + + for (Dwarf_Unsigned i = 0; i < die->di_abbrev_list->abl_abbrev_count; i++) { + Dwarf_Unsigned attr_form = die->di_abbrev_list->abl_form[i]; + Dwarf_Unsigned sov = 0; + int ret; + + /* todo test if this is needed */ + if (attr_form == DW_FORM_implicit_const) { + continue; + } + + ret = _dwarf_get_size_of_val( + dbg, attr_form, + die->di_cu_context->cc_version_stamp, + die->di_cu_context->cc_address_size, + abbrev_ptr, + die->di_cu_context->cc_length_size, + &sov, + die_info_end, + &error + ); + if (ret != DW_DLV_OK) + si_panic("_dwarf_get_size_of_val fail, ret: %d\n", ret); + + uint32_t *dst_ptr = di_ptr + (abbrev_ptr - di_base); + switch (die->di_abbrev_list->abl_form[i]) { + case DW_FORM_addr: + *dst_ptr += bias_info->text; + break; + case DW_FORM_line_strp: + *dst_ptr += bias_info->debug_line_str; + break; + case DW_FORM_strp: + *dst_ptr += bias_info->debug_str; + // printf("offset: %lx, *abbrev_ptr: %x *dst_ptr: %x\n", + // (abbrev_ptr - di_base), + // *(uint32_t *)abbrev_ptr, *dst_ptr); + break; + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + /* no need to modify */ + break; + case DW_FORM_block2: + case DW_FORM_string: + case DW_FORM_sdata: + case DW_FORM_ref4: + case DW_FORM_implicit_const: + case DW_FORM_exprloc: + case DW_FORM_flag_present: + case DW_FORM_sec_offset: + /* TODO */ + break; + case DW_FORM_block4: + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_flag: + case DW_FORM_udata: + case DW_FORM_ref_addr: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + case DW_FORM_indirect: + case DW_FORM_strx: + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + case DW_FORM_ref_sup4: + case DW_FORM_strp_sup: + case DW_FORM_data16: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_ref_sup8: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + case DW_FORM_ref_sig8: + /* not present in bash */ + si_panic("unsupported die FORM 0x%x\n", + die->di_abbrev_list->abl_form[i]); + break; + default: + si_panic("unknown die FORM 0x%x\n", + die->di_abbrev_list->abl_form[i]); + break; + } + abbrev_ptr += sov; + } + + return DW_DLV_OK; +} + +int dwarf_traverse_die(Dwarf_Debug dbg, Dwarf_Die parent_die, + void *di_ptr, struct dwarf_bias_info *bias_info) +{ + Dwarf_Die son_die; + int res; + + dwarf_modify_di_abbrev(parent_die, di_ptr, bias_info); + + res = dwarf_child(parent_die, &son_die, NULL); + while (res == DW_DLV_OK) { + dwarf_traverse_die(dbg, son_die, di_ptr, bias_info); + res = dwarf_siblingof_b(dbg, son_die, true, &son_die, NULL); + } + if (res == DW_DLV_NO_ENTRY) { + // no more child + return DW_DLV_OK; + } else { + printf("dwarf_child or dwarf_siblingof_b ERROR\n"); + return res; + } +} + +void dwarf_traverse_cu(Dwarf_Debug dbg, void *di_ptr, struct dwarf_bias_info *bias_info) +{ + int res = 0; + + Dwarf_Die first_die; + for (;;) { + res = dwarf_get_first_die_of_next_cu(dbg, &first_die); + if (res == DW_DLV_NO_ENTRY) { + /* no entry */ + break; + } + dwarf_traverse_die(dbg, first_die, di_ptr, bias_info); + } +} + +/* delete it later */ +char *temp_get_file_name(char *name) +{ + char *result = malloc(strlen(name)); + memset(result, 0, strlen(name)); + memcpy(result, name, strlen(name) - 11); + return result; +} + +void prep_bias_info(elf_link_t *elf_link, elf_file_t *ef, struct dwarf_bias_info *bias_info) +{ + /* .text starts from .init */ + unsigned long text_base_addr = + elf_find_section_by_name(ef, ".init")->sh_addr; + unsigned long ds_base_offset = + elf_find_section_by_name(get_out_ef(elf_link), ".debug_str")->sh_offset; + unsigned long dls_base_offset = + elf_find_section_by_name(get_out_ef(elf_link), ".debug_line_str")->sh_offset; + + Elf64_Shdr *text_sec = elf_find_section_by_name(ef, ".init"); + unsigned long text_addr = get_new_addr_by_old_addr( + elf_link, ef, text_sec->sh_addr + ); + Elf64_Shdr *ds_sec = elf_find_section_by_name(ef, ".debug_str"); + unsigned long ds_offset = get_new_offset_by_old_offset( + elf_link, ef, ds_sec->sh_offset + ); + Elf64_Shdr *dls_sec = elf_find_section_by_name(ef, ".debug_line_str"); + unsigned long dls_offset = get_new_offset_by_old_offset( + elf_link, ef, dls_sec->sh_offset + ); + + bias_info->text = text_addr - text_base_addr; + bias_info->debug_str = ds_offset - ds_base_offset; + bias_info->debug_line_str = dls_offset - dls_base_offset; + SI_LOG_DEBUG("%s, text: %lx, debug_str: %lx, debug_line_str: %lx\n", + ef->file_name, + bias_info->text, bias_info->debug_str, bias_info->debug_line_str); + SI_LOG_DEBUG("text_addr: %lx, out_text_base_addr: %lx\n", + text_addr, text_base_addr); +} + +int modify_debug_info(elf_link_t *elf_link) +{ + elf_file_t *ef; + char *temp_path; + struct dwarf_bias_info bias_info; + + foreach_infile(elf_link, ef) { + Elf64_Shdr *di_sec = elf_find_section_by_name(ef, ".debug_info"); + unsigned long dst_offset = get_new_offset_by_old_offset( + elf_link, ef, di_sec->sh_offset + ); + void *di_ptr = get_out_ef(elf_link)->data + dst_offset; + prep_bias_info(elf_link, ef, &bias_info); + + temp_path = temp_get_file_name(ef->file_name); + Dwarf_Debug dbg = dwarf_init(temp_path); + if (!dbg) + si_panic("dwarf_init fail, file: %s\n", temp_path); + dwarf_traverse_cu(dbg, di_ptr, &bias_info); + dwarf_finish(dbg); + } + return 0; +} + static void modify_debug(elf_link_t *elf_link) { modify_debug_info_abbrev_offset(elf_link); + modify_debug_info(elf_link); } /* debug modify end */ diff --git a/src/elfmerge/meson.build b/src/elfmerge/meson.build index b11a41e0a4c175ac68f9cc3744304bd347fccf3f..d425113b4bf0c84b8823a39ab89646ce634a8937 100644 --- a/src/elfmerge/meson.build +++ b/src/elfmerge/meson.build @@ -18,6 +18,8 @@ core_sources = files( cflags += ['-fpic', '-pie'] +default_ldflags += ['/usr/lib64/libdwarf.a'] + includes += '/usr/src/debug/libdwarf-0.7.0-1.oe2309.aarch64/src/lib/libdwarf/' includes += '/usr/include/libdwarf-0/'