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