diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 4a7ccc32..95850e58 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -343,7 +343,7 @@ dw_string_list_from_cfi_program(Arena *arena, DW_Ext ext, DW_Format format, U64 pc_begin, - DW_CIE *cie, + DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program) @@ -494,6 +494,64 @@ exit:; return list; } +internal String8 +dw_string_from_cfa(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa) +{ + String8 cfa_str = str8_lit("???"); + switch (cfa.rule) { + case DW_CFA_Rule_Null: {} break; + case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(arena, arch, cfa.reg, cfa.off); } break; + case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(arena, cfa.expr, max_U64, address_size, arch, version, ext, format); } break; + default: { InvalidPath; } break; + } + return cfa_str; +} + +internal String8 +dw_string_from_cfi_row(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List cfi_regs_list = {0}; + U64 reg_count = dw_reg_count_from_arch(arch); + for EachIndex(reg_idx, reg_count) { + DW_CFI_Register *cfi_reg = &row->regs[reg_idx]; + String8 rule_str = str8_lit("???"); + switch (cfi_reg->rule) { + case DW_CFI_RegisterRule_Undefined: { + rule_str = str8f(scratch.arena, "Undefined(%S)", dw_string_from_reg(scratch.arena, arch, cfi_reg->n)); + } break; + case DW_CFI_RegisterRule_SameValue: { + rule_str = str8_zero(); + } break; + case DW_CFI_RegisterRule_Offset: { + rule_str = str8f(scratch.arena, "[CFA%+I64d]", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_ValOffset: { + rule_str = str8f(scratch.arena, "Val(CFA%+I64d)", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_Expression: { + rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); + } break; + case DW_CFI_RegisterRule_ValExpression: { + rule_str = str8f(scratch.arena, "ValExpression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); + } break; + case DW_CFI_RegisterRule_Architectural: { + rule_str = str8_lit("???"); + } break; + default: { InvalidPath; } break; + } + + if (rule_str.size) { + str8_list_pushf(scratch.arena, &cfi_regs_list, "%S: %S", dw_string_from_reg(scratch.arena, arch, reg_idx), rule_str); + } + } + + String8 string = str8_list_join(arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")}); + + scratch_end(scratch); + return string; +} + internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { @@ -1674,12 +1732,6 @@ dw_string_from_attrib_value(Arena *arena, DW_Input *input, Arch arch, DW_CompUni return result; } -internal -DW_CIE_FROM_OFFSET_FUNC(dwarf_dump_cie_from_offset) -{ - return hash_table_search_u64_raw(ud, offset); -} - internal String8List dw_dump_list_from_sections(Arena *arena, DW_Input *input, @@ -1712,7 +1764,8 @@ dw_dump_list_from_sections(Arena *arena, //- rjf: dump .debug_info // DumpSubset(DebugInfo) - { Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); + { + Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list); for EachIndex(unit_idx, unit_ranges.count) { @@ -2181,12 +2234,12 @@ dw_dump_list_from_sections(Arena *arena, dumpf("CIE: // entry range: %r\n", desc.entry_range); dumpf("{\n"); - dumpf(" Format: %S\n", dw_string_from_format(desc.format)); - dumpf(" Version: %u\n", cie.version); - dumpf(" Aug string: %S\n", cie.aug_string.size ? cie.aug_string : str8_lit("None")); - dumpf(" Code align: %I64u\n", cie.code_align_factor); - dumpf(" Data align: %I64d\n", cie.data_align_factor); - dumpf(" Return addr reg: %u\n", cie.ret_addr_reg); + dumpf(" Format: %S\n", dw_string_from_format(desc.format)); + dumpf(" Version: %u\n", cie.version); + dumpf(" Aug string: \"%S\"\n", cie.aug_string); + dumpf(" Code align: %I64u\n", cie.code_align_factor); + dumpf(" Data align: %I64d\n", cie.data_align_factor); + dumpf(" Return addr reg: %u\n", cie.ret_addr_reg); if (cie.version > DW_Version_3) { dumpf(" Address size: %u\n", cie.address_size); dumpf(" Segment selector size: %u\n", cie.segment_selector_size); @@ -2201,15 +2254,18 @@ dw_dump_list_from_sections(Arena *arena, } } break; case DW_DescriptorEntryType_FDE: { + DW_DescriptorEntry cie_desc = {0}; + U64 cie_desc_size = dw_parse_descriptor_entry_header(debug_frame, desc.cie_pointer, &cie_desc); + String8 cie_data = str8_substr(debug_frame, cie_desc.entry_range); + DW_CIE cie = {0}; + dw_parse_cie(cie_data, cie_desc.format, arch, &cie); + DW_FDE fde = {0}; - if (dw_parse_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) { - DW_Version version = DW_Version_5; - DW_Ext ext = DW_Ext_All; - - DW_CIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer); - String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, version, ext, fde.format, fde.pc_range.min, cie, dw_decode_ptr_debug_frame, cie, fde.insts); - - dumpf("FDE: // entry range: %r\n", desc.entry_range, dw_string_from_format(fde.format), fde.cie_pointer, fde.pc_range); + if (dw_parse_fde(raw_desc, desc.format, &cie, &fde)) { + DW_Version version = DW_Version_5; + DW_Ext ext = DW_Ext_All; + String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, version, ext, fde.format, fde.pc_range.min, &cie, dw_decode_ptr_debug_frame, &cie, fde.insts); + dumpf("FDE: // entry range: %r\n", desc.entry_range); dumpf("{\n"); { dumpf(" Format: %S\n", dw_string_from_format(fde.format)); @@ -2220,60 +2276,12 @@ dw_dump_list_from_sections(Arena *arena, for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); } dumpf(" }\n"); } - dumpf(" Unwind:\n"); dumpf(" {\n"); - DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, cie, &fde, dw_decode_ptr_debug_frame, cie); + DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, dw_decode_ptr_debug_frame, &cie); do { - String8 cfa_str = str8_lit("???"); - DW_CFA cfa = cfi_unwind->row->cfa; - switch (cfa.rule) { - case DW_CFA_Rule_Null: {} break; - case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(scratch.arena, arch, cfa.reg, cfa.off); } break; - case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(scratch.arena, cfa.expr, max_U64, cie->address_size, arch, version, ext, fde.format); } break; - default: { InvalidPath; } break; - } - - String8 cfi_regs_str = {0}; - { - String8List cfi_regs_list = {0}; - U64 reg_count = dw_reg_count_from_arch(arch); - for EachIndex(reg_idx, reg_count) { - DW_CFI_Register *cfi_reg = &cfi_unwind->row->regs[reg_idx]; - String8 rule_str = str8_lit("???"); - switch (cfi_reg->rule) { - case DW_CFI_RegisterRule_Undefined: { - rule_str = str8f(scratch.arena, "Undefined(%S)", dw_string_from_reg(scratch.arena, arch, cfi_reg->n)); - } break; - case DW_CFI_RegisterRule_SameValue: { - rule_str = str8_zero(); - } break; - case DW_CFI_RegisterRule_Offset: { - rule_str = str8f(scratch.arena, "[CFA%+I64d]", cfi_reg->n); - } break; - case DW_CFI_RegisterRule_ValOffset: { - rule_str = str8f(scratch.arena, "Val(CFA%+I64d)", cfi_reg->n); - } break; - case DW_CFI_RegisterRule_Expression: { - rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, cie->address_size, arch, version, ext, fde.format)); - } break; - case DW_CFI_RegisterRule_ValExpression: { - rule_str = str8f(scratch.arena, "ValExpression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, cie->address_size, arch, version, ext, fde.format)); - } break; - case DW_CFI_RegisterRule_Architectural: { - rule_str = str8_lit("???"); - } break; - default: { InvalidPath; } break; - } - - if (rule_str.size) { - str8_list_pushf(scratch.arena, &cfi_regs_list, "%S: %S", dw_string_from_reg(scratch.arena, arch, reg_idx), rule_str); - } - } - - cfi_regs_str = str8_list_join(scratch.arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")}); - } - + String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row->cfa); + String8 cfi_regs_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row); dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_regs_str); } while (dw_cfi_next_row(scratch.arena, cfi_unwind)); dumpf(" }\n"); diff --git a/src/dwarf/dwarf_dump.h b/src/dwarf/dwarf_dump.h index 4ff7c1c0..472bb7b7 100644 --- a/src/dwarf/dwarf_dump.h +++ b/src/dwarf/dwarf_dump.h @@ -59,12 +59,16 @@ read_only global String8 dw_name_title_from_dump_subset_table[] = //~ rjf: Stringification Helpers internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off); -internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); -internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal String8 dw_string_from_reg(Arena *arena, Arch arch, DW_Reg reg_idx); +internal String8List dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal String8 dw_string_from_expression(Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); + +internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program); + +internal String8 dw_string_from_cfa(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa); +internal String8 dw_string_from_cfi_row(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row); #if 0 -internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); - internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx); internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); diff --git a/src/dwarf/dwarf_help.c b/src/dwarf/dwarf_help.c index 547c171f..84ccf52c 100644 --- a/src/dwarf/dwarf_help.c +++ b/src/dwarf/dwarf_help.c @@ -1,12 +1,6 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal -DW_CIE_FROM_OFFSET_FUNC(dw_call_frame_info_cie_from_offset) -{ - return hash_table_search_u64_raw(ud, offset); -} - internal DW_CallFrameInfo dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_frame) { @@ -49,7 +43,8 @@ dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_ desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc); if (desc_size == 0) { break; } if (desc.type == DW_DescriptorEntryType_FDE) { - if (dw_parse_fde(str8_skip(debug_frame, cursor), desc.format, dw_call_frame_info_cie_from_offset, cie_ht, &fde[parse_fde_count])) { + DW_CIE *cie = hash_table_search_u64_raw(cie_ht, desc.cie_pointer); + if (dw_parse_fde(str8_skip(debug_frame, cursor), desc.format, cie, &fde[parse_fde_count])) { fde[parse_fde_count].pc_range.min += rebase; fde[parse_fde_count].pc_range.max += rebase; parse_fde_count += 1; diff --git a/src/dwarf/dwarf_inc.c b/src/dwarf/dwarf_inc.c index b4ab74b0..df0cc700 100644 --- a/src/dwarf/dwarf_inc.c +++ b/src/dwarf/dwarf_inc.c @@ -9,3 +9,5 @@ #include "dwarf/dwarf_unwind.c" #include "dwarf/dwarf_dump.c" #include "dwarf/dwarf_help.c" +#include "dwarf/eh_frame.c" +#include "dwarf/eh_dump.c" diff --git a/src/dwarf/dwarf_inc.h b/src/dwarf/dwarf_inc.h index 26c24302..44783a34 100644 --- a/src/dwarf/dwarf_inc.h +++ b/src/dwarf/dwarf_inc.h @@ -12,5 +12,7 @@ #include "dwarf/dwarf_unwind.h" #include "dwarf/dwarf_dump.h" #include "dwarf/dwarf_help.h" +#include "dwarf/eh_frame.h" +#include "dwarf/eh_dump.h" #endif // DWARF_INC_H diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 0998b75f..d65f304f 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -3369,9 +3369,11 @@ dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc if (id_size == 0) { goto exit; } U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64; - desc_out->format = format; - desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE; - desc_out->entry_range = entry_range; + desc_out->format = format; + desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE; + desc_out->entry_range = entry_range; + desc_out->cie_pointer = id; + desc_out->cie_pointer_off = length_size; exit:; return length + length_size; @@ -3447,11 +3449,7 @@ exit:; } internal B32 -dw_parse_fde(String8 data, - DW_Format format, - DW_CIEFromOffsetFunc *cie_from_offset_func, - void *cie_from_offset_ud, - DW_FDE *fde_out) +dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out) { B32 is_parsed = 0; U64 cursor = format == DW_Format_32Bit ? 4 : 12; @@ -3462,10 +3460,6 @@ dw_parse_fde(String8 data, if (cie_pointer_size == 0) { goto exit; } cursor += cie_pointer_size; - // map offset -> CIE - DW_CIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer); - if (cie == 0) { goto exit; } - // extract address of first instruction U64 pc_begin = 0; U64 pc_begin_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin); @@ -3485,7 +3479,6 @@ dw_parse_fde(String8 data, // commit values to out fde_out->format = format; fde_out->cie_pointer = cie_pointer; - fde_out->cie = cie; fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range); fde_out->insts = str8_skip(data, cursor); @@ -3494,12 +3487,6 @@ exit:; return is_parsed; } -internal -DW_CIE_FROM_OFFSET_FUNC(dw_parse_cfi_cie_from_offset) -{ - return ud; -} - internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out) { @@ -3515,7 +3502,7 @@ dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *f dw_parse_descriptor_entry_header(data, cie_pointer, &cie_desc); if (cie_desc.type == DW_DescriptorEntryType_CIE) { if (dw_parse_cie(str8_substr(data, cie_desc.entry_range), cie_desc.format, arch, cie_out)) { - if (dw_parse_fde(str8_substr(data, fde_desc.entry_range), fde_desc.format, dw_parse_cfi_cie_from_offset, cie_out, fde_out)) { + if (dw_parse_fde(str8_substr(data, fde_desc.entry_range), fde_desc.format, cie_out, fde_out)) { is_parsed = 1; } } diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index fc8ce759..e6bd6cc6 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -368,6 +368,8 @@ typedef struct DW_DescriptorEntry DW_DescriptorEntryType type; DW_Format format; Rng1U64 entry_range; + U64 cie_pointer_off; + U64 cie_pointer; } DW_DescriptorEntry; typedef struct DW_CIE @@ -389,7 +391,6 @@ typedef struct DW_FDE { DW_Format format; U64 cie_pointer; - DW_CIE *cie; Rng1U64 pc_range; String8 insts; } DW_FDE; @@ -430,9 +431,6 @@ typedef struct DW_CFA_InstList #define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out) typedef DW_DECODE_PTR(DW_DecodePtr); -#define DW_CIE_FROM_OFFSET_FUNC(name) DW_CIE * name(void *ud, U64 offset) -typedef DW_CIE_FROM_OFFSET_FUNC(DW_CIEFromOffsetFunc); - // hasher internal U64 dw_hash_from_string(String8 string); @@ -559,7 +557,7 @@ internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out); internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out); -internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_FDE *fde_out); +internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out); internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out); internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out); diff --git a/src/eh/eh_frame.c b/src/eh/eh_frame.c deleted file mode 100644 index c89c0ee5..00000000 --- a/src/eh/eh_frame.c +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal U64 -eh_parse_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out) -{ - U64 ptr_off = off; - - if (encoding == EH_PtrEnc_Omit) { - return 0; - } - - // align read offset as needed - if (encoding == EH_PtrEnc_Aligned) { - ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align); - encoding = EH_PtrEnc_Ptr; - } - - // decode pointer value - U64 decode_size = 0; - U64 raw_ptr_size = 0; - U64 raw_ptr = 0; - switch (encoding & EH_PtrEnc_TypeMask) { - default: { InvalidPath; } break; - - case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed; - case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed; - case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed; - case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed; - ufixed: { - decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size); - } break; - - // TODO: Signed is actually just a flag that indicates this int is negavite. - // There shouldn't be a read for Signed. - // For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc. - case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed; - - case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed; - case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed; - case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed; - sfixed: { - decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size); - raw_ptr = extend_sign64(raw_ptr, raw_ptr_size); - } break; - - case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break; - case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break; - } - - // apply relative bases - if (decode_size > 0) { - U64 ptr = raw_ptr; - switch (encoding & EH_PtrEnc_ModifierMask) { - case EH_PtrEnc_PcRel: { ptr = ptr_ctx->raw_base_vaddr + off + raw_ptr; } break; - case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break; - case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break; - case EH_PtrEnc_FuncRel: { - Assert(!"TODO: need a sample to verify implementation"); - ptr = ptr_ctx->func_vaddr + raw_ptr; - } break; - } - - if (ptr_out) { - *ptr_out = raw_ptr; - } - } - - return decode_size; -} - -internal EH_FrameHdr -eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx) -{ - EH_FrameHdr header = {0}; - U64 cursor = 0; - - U64 version_size = str8_deserial_read_struct(data, cursor, &header.version); - if (version_size == 0) { goto exit; } - cursor += version_size; - - if (header.version == 1) { - U64 eh_frame_ptr_enc_size = str8_deserial_read_struct(data, cursor, &header.eh_frame_ptr_enc); - if (eh_frame_ptr_enc_size == 0) { goto exit; } - cursor += eh_frame_ptr_enc_size; - - EH_PtrEnc fde_count_enc = 0; - U64 fde_count_enc_size = str8_deserial_read_struct(data, cursor, &fde_count_enc); - if (fde_count_enc_size == 0) { goto exit; } - cursor += fde_count_enc_size; - - U64 table_enc_size = str8_deserial_read_struct(data, cursor, &header.table_enc); - if (table_enc_size == 0) { goto exit; } - cursor += table_enc_size; - - U64 eh_frame_ptr = 0; - cursor += eh_parse_ptr(data, cursor, ptr_ctx, header.eh_frame_ptr_enc, &eh_frame_ptr); - - cursor += eh_parse_ptr(data, cursor, ptr_ctx, header.fde_count_enc, &header.fde_count); - - switch (header.table_enc) { - case EH_PtrEnc_Ptr: { header.field_byte_size = address_size; } break; - case EH_PtrEnc_ULEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8 - case EH_PtrEnc_UData2: { header.field_byte_size = 2; } break; - case EH_PtrEnc_UData4: { header.field_byte_size = 4; } break; - case EH_PtrEnc_UData8: { header.field_byte_size = 8; } break; - case EH_PtrEnc_Signed: { header.field_byte_size = address_size; } break; - case EH_PtrEnc_SLEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8 - case EH_PtrEnc_SData2: { header.field_byte_size = 2; } break; - case EH_PtrEnc_SData4: { header.field_byte_size = 4; } break; - case EH_PtrEnc_SData8: { header.field_byte_size = 8; } break; - default: { InvalidPath; } break; - } - header.entry_byte_size = header.field_byte_size * 2; - - header.table = str8_skip(data, cursor); - AssertAlways(header.table.size == header.entry_byte_size * header.fde_count); - } else { - Assert(0 && "unknown version"); - } - -exit:; - return header; -} - -internal U64 -eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out) -{ - // TODO: - // Handle "eh" param, it indicates presence of EH Data field. - // On 32bit arch it is a 4-byte and on 64-bit 8-byte value. - // Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html - // Reference doc doesn't clarify structure for EH Data though - - U64 cursor = 0; - - EH_AugFlags aug_flags = 0; - EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit; - EH_PtrEnc addr_encoding = EH_PtrEnc_UData8; - EH_PtrEnc handler_encoding = EH_PtrEnc_Omit; - U64 handler_ip = 0; - if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) { - U64 aug_cursor = 0; - for (U8 *ptr = aug_string.str; ptr < (aug_string.str+aug_string.size); ptr += 1) { - switch (*ptr) { - case 'L': { - aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &lsda_encoding); - aug_flags |= EH_AugFlag_HasLSDA; - } break; - case 'P': { - aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &handler_encoding); - aug_cursor += eh_parse_ptr(aug_data, aug_cursor, ptr_ctx, handler_encoding, &handler_ip); - aug_flags |= EH_AugFlag_HasHandler; - } break; - case 'R': { - aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &addr_encoding); - aug_flags |= EH_AugFlag_HasAddrEnc; - } break; - default: { Assert(!"failed to parse augmentation string"); goto exit; } break; - } - } - } - - if (aug_out) { - aug_out->handler_ip = handler_ip; - aug_out->handler_encoding = handler_encoding; - aug_out->lsda_encoding = handler_encoding; - aug_out->addr_encoding = addr_encoding; - aug_out->flags = aug_flags; - } - -exit:; - U64 parse_size = cursor; - return parse_size; -} - -internal B32 -eh_parse_cie(String8 data, DW_Format format, Arch arch, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out) -{ - B32 is_parsed = 0; - U64 cursor = format == DW_Format_32Bit ? 4 : 12; - - U64 cie_id = 0; - U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id); - if (cie_id_size == 0) { goto exit; } - cursor += cie_id_size; - - U8 version = 0; - U64 version_size = str8_deserial_read_struct(data, cursor, &version); - if (version_size == 0) { goto exit; } - cursor += version_size; - - String8 aug_string = {0}; - EH_Augmentation aug = {0}; - U64 code_align_factor = 0; - S64 data_align_factor = 0; - U64 ret_addr_reg = max_U64; - if (version == 1) { - U64 aug_string_size = str8_deserial_read_cstr(data, cursor, &aug_string); - if (aug_string_size == 0) { goto exit; } - cursor += aug_string_size; - - U64 aug_data_size = eh_parse_aug_data(aug_string, str8_skip(data, cursor), ptr_ctx, &aug); - cursor += aug_data_size; - - U64 code_align_factor_size = str8_deserial_read_uleb128(data, cursor, &code_align_factor); - if (code_align_factor_size == 0) { goto exit; } - cursor += code_align_factor_size; - - U64 data_align_factor_size = str8_deserial_read_sleb128(data, cursor, &data_align_factor); - if (data_align_factor_size == 0) { goto exit; } - cursor += data_align_factor_size; - - ret_addr_reg = 0; - U64 ret_addr_reg_size = str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)); - if (ret_addr_reg_size == 0) { goto exit; } - cursor += ret_addr_reg_size; - } - - cie_out->insts = str8_skip(data, cursor); - cie_out->aug_string = aug_string; - cie_out->code_align_factor = code_align_factor; - cie_out->data_align_factor = data_align_factor; - cie_out->ret_addr_reg = ret_addr_reg; - cie_out->format = format; - cie_out->version = version; - cie_out->address_size = byte_size_from_arch(arch); - cie_out->segment_selector_size = 0; - - cie_out->ext[EH_CIE_Ext_LSDAEnc] = EH_PtrEnc_Omit; - cie_out->ext[EH_CIE_Ext_AddrEnc] = EH_PtrEnc_Omit; - cie_out->ext[EH_CIE_Ext_HandlerEnc] = EH_PtrEnc_Omit; - - if (aug.flags & EH_AugFlag_HasLSDA) { - cie_out->ext[EH_CIE_Ext_LSDAEnc] = aug.lsda_encoding; - } - if (aug.flags & EH_AugFlag_HasAddrEnc) { - cie_out->ext[EH_CIE_Ext_AddrEnc] = aug.addr_encoding; - } - if (aug.flags & EH_AugFlag_HasHandler) { - cie_out->ext[EH_CIE_Ext_HandlerEnc] = aug.handler_encoding; - cie_out->ext[EH_CIE_Ext_HandlerIp ] = aug.handler_ip; - } - - is_parsed = 1; -exit:; - return is_parsed; -} - -internal B32 -eh_parse_fde(String8 data, - DW_Format format, - DW_CIEFromOffsetFunc *cie_from_offset_func, - void *cie_from_offset_ud, - EH_PtrCtx *ptr_ctx, - DW_FDE *fde_out) -{ - B32 is_parsed = 0; - U64 cursor = format == DW_Format_32Bit ? 4 : 12; - - U64 cie_pointer = 0; - U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_pointer); - if (cie_pointer_size == 0) { goto exit; } - - DW_CIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer); - if (cie == 0) { goto exit; } - - EH_PtrEnc addr_enc = cie->ext[EH_CIE_Ext_AddrEnc]; - - U64 pc_begin = 0; - U64 pc_range = 0; - if (addr_enc != EH_PtrEnc_Omit) { - U64 pc_begin_size = eh_parse_ptr(data, cursor, ptr_ctx, addr_enc, &pc_begin); - if (pc_begin_size == 0) { goto exit; } - cursor += pc_begin_size; - - U64 pc_range_size = eh_parse_ptr(data, cursor, ptr_ctx, addr_enc, &pc_range_size); - if (pc_range_size == 0) { goto exit; } - cursor += pc_range_size; - } - - if (cursor + cie->aug_data.size > data.size) { goto exit; } - cursor += cie->aug_data.size; - - fde_out->format = format; - fde_out->cie_pointer = cie_pointer; - fde_out->cie = cie; - fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range); - fde_out->insts = str8_skip(data, cursor); - - is_parsed = 1; -exit:; - return is_parsed; -} - -internal -DW_CIE_FROM_OFFSET_FUNC(eh_parse_cfi_cie_from_offset) -{ - return ud; -} - -internal B32 -eh_parse_cfi(String8 eh_frame, U64 fde_offset, Arch arch, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out, DW_FDE *fde_out) -{ - B32 is_parsed = 0; - DW_DescriptorEntry fde_desc = {0}; - dw_parse_descriptor_entry_header(eh_frame, fde_offset, &fde_desc); - if (fde_desc.type == DW_DescriptorEntryType_FDE) { - U64 cie_pointer_off = fde_desc.format == DW_Format_32Bit ? 4 : 12; - U64 cie_pointer = 0; - U64 cie_pointer_size = str8_deserial_read_dwarf_uint(eh_frame, fde_offset + cie_pointer_off, fde_desc.format, &cie_pointer); - if (cie_pointer_size) { - DW_DescriptorEntry cie_desc = {0}; - dw_parse_descriptor_entry_header(eh_frame, cie_pointer, &cie_desc); - if (cie_desc.type == DW_DescriptorEntryType_CIE) { - if (eh_parse_cie(str8_substr(eh_frame, cie_desc.entry_range), cie_desc.format, arch, ptr_ctx, cie_out)) { - if (eh_parse_fde(str8_substr(eh_frame, fde_desc.entry_range), fde_desc.format, eh_parse_cfi_cie_from_offset, cie_out, ptr_ctx, fde_out)) { - return is_parsed; - } - } - } - } - } - return is_parsed; -} - -internal U64 -eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc) -{ - U64 fde_offset = max_U64; - U64 fde_idx = max_U64; - - if (header.version == 1) { - if (header.fde_count > 0) { - U64 first = 0; - U64 first_size = eh_parse_ptr(header.table, 0, ptr_ctx, header.table_enc, &first); - AssertAlways(first_size); - if (first == pc) { - fde_idx = 0; - goto exit; - } - if (first > pc) { - goto exit; - } - - U64 last = 0; - U64 last_size = eh_parse_ptr(header.table, header.table.size - header.entry_byte_size, ptr_ctx, header.table_enc, &last); - AssertAlways(last_size); - if (last <= pc) { - fde_idx = header.fde_count - 1; - goto exit; - } - - if (first <= pc && pc < last) { - U64 l = 0; - U64 r = header.fde_count - 1; - while (l <= r) { - U64 m = l + (r - l) / 2; - U64 m_pc = 0; - U64 m_pc_size = eh_parse_ptr(header.table, m * header.entry_byte_size, ptr_ctx, header.table_enc, &m_pc); - Assert(m_pc_size); - - if (m_pc == pc) { - fde_idx = m; - goto exit; - } else if (m_pc < pc) { - l = m + 1; - } else { - r = m - 1; - } - } - fde_idx = l; - } - } - - } - -exit:; - if (fde_idx < header.fde_count) { - U64 fde_offset_size = eh_parse_ptr(header.table, (fde_idx * header.entry_byte_size) + header.field_byte_size, ptr_ctx, header.table_enc, &fde_offset); - Assert(fde_offset_size); - } - return fde_offset; -} - -internal int -eh_frame_hdr_entry_sort(void *raw_a, void *raw_b) -{ - return ((EH_FrameHdrEntry *)raw_a)->addr < ((EH_FrameHdrEntry *)raw_b)->addr; -} - -internal String8 -eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, DW_FDE *fde) -{ - Temp scratch = scratch_begin(&arena, 1); - - // make .eh_frame_hdr - String8List srl = {0}; - str8_serial_begin(scratch.arena, &srl); - str8_serial_push_u8(scratch.arena, &srl, 1); // version - str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_Omit); // omit eh_frame_ptr field - str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // fde_count encoding - str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // table encoding - str8_serial_push_u64(scratch.arena, &srl, fde_count); // fde_count - String8 header = str8_serial_end(scratch.arena, &srl); - - // alloc buffer for output - U64 buffer_size = header.size + sizeof(EH_FrameHdrEntry) * fde_count; - U8 *buffer = push_array(arena, U8, buffer_size); - - // copy header - MemoryCopyStr8(buffer, header); - - // write the table - EH_FrameHdrEntry *table = (EH_FrameHdrEntry *)(buffer + header.size); - for EachIndex(fde_idx, fde_count) { - table[fde_idx].addr = fde[fde_idx].pc_range.min; - table[fde_idx].fde_offset = fde_offsets[fde_idx]; - } - radsort(table, fde_count, eh_frame_hdr_entry_sort); - - String8 eh_frame_hdr = str8(buffer, buffer_size); - scratch_end(scratch); - return eh_frame_hdr; -} - -internal -DW_DECODE_PTR(eh_decode_ptr) -{ - EH_DecodePtrCtx *ctx = ud; - return eh_parse_ptr(data, 0, ctx->ptr_ctx, ctx->addr_enc, ptr_out); -} - -internal String8 -eh_string_from_ptr_enc_type(EH_PtrEnc type) -{ - switch (type) { - case EH_PtrEnc_Ptr: return str8_lit("Ptr"); - case EH_PtrEnc_ULEB128: return str8_lit("ULEB128"); - case EH_PtrEnc_UData2: return str8_lit("UData2"); - case EH_PtrEnc_UData4: return str8_lit("UData4"); - case EH_PtrEnc_UData8: return str8_lit("UData8"); - case EH_PtrEnc_Signed: return str8_lit("Signed"); - case EH_PtrEnc_SLEB128: return str8_lit("SLEB128"); - case EH_PtrEnc_SData2: return str8_lit("SData2"); - case EH_PtrEnc_SData4: return str8_lit("SData4"); - case EH_PtrEnc_SData8: return str8_lit("SData8"); - } - return str8_zero(); -} - -internal String8 -eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier) -{ - switch (modifier) { - case EH_PtrEnc_PcRel: return str8_lit("PcRel"); - case EH_PtrEnc_TextRel: return str8_lit("TextRel"); - case EH_PtrEnc_DataRel: return str8_lit("DataRel"); - case EH_PtrEnc_FuncRel: return str8_lit("FuncRel"); - case EH_PtrEnc_Aligned: return str8_lit("Aligned"); - } - return str8_zero(); -} - -internal String8 -eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc) -{ - String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask); - String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask); - String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero(); - String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str); - return result; -} diff --git a/src/eh/eh_frame.h b/src/eh/eh_frame.h deleted file mode 100644 index 6139ca67..00000000 --- a/src/eh/eh_frame.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef EH_FRAME_H -#define EH_FRAME_H - -//////////////////////////////// -//~ Format - -typedef U8 EH_PtrEnc; -enum -{ - EH_PtrEnc_Ptr = 0x00, // Pointer sized unsigned value - EH_PtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value - EH_PtrEnc_UData2 = 0x02, // Unsigned 16-bit value - EH_PtrEnc_UData4 = 0x03, // Unsigned 32-bit value - EH_PtrEnc_UData8 = 0x04, // Unsigned 64-bit value - EH_PtrEnc_Signed = 0x08, // Signed pointer - EH_PtrEnc_SLEB128 = 0x09, // Signed LE base-128 value - EH_PtrEnc_SData2 = 0x0A, // Signed 16-bit value - EH_PtrEnc_SData4 = 0x0B, // Signed 32-bit value - EH_PtrEnc_SData8 = 0x0C, // Signed 64-bit value - - EH_PtrEnc_TypeMask = 0x0F, -}; - -enum -{ - EH_PtrEnc_PcRel = 0x10, // Value is relative to the current program counter. - EH_PtrEnc_TextRel = 0x20, // Value is relative to the .text section. - EH_PtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section. - EH_PtrEnc_FuncRel = 0x40, // Value is relative to the function. - EH_PtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary. - - EH_PtrEnc_ModifierMask = 0x70, -}; - -enum -{ - EH_PtrEnc_Indirect = 0x80, // Value is stored in virtual memory. - EH_PtrEnc_Omit = 0xFF, -}; - -typedef struct EH_PtrCtx -{ - U64 raw_base_vaddr; // address where pointer is being read - U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) - U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) - U64 func_vaddr; // base address of function where IP is located - U64 ptr_align; -} EH_PtrCtx; - -typedef U8 EH_AugFlags; -enum -{ - EH_AugFlag_HasLSDA = (1 << 0), - EH_AugFlag_HasHandler = (1 << 1), - EH_AugFlag_HasAddrEnc = (1 << 2), -}; - -typedef struct EH_Augmentation -{ - EH_AugFlags flags; - U64 handler_ip; - EH_PtrEnc handler_encoding; - EH_PtrEnc lsda_encoding; - EH_PtrEnc addr_encoding; -} EH_Augmentation; - -//////////////////////////////// -//~ Parser - -enum -{ - EH_CIE_Ext_AddrEnc, - EH_CIE_Ext_LSDAEnc, - EH_CIE_Ext_HandlerEnc, - EH_CIE_Ext_HandlerIp, -} EH_CIE_Ext; - -typedef struct EH_FrameHdrEntry -{ - U64 addr; - U64 fde_offset; -} EH_FrameHdrEntry; - -typedef struct EH_FrameHdr -{ - U8 version; - EH_PtrEnc eh_frame_ptr_enc; - EH_PtrEnc fde_count_enc; - EH_PtrEnc table_enc; - U64 field_byte_size; - U64 entry_byte_size; - U64 fde_count; - String8 table; -} EH_FrameHdr; - -typedef struct EH_DecodePtrCtx -{ - EH_PtrEnc addr_enc; - EH_PtrCtx *ptr_ctx; -} EH_DecodePtrCtx; - -//////////////////////////////// - -internal U64 eh_parse_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out); -internal EH_FrameHdr eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx); -internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out); -internal B32 eh_parse_cfi(String8 eh_frame, U64 fde_offset, Arch arch, EH_PtrCtx *ptr_ctx, struct DW_CIE *cie_out, struct DW_FDE *fde_out); -internal U64 eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc); -internal String8 eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, struct DW_FDE *fde); - -//////////////////////////////// -//~ Enum -> String - -internal String8 eh_string_from_ptr_enc_type(EH_PtrEnc type); -internal String8 eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier); -internal String8 eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc); - -#endif // EH_FRAME_H - diff --git a/src/elf/elf.h b/src/elf/elf.h index 14955224..c9fbe15e 100644 --- a/src/elf/elf.h +++ b/src/elf/elf.h @@ -106,6 +106,20 @@ enum ELF_Data_2MSB = 2, }; +typedef U16 ELF_Type; +enum +{ + ELF_Type_None = 0, + ELF_Type_Rel = 1, + ELF_Type_Exec = 2, + ELF_Type_Dyn = 3, + ELF_Type_Core = 4, + ELF_Type_LoOs = 0xfe00, + ELF_Type_HiOs = 0xff00, + ELF_Type_LoProc = 0xff00, + ELF_Type_HiProc = 0xffff +}; + typedef U32 ELF_PType; enum { @@ -123,15 +137,10 @@ enum ELF_PType_LowProc = 0x70000000, ELF_PType_HighProc = 0x7fffffff, - // specific to Sun - ELF_PType_LowSunW = 0x6ffffffa, - ELF_PType_SunWBSS = 0x6ffffffb, - ELF_PType_GnuEHFrame = 0x6474E550, - - ELF_PType_GnuStack = ELF_PType_LoOs + 0x474e550, // frame unwind information - ELF_PType_GnuRelro = ELF_PType_LoOs + 0x474e551, // stack flags - ELF_PType_GnuProperty = ELF_PType_LoOs + 0x474e552, // read-only after relocations - ELF_PType_SunEHFrame = ELF_PType_GnuEHFrame, + ELF_PType_GnuEHFrame = ELF_PType_LoOs + 0x474E550, // segment with .eh_frame_hdr + ELF_PType_GnuStack = ELF_PType_LoOs + 0x474e551, // frame unwind information + ELF_PType_GnuRelro = ELF_PType_LoOs + 0x474e552, // stack flags + ELF_PType_GnuProperty = ELF_PType_LoOs + 0x474e553, // read-only after relocations }; typedef U32 ELF_PFlag; @@ -674,20 +683,6 @@ typedef enum ELF_Identifier read_only global U8 elf_magic[] = {0x7f, 'E', 'L', 'F'}; read_only global String8 elf_magic_string = {elf_magic, sizeof(elf_magic)}; -typedef U16 ELF_Type; -typedef enum ELF_TypeEnum -{ - ELF_Type_None = 0, - ELF_Type_Rel = 1, - ELF_Type_Exec = 2, - ELF_Type_Dyn = 3, - ELF_Type_Core = 4, - ELF_Type_LoOs = 0xfe00, - ELF_Type_HiOs = 0xfeff, - ELF_Type_LoProc = 0xff00, - ELF_Type_HiProc = 0xffff, -} ELF_TypeEnum; - typedef struct ELF_Hdr64 { U8 e_ident[ELF_Identifier_Max]; diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 9274a100..8f09207d 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -1040,12 +1040,14 @@ rb_thread_entry_point(void *p) //- rjf: unpack dump subset flags RDI_DumpSubsetFlags rdi_dump_subset_flags = RDI_DumpSubsetFlag_All; DW_DumpSubsetFlags dw_dump_subset_flags = DW_DumpSubsetFlag_All; + EH_DumpSubsetFlags eh_dump_subset_flags = EH_DumpSubsetFlag_All; { String8List only_names = cmd_line_strings(cmdline, str8_lit("only")); if(only_names.node_count != 0) { rdi_dump_subset_flags = 0; dw_dump_subset_flags = 0; + eh_dump_subset_flags = 0; } for(String8Node *n = only_names.first; n != 0; n = n->next) { @@ -1055,6 +1057,9 @@ rb_thread_entry_point(void *p) #undef X #define X(name, name_lower, title) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { dw_dump_subset_flags |= DW_DumpSubsetFlag_##name; } DW_DumpSubset_XList +#undef X +#define X(name, name_lower, title) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { eh_dump_subset_flags |= EH_DumpSubsetFlag_##name; } + EH_DumpSubset_XList #undef X } String8List omit_names = cmd_line_strings(cmdline, str8_lit("omit")); @@ -1066,6 +1071,9 @@ rb_thread_entry_point(void *p) #undef X #define X(name, name_lower, title) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { dw_dump_subset_flags &= ~DW_DumpSubsetFlag_##name; } DW_DumpSubset_XList +#undef X +#define X(name, name_lower, title) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { eh_dump_subset_flags &= ~EH_DumpSubsetFlag_##name; } + EH_DumpSubset_XList #undef X } } @@ -1085,6 +1093,10 @@ rb_thread_entry_point(void *p) PE_BinInfo pe = {0}; ELF_Bin elf = {0}; DW_Input dw = {0}; + U64 eh_frame_hdr_vaddr = 0; + U64 eh_frame_vaddr = 0; + String8 eh_frame_hdr = {0}; + String8 eh_frame = {0}; { if(f->format == RB_FileFormat_PE) { @@ -1111,6 +1123,22 @@ rb_thread_entry_point(void *p) f->format == RB_FileFormat_ELF64) { dw = dw_input_from_elf_bin(arena, f->data, &elf); + for EachIndex(sect_idx, elf.hdr.e_shnum) + { + ELF_Shdr64 *shdr = &elf.shdrs.v[sect_idx]; + String8 name = elf_name_from_shdr64(f->data, &elf, shdr); + if (str8_match(name, str8_lit(".eh_frame_hdr"), 0)) + { + eh_frame_hdr = str8_substr(f->data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size)); + eh_frame_hdr_vaddr = shdr->sh_addr; + + } + else if(str8_match(name, str8_lit(".eh_frame"), 0)) + { + eh_frame = str8_substr(f->data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size)); + eh_frame_vaddr = shdr->sh_addr; + } + } } } } @@ -1204,6 +1232,16 @@ rb_thread_entry_point(void *p) } } } + + if(eh_dump_subset_flags) + { + if(lane_idx() == 0) + { + String8List dump = eh_dump_list_from_data(arena, arch, eh_frame_hdr_vaddr, eh_frame_vaddr, eh_frame_hdr, eh_frame, eh_dump_subset_flags); + str8_list_concat_in_place(&output_blobs, &dump); + } + lane_sync(); + } } }break; } diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index 51a65730..e1abc2fc 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -22,7 +22,6 @@ #include "elf/elf_parse.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" -#include "eh/eh_frame.h" #include "dwarf/dwarf_inc.h" #include "msf/msf.h" #include "msf/msf_parse.h" @@ -47,7 +46,6 @@ #include "elf/elf_parse.c" #include "codeview/codeview.c" #include "codeview/codeview_parse.c" -#include "eh/eh_frame.c" #include "dwarf/dwarf_inc.c" #include "msf/msf.c" #include "msf/msf_parse.c" diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 723b0c64..60693051 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -218,7 +218,6 @@ #include "pdb/pdb_parse.h" #include "pdb/pdb_stringize.h" #include "dwarf/dwarf_inc.h" -#include "eh/eh_frame.h" #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" #include "rdi_from_pdb/rdi_from_pdb.h" @@ -266,7 +265,6 @@ #include "pdb/pdb_parse.c" #include "pdb/pdb_stringize.c" #include "dwarf/dwarf_inc.c" -#include "eh/eh_frame.c" #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" #include "rdi_from_pdb/rdi_from_pdb.c"