| ... | ... | @@ -1,14 +1,13 @@ |
| 1 | 1 | //! Implements parsing, decoding, and caching of DWARF information. |
| 2 | 2 | //! |
| 3 | | //! This API does not assume the current executable is itself the thing being |
| 4 | | //! debugged, however, it does assume the debug info has the same CPU |
| 5 | | //! architecture and OS as the current executable. It is planned to remove this |
| 6 | | //! limitation. |
| 3 | //! This API makes no assumptions about the relationship between the host and |
| 4 | //! the target being debugged. In other words, any DWARF information can be used |
| 5 | //! from any host via this API. Note, however, that the limits of 32-bit |
| 6 | //! addressing can cause very large 64-bit binaries to be impossible to open on |
| 7 | //! 32-bit hosts. |
| 7 | 8 | //! |
| 8 | 9 | //! For unopinionated types and bits, see `std.dwarf`. |
| 9 | 10 | |
| 10 | | const builtin = @import("builtin"); |
| 11 | | |
| 12 | 11 | const std = @import("../std.zig"); |
| 13 | 12 | const Allocator = std.mem.Allocator; |
| 14 | 13 | const mem = std.mem; |
| ... | ... | @@ -57,9 +56,6 @@ pub const Range = struct { |
| 57 | 56 | |
| 58 | 57 | pub const Section = struct { |
| 59 | 58 | data: []const u8, |
| 60 | | // Module-relative virtual address. |
| 61 | | // Only set if the section data was loaded from disk. |
| 62 | | virtual_address: ?usize = null, |
| 63 | 59 | // If `data` is owned by this Dwarf. |
| 64 | 60 | owned: bool, |
| 65 | 61 | |
| ... | ... | @@ -120,6 +116,7 @@ pub const Abbrev = struct { |
| 120 | 116 | pub const CompileUnit = struct { |
| 121 | 117 | version: u16, |
| 122 | 118 | format: Format, |
| 119 | addr_size_bytes: u8, |
| 123 | 120 | die: Die, |
| 124 | 121 | pc_range: ?PcRange, |
| 125 | 122 | |
| ... | ... | @@ -170,7 +167,7 @@ pub const CompileUnit = struct { |
| 170 | 167 | |
| 171 | 168 | pub const FormValue = union(enum) { |
| 172 | 169 | addr: u64, |
| 173 | | addrx: usize, |
| 170 | addrx: u64, |
| 174 | 171 | block: []const u8, |
| 175 | 172 | udata: u64, |
| 176 | 173 | data16: *const [16]u8, |
| ... | ... | @@ -182,7 +179,7 @@ pub const FormValue = union(enum) { |
| 182 | 179 | ref_addr: u64, |
| 183 | 180 | string: [:0]const u8, |
| 184 | 181 | strp: u64, |
| 185 | | strx: usize, |
| 182 | strx: u64, |
| 186 | 183 | line_strp: u64, |
| 187 | 184 | loclistx: u64, |
| 188 | 185 | rnglistx: u64, |
| ... | ... | @@ -392,12 +389,11 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator, endian: Endian) ScanError! |
| 392 | 389 | const unit_type = try fr.takeByte(); |
| 393 | 390 | if (unit_type != DW.UT.compile) return bad(); |
| 394 | 391 | address_size = try fr.takeByte(); |
| 395 | | debug_abbrev_offset = try readAddress(&fr, unit_header.format, endian); |
| 392 | debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian); |
| 396 | 393 | } else { |
| 397 | | debug_abbrev_offset = try readAddress(&fr, unit_header.format, endian); |
| 394 | debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian); |
| 398 | 395 | address_size = try fr.takeByte(); |
| 399 | 396 | } |
| 400 | | if (address_size != @sizeOf(usize)) return bad(); |
| 401 | 397 | |
| 402 | 398 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 403 | 399 | |
| ... | ... | @@ -424,6 +420,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator, endian: Endian) ScanError! |
| 424 | 420 | var compile_unit: CompileUnit = .{ |
| 425 | 421 | .version = version, |
| 426 | 422 | .format = unit_header.format, |
| 423 | .addr_size_bytes = address_size, |
| 427 | 424 | .die = undefined, |
| 428 | 425 | .pc_range = null, |
| 429 | 426 | |
| ... | ... | @@ -446,6 +443,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator, endian: Endian) ScanError! |
| 446 | 443 | abbrev_table, |
| 447 | 444 | unit_header.format, |
| 448 | 445 | endian, |
| 446 | address_size, |
| 449 | 447 | )) orelse continue; |
| 450 | 448 | |
| 451 | 449 | switch (die_obj.tag_id) { |
| ... | ... | @@ -480,6 +478,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator, endian: Endian) ScanError! |
| 480 | 478 | abbrev_table, // wrong abbrev table for different cu |
| 481 | 479 | unit_header.format, |
| 482 | 480 | endian, |
| 481 | address_size, |
| 483 | 482 | )) orelse return bad(); |
| 484 | 483 | } else if (this_die_obj.getAttr(AT.specification)) |_| { |
| 485 | 484 | const after_die_offset = fr.seek; |
| ... | ... | @@ -494,6 +493,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator, endian: Endian) ScanError! |
| 494 | 493 | abbrev_table, // wrong abbrev table for different cu |
| 495 | 494 | unit_header.format, |
| 496 | 495 | endian, |
| 496 | address_size, |
| 497 | 497 | )) orelse return bad(); |
| 498 | 498 | } else { |
| 499 | 499 | break :x null; |
| ... | ... | @@ -584,12 +584,11 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator, endian: Endian) ScanErr |
| 584 | 584 | const unit_type = try fr.takeByte(); |
| 585 | 585 | if (unit_type != UT.compile) return bad(); |
| 586 | 586 | address_size = try fr.takeByte(); |
| 587 | | debug_abbrev_offset = try readAddress(&fr, unit_header.format, endian); |
| 587 | debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian); |
| 588 | 588 | } else { |
| 589 | | debug_abbrev_offset = try readAddress(&fr, unit_header.format, endian); |
| 589 | debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian); |
| 590 | 590 | address_size = try fr.takeByte(); |
| 591 | 591 | } |
| 592 | | if (address_size != @sizeOf(usize)) return bad(); |
| 593 | 592 | |
| 594 | 593 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 595 | 594 | |
| ... | ... | @@ -605,6 +604,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator, endian: Endian) ScanErr |
| 605 | 604 | abbrev_table, |
| 606 | 605 | unit_header.format, |
| 607 | 606 | endian, |
| 607 | address_size, |
| 608 | 608 | )) orelse return bad(); |
| 609 | 609 | |
| 610 | 610 | if (compile_unit_die.tag_id != DW.TAG.compile_unit) return bad(); |
| ... | ... | @@ -614,6 +614,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator, endian: Endian) ScanErr |
| 614 | 614 | var compile_unit: CompileUnit = .{ |
| 615 | 615 | .version = version, |
| 616 | 616 | .format = unit_header.format, |
| 617 | .addr_size_bytes = address_size, |
| 617 | 618 | .pc_range = null, |
| 618 | 619 | .die = compile_unit_die, |
| 619 | 620 | .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0, |
| ... | ... | @@ -702,15 +703,15 @@ const DebugRangeIterator = struct { |
| 702 | 703 | .rnglistx => |idx| off: { |
| 703 | 704 | switch (compile_unit.format) { |
| 704 | 705 | .@"32" => { |
| 705 | | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 4 * idx)); |
| 706 | const offset_loc = compile_unit.rnglists_base + 4 * idx; |
| 706 | 707 | if (offset_loc + 4 > debug_ranges.len) return bad(); |
| 707 | | const offset = mem.readInt(u32, debug_ranges[offset_loc..][0..4], endian); |
| 708 | const offset = mem.readInt(u32, debug_ranges[@intCast(offset_loc)..][0..4], endian); |
| 708 | 709 | break :off compile_unit.rnglists_base + offset; |
| 709 | 710 | }, |
| 710 | 711 | .@"64" => { |
| 711 | | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 8 * idx)); |
| 712 | const offset_loc = compile_unit.rnglists_base + 8 * idx; |
| 712 | 713 | if (offset_loc + 8 > debug_ranges.len) return bad(); |
| 713 | | const offset = mem.readInt(u64, debug_ranges[offset_loc..][0..8], endian); |
| 714 | const offset = mem.readInt(u64, debug_ranges[@intCast(offset_loc)..][0..8], endian); |
| 714 | 715 | break :off compile_unit.rnglists_base + offset; |
| 715 | 716 | }, |
| 716 | 717 | } |
| ... | ... | @@ -743,21 +744,22 @@ const DebugRangeIterator = struct { |
| 743 | 744 | // Returns the next range in the list, or null if the end was reached. |
| 744 | 745 | pub fn next(self: *@This()) !?PcRange { |
| 745 | 746 | const endian = self.endian; |
| 747 | const addr_size_bytes = self.compile_unit.addr_size_bytes; |
| 746 | 748 | switch (self.section_type) { |
| 747 | 749 | .debug_rnglists => { |
| 748 | 750 | const kind = try self.fr.takeByte(); |
| 749 | 751 | switch (kind) { |
| 750 | 752 | RLE.end_of_list => return null, |
| 751 | 753 | RLE.base_addressx => { |
| 752 | | const index = try self.fr.takeLeb128(usize); |
| 754 | const index = try self.fr.takeLeb128(u64); |
| 753 | 755 | self.base_address = try self.di.readDebugAddr(endian, self.compile_unit, index); |
| 754 | 756 | return try self.next(); |
| 755 | 757 | }, |
| 756 | 758 | RLE.startx_endx => { |
| 757 | | const start_index = try self.fr.takeLeb128(usize); |
| 759 | const start_index = try self.fr.takeLeb128(u64); |
| 758 | 760 | const start_addr = try self.di.readDebugAddr(endian, self.compile_unit, start_index); |
| 759 | 761 | |
| 760 | | const end_index = try self.fr.takeLeb128(usize); |
| 762 | const end_index = try self.fr.takeLeb128(u64); |
| 761 | 763 | const end_addr = try self.di.readDebugAddr(endian, self.compile_unit, end_index); |
| 762 | 764 | |
| 763 | 765 | return .{ |
| ... | ... | @@ -766,10 +768,10 @@ const DebugRangeIterator = struct { |
| 766 | 768 | }; |
| 767 | 769 | }, |
| 768 | 770 | RLE.startx_length => { |
| 769 | | const start_index = try self.fr.takeLeb128(usize); |
| 771 | const start_index = try self.fr.takeLeb128(u64); |
| 770 | 772 | const start_addr = try self.di.readDebugAddr(endian, self.compile_unit, start_index); |
| 771 | 773 | |
| 772 | | const len = try self.fr.takeLeb128(usize); |
| 774 | const len = try self.fr.takeLeb128(u64); |
| 773 | 775 | const end_addr = start_addr + len; |
| 774 | 776 | |
| 775 | 777 | return .{ |
| ... | ... | @@ -778,8 +780,8 @@ const DebugRangeIterator = struct { |
| 778 | 780 | }; |
| 779 | 781 | }, |
| 780 | 782 | RLE.offset_pair => { |
| 781 | | const start_addr = try self.fr.takeLeb128(usize); |
| 782 | | const end_addr = try self.fr.takeLeb128(usize); |
| 783 | const start_addr = try self.fr.takeLeb128(u64); |
| 784 | const end_addr = try self.fr.takeLeb128(u64); |
| 783 | 785 | |
| 784 | 786 | // This is the only kind that uses the base address |
| 785 | 787 | return .{ |
| ... | ... | @@ -788,12 +790,12 @@ const DebugRangeIterator = struct { |
| 788 | 790 | }; |
| 789 | 791 | }, |
| 790 | 792 | RLE.base_address => { |
| 791 | | self.base_address = try self.fr.takeInt(usize, endian); |
| 793 | self.base_address = try readAddress(&self.fr, endian, addr_size_bytes); |
| 792 | 794 | return try self.next(); |
| 793 | 795 | }, |
| 794 | 796 | RLE.start_end => { |
| 795 | | const start_addr = try self.fr.takeInt(usize, endian); |
| 796 | | const end_addr = try self.fr.takeInt(usize, endian); |
| 797 | const start_addr = try readAddress(&self.fr, endian, addr_size_bytes); |
| 798 | const end_addr = try readAddress(&self.fr, endian, addr_size_bytes); |
| 797 | 799 | |
| 798 | 800 | return .{ |
| 799 | 801 | .start = start_addr, |
| ... | ... | @@ -801,8 +803,8 @@ const DebugRangeIterator = struct { |
| 801 | 803 | }; |
| 802 | 804 | }, |
| 803 | 805 | RLE.start_length => { |
| 804 | | const start_addr = try self.fr.takeInt(usize, endian); |
| 805 | | const len = try self.fr.takeLeb128(usize); |
| 806 | const start_addr = try readAddress(&self.fr, endian, addr_size_bytes); |
| 807 | const len = try self.fr.takeLeb128(u64); |
| 806 | 808 | const end_addr = start_addr + len; |
| 807 | 809 | |
| 808 | 810 | return .{ |
| ... | ... | @@ -814,12 +816,13 @@ const DebugRangeIterator = struct { |
| 814 | 816 | } |
| 815 | 817 | }, |
| 816 | 818 | .debug_ranges => { |
| 817 | | const start_addr = try self.fr.takeInt(usize, endian); |
| 818 | | const end_addr = try self.fr.takeInt(usize, endian); |
| 819 | const start_addr = try readAddress(&self.fr, endian, addr_size_bytes); |
| 820 | const end_addr = try readAddress(&self.fr, endian, addr_size_bytes); |
| 819 | 821 | if (start_addr == 0 and end_addr == 0) return null; |
| 820 | 822 | |
| 821 | | // This entry selects a new value for the base address |
| 822 | | if (start_addr == maxInt(usize)) { |
| 823 | // The entry with start_addr = max_representable_address selects a new value for the base address |
| 824 | const max_representable_address = ~@as(u64, 0) >> @intCast(64 - addr_size_bytes); |
| 825 | if (start_addr == max_representable_address) { |
| 823 | 826 | self.base_address = end_addr; |
| 824 | 827 | return try self.next(); |
| 825 | 828 | } |
| ... | ... | @@ -921,6 +924,7 @@ fn parseDie( |
| 921 | 924 | abbrev_table: *const Abbrev.Table, |
| 922 | 925 | format: Format, |
| 923 | 926 | endian: Endian, |
| 927 | addr_size_bytes: u8, |
| 924 | 928 | ) ScanError!?Die { |
| 925 | 929 | const abbrev_code = try fr.takeLeb128(u64); |
| 926 | 930 | if (abbrev_code == 0) return null; |
| ... | ... | @@ -929,7 +933,7 @@ fn parseDie( |
| 929 | 933 | const attrs = attrs_buf[0..table_entry.attrs.len]; |
| 930 | 934 | for (attrs, table_entry.attrs) |*result_attr, attr| result_attr.* = .{ |
| 931 | 935 | .id = attr.id, |
| 932 | | .value = try parseFormValue(fr, attr.form_id, format, endian, attr.payload), |
| 936 | .value = try parseFormValue(fr, attr.form_id, format, endian, addr_size_bytes, attr.payload), |
| 933 | 937 | }; |
| 934 | 938 | return .{ |
| 935 | 939 | .tag_id = table_entry.tag_id, |
| ... | ... | @@ -954,20 +958,16 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: |
| 954 | 958 | const version = try fr.takeInt(u16, endian); |
| 955 | 959 | if (version < 2) return bad(); |
| 956 | 960 | |
| 957 | | const addr_size: u8, const seg_size: u8 = if (version >= 5) .{ |
| 961 | const addr_size_bytes: u8, const seg_size: u8 = if (version >= 5) .{ |
| 958 | 962 | try fr.takeByte(), |
| 959 | 963 | try fr.takeByte(), |
| 960 | 964 | } else .{ |
| 961 | | switch (unit_header.format) { |
| 962 | | .@"32" => 4, |
| 963 | | .@"64" => 8, |
| 964 | | }, |
| 965 | compile_unit.addr_size_bytes, |
| 965 | 966 | 0, |
| 966 | 967 | }; |
| 967 | 968 | if (seg_size != 0) return bad(); // unsupported |
| 968 | | _ = addr_size; // TODO: ignoring this is incorrect, we should use it to decide address lengths |
| 969 | 969 | |
| 970 | | const prologue_length = try readAddress(&fr, unit_header.format, endian); |
| 970 | const prologue_length = try readFormatSizedInt(&fr, unit_header.format, endian); |
| 971 | 971 | const prog_start_offset = fr.seek + prologue_length; |
| 972 | 972 | |
| 973 | 973 | const minimum_instruction_length = try fr.takeByte(); |
| ... | ... | @@ -1036,7 +1036,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: |
| 1036 | 1036 | for (try directories.addManyAsSlice(gpa, directories_count)) |*e| { |
| 1037 | 1037 | e.* = .{ .path = &.{} }; |
| 1038 | 1038 | for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| { |
| 1039 | | const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, null); |
| 1039 | const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null); |
| 1040 | 1040 | switch (ent_fmt.content_type_code) { |
| 1041 | 1041 | DW.LNCT.path => e.path = try form_value.getString(d.*), |
| 1042 | 1042 | DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), |
| ... | ... | @@ -1068,7 +1068,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: |
| 1068 | 1068 | for (try file_entries.addManyAsSlice(gpa, file_names_count)) |*e| { |
| 1069 | 1069 | e.* = .{ .path = &.{} }; |
| 1070 | 1070 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| { |
| 1071 | | const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, null); |
| 1071 | const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null); |
| 1072 | 1072 | switch (ent_fmt.content_type_code) { |
| 1073 | 1073 | DW.LNCT.path => e.path = try form_value.getString(d.*), |
| 1074 | 1074 | DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), |
| ... | ... | @@ -1117,8 +1117,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: |
| 1117 | 1117 | prog.reset(); |
| 1118 | 1118 | }, |
| 1119 | 1119 | DW.LNE.set_address => { |
| 1120 | | const addr = try fr.takeInt(usize, endian); |
| 1121 | | prog.address = addr; |
| 1120 | prog.address = try readAddress(&fr, endian, addr_size_bytes); |
| 1122 | 1121 | }, |
| 1123 | 1122 | DW.LNE.define_file => { |
| 1124 | 1123 | const path = try fr.takeSentinel(0); |
| ... | ... | @@ -1150,7 +1149,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: |
| 1150 | 1149 | prog.basic_block = false; |
| 1151 | 1150 | }, |
| 1152 | 1151 | DW.LNS.advance_pc => { |
| 1153 | | const arg = try fr.takeLeb128(usize); |
| 1152 | const arg = try fr.takeLeb128(u64); |
| 1154 | 1153 | prog.address += arg * minimum_instruction_length; |
| 1155 | 1154 | }, |
| 1156 | 1155 | DW.LNS.advance_line => { |
| ... | ... | @@ -1258,13 +1257,13 @@ fn readDebugAddr(di: Dwarf, endian: Endian, compile_unit: *const CompileUnit, in |
| 1258 | 1257 | const addr_size = debug_addr[compile_unit.addr_base - 2]; |
| 1259 | 1258 | const seg_size = debug_addr[compile_unit.addr_base - 1]; |
| 1260 | 1259 | |
| 1261 | | const byte_offset = @as(usize, @intCast(compile_unit.addr_base + (addr_size + seg_size) * index)); |
| 1260 | const byte_offset = compile_unit.addr_base + (addr_size + seg_size) * index; |
| 1262 | 1261 | if (byte_offset + addr_size > debug_addr.len) return bad(); |
| 1263 | 1262 | return switch (addr_size) { |
| 1264 | | 1 => debug_addr[byte_offset], |
| 1265 | | 2 => mem.readInt(u16, debug_addr[byte_offset..][0..2], endian), |
| 1266 | | 4 => mem.readInt(u32, debug_addr[byte_offset..][0..4], endian), |
| 1267 | | 8 => mem.readInt(u64, debug_addr[byte_offset..][0..8], endian), |
| 1263 | 1 => debug_addr[@intCast(byte_offset)], |
| 1264 | 2 => mem.readInt(u16, debug_addr[@intCast(byte_offset)..][0..2], endian), |
| 1265 | 4 => mem.readInt(u32, debug_addr[@intCast(byte_offset)..][0..4], endian), |
| 1266 | 8 => mem.readInt(u64, debug_addr[@intCast(byte_offset)..][0..8], endian), |
| 1268 | 1267 | else => bad(), |
| 1269 | 1268 | }; |
| 1270 | 1269 | } |
| ... | ... | @@ -1274,17 +1273,18 @@ fn parseFormValue( |
| 1274 | 1273 | form_id: u64, |
| 1275 | 1274 | format: Format, |
| 1276 | 1275 | endian: Endian, |
| 1276 | addr_size_bytes: u8, |
| 1277 | 1277 | implicit_const: ?i64, |
| 1278 | 1278 | ) ScanError!FormValue { |
| 1279 | 1279 | return switch (form_id) { |
| 1280 | 1280 | // DWARF5.pdf page 213: the size of this value is encoded in the |
| 1281 | 1281 | // compilation unit header as address size. |
| 1282 | | FORM.addr => .{ .addr = try readAddress(r, nativeFormat(), endian) }, |
| 1282 | FORM.addr => .{ .addr = try readAddress(r, endian, addr_size_bytes) }, |
| 1283 | 1283 | FORM.addrx1 => .{ .addrx = try r.takeByte() }, |
| 1284 | 1284 | FORM.addrx2 => .{ .addrx = try r.takeInt(u16, endian) }, |
| 1285 | 1285 | FORM.addrx3 => .{ .addrx = try r.takeInt(u24, endian) }, |
| 1286 | 1286 | FORM.addrx4 => .{ .addrx = try r.takeInt(u32, endian) }, |
| 1287 | | FORM.addrx => .{ .addrx = try r.takeLeb128(usize) }, |
| 1287 | FORM.addrx => .{ .addrx = try r.takeLeb128(u64) }, |
| 1288 | 1288 | |
| 1289 | 1289 | FORM.block1 => .{ .block = try r.take(try r.takeByte()) }, |
| 1290 | 1290 | FORM.block2 => .{ .block = try r.take(try r.takeInt(u16, endian)) }, |
| ... | ... | @@ -1301,7 +1301,7 @@ fn parseFormValue( |
| 1301 | 1301 | FORM.exprloc => .{ .exprloc = try r.take(try r.takeLeb128(usize)) }, |
| 1302 | 1302 | FORM.flag => .{ .flag = (try r.takeByte()) != 0 }, |
| 1303 | 1303 | FORM.flag_present => .{ .flag = true }, |
| 1304 | | FORM.sec_offset => .{ .sec_offset = try readAddress(r, format, endian) }, |
| 1304 | FORM.sec_offset => .{ .sec_offset = try readFormatSizedInt(r, format, endian) }, |
| 1305 | 1305 | |
| 1306 | 1306 | FORM.ref1 => .{ .ref = try r.takeByte() }, |
| 1307 | 1307 | FORM.ref2 => .{ .ref = try r.takeInt(u16, endian) }, |
| ... | ... | @@ -1309,18 +1309,18 @@ fn parseFormValue( |
| 1309 | 1309 | FORM.ref8 => .{ .ref = try r.takeInt(u64, endian) }, |
| 1310 | 1310 | FORM.ref_udata => .{ .ref = try r.takeLeb128(u64) }, |
| 1311 | 1311 | |
| 1312 | | FORM.ref_addr => .{ .ref_addr = try readAddress(r, format, endian) }, |
| 1312 | FORM.ref_addr => .{ .ref_addr = try readFormatSizedInt(r, format, endian) }, |
| 1313 | 1313 | FORM.ref_sig8 => .{ .ref = try r.takeInt(u64, endian) }, |
| 1314 | 1314 | |
| 1315 | 1315 | FORM.string => .{ .string = try r.takeSentinel(0) }, |
| 1316 | | FORM.strp => .{ .strp = try readAddress(r, format, endian) }, |
| 1316 | FORM.strp => .{ .strp = try readFormatSizedInt(r, format, endian) }, |
| 1317 | 1317 | FORM.strx1 => .{ .strx = try r.takeByte() }, |
| 1318 | 1318 | FORM.strx2 => .{ .strx = try r.takeInt(u16, endian) }, |
| 1319 | 1319 | FORM.strx3 => .{ .strx = try r.takeInt(u24, endian) }, |
| 1320 | 1320 | FORM.strx4 => .{ .strx = try r.takeInt(u32, endian) }, |
| 1321 | 1321 | FORM.strx => .{ .strx = try r.takeLeb128(usize) }, |
| 1322 | | FORM.line_strp => .{ .line_strp = try readAddress(r, format, endian) }, |
| 1323 | | FORM.indirect => parseFormValue(r, try r.takeLeb128(u64), format, endian, implicit_const), |
| 1322 | FORM.line_strp => .{ .line_strp = try readFormatSizedInt(r, format, endian) }, |
| 1323 | FORM.indirect => parseFormValue(r, try r.takeLeb128(u64), format, endian, addr_size_bytes, implicit_const), |
| 1324 | 1324 | FORM.implicit_const => .{ .sdata = implicit_const orelse return bad() }, |
| 1325 | 1325 | FORM.loclistx => .{ .loclistx = try r.takeLeb128(u64) }, |
| 1326 | 1326 | FORM.rnglistx => .{ .rnglistx = try r.takeLeb128(u64) }, |
| ... | ... | @@ -1464,20 +1464,24 @@ pub fn getSymbol(di: *Dwarf, allocator: Allocator, endian: Endian, address: u64) |
| 1464 | 1464 | }; |
| 1465 | 1465 | } |
| 1466 | 1466 | |
| 1467 | | fn readAddress(r: *Reader, format: std.dwarf.Format, endian: Endian) !u64 { |
| 1468 | | // MLUGG TODO FIX BEFORE MERGE: this function is slightly bogus. addresses have a byte width which is independent of the `dwarf.Format`! |
| 1467 | /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and |
| 1468 | /// offsets relative to the beginning of DWARF sections are represented using four bytes. In the |
| 1469 | /// 64-bit DWARF format, all values that represent lengths of DWARF sections and offsets relative to |
| 1470 | /// the beginning of DWARF sections are represented using eight bytes". |
| 1471 | /// |
| 1472 | /// This function is for reading such values. |
| 1473 | fn readFormatSizedInt(r: *Reader, format: std.dwarf.Format, endian: Endian) !u64 { |
| 1469 | 1474 | return switch (format) { |
| 1470 | 1475 | .@"32" => try r.takeInt(u32, endian), |
| 1471 | 1476 | .@"64" => try r.takeInt(u64, endian), |
| 1472 | 1477 | }; |
| 1473 | 1478 | } |
| 1474 | 1479 | |
| 1475 | | fn nativeFormat() std.dwarf.Format { |
| 1476 | | // MLUGG TODO FIX BEFORE MERGE: this is nonsensical. this is neither what `dwarf.Format` is for, nor does it make sense to check the NATIVE FUCKING FORMAT |
| 1477 | | // when parsing ARBITRARY DWARF. |
| 1478 | | return switch (@sizeOf(usize)) { |
| 1479 | | 4 => .@"32", |
| 1480 | | 8 => .@"64", |
| 1481 | | else => @compileError("unsupported @sizeOf(usize)"), |
| 1480 | fn readAddress(r: *Reader, endian: Endian, addr_size_bytes: u8) !u64 { |
| 1481 | return switch (addr_size_bytes) { |
| 1482 | 2 => try r.takeInt(u16, endian), |
| 1483 | 4 => try r.takeInt(u32, endian), |
| 1484 | 8 => try r.takeInt(u64, endian), |
| 1485 | else => return bad(), |
| 1482 | 1486 | }; |
| 1483 | 1487 | } |