| author | |
| committer | |
| log | f6148f123e35dcbec4b9ab7458967fa93277e443 |
| tree | d1ee3ee1c739d339252871b3da3169a782f24161 |
| parent | ea9917d9bd921f9fc14028a8dbf9e3f0f2579120 |
3 files changed, 245 insertions(+), 127 deletions(-)
lib/std/debug.zig+32-104| ... | ... | @@ -800,52 +800,20 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDe |
| 800 | 800 | // This coff file has embedded DWARF debug info |
| 801 | 801 | _ = sec; |
| 802 | 802 | |
| 803 | const debug_info = coff_obj.getSectionDataAlloc(".debug_info", allocator) catch return error.MissingDebugInfo; | |
| 804 | errdefer allocator.free(debug_info); | |
| 805 | const debug_abbrev = coff_obj.getSectionDataAlloc(".debug_abbrev", allocator) catch return error.MissingDebugInfo; | |
| 806 | errdefer allocator.free(debug_abbrev); | |
| 807 | const debug_str = coff_obj.getSectionDataAlloc(".debug_str", allocator) catch return error.MissingDebugInfo; | |
| 808 | errdefer allocator.free(debug_str); | |
| 809 | const debug_line = coff_obj.getSectionDataAlloc(".debug_line", allocator) catch return error.MissingDebugInfo; | |
| 810 | errdefer allocator.free(debug_line); | |
| 811 | ||
| 812 | const debug_str_offsets = coff_obj.getSectionDataAlloc(".debug_str_offsets", allocator) catch null; | |
| 813 | const debug_line_str = coff_obj.getSectionDataAlloc(".debug_line_str", allocator) catch null; | |
| 814 | const debug_ranges = coff_obj.getSectionDataAlloc(".debug_ranges", allocator) catch null; | |
| 815 | const debug_loclists = coff_obj.getSectionDataAlloc(".debug_loclists", allocator) catch null; | |
| 816 | const debug_rnglists = coff_obj.getSectionDataAlloc(".debug_rnglists", allocator) catch null; | |
| 817 | const debug_addr = coff_obj.getSectionDataAlloc(".debug_addr", allocator) catch null; | |
| 818 | const debug_names = coff_obj.getSectionDataAlloc(".debug_names", allocator) catch null; | |
| 819 | const debug_frame = coff_obj.getSectionDataAlloc(".debug_frame", allocator) catch null; | |
| 803 | const num_sections = std.enums.directEnumArrayLen(DW.DwarfSection, 0); | |
| 804 | var sections: [num_sections]?[]const u8 = [_]?[]const u8{null} ** num_sections; | |
| 805 | errdefer for (sections) |section| if (section) |s| allocator.free(s); | |
| 806 | ||
| 807 | inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| { | |
| 808 | sections[i] = try coff_obj.getSectionDataAlloc("." ++ section.name, allocator); | |
| 809 | } | |
| 820 | 810 | |
| 821 | 811 | var dwarf = DW.DwarfInfo{ |
| 822 | 812 | .endian = native_endian, |
| 823 | .debug_info = debug_info, | |
| 824 | .debug_abbrev = debug_abbrev, | |
| 825 | .debug_str = debug_str, | |
| 826 | .debug_str_offsets = debug_str_offsets, | |
| 827 | .debug_line = debug_line, | |
| 828 | .debug_line_str = debug_line_str, | |
| 829 | .debug_ranges = debug_ranges, | |
| 830 | .debug_loclists = debug_loclists, | |
| 831 | .debug_rnglists = debug_rnglists, | |
| 832 | .debug_addr = debug_addr, | |
| 833 | .debug_names = debug_names, | |
| 834 | .debug_frame = debug_frame, | |
| 835 | }; | |
| 836 | ||
| 837 | DW.openDwarfDebugInfo(&dwarf, allocator) catch |err| { | |
| 838 | if (debug_str_offsets) |d| allocator.free(d); | |
| 839 | if (debug_line_str) |d| allocator.free(d); | |
| 840 | if (debug_ranges) |d| allocator.free(d); | |
| 841 | if (debug_loclists) |d| allocator.free(d); | |
| 842 | if (debug_rnglists) |d| allocator.free(d); | |
| 843 | if (debug_addr) |d| allocator.free(d); | |
| 844 | if (debug_names) |d| allocator.free(d); | |
| 845 | if (debug_frame) |d| allocator.free(d); | |
| 846 | return err; | |
| 813 | .sections = sections, | |
| 847 | 814 | }; |
| 848 | 815 | |
| 816 | try DW.openDwarfDebugInfo(&dwarf, allocator); | |
| 849 | 817 | di.debug_data = PdbOrDwarf{ .dwarf = dwarf }; |
| 850 | 818 | return di; |
| 851 | 819 | } |
| ... | ... | @@ -901,7 +869,7 @@ pub fn readElfDebugInfo( |
| 901 | 869 | }; |
| 902 | 870 | |
| 903 | 871 | const mapped_mem = try mapWholeFile(elf_file); |
| 904 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32SmallWithPoly(.IEEE).hash(mapped_mem)) return error.MissingDebugInfo; | |
| 872 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32SmallWithPoly(.IEEE).hash(mapped_mem)) return error.InvalidDebugInfo; | |
| 905 | 873 | |
| 906 | 874 | const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]); |
| 907 | 875 | if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
| ... | ... | @@ -916,36 +884,23 @@ pub fn readElfDebugInfo( |
| 916 | 884 | |
| 917 | 885 | const shoff = hdr.e_shoff; |
| 918 | 886 | const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx); |
| 919 | const str_shdr: *const elf.Shdr = @ptrCast(@alignCast( | |
| 920 | &mapped_mem[math.cast(usize, str_section_off) orelse return error.Overflow], | |
| 921 | )); | |
| 922 | const header_strings = mapped_mem[str_shdr.sh_offset .. str_shdr.sh_offset + str_shdr.sh_size]; | |
| 887 | const str_shdr: *const elf.Shdr = @ptrCast(@alignCast(&mapped_mem[math.cast(usize, str_section_off) orelse return error.Overflow])); | |
| 888 | const header_strings = mapped_mem[str_shdr.sh_offset..][0..str_shdr.sh_size]; | |
| 923 | 889 | const shdrs = @as( |
| 924 | 890 | [*]const elf.Shdr, |
| 925 | 891 | @ptrCast(@alignCast(&mapped_mem[shoff])), |
| 926 | 892 | )[0..hdr.e_shnum]; |
| 927 | 893 | |
| 928 | var opt_debug_info: ?[]const u8 = null; | |
| 929 | var opt_debug_abbrev: ?[]const u8 = null; | |
| 930 | var opt_debug_str: ?[]const u8 = null; | |
| 931 | var opt_debug_str_offsets: ?[]const u8 = null; | |
| 932 | var opt_debug_line: ?[]const u8 = null; | |
| 933 | var opt_debug_line_str: ?[]const u8 = null; | |
| 934 | var opt_debug_ranges: ?[]const u8 = null; | |
| 935 | var opt_debug_loclists: ?[]const u8 = null; | |
| 936 | var opt_debug_rnglists: ?[]const u8 = null; | |
| 937 | var opt_debug_addr: ?[]const u8 = null; | |
| 938 | var opt_debug_names: ?[]const u8 = null; | |
| 939 | var opt_debug_frame: ?[]const u8 = null; | |
| 940 | ||
| 941 | var owned_sections: [ModuleDebugInfo.num_sections][]const u8 = [_][]const u8{&.{}} ** ModuleDebugInfo.num_sections; | |
| 894 | const num_sections = std.enums.directEnumArrayLen(DW.DwarfSection, 0); | |
| 895 | var sections: [num_sections]?[]const u8 = [_]?[]const u8{null} ** num_sections; | |
| 896 | var owned_sections: [num_sections][]const u8 = [_][]const u8{&.{}} ** num_sections; | |
| 942 | 897 | errdefer for (owned_sections) |section| allocator.free(section); |
| 943 | 898 | |
| 944 | 899 | var separate_debug_filename: ?[]const u8 = null; |
| 945 | 900 | var separate_debug_crc: ?u32 = null; |
| 946 | 901 | |
| 947 | 902 | for (shdrs) |*shdr| { |
| 948 | if (shdr.sh_type == elf.SHT_NULL) continue; | |
| 903 | if (shdr.sh_type == elf.SHT_NULL or shdr.sh_type == elf.SHT_NOBITS) continue; | |
| 949 | 904 | const name = mem.sliceTo(header_strings[shdr.sh_name..], 0); |
| 950 | 905 | |
| 951 | 906 | if (mem.eql(u8, name, ".gnu_debuglink")) { |
| ... | ... | @@ -958,26 +913,11 @@ pub fn readElfDebugInfo( |
| 958 | 913 | continue; |
| 959 | 914 | } |
| 960 | 915 | |
| 961 | const sections = [_]struct { name: []const u8, out: *?[]const u8 }{ | |
| 962 | .{ .name = ".debug_info", .out = &opt_debug_info }, | |
| 963 | .{ .name = ".debug_abbrev", .out = &opt_debug_abbrev }, | |
| 964 | .{ .name = ".debug_str", .out = &opt_debug_str }, | |
| 965 | .{ .name = ".debug_str_offsets", .out = &opt_debug_str_offsets }, | |
| 966 | .{ .name = ".debug_line", .out = &opt_debug_line }, | |
| 967 | .{ .name = ".debug_line_str", .out = &opt_debug_line_str }, | |
| 968 | .{ .name = ".debug_ranges", .out = &opt_debug_ranges }, | |
| 969 | .{ .name = ".debug_loclists", .out = &opt_debug_loclists }, | |
| 970 | .{ .name = ".debug_rnglists", .out = &opt_debug_rnglists }, | |
| 971 | .{ .name = ".debug_addr", .out = &opt_debug_addr }, | |
| 972 | .{ .name = ".debug_names", .out = &opt_debug_names }, | |
| 973 | .{ .name = ".debug_frame", .out = &opt_debug_frame }, | |
| 974 | }; | |
| 975 | ||
| 976 | var section_index = for (sections, 0..) |section, i| { | |
| 977 | if (mem.eql(u8, section.name, name)) { | |
| 978 | break i; | |
| 979 | } | |
| 980 | } else continue; | |
| 916 | var section_index: ?usize = null; | |
| 917 | inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| { | |
| 918 | if (mem.eql(u8, "." ++ section.name, name)) section_index = i; | |
| 919 | } | |
| 920 | if (section_index == null) continue; | |
| 981 | 921 | |
| 982 | 922 | const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); |
| 983 | 923 | if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) { |
| ... | ... | @@ -997,25 +937,24 @@ pub fn readElfDebugInfo( |
| 997 | 937 | const read = zlib_stream.reader().readAll(decompressed_section) catch continue; |
| 998 | 938 | assert(read == decompressed_section.len); |
| 999 | 939 | |
| 1000 | sections[section_index].out.* = decompressed_section; | |
| 1001 | owned_sections[section_index] = decompressed_section; | |
| 940 | sections[section_index.?] = decompressed_section; | |
| 941 | owned_sections[section_index.?] = decompressed_section; | |
| 1002 | 942 | } else { |
| 1003 | sections[section_index].out.* = section_bytes; | |
| 1004 | } | |
| 943 | sections[section_index.?] = section_bytes; | |
| 944 | } | |
| 1005 | 945 | } |
| 1006 | 946 | |
| 1007 | 947 | const missing_debug_info = |
| 1008 | opt_debug_info == null or | |
| 1009 | opt_debug_abbrev == null or | |
| 1010 | opt_debug_str == null or | |
| 1011 | opt_debug_line == null; | |
| 948 | sections[@enumToInt(DW.DwarfSection.debug_info)] == null or | |
| 949 | sections[@enumToInt(DW.DwarfSection.debug_abbrev)] == null or | |
| 950 | sections[@enumToInt(DW.DwarfSection.debug_str)] == null or | |
| 951 | sections[@enumToInt(DW.DwarfSection.debug_line)] == null; | |
| 1012 | 952 | |
| 1013 | 953 | // Attempt to load debug info from an external file |
| 1014 | 954 | // See: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html |
| 1015 | 955 | if (missing_debug_info) { |
| 1016 | 956 | const global_debug_directories = [_][]const u8{ |
| 1017 | 957 | "/usr/lib/debug", |
| 1018 | // TODO: Determine the set of directories used by most distros for this path (check GDB sources) | |
| 1019 | 958 | }; |
| 1020 | 959 | |
| 1021 | 960 | // <global debug directory>/.build-id/<2-character id prefix>/<id remainder>.debug |
| ... | ... | @@ -1074,18 +1013,7 @@ pub fn readElfDebugInfo( |
| 1074 | 1013 | |
| 1075 | 1014 | var di = DW.DwarfInfo{ |
| 1076 | 1015 | .endian = endian, |
| 1077 | .debug_info = opt_debug_info.?, | |
| 1078 | .debug_abbrev = opt_debug_abbrev.?, | |
| 1079 | .debug_str = opt_debug_str.?, | |
| 1080 | .debug_str_offsets = opt_debug_str_offsets, | |
| 1081 | .debug_line = opt_debug_line.?, | |
| 1082 | .debug_line_str = opt_debug_line_str, | |
| 1083 | .debug_ranges = opt_debug_ranges, | |
| 1084 | .debug_loclists = opt_debug_loclists, | |
| 1085 | .debug_rnglists = opt_debug_rnglists, | |
| 1086 | .debug_addr = opt_debug_addr, | |
| 1087 | .debug_names = opt_debug_names, | |
| 1088 | .debug_frame = opt_debug_frame, | |
| 1016 | .sections = sections, | |
| 1089 | 1017 | }; |
| 1090 | 1018 | |
| 1091 | 1019 | try DW.openDwarfDebugInfo(&di, allocator); |
| ... | ... | @@ -1882,7 +1810,7 @@ pub const ModuleDebugInfo = switch (native_os) { |
| 1882 | 1810 | mapped_memory: []align(mem.page_size) const u8, |
| 1883 | 1811 | owned_sections: [num_sections][]const u8 = [_][]const u8{&.{}} ** num_sections, |
| 1884 | 1812 | |
| 1885 | const num_sections = 12; | |
| 1813 | const num_sections = 14; | |
| 1886 | 1814 | |
| 1887 | 1815 | fn deinit(self: *@This(), allocator: mem.Allocator) void { |
| 1888 | 1816 | self.dwarf.deinit(allocator); |
| ... | ... | @@ -1916,7 +1844,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo) |
| 1916 | 1844 | if (nosuspend di.findCompileUnit(address)) |compile_unit| { |
| 1917 | 1845 | return SymbolInfo{ |
| 1918 | 1846 | .symbol_name = nosuspend di.getSymbolName(address) orelse "???", |
| 1919 | .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name, di.debug_str, compile_unit.*) catch |err| switch (err) { | |
| 1847 | .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name, di.section(.debug_str), compile_unit.*) catch |err| switch (err) { | |
| 1920 | 1848 | error.MissingDebugInfo, error.InvalidDebugInfo => "???", |
| 1921 | 1849 | }, |
| 1922 | 1850 | .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) { |
lib/std/dwarf.zig+194-23| ... | ... | @@ -13,6 +13,7 @@ pub const OP = @import("dwarf/OP.zig"); |
| 13 | 13 | pub const LANG = @import("dwarf/LANG.zig"); |
| 14 | 14 | pub const FORM = @import("dwarf/FORM.zig"); |
| 15 | 15 | pub const ATE = @import("dwarf/ATE.zig"); |
| 16 | pub const EH = @import("dwarf/EH.zig"); | |
| 16 | 17 | |
| 17 | 18 | pub const LLE = struct { |
| 18 | 19 | pub const end_of_list = 0x00; |
| ... | ... | @@ -337,7 +338,7 @@ const Die = struct { |
| 337 | 338 | FormValue.String => |value| return value, |
| 338 | 339 | FormValue.StrPtr => |offset| return di.getString(offset), |
| 339 | 340 | FormValue.StrOffset => |index| { |
| 340 | const debug_str_offsets = di.debug_str_offsets orelse return badDwarf(); | |
| 341 | const debug_str_offsets = di.section(.debug_str_offsets) orelse return badDwarf(); | |
| 341 | 342 | if (compile_unit.str_offsets_base == 0) return badDwarf(); |
| 342 | 343 | if (compile_unit.is_64) { |
| 343 | 344 | const byte_offset = compile_unit.str_offsets_base + 8 * index; |
| ... | ... | @@ -642,26 +643,36 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con |
| 642 | 643 | return null; |
| 643 | 644 | } |
| 644 | 645 | |
| 646 | pub const DwarfSection = enum { | |
| 647 | debug_info, | |
| 648 | debug_abbrev, | |
| 649 | debug_str, | |
| 650 | debug_str_offsets, | |
| 651 | debug_line, | |
| 652 | debug_line_str, | |
| 653 | debug_ranges, | |
| 654 | debug_loclists, | |
| 655 | debug_rnglists, | |
| 656 | debug_addr, | |
| 657 | debug_names, | |
| 658 | debug_frame, | |
| 659 | eh_frame, | |
| 660 | eh_frame_hdr, | |
| 661 | }; | |
| 662 | ||
| 645 | 663 | pub const DwarfInfo = struct { |
| 646 | 664 | endian: std.builtin.Endian, |
| 647 | 665 | // No memory is owned by the DwarfInfo |
| 648 | debug_info: []const u8, | |
| 649 | debug_abbrev: []const u8, | |
| 650 | debug_str: []const u8, | |
| 651 | debug_str_offsets: ?[]const u8, | |
| 652 | debug_line: []const u8, | |
| 653 | debug_line_str: ?[]const u8, | |
| 654 | debug_ranges: ?[]const u8, | |
| 655 | debug_loclists: ?[]const u8, | |
| 656 | debug_rnglists: ?[]const u8, | |
| 657 | debug_addr: ?[]const u8, | |
| 658 | debug_names: ?[]const u8, | |
| 659 | debug_frame: ?[]const u8, | |
| 666 | sections: [std.enums.directEnumArrayLen(DwarfSection, 0)]?[]const u8, | |
| 660 | 667 | // Filled later by the initializer |
| 661 | 668 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, |
| 662 | 669 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 663 | 670 | func_list: std.ArrayListUnmanaged(Func) = .{}, |
| 664 | 671 | |
| 672 | pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 { | |
| 673 | return di.sections[@enumToInt(dwarf_section)]; | |
| 674 | } | |
| 675 | ||
| 665 | 676 | pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void { |
| 666 | 677 | for (di.abbrev_table_list.items) |*abbrev| { |
| 667 | 678 | abbrev.deinit(); |
| ... | ... | @@ -691,7 +702,7 @@ pub const DwarfInfo = struct { |
| 691 | 702 | } |
| 692 | 703 | |
| 693 | 704 | fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 694 | var stream = io.fixedBufferStream(di.debug_info); | |
| 705 | var stream = io.fixedBufferStream(di.section(.debug_info).?); | |
| 695 | 706 | const in = stream.reader(); |
| 696 | 707 | const seekable = &stream.seekableStream(); |
| 697 | 708 | var this_unit_offset: u64 = 0; |
| ... | ... | @@ -764,7 +775,7 @@ pub const DwarfInfo = struct { |
| 764 | 775 | // Prevent endless loops |
| 765 | 776 | while (depth > 0) : (depth -= 1) { |
| 766 | 777 | if (this_die_obj.getAttr(AT.name)) |_| { |
| 767 | const name = try this_die_obj.getAttrString(di, AT.name, di.debug_str, compile_unit); | |
| 778 | const name = try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit); | |
| 768 | 779 | break :x try allocator.dupe(u8, name); |
| 769 | 780 | } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| { |
| 770 | 781 | // Follow the DIE it points to and repeat |
| ... | ... | @@ -836,7 +847,7 @@ pub const DwarfInfo = struct { |
| 836 | 847 | } |
| 837 | 848 | |
| 838 | 849 | fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 839 | var stream = io.fixedBufferStream(di.debug_info); | |
| 850 | var stream = io.fixedBufferStream(di.section(.debug_info).?); | |
| 840 | 851 | const in = &stream.reader(); |
| 841 | 852 | const seekable = &stream.seekableStream(); |
| 842 | 853 | var this_unit_offset: u64 = 0; |
| ... | ... | @@ -930,7 +941,7 @@ pub const DwarfInfo = struct { |
| 930 | 941 | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 931 | 942 | } |
| 932 | 943 | |
| 933 | const opt_debug_ranges = if (compile_unit.version >= 5) di.debug_rnglists else di.debug_ranges; | |
| 944 | const opt_debug_ranges = if (compile_unit.version >= 5) di.section(.debug_rnglists) else di.section(.debug_ranges); | |
| 934 | 945 | const debug_ranges = opt_debug_ranges orelse continue; |
| 935 | 946 | |
| 936 | 947 | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| ... | ... | @@ -1065,7 +1076,7 @@ pub const DwarfInfo = struct { |
| 1065 | 1076 | } |
| 1066 | 1077 | |
| 1067 | 1078 | fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable { |
| 1068 | var stream = io.fixedBufferStream(di.debug_abbrev); | |
| 1079 | var stream = io.fixedBufferStream(di.section(.debug_abbrev).?); | |
| 1069 | 1080 | const in = &stream.reader(); |
| 1070 | 1081 | const seekable = &stream.seekableStream(); |
| 1071 | 1082 | |
| ... | ... | @@ -1146,11 +1157,11 @@ pub const DwarfInfo = struct { |
| 1146 | 1157 | compile_unit: CompileUnit, |
| 1147 | 1158 | target_address: u64, |
| 1148 | 1159 | ) !debug.LineInfo { |
| 1149 | var stream = io.fixedBufferStream(di.debug_line); | |
| 1160 | var stream = io.fixedBufferStream(di.section(.debug_line).?); | |
| 1150 | 1161 | const in = &stream.reader(); |
| 1151 | 1162 | const seekable = &stream.seekableStream(); |
| 1152 | 1163 | |
| 1153 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.debug_line_str, compile_unit); | |
| 1164 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit); | |
| 1154 | 1165 | const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); |
| 1155 | 1166 | |
| 1156 | 1167 | try seekable.seekTo(line_info_offset); |
| ... | ... | @@ -1416,15 +1427,15 @@ pub const DwarfInfo = struct { |
| 1416 | 1427 | } |
| 1417 | 1428 | |
| 1418 | 1429 | fn getString(di: DwarfInfo, offset: u64) ![]const u8 { |
| 1419 | return getStringGeneric(di.debug_str, offset); | |
| 1430 | return getStringGeneric(di.section(.debug_str), offset); | |
| 1420 | 1431 | } |
| 1421 | 1432 | |
| 1422 | 1433 | fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 { |
| 1423 | return getStringGeneric(di.debug_line_str, offset); | |
| 1434 | return getStringGeneric(di.section(.debug_line_str), offset); | |
| 1424 | 1435 | } |
| 1425 | 1436 | |
| 1426 | 1437 | fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 { |
| 1427 | const debug_addr = di.debug_addr orelse return badDwarf(); | |
| 1438 | const debug_addr = di.section(.debug_addr) orelse return badDwarf(); | |
| 1428 | 1439 | |
| 1429 | 1440 | // addr_base points to the first item after the header, however we |
| 1430 | 1441 | // need to read the header to know the size of each item. Empirically, |
| ... | ... | @@ -1455,6 +1466,12 @@ pub const DwarfInfo = struct { |
| 1455 | 1466 | pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 1456 | 1467 | try di.scanAllFunctions(allocator); |
| 1457 | 1468 | try di.scanAllCompileUnits(allocator); |
| 1469 | ||
| 1470 | // DEBUG | |
| 1471 | if (di.section(.eh_frame)) |eh_frame| { | |
| 1472 | _ = try CommonInformationEntry.parse(eh_frame, 8, .Little); | |
| 1473 | } | |
| 1474 | ||
| 1458 | 1475 | } |
| 1459 | 1476 | |
| 1460 | 1477 | /// This function is to make it handy to comment out the return and make it |
| ... | ... | @@ -1477,3 +1494,157 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { |
| 1477 | 1494 | const last = mem.indexOfScalarPos(u8, str, casted_offset, 0) orelse return badDwarf(); |
| 1478 | 1495 | return str[casted_offset..last :0]; |
| 1479 | 1496 | } |
| 1497 | ||
| 1498 | const EhPointer = struct { | |
| 1499 | value: union(enum) { | |
| 1500 | signed: i64, | |
| 1501 | unsigned: u64, | |
| 1502 | }, | |
| 1503 | relative_to: u8, | |
| 1504 | ||
| 1505 | // address of the encoded value | |
| 1506 | pc: u64, | |
| 1507 | ||
| 1508 | // TODO: Function to resolve the value given input state (.text start, .eh_frame_hdr start, functions start) | |
| 1509 | }; | |
| 1510 | ||
| 1511 | fn readEhPointer(enc: u8, pc: usize, addr_size_bytes: u8, endian: std.builtin.Endian, reader: anytype) !?EhPointer { | |
| 1512 | if (enc == EH.PE.omit) return null; | |
| 1513 | return EhPointer{ | |
| 1514 | .value = switch (enc & 0x0f) { | |
| 1515 | EH.PE.absptr => .{ .unsigned = switch (addr_size_bytes) { | |
| 1516 | 2 => try reader.readInt(u16, endian), | |
| 1517 | 4 => try reader.readInt(u32, endian), | |
| 1518 | 8 => try reader.readInt(u64, endian), | |
| 1519 | else => return error.InvalidAddrSize, | |
| 1520 | } }, | |
| 1521 | EH.PE.uleb128 => .{ .unsigned = try leb.readULEB128(u64, reader) }, | |
| 1522 | EH.PE.udata2 => .{ .unsigned = try reader.readInt(u16, endian) }, | |
| 1523 | EH.PE.udata4 => .{ .unsigned = try reader.readInt(u32, endian) }, | |
| 1524 | EH.PE.udata8 => .{ .unsigned = try reader.readInt(u64, endian) }, | |
| 1525 | EH.PE.sleb128 => .{ .signed = try leb.readILEB128(i64, reader) }, | |
| 1526 | EH.PE.sdata2 => .{ .signed = try reader.readInt(i16, endian) }, | |
| 1527 | EH.PE.sdata4 => .{ .signed = try reader.readInt(i32, endian) }, | |
| 1528 | EH.PE.sdata8 => .{ .signed = try reader.readInt(i64, endian) }, | |
| 1529 | else => return badDwarf(), | |
| 1530 | }, | |
| 1531 | .relative_to = enc & 0xf0, | |
| 1532 | .pc = pc | |
| 1533 | }; | |
| 1534 | } | |
| 1535 | ||
| 1536 | const CommonInformationEntry = struct { | |
| 1537 | length: u32, | |
| 1538 | id: u32, | |
| 1539 | version: u8, | |
| 1540 | code_alignment_factor: u64, | |
| 1541 | data_alignment_factor: u64, | |
| 1542 | return_address_register: u64, | |
| 1543 | ||
| 1544 | // Augmented data | |
| 1545 | lsda_pointer_enc: ?u8, | |
| 1546 | personality_routine_pointer: ?EhPointer, | |
| 1547 | fde_pointer_enc: ?u8, | |
| 1548 | ||
| 1549 | initial_instructions: []const u8, | |
| 1550 | ||
| 1551 | // The returned struct references memory in `bytes`. | |
| 1552 | pub fn parse(bytes: []const u8, addr_size_bytes: u8, endian: std.builtin.Endian) !CommonInformationEntry { | |
| 1553 | if (addr_size_bytes > 8) return error.InvalidAddrSize; | |
| 1554 | if (bytes.len < 4) return badDwarf(); | |
| 1555 | const length = mem.readInt(u32, bytes[0..4], endian); | |
| 1556 | const cie_bytes = bytes[4..][0..length]; | |
| 1557 | ||
| 1558 | var stream = io.fixedBufferStream(cie_bytes); | |
| 1559 | const reader = stream.reader(); | |
| 1560 | ||
| 1561 | const id = try reader.readInt(u32, endian); | |
| 1562 | if (id != 0) return badDwarf(); | |
| 1563 | ||
| 1564 | const version = try reader.readByte(); | |
| 1565 | if (version != 1) return badDwarf(); | |
| 1566 | ||
| 1567 | var has_eh_data = false; | |
| 1568 | var has_aug_data = false; | |
| 1569 | ||
| 1570 | var aug_str_len: usize = 0; | |
| 1571 | var aug_str_start = stream.pos; | |
| 1572 | var aug_byte = try reader.readByte(); | |
| 1573 | while (aug_byte != 0) : (aug_byte = try reader.readByte()) { | |
| 1574 | switch (aug_byte) { | |
| 1575 | 'z' => { | |
| 1576 | if (aug_str_len != 0) return badDwarf(); | |
| 1577 | has_aug_data = true; | |
| 1578 | aug_str_start = stream.pos; | |
| 1579 | }, | |
| 1580 | 'e' => { | |
| 1581 | if (has_aug_data or aug_str_len != 0) return badDwarf(); | |
| 1582 | if (try reader.readByte() != 'h') return badDwarf(); | |
| 1583 | has_eh_data = true; | |
| 1584 | }, | |
| 1585 | else => { | |
| 1586 | if (has_eh_data) return badDwarf(); | |
| 1587 | aug_str_len += 1; | |
| 1588 | }, | |
| 1589 | } | |
| 1590 | } | |
| 1591 | ||
| 1592 | if (has_eh_data) { | |
| 1593 | // legacy data created by older versions of gcc - ignored here | |
| 1594 | for (0..addr_size_bytes) |_| _ = try reader.readByte(); | |
| 1595 | } | |
| 1596 | ||
| 1597 | const code_alignment_factor = try leb.readULEB128(u64, reader); | |
| 1598 | const data_alignment_factor = try leb.readULEB128(u64, reader); | |
| 1599 | const return_address_register = try leb.readULEB128(u64, reader); | |
| 1600 | ||
| 1601 | var lsda_pointer_enc: ?u8 = null; | |
| 1602 | var personality_routine_pointer: ?EhPointer = null; | |
| 1603 | var fde_pointer_enc: ?u8 = null; | |
| 1604 | ||
| 1605 | if (has_aug_data) { | |
| 1606 | const aug_data_len = try leb.readULEB128(usize, reader); | |
| 1607 | const aug_data_start = stream.pos; | |
| 1608 | ||
| 1609 | const aug_str = cie_bytes[aug_str_start..][0..aug_str_len]; | |
| 1610 | for (aug_str) |byte| { | |
| 1611 | switch (byte) { | |
| 1612 | 'L' => { | |
| 1613 | lsda_pointer_enc = try reader.readByte(); | |
| 1614 | }, | |
| 1615 | 'P' => { | |
| 1616 | const personality_enc = try reader.readByte(); | |
| 1617 | personality_routine_pointer = try readEhPointer( | |
| 1618 | personality_enc, | |
| 1619 | @ptrToInt(&cie_bytes[stream.pos]), | |
| 1620 | addr_size_bytes, | |
| 1621 | endian, | |
| 1622 | reader, | |
| 1623 | ); | |
| 1624 | }, | |
| 1625 | 'R' => { | |
| 1626 | fde_pointer_enc = try reader.readByte(); | |
| 1627 | }, | |
| 1628 | else => return badDwarf(), | |
| 1629 | } | |
| 1630 | } | |
| 1631 | ||
| 1632 | // verify length field | |
| 1633 | if (stream.pos != (aug_data_start + aug_data_len)) return badDwarf(); | |
| 1634 | } | |
| 1635 | ||
| 1636 | const initial_instructions = cie_bytes[stream.pos..]; | |
| 1637 | return .{ | |
| 1638 | .length = length, | |
| 1639 | .id = id, | |
| 1640 | .version = version, | |
| 1641 | .code_alignment_factor = code_alignment_factor, | |
| 1642 | .data_alignment_factor = data_alignment_factor, | |
| 1643 | .return_address_register = return_address_register, | |
| 1644 | .lsda_pointer_enc = lsda_pointer_enc, | |
| 1645 | .personality_routine_pointer = personality_routine_pointer, | |
| 1646 | .fde_pointer_enc = fde_pointer_enc, | |
| 1647 | .initial_instructions = initial_instructions, | |
| 1648 | }; | |
| 1649 | } | |
| 1650 | }; |
lib/std/dwarf/EH.zig created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | pub const PE = struct { | |
| 2 | pub const absptr = 0x00; | |
| 3 | pub const uleb128 = 0x01; | |
| 4 | pub const udata2 = 0x02; | |
| 5 | pub const udata4 = 0x03; | |
| 6 | pub const udata8 = 0x04; | |
| 7 | pub const sleb128 = 0x09; | |
| 8 | pub const sdata2 = 0x0A; | |
| 9 | pub const sdata4 = 0x0B; | |
| 10 | pub const sdata8 = 0x0C; | |
| 11 | ||
| 12 | pub const pcrel = 0x10; | |
| 13 | pub const textrel = 0x20; | |
| 14 | pub const datarel = 0x30; | |
| 15 | pub const funcrel = 0x40; | |
| 16 | pub const aligned = 0x50; | |
| 17 | ||
| 18 | pub const omit = 0xff; | |
| 19 | }; |