authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-05-04 01:35:43-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:12-04:00
logf6148f123e35dcbec4b9ab7458967fa93277e443
treed1ee3ee1c739d339252871b3da3169a782f24161
parentea9917d9bd921f9fc14028a8dbf9e3f0f2579120

add CommonInformationEntry parser


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,52 +800,20 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDe
800 // This coff file has embedded DWARF debug info800 // This coff file has embedded DWARF debug info
801 _ = sec;801 _ = sec;
802802
803 const debug_info = coff_obj.getSectionDataAlloc(".debug_info", allocator) catch return error.MissingDebugInfo;803 const num_sections = std.enums.directEnumArrayLen(DW.DwarfSection, 0);
804 errdefer allocator.free(debug_info);804 var sections: [num_sections]?[]const u8 = [_]?[]const u8{null} ** num_sections;
805 const debug_abbrev = coff_obj.getSectionDataAlloc(".debug_abbrev", allocator) catch return error.MissingDebugInfo;805 errdefer for (sections) |section| if (section) |s| allocator.free(s);
806 errdefer allocator.free(debug_abbrev);806
807 const debug_str = coff_obj.getSectionDataAlloc(".debug_str", allocator) catch return error.MissingDebugInfo;807 inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
808 errdefer allocator.free(debug_str);808 sections[i] = try coff_obj.getSectionDataAlloc("." ++ section.name, allocator);
809 const debug_line = coff_obj.getSectionDataAlloc(".debug_line", allocator) catch return error.MissingDebugInfo;809 }
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;
820810
821 var dwarf = DW.DwarfInfo{811 var dwarf = DW.DwarfInfo{
822 .endian = native_endian,812 .endian = native_endian,
823 .debug_info = debug_info,813 .sections = sections,
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;
847 };814 };
848815
816 try DW.openDwarfDebugInfo(&dwarf, allocator);
849 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };817 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
850 return di;818 return di;
851 }819 }
...@@ -901,7 +869,7 @@ pub fn readElfDebugInfo(...@@ -901,7 +869,7 @@ pub fn readElfDebugInfo(
901 };869 };
902870
903 const mapped_mem = try mapWholeFile(elf_file);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;
905873
906 const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]);874 const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]);
907 if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;875 if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
...@@ -916,36 +884,23 @@ pub fn readElfDebugInfo(...@@ -916,36 +884,23 @@ pub fn readElfDebugInfo(
916884
917 const shoff = hdr.e_shoff;885 const shoff = hdr.e_shoff;
918 const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx);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(887 const str_shdr: *const elf.Shdr = @ptrCast(@alignCast(&mapped_mem[math.cast(usize, str_section_off) orelse return error.Overflow]));
920 &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];
921 ));
922 const header_strings = mapped_mem[str_shdr.sh_offset .. str_shdr.sh_offset + str_shdr.sh_size];
923 const shdrs = @as(889 const shdrs = @as(
924 [*]const elf.Shdr,890 [*]const elf.Shdr,
925 @ptrCast(@alignCast(&mapped_mem[shoff])),891 @ptrCast(@alignCast(&mapped_mem[shoff])),
926 )[0..hdr.e_shnum];892 )[0..hdr.e_shnum];
927893
928 var opt_debug_info: ?[]const u8 = null;894 const num_sections = std.enums.directEnumArrayLen(DW.DwarfSection, 0);
929 var opt_debug_abbrev: ?[]const u8 = null;895 var sections: [num_sections]?[]const u8 = [_]?[]const u8{null} ** num_sections;
930 var opt_debug_str: ?[]const u8 = null;896 var owned_sections: [num_sections][]const u8 = [_][]const u8{&.{}} ** num_sections;
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;
942 errdefer for (owned_sections) |section| allocator.free(section);897 errdefer for (owned_sections) |section| allocator.free(section);
943898
944 var separate_debug_filename: ?[]const u8 = null;899 var separate_debug_filename: ?[]const u8 = null;
945 var separate_debug_crc: ?u32 = null;900 var separate_debug_crc: ?u32 = null;
946901
947 for (shdrs) |*shdr| {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 const name = mem.sliceTo(header_strings[shdr.sh_name..], 0);904 const name = mem.sliceTo(header_strings[shdr.sh_name..], 0);
950905
951 if (mem.eql(u8, name, ".gnu_debuglink")) {906 if (mem.eql(u8, name, ".gnu_debuglink")) {
...@@ -958,26 +913,11 @@ pub fn readElfDebugInfo(...@@ -958,26 +913,11 @@ pub fn readElfDebugInfo(
958 continue;913 continue;
959 }914 }
960915
961 const sections = [_]struct { name: []const u8, out: *?[]const u8 }{916 var section_index: ?usize = null;
962 .{ .name = ".debug_info", .out = &opt_debug_info },917 inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
963 .{ .name = ".debug_abbrev", .out = &opt_debug_abbrev },918 if (mem.eql(u8, "." ++ section.name, name)) section_index = i;
964 .{ .name = ".debug_str", .out = &opt_debug_str },919 }
965 .{ .name = ".debug_str_offsets", .out = &opt_debug_str_offsets },920 if (section_index == null) continue;
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;
981921
982 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);922 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
983 if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) {923 if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) {
...@@ -997,25 +937,24 @@ pub fn readElfDebugInfo(...@@ -997,25 +937,24 @@ pub fn readElfDebugInfo(
997 const read = zlib_stream.reader().readAll(decompressed_section) catch continue;937 const read = zlib_stream.reader().readAll(decompressed_section) catch continue;
998 assert(read == decompressed_section.len);938 assert(read == decompressed_section.len);
999939
1000 sections[section_index].out.* = decompressed_section;940 sections[section_index.?] = decompressed_section;
1001 owned_sections[section_index] = decompressed_section;941 owned_sections[section_index.?] = decompressed_section;
1002 } else {942 } else {
1003 sections[section_index].out.* = section_bytes;943 sections[section_index.?] = section_bytes;
1004 }944 }
1005 }945 }
1006946
1007 const missing_debug_info =947 const missing_debug_info =
1008 opt_debug_info == null or948 sections[@enumToInt(DW.DwarfSection.debug_info)] == null or
1009 opt_debug_abbrev == null or949 sections[@enumToInt(DW.DwarfSection.debug_abbrev)] == null or
1010 opt_debug_str == null or950 sections[@enumToInt(DW.DwarfSection.debug_str)] == null or
1011 opt_debug_line == null;951 sections[@enumToInt(DW.DwarfSection.debug_line)] == null;
1012952
1013 // Attempt to load debug info from an external file953 // Attempt to load debug info from an external file
1014 // See: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html954 // See: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
1015 if (missing_debug_info) {955 if (missing_debug_info) {
1016 const global_debug_directories = [_][]const u8{956 const global_debug_directories = [_][]const u8{
1017 "/usr/lib/debug",957 "/usr/lib/debug",
1018 // TODO: Determine the set of directories used by most distros for this path (check GDB sources)
1019 };958 };
1020959
1021 // <global debug directory>/.build-id/<2-character id prefix>/<id remainder>.debug960 // <global debug directory>/.build-id/<2-character id prefix>/<id remainder>.debug
...@@ -1074,18 +1013,7 @@ pub fn readElfDebugInfo(...@@ -1074,18 +1013,7 @@ pub fn readElfDebugInfo(
10741013
1075 var di = DW.DwarfInfo{1014 var di = DW.DwarfInfo{
1076 .endian = endian,1015 .endian = endian,
1077 .debug_info = opt_debug_info.?,1016 .sections = sections,
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,
1089 };1017 };
10901018
1091 try DW.openDwarfDebugInfo(&di, allocator);1019 try DW.openDwarfDebugInfo(&di, allocator);
...@@ -1882,7 +1810,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1882,7 +1810,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1882 mapped_memory: []align(mem.page_size) const u8,1810 mapped_memory: []align(mem.page_size) const u8,
1883 owned_sections: [num_sections][]const u8 = [_][]const u8{&.{}} ** num_sections,1811 owned_sections: [num_sections][]const u8 = [_][]const u8{&.{}} ** num_sections,
18841812
1885 const num_sections = 12;1813 const num_sections = 14;
18861814
1887 fn deinit(self: *@This(), allocator: mem.Allocator) void {1815 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1888 self.dwarf.deinit(allocator);1816 self.dwarf.deinit(allocator);
...@@ -1916,7 +1844,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)...@@ -1916,7 +1844,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)
1916 if (nosuspend di.findCompileUnit(address)) |compile_unit| {1844 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
1917 return SymbolInfo{1845 return SymbolInfo{
1918 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",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 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1848 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1921 },1849 },
1922 .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {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,6 +13,7 @@ pub const OP = @import("dwarf/OP.zig");
13pub const LANG = @import("dwarf/LANG.zig");13pub const LANG = @import("dwarf/LANG.zig");
14pub const FORM = @import("dwarf/FORM.zig");14pub const FORM = @import("dwarf/FORM.zig");
15pub const ATE = @import("dwarf/ATE.zig");15pub const ATE = @import("dwarf/ATE.zig");
16pub const EH = @import("dwarf/EH.zig");
1617
17pub const LLE = struct {18pub const LLE = struct {
18 pub const end_of_list = 0x00;19 pub const end_of_list = 0x00;
...@@ -337,7 +338,7 @@ const Die = struct {...@@ -337,7 +338,7 @@ const Die = struct {
337 FormValue.String => |value| return value,338 FormValue.String => |value| return value,
338 FormValue.StrPtr => |offset| return di.getString(offset),339 FormValue.StrPtr => |offset| return di.getString(offset),
339 FormValue.StrOffset => |index| {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 if (compile_unit.str_offsets_base == 0) return badDwarf();342 if (compile_unit.str_offsets_base == 0) return badDwarf();
342 if (compile_unit.is_64) {343 if (compile_unit.is_64) {
343 const byte_offset = compile_unit.str_offsets_base + 8 * index;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,26 +643,36 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
642 return null;643 return null;
643}644}
644645
646pub 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
645pub const DwarfInfo = struct {663pub const DwarfInfo = struct {
646 endian: std.builtin.Endian,664 endian: std.builtin.Endian,
647 // No memory is owned by the DwarfInfo665 // No memory is owned by the DwarfInfo
648 debug_info: []const u8,666 sections: [std.enums.directEnumArrayLen(DwarfSection, 0)]?[]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,
660 // Filled later by the initializer667 // Filled later by the initializer
661 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},668 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
662 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},669 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
663 func_list: std.ArrayListUnmanaged(Func) = .{},670 func_list: std.ArrayListUnmanaged(Func) = .{},
664671
672 pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 {
673 return di.sections[@enumToInt(dwarf_section)];
674 }
675
665 pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void {676 pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void {
666 for (di.abbrev_table_list.items) |*abbrev| {677 for (di.abbrev_table_list.items) |*abbrev| {
667 abbrev.deinit();678 abbrev.deinit();
...@@ -691,7 +702,7 @@ pub const DwarfInfo = struct {...@@ -691,7 +702,7 @@ pub const DwarfInfo = struct {
691 }702 }
692703
693 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {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 const in = stream.reader();706 const in = stream.reader();
696 const seekable = &stream.seekableStream();707 const seekable = &stream.seekableStream();
697 var this_unit_offset: u64 = 0;708 var this_unit_offset: u64 = 0;
...@@ -764,7 +775,7 @@ pub const DwarfInfo = struct {...@@ -764,7 +775,7 @@ pub const DwarfInfo = struct {
764 // Prevent endless loops775 // Prevent endless loops
765 while (depth > 0) : (depth -= 1) {776 while (depth > 0) : (depth -= 1) {
766 if (this_die_obj.getAttr(AT.name)) |_| {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 break :x try allocator.dupe(u8, name);779 break :x try allocator.dupe(u8, name);
769 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {780 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
770 // Follow the DIE it points to and repeat781 // Follow the DIE it points to and repeat
...@@ -836,7 +847,7 @@ pub const DwarfInfo = struct {...@@ -836,7 +847,7 @@ pub const DwarfInfo = struct {
836 }847 }
837848
838 fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void {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 const in = &stream.reader();851 const in = &stream.reader();
841 const seekable = &stream.seekableStream();852 const seekable = &stream.seekableStream();
842 var this_unit_offset: u64 = 0;853 var this_unit_offset: u64 = 0;
...@@ -930,7 +941,7 @@ pub const DwarfInfo = struct {...@@ -930,7 +941,7 @@ pub const DwarfInfo = struct {
930 if (target_address >= range.start and target_address < range.end) return compile_unit;941 if (target_address >= range.start and target_address < range.end) return compile_unit;
931 }942 }
932943
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 const debug_ranges = opt_debug_ranges orelse continue;945 const debug_ranges = opt_debug_ranges orelse continue;
935946
936 const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue;947 const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue;
...@@ -1065,7 +1076,7 @@ pub const DwarfInfo = struct {...@@ -1065,7 +1076,7 @@ pub const DwarfInfo = struct {
1065 }1076 }
10661077
1067 fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable {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 const in = &stream.reader();1080 const in = &stream.reader();
1070 const seekable = &stream.seekableStream();1081 const seekable = &stream.seekableStream();
10711082
...@@ -1146,11 +1157,11 @@ pub const DwarfInfo = struct {...@@ -1146,11 +1157,11 @@ pub const DwarfInfo = struct {
1146 compile_unit: CompileUnit,1157 compile_unit: CompileUnit,
1147 target_address: u64,1158 target_address: u64,
1148 ) !debug.LineInfo {1159 ) !debug.LineInfo {
1149 var stream = io.fixedBufferStream(di.debug_line);1160 var stream = io.fixedBufferStream(di.section(.debug_line).?);
1150 const in = &stream.reader();1161 const in = &stream.reader();
1151 const seekable = &stream.seekableStream();1162 const seekable = &stream.seekableStream();
11521163
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 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);1165 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
11551166
1156 try seekable.seekTo(line_info_offset);1167 try seekable.seekTo(line_info_offset);
...@@ -1416,15 +1427,15 @@ pub const DwarfInfo = struct {...@@ -1416,15 +1427,15 @@ pub const DwarfInfo = struct {
1416 }1427 }
14171428
1418 fn getString(di: DwarfInfo, offset: u64) ![]const u8 {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 }
14211432
1422 fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 {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 }
14251436
1426 fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 {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();
14281439
1429 // addr_base points to the first item after the header, however we1440 // addr_base points to the first item after the header, however we
1430 // need to read the header to know the size of each item. Empirically,1441 // need to read the header to know the size of each item. Empirically,
...@@ -1455,6 +1466,12 @@ pub const DwarfInfo = struct {...@@ -1455,6 +1466,12 @@ pub const DwarfInfo = struct {
1455pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {1466pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
1456 try di.scanAllFunctions(allocator);1467 try di.scanAllFunctions(allocator);
1457 try di.scanAllCompileUnits(allocator);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}
14591476
1460/// This function is to make it handy to comment out the return and make it1477/// 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,3 +1494,157 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 {
1477 const last = mem.indexOfScalarPos(u8, str, casted_offset, 0) orelse return badDwarf();1494 const last = mem.indexOfScalarPos(u8, str, casted_offset, 0) orelse return badDwarf();
1478 return str[casted_offset..last :0];1495 return str[casted_offset..last :0];
1479}1496}
1497
1498const 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
1511fn 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
1536const 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 @@
1pub 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};