|
| 1 | +// Copyright (c) Epic Games Tools |
| 2 | +// Licensed under the MIT license (https://opensource.org/license/mit/) |
| 3 | + |
| 4 | +internal String8List |
| 5 | +eh_dump_list_from_data(Arena *arena, Arch arch, U64 eh_frame_hdr_vaddr, U64 eh_frame_vaddr, String8 eh_frame_hdr, String8 eh_frame, EH_DumpSubsetFlags subset_flags) |
| 6 | +{ |
| 7 | + Temp scratch = scratch_begin(&arena, 1); |
| 8 | + String8List strings = {0}; |
| 9 | +#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__) |
| 10 | + |
| 11 | + EH_PtrCtx ptr_ctx = { .data_vaddr = eh_frame_hdr_vaddr }; |
| 12 | + EH_FrameHdr hdr = eh_parse_frame_hdr(eh_frame_hdr, byte_size_from_arch(arch), &ptr_ctx); |
| 13 | + DW_Ext ext = DW_Ext_All; |
| 14 | + |
| 15 | + if (subset_flags & EH_DumpSubsetFlag_EhFrameHdr) { |
| 16 | + dumpf("eh_frame_hdr:\n"); |
| 17 | + dumpf("{\n"); |
| 18 | + dumpf(" version: %u\n", hdr.version); |
| 19 | + dumpf(" eh_frame_ptr_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.eh_frame_ptr_enc)); |
| 20 | + dumpf(" table_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.table_enc)); |
| 21 | + dumpf(" fde_count: %llu\n", hdr.fde_count); |
| 22 | + if (hdr.eh_frame_ptr_enc != EH_PtrEnc_Omit) { |
| 23 | + dumpf(" eh_frame_ptr: 0x%I64x\n", hdr.eh_frame_ptr); |
| 24 | + } |
| 25 | + |
| 26 | + dumpf(" Entries:\n"); |
| 27 | + dumpf(" {\n"); |
| 28 | + for (U64 cursor = 0; cursor < hdr.table.size; ) { |
| 29 | + U64 entry_off = cursor; |
| 30 | + |
| 31 | + U64 pc = 0; |
| 32 | + U64 pc_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &pc); |
| 33 | + if (pc_size == 0) { break; } |
| 34 | + cursor += pc_size; |
| 35 | + |
| 36 | + U64 fde_addr = 0; |
| 37 | + U64 fde_addr_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &fde_addr); |
| 38 | + if (fde_addr_size == 0) { break; } |
| 39 | + cursor += fde_addr_size; |
| 40 | + |
| 41 | + U64 fde_offset = fde_addr - eh_frame_vaddr; |
| 42 | + dumpf(" { off=0x%04I64x, pc=0x%I64x, fde=0x%I64x }\n", entry_off, pc, fde_offset); |
| 43 | + } |
| 44 | + dumpf(" }\n"); |
| 45 | + |
| 46 | + dumpf("}\n"); |
| 47 | + |
| 48 | + } |
| 49 | + |
| 50 | + if (subset_flags & EH_DumpSubsetFlag_EhFrame) { |
| 51 | + dumpf(".eh_frame:\n"); |
| 52 | + dumpf("{\n"); |
| 53 | + for (U64 cursor = 0; cursor < eh_frame.size; ) { |
| 54 | + DW_DescriptorEntry desc = {0}; |
| 55 | + U64 desc_size = eh_parse_descriptor_entry_header(eh_frame, cursor, &desc); |
| 56 | + if (desc_size == 0) { break; } |
| 57 | + |
| 58 | + switch (desc.type) { |
| 59 | + case DW_DescriptorEntryType_Null: break; |
| 60 | + case DW_DescriptorEntryType_CIE: { |
| 61 | + String8 cie_data = str8_substr(eh_frame, desc.entry_range); |
| 62 | + DW_CIE cie = {0}; |
| 63 | + if (eh_parse_cie(cie_data, desc.format, arch, eh_frame_vaddr + cursor, &ptr_ctx, &cie)) { |
| 64 | + String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, ext, cie.format, 0, &cie, eh_decode_ptr, &ptr_ctx, cie.insts); |
| 65 | + dumpf(" CIE: // entry range: %r\n", desc.entry_range); |
| 66 | + dumpf(" {\n"); |
| 67 | + dumpf(" Format: %S\n", dw_string_from_format(desc.format)); |
| 68 | + dumpf(" Version: %u\n", cie.version); |
| 69 | + dumpf(" Aug string: \"%S\"\n", cie.aug_string); |
| 70 | + dumpf(" Code align: %I64u\n", cie.code_align_factor); |
| 71 | + dumpf(" Data align: %I64d\n", cie.data_align_factor); |
| 72 | + dumpf(" Return addr reg: %u\n", cie.ret_addr_reg); |
| 73 | + if (cie.version > DW_Version_3) { |
| 74 | + dumpf(" Address size: %u\n", cie.address_size); |
| 75 | + dumpf(" Segment selector size: %u\n", cie.segment_selector_size); |
| 76 | + } |
| 77 | + dumpf(" Initial Insturction:\n"); |
| 78 | + dumpf(" {\n"); |
| 79 | + for EachNode(n, String8Node, init_insts_str_list.first) { dumpf(" %S\n", n->string); } |
| 80 | + dumpf(" }\n"); |
| 81 | + dumpf(" }\n"); |
| 82 | + } else { |
| 83 | + dumpf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min); |
| 84 | + } |
| 85 | + } break; |
| 86 | + case DW_DescriptorEntryType_FDE: { |
| 87 | + U64 cie_offset = desc.cie_pointer_off - desc.cie_pointer; |
| 88 | + |
| 89 | + DW_CIE cie = {0}; |
| 90 | + { |
| 91 | + DW_DescriptorEntry cie_desc = {0}; |
| 92 | + eh_parse_descriptor_entry_header(eh_frame, cie_offset, &cie_desc); |
| 93 | + if (cie_desc.type == DW_DescriptorEntryType_CIE) { |
| 94 | + String8 cie_data = str8_substr(eh_frame, cie_desc.entry_range); |
| 95 | + eh_parse_cie(cie_data, cie_desc.format, arch, eh_frame_vaddr + cie_offset, &ptr_ctx, &cie); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + String8 fde_raw = str8_substr(eh_frame, desc.entry_range); |
| 100 | + DW_FDE fde = {0}; |
| 101 | + if (eh_parse_fde(fde_raw, desc.format, eh_frame_vaddr + cursor, &cie, &ptr_ctx, &fde)) { |
| 102 | + String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, hdr.version, ext, fde.format, 0, &cie, eh_decode_ptr, &ptr_ctx, fde.insts); |
| 103 | + |
| 104 | + dumpf(" FDE: // entry range: %r\n", desc.entry_range); |
| 105 | + dumpf(" {\n"); |
| 106 | + { |
| 107 | + dumpf(" Format: %S\n", dw_string_from_format(fde.format)); |
| 108 | + dumpf(" CIE: 0x%I64x\n", cie_offset); |
| 109 | + dumpf(" PC range: %r\n", fde.pc_range); |
| 110 | + dumpf(" Instructions:\n"); |
| 111 | + dumpf(" {\n"); |
| 112 | + for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); } |
| 113 | + dumpf(" }\n"); |
| 114 | + |
| 115 | + dumpf(" Unwind:\n"); |
| 116 | + dumpf(" {\n"); |
| 117 | + DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, eh_decode_ptr, &ptr_ctx); |
| 118 | + do { |
| 119 | + String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row->cfa); |
| 120 | + String8 cfi_row_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row); |
| 121 | + dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_row_str); |
| 122 | + } while (dw_cfi_next_row(scratch.arena, cfi_unwind)); |
| 123 | + dumpf(" }\n"); |
| 124 | + } |
| 125 | + } else { |
| 126 | + dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min); |
| 127 | + } |
| 128 | + dumpf(" }\n"); |
| 129 | + } break; |
| 130 | + } |
| 131 | + |
| 132 | + cursor += desc_size; |
| 133 | + } |
| 134 | + dumpf("}\n"); |
| 135 | + } |
| 136 | + |
| 137 | +#undef dumpf |
| 138 | + scratch_end(scratch); |
| 139 | + return strings; |
| 140 | +} |
| 141 | + |
0 commit comments