authorgravatar for william@sengir.comWilliam Sengir <william@sengir.com> 2022-03-15 02:07:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-15 16:53:45-04:00
log6de8b4bc3d105c15cd473c5bf100db4c9328dd54
tree6f15f1b038b04aaf50ed03d7663c7e54d255a9b4
parent47e004d975669fea1297224e33a868742178c4b4

std.dwarf: implement basic DWARF 5 parsing

DWARF 5 moves around some fields and adds a few new ones that can't be parsed or ignored by our current DWARF 4 parser. This isn't a complete implementation of DWARF 5, but this is enough to make stack traces mostly work. Line numbers from C++ don't show up, but I know the info is there. I think the answer is to iterate through .debug_line_str in getLineNumberInfo, but I didn't want to fall into an even deeper rabbit hole tonight.

9 files changed, 310 insertions(+), 127 deletions(-)

lib/std/debug.zig+13
...@@ -797,6 +797,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo...@@ -797,6 +797,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
797 const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null;797 const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null;
798 const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null;798 const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null;
799 const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null;799 const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null;
800 const debug_line_str_data = di.coff.getSectionData(".debug_line_str", allocator) catch null;
800 const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null;801 const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null;
801802
802 var dwarf = DW.DwarfInfo{803 var dwarf = DW.DwarfInfo{
...@@ -805,6 +806,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo...@@ -805,6 +806,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
805 .debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo,806 .debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo,
806 .debug_str = debug_str_data orelse return error.MissingDebugInfo,807 .debug_str = debug_str_data orelse return error.MissingDebugInfo,
807 .debug_line = debug_line_data orelse return error.MissingDebugInfo,808 .debug_line = debug_line_data orelse return error.MissingDebugInfo,
809 .debug_line_str = debug_line_str_data,
808 .debug_ranges = debug_ranges_data,810 .debug_ranges = debug_ranges_data,
809 };811 };
810 try DW.openDwarfDebugInfo(&dwarf, allocator);812 try DW.openDwarfDebugInfo(&dwarf, allocator);
...@@ -871,6 +873,7 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -871,6 +873,7 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
871 var opt_debug_abbrev: ?[]const u8 = null;873 var opt_debug_abbrev: ?[]const u8 = null;
872 var opt_debug_str: ?[]const u8 = null;874 var opt_debug_str: ?[]const u8 = null;
873 var opt_debug_line: ?[]const u8 = null;875 var opt_debug_line: ?[]const u8 = null;
876 var opt_debug_line_str: ?[]const u8 = null;
874 var opt_debug_ranges: ?[]const u8 = null;877 var opt_debug_ranges: ?[]const u8 = null;
875878
876 for (shdrs) |*shdr| {879 for (shdrs) |*shdr| {
...@@ -885,6 +888,8 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -885,6 +888,8 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
885 opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);888 opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
886 } else if (mem.eql(u8, name, ".debug_line")) {889 } else if (mem.eql(u8, name, ".debug_line")) {
887 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);890 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
891 } else if (mem.eql(u8, name, ".debug_line_str")) {
892 opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
888 } else if (mem.eql(u8, name, ".debug_ranges")) {893 } else if (mem.eql(u8, name, ".debug_ranges")) {
889 opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);894 opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
890 }895 }
...@@ -896,6 +901,7 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -896,6 +901,7 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
896 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,901 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
897 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,902 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
898 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,903 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
904 .debug_line_str = opt_debug_line_str,
899 .debug_ranges = opt_debug_ranges,905 .debug_ranges = opt_debug_ranges,
900 };906 };
901907
...@@ -1434,6 +1440,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1434,6 +1440,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1434 var opt_debug_info: ?*const macho.section_64 = null;1440 var opt_debug_info: ?*const macho.section_64 = null;
1435 var opt_debug_abbrev: ?*const macho.section_64 = null;1441 var opt_debug_abbrev: ?*const macho.section_64 = null;
1436 var opt_debug_str: ?*const macho.section_64 = null;1442 var opt_debug_str: ?*const macho.section_64 = null;
1443 var opt_debug_line_str: ?*const macho.section_64 = null;
1437 var opt_debug_ranges: ?*const macho.section_64 = null;1444 var opt_debug_ranges: ?*const macho.section_64 = null;
14381445
1439 const sections = @ptrCast(1446 const sections = @ptrCast(
...@@ -1456,6 +1463,8 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1456,6 +1463,8 @@ pub const ModuleDebugInfo = switch (native_os) {
1456 opt_debug_abbrev = sect;1463 opt_debug_abbrev = sect;
1457 } else if (mem.eql(u8, name, "__debug_str")) {1464 } else if (mem.eql(u8, name, "__debug_str")) {
1458 opt_debug_str = sect;1465 opt_debug_str = sect;
1466 } else if (mem.eql(u8, name, "__debug_line_str")) {
1467 opt_debug_line_str = sect;
1459 } else if (mem.eql(u8, name, "__debug_ranges")) {1468 } else if (mem.eql(u8, name, "__debug_ranges")) {
1460 opt_debug_ranges = sect;1469 opt_debug_ranges = sect;
1461 }1470 }
...@@ -1476,6 +1485,10 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1476,6 +1485,10 @@ pub const ModuleDebugInfo = switch (native_os) {
1476 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),1485 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
1477 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),1486 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
1478 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),1487 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
1488 .debug_line_str = if (opt_debug_line_str) |debug_line_str|
1489 try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)
1490 else
1491 null,
1479 .debug_ranges = if (opt_debug_ranges) |debug_ranges|1492 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
1480 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)1493 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
1481 else1494 else
lib/std/dwarf.zig+88-127
...@@ -11,87 +11,20 @@ const ArrayList = std.ArrayList;...@@ -11,87 +11,20 @@ const ArrayList = std.ArrayList;
11pub const TAG = @import("dwarf/TAG.zig");11pub const TAG = @import("dwarf/TAG.zig");
12pub const AT = @import("dwarf/AT.zig");12pub const AT = @import("dwarf/AT.zig");
13pub const OP = @import("dwarf/OP.zig");13pub const OP = @import("dwarf/OP.zig");
1414pub const LANG = @import("dwarf/LANG.zig");
15pub const FORM = struct {15pub const FORM = @import("dwarf/FORM.zig");
16 pub const addr = 0x01;16pub const ATE = @import("dwarf/ATE.zig");
17 pub const block2 = 0x03;17
18 pub const block4 = 0x04;18pub const LLE = struct {
19 pub const data2 = 0x05;19 pub const end_of_list = 0x00;
20 pub const data4 = 0x06;20 pub const base_addressx = 0x01;
21 pub const data8 = 0x07;21 pub const startx_endx = 0x02;
22 pub const string = 0x08;22 pub const startx_length = 0x03;
23 pub const block = 0x09;23 pub const offset_pair = 0x04;
24 pub const block1 = 0x0a;24 pub const default_location = 0x05;
25 pub const data1 = 0x0b;25 pub const base_address = 0x06;
26 pub const flag = 0x0c;26 pub const start_end = 0x07;
27 pub const sdata = 0x0d;27 pub const start_length = 0x08;
28 pub const strp = 0x0e;
29 pub const udata = 0x0f;
30 pub const ref_addr = 0x10;
31 pub const ref1 = 0x11;
32 pub const ref2 = 0x12;
33 pub const ref4 = 0x13;
34 pub const ref8 = 0x14;
35 pub const ref_udata = 0x15;
36 pub const indirect = 0x16;
37 pub const sec_offset = 0x17;
38 pub const exprloc = 0x18;
39 pub const flag_present = 0x19;
40 pub const ref_sig8 = 0x20;
41
42 // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
43 pub const GNU_addr_index = 0x1f01;
44 pub const GNU_str_index = 0x1f02;
45
46 // Extensions for DWZ multifile.
47 // See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .
48 pub const GNU_ref_alt = 0x1f20;
49 pub const GNU_strp_alt = 0x1f21;
50};
51
52pub const ATE = struct {
53 pub const @"void" = 0x0;
54 pub const address = 0x1;
55 pub const boolean = 0x2;
56 pub const complex_float = 0x3;
57 pub const float = 0x4;
58 pub const signed = 0x5;
59 pub const signed_char = 0x6;
60 pub const unsigned = 0x7;
61 pub const unsigned_char = 0x8;
62
63 // DWARF 3.
64 pub const imaginary_float = 0x9;
65 pub const packed_decimal = 0xa;
66 pub const numeric_string = 0xb;
67 pub const edited = 0xc;
68 pub const signed_fixed = 0xd;
69 pub const unsigned_fixed = 0xe;
70 pub const decimal_float = 0xf;
71
72 // DWARF 4.
73 pub const UTF = 0x10;
74
75 pub const lo_user = 0x80;
76 pub const hi_user = 0xff;
77
78 // HP extensions.
79 pub const HP_float80 = 0x80; // Floating-point (80 bit).
80 pub const HP_complex_float80 = 0x81; // Complex floating-point (80 bit).
81 pub const HP_float128 = 0x82; // Floating-point (128 bit).
82 pub const HP_complex_float128 = 0x83; // Complex fp (128 bit).
83 pub const HP_floathpintel = 0x84; // Floating-point (82 bit IA64).
84 pub const HP_imaginary_float80 = 0x85;
85 pub const HP_imaginary_float128 = 0x86;
86 pub const HP_VAX_float = 0x88; // F or G floating.
87 pub const HP_VAX_float_d = 0x89; // D floating.
88 pub const HP_packed_decimal = 0x8a; // Cobol.
89 pub const HP_zoned_decimal = 0x8b; // Cobol.
90 pub const HP_edited = 0x8c; // Cobol.
91 pub const HP_signed_fixed = 0x8d; // Cobol.
92 pub const HP_unsigned_fixed = 0x8e; // Cobol.
93 pub const HP_VAX_complex_float = 0x8f; // F or G floating complex.
94 pub const HP_VAX_complex_float_d = 0x90; // D floating complex.
95};28};
9629
97pub const CFA = struct {30pub const CFA = struct {
...@@ -166,45 +99,6 @@ pub const LNE = struct {...@@ -166,45 +99,6 @@ pub const LNE = struct {
166 pub const hi_user = 0xff;99 pub const hi_user = 0xff;
167};100};
168101
169pub const LANG = struct {
170 pub const C89 = 0x0001;
171 pub const C = 0x0002;
172 pub const Ada83 = 0x0003;
173 pub const C_plus_plus = 0x0004;
174 pub const Cobol74 = 0x0005;
175 pub const Cobol85 = 0x0006;
176 pub const Fortran77 = 0x0007;
177 pub const Fortran90 = 0x0008;
178 pub const Pascal83 = 0x0009;
179 pub const Modula2 = 0x000a;
180 pub const Java = 0x000b;
181 pub const C99 = 0x000c;
182 pub const Ada95 = 0x000d;
183 pub const Fortran95 = 0x000e;
184 pub const PLI = 0x000f;
185 pub const ObjC = 0x0010;
186 pub const ObjC_plus_plus = 0x0011;
187 pub const UPC = 0x0012;
188 pub const D = 0x0013;
189 pub const Python = 0x0014;
190 pub const Go = 0x0016;
191 pub const C_plus_plus_11 = 0x001a;
192 pub const Rust = 0x001c;
193 pub const C11 = 0x001d;
194 pub const C_plus_plus_14 = 0x0021;
195 pub const Fortran03 = 0x0022;
196 pub const Fortran08 = 0x0023;
197 pub const lo_user = 0x8000;
198 pub const hi_user = 0xffff;
199 pub const Mips_Assembler = 0x8001;
200 pub const Upc = 0x8765;
201 pub const HP_Bliss = 0x8003;
202 pub const HP_Basic91 = 0x8004;
203 pub const HP_Pascal91 = 0x8005;
204 pub const HP_IMacro = 0x8006;
205 pub const HP_Assembler = 0x8007;
206};
207
208pub const UT = struct {102pub const UT = struct {
209 pub const compile = 0x01;103 pub const compile = 0x01;
210 pub const @"type" = 0x02;104 pub const @"type" = 0x02;
...@@ -212,6 +106,7 @@ pub const UT = struct {...@@ -212,6 +106,7 @@ pub const UT = struct {
212 pub const skeleton = 0x04;106 pub const skeleton = 0x04;
213 pub const split_compile = 0x05;107 pub const split_compile = 0x05;
214 pub const split_type = 0x06;108 pub const split_type = 0x06;
109
215 pub const lo_user = 0x80;110 pub const lo_user = 0x80;
216 pub const hi_user = 0xff;111 pub const hi_user = 0xff;
217};112};
...@@ -222,10 +117,22 @@ pub const LNCT = struct {...@@ -222,10 +117,22 @@ pub const LNCT = struct {
222 pub const timestamp = 0x3;117 pub const timestamp = 0x3;
223 pub const size = 0x4;118 pub const size = 0x4;
224 pub const MD5 = 0x5;119 pub const MD5 = 0x5;
120
225 pub const lo_user = 0x2000;121 pub const lo_user = 0x2000;
226 pub const hi_user = 0x3fff;122 pub const hi_user = 0x3fff;
227};123};
228124
125pub const RLE = struct {
126 pub const end_of_list = 0x00;
127 pub const base_addressx = 0x01;
128 pub const startx_endx = 0x02;
129 pub const startx_length = 0x03;
130 pub const offset_pair = 0x04;
131 pub const base_address = 0x05;
132 pub const start_end = 0x06;
133 pub const start_length = 0x07;
134};
135
229pub const CC = enum(u8) {136pub const CC = enum(u8) {
230 normal = 0x1,137 normal = 0x1,
231 program = 0x2,138 program = 0x2,
...@@ -276,6 +183,8 @@ const AbbrevTableEntry = struct {...@@ -276,6 +183,8 @@ const AbbrevTableEntry = struct {
276const AbbrevAttr = struct {183const AbbrevAttr = struct {
277 attr_id: u64,184 attr_id: u64,
278 form_id: u64,185 form_id: u64,
186 /// Only valid if form_id is .implicit_const
187 payload: i64,
279};188};
280189
281const FormValue = union(enum) {190const FormValue = union(enum) {
...@@ -289,6 +198,7 @@ const FormValue = union(enum) {...@@ -289,6 +198,7 @@ const FormValue = union(enum) {
289 RefAddr: u64,198 RefAddr: u64,
290 String: []const u8,199 String: []const u8,
291 StrPtr: u64,200 StrPtr: u64,
201 LineStrPtr: u64,
292};202};
293203
294const Constant = struct {204const Constant = struct {
...@@ -356,6 +266,7 @@ const Die = struct {...@@ -356,6 +266,7 @@ const Die = struct {
356 return switch (form_value.*) {266 return switch (form_value.*) {
357 FormValue.String => |value| value,267 FormValue.String => |value| value,
358 FormValue.StrPtr => |offset| di.getString(offset),268 FormValue.StrPtr => |offset| di.getString(offset),
269 FormValue.LineStrPtr => |offset| di.getLineString(offset),
359 else => error.InvalidDebugInfo,270 else => error.InvalidDebugInfo,
360 };271 };
361 }272 }
...@@ -588,6 +499,7 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -588,6 +499,7 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
588499
589 FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },500 FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
590 FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },501 FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },
502 FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) },
591 FORM.indirect => {503 FORM.indirect => {
592 const child_form_id = try nosuspend leb.readULEB128(u64, in_stream);504 const child_form_id = try nosuspend leb.readULEB128(u64, in_stream);
593 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64));505 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64));
...@@ -595,7 +507,12 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -595,7 +507,12 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
595 defer allocator.destroy(frame);507 defer allocator.destroy(frame);
596 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });508 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });
597 },509 },
598 else => error.InvalidDebugInfo,510 FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } },
511
512 else => {
513 std.debug.print("dwarf: unhandled form_id: 0x{x}\n", .{form_id});
514 return error.InvalidDebugInfo;
515 },
599 };516 };
600}517}
601518
...@@ -613,6 +530,7 @@ pub const DwarfInfo = struct {...@@ -613,6 +530,7 @@ pub const DwarfInfo = struct {
613 debug_abbrev: []const u8,530 debug_abbrev: []const u8,
614 debug_str: []const u8,531 debug_str: []const u8,
615 debug_line: []const u8,532 debug_line: []const u8,
533 debug_line_str: ?[]const u8,
616 debug_ranges: ?[]const u8,534 debug_ranges: ?[]const u8,
617 // Filled later by the initializer535 // Filled later by the initializer
618 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,536 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
...@@ -652,9 +570,20 @@ pub const DwarfInfo = struct {...@@ -652,9 +570,20 @@ pub const DwarfInfo = struct {
652 const version = try in.readInt(u16, di.endian);570 const version = try in.readInt(u16, di.endian);
653 if (version < 2 or version > 5) return error.InvalidDebugInfo;571 if (version < 2 or version > 5) return error.InvalidDebugInfo;
654572
655 const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);573 var address_size: u8 = undefined;
656574 var debug_abbrev_offset: u64 = undefined;
657 const address_size = try in.readByte();575 switch (version) {
576 5 => {
577 const unit_type = try in.readInt(u8, di.endian);
578 if (unit_type != UT.compile) return error.InvalidDebugInfo;
579 address_size = try in.readByte();
580 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
581 },
582 else => {
583 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
584 address_size = try in.readByte();
585 },
586 }
658 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;587 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
659588
660 const compile_unit_pos = try seekable.getPos();589 const compile_unit_pos = try seekable.getPos();
...@@ -756,9 +685,20 @@ pub const DwarfInfo = struct {...@@ -756,9 +685,20 @@ pub const DwarfInfo = struct {
756 const version = try in.readInt(u16, di.endian);685 const version = try in.readInt(u16, di.endian);
757 if (version < 2 or version > 5) return error.InvalidDebugInfo;686 if (version < 2 or version > 5) return error.InvalidDebugInfo;
758687
759 const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);688 var address_size: u8 = undefined;
760689 var debug_abbrev_offset: u64 = undefined;
761 const address_size = try in.readByte();690 switch (version) {
691 5 => {
692 const unit_type = try in.readInt(u8, di.endian);
693 if (unit_type != UT.compile) return error.InvalidDebugInfo;
694 address_size = try in.readByte();
695 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
696 },
697 else => {
698 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
699 address_size = try in.readByte();
700 },
701 }
762 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;702 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
763703
764 const compile_unit_pos = try seekable.getPos();704 const compile_unit_pos = try seekable.getPos();
...@@ -890,9 +830,12 @@ pub const DwarfInfo = struct {...@@ -890,9 +830,12 @@ pub const DwarfInfo = struct {
890 const attr_id = try leb.readULEB128(u64, in);830 const attr_id = try leb.readULEB128(u64, in);
891 const form_id = try leb.readULEB128(u64, in);831 const form_id = try leb.readULEB128(u64, in);
892 if (attr_id == 0 and form_id == 0) break;832 if (attr_id == 0 and form_id == 0) break;
833 // DW_FORM_implicit_const stores its value immediately after the attribute pair :(
834 const payload = if (form_id == FORM.implicit_const) try leb.readILEB128(i64, in) else undefined;
893 try attrs.append(AbbrevAttr{835 try attrs.append(AbbrevAttr{
894 .attr_id = attr_id,836 .attr_id = attr_id,
895 .form_id = form_id,837 .form_id = form_id,
838 .payload = payload,
896 });839 });
897 }840 }
898 }841 }
...@@ -914,6 +857,9 @@ pub const DwarfInfo = struct {...@@ -914,6 +857,9 @@ pub const DwarfInfo = struct {
914 .id = attr.attr_id,857 .id = attr.attr_id,
915 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, di.endian, is_64),858 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, di.endian, is_64),
916 };859 };
860 if (attr.form_id == FORM.implicit_const) {
861 result.attrs.items[i].value.Const.payload = @bitCast(u64, attr.payload);
862 }
917 }863 }
918 return result;864 return result;
919 }865 }
...@@ -1101,6 +1047,21 @@ pub const DwarfInfo = struct {...@@ -1101,6 +1047,21 @@ pub const DwarfInfo = struct {
11011047
1102 return error.InvalidDebugInfo;1048 return error.InvalidDebugInfo;
1103 }1049 }
1050
1051 fn getLineString(di: *DwarfInfo, offset: u64) ![]const u8 {
1052 const debug_line_str = di.debug_line_str orelse return error.InvalidDebugInfo;
1053 if (offset > debug_line_str.len)
1054 return error.InvalidDebugInfo;
1055 const casted_offset = math.cast(usize, offset) catch
1056 return error.InvalidDebugInfo;
1057
1058 // Valid strings always have a terminating zero byte
1059 if (mem.indexOfScalarPos(u8, debug_line_str, casted_offset, 0)) |last| {
1060 return debug_line_str[casted_offset..last];
1061 }
1062
1063 return error.InvalidDebugInfo;
1064 }
1104};1065};
11051066
1106/// Initialize DWARF info. The caller has the responsibility to initialize most1067/// Initialize DWARF info. The caller has the responsibility to initialize most
lib/std/dwarf/AT.zig+28
...@@ -99,7 +99,35 @@ pub const enum_class = 0x6d;...@@ -99,7 +99,35 @@ pub const enum_class = 0x6d;
99pub const linkage_name = 0x6e;99pub const linkage_name = 0x6e;
100100
101// DWARF 5101// DWARF 5
102pub const string_length_bit_size = 0x6f;
103pub const string_length_byte_size = 0x70;
104pub const rank = 0x71;
105pub const str_offsets_base = 0x72;
106pub const addr_base = 0x73;
107pub const rnglists_base = 0x74;
108pub const dwo_name = 0x76;
109pub const reference = 0x77;
110pub const rvalue_reference = 0x78;
111pub const macros = 0x79;
112pub const call_all_calls = 0x7a;
113pub const call_all_source_calls = 0x7b;
114pub const call_all_tail_calls = 0x7c;
115pub const call_return_pc = 0x7d;
116pub const call_value = 0x7e;
117pub const call_origin = 0x7f;
118pub const call_parameter = 0x80;
119pub const call_pc = 0x81;
120pub const call_tail_call = 0x82;
121pub const call_target = 0x83;
122pub const call_target_clobbered = 0x84;
123pub const call_data_location = 0x85;
124pub const call_data_value = 0x86;
125pub const @"noreturn" = 0x87;
102pub const alignment = 0x88;126pub const alignment = 0x88;
127pub const export_symbols = 0x89;
128pub const deleted = 0x8a;
129pub const defaulted = 0x8b;
130pub const loclists_base = 0x8c;
103131
104pub const lo_user = 0x2000; // Implementation-defined range start.132pub const lo_user = 0x2000; // Implementation-defined range start.
105pub const hi_user = 0x3fff; // Implementation-defined range end.133pub const hi_user = 0x3fff; // Implementation-defined range end.
lib/std/dwarf/ATE.zig created+46
...@@ -0,0 +1,46 @@
1pub const @"void" = 0x0;
2pub const address = 0x1;
3pub const boolean = 0x2;
4pub const complex_float = 0x3;
5pub const float = 0x4;
6pub const signed = 0x5;
7pub const signed_char = 0x6;
8pub const unsigned = 0x7;
9pub const unsigned_char = 0x8;
10
11// DWARF 3.
12pub const imaginary_float = 0x9;
13pub const packed_decimal = 0xa;
14pub const numeric_string = 0xb;
15pub const edited = 0xc;
16pub const signed_fixed = 0xd;
17pub const unsigned_fixed = 0xe;
18pub const decimal_float = 0xf;
19
20// DWARF 4.
21pub const UTF = 0x10;
22
23// DWARF 5.
24pub const UCS = 0x11;
25pub const ASCII = 0x12;
26
27pub const lo_user = 0x80;
28pub const hi_user = 0xff;
29
30// HP extensions.
31pub const HP_float80 = 0x80; // Floating-point (80 bit).
32pub const HP_complex_float80 = 0x81; // Complex floating-point (80 bit).
33pub const HP_float128 = 0x82; // Floating-point (128 bit).
34pub const HP_complex_float128 = 0x83; // Complex fp (128 bit).
35pub const HP_floathpintel = 0x84; // Floating-point (82 bit IA64).
36pub const HP_imaginary_float80 = 0x85;
37pub const HP_imaginary_float128 = 0x86;
38pub const HP_VAX_float = 0x88; // F or G floating.
39pub const HP_VAX_float_d = 0x89; // D floating.
40pub const HP_packed_decimal = 0x8a; // Cobol.
41pub const HP_zoned_decimal = 0x8b; // Cobol.
42pub const HP_edited = 0x8c; // Cobol.
43pub const HP_signed_fixed = 0x8d; // Cobol.
44pub const HP_unsigned_fixed = 0x8e; // Cobol.
45pub const HP_VAX_complex_float = 0x8f; // F or G floating complex.
46pub const HP_VAX_complex_float_d = 0x90; // D floating complex.
lib/std/dwarf/FORM.zig created+52
...@@ -0,0 +1,52 @@
1pub const addr = 0x01;
2pub const block2 = 0x03;
3pub const block4 = 0x04;
4pub const data2 = 0x05;
5pub const data4 = 0x06;
6pub const data8 = 0x07;
7pub const string = 0x08;
8pub const block = 0x09;
9pub const block1 = 0x0a;
10pub const data1 = 0x0b;
11pub const flag = 0x0c;
12pub const sdata = 0x0d;
13pub const strp = 0x0e;
14pub const udata = 0x0f;
15pub const ref_addr = 0x10;
16pub const ref1 = 0x11;
17pub const ref2 = 0x12;
18pub const ref4 = 0x13;
19pub const ref8 = 0x14;
20pub const ref_udata = 0x15;
21pub const indirect = 0x16;
22pub const sec_offset = 0x17;
23pub const exprloc = 0x18;
24pub const flag_present = 0x19;
25pub const strx = 0x1a;
26pub const addrx = 0x1b;
27pub const ref_sup4 = 0x1c;
28pub const strp_sup = 0x1d;
29pub const data16 = 0x1e;
30pub const line_strp = 0x1f;
31pub const ref_sig8 = 0x20;
32pub const implicit_const = 0x21;
33pub const loclistx = 0x22;
34pub const rnglistx = 0x23;
35pub const ref_sup8 = 0x24;
36pub const strx1 = 0x25;
37pub const strx2 = 0x26;
38pub const strx3 = 0x27;
39pub const strx4 = 0x28;
40pub const addrx1 = 0x29;
41pub const addrx2 = 0x2a;
42pub const addrx3 = 0x2b;
43pub const addrx4 = 0x2c;
44
45// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
46pub const GNU_addr_index = 0x1f01;
47pub const GNU_str_index = 0x1f02;
48
49// Extensions for DWZ multifile.
50// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .
51pub const GNU_ref_alt = 0x1f20;
52pub const GNU_strp_alt = 0x1f21;
lib/std/dwarf/LANG.zig created+48
...@@ -0,0 +1,48 @@
1pub const C89 = 0x0001;
2pub const C = 0x0002;
3pub const Ada83 = 0x0003;
4pub const C_plus_plus = 0x0004;
5pub const Cobol74 = 0x0005;
6pub const Cobol85 = 0x0006;
7pub const Fortran77 = 0x0007;
8pub const Fortran90 = 0x0008;
9pub const Pascal83 = 0x0009;
10pub const Modula2 = 0x000a;
11pub const Java = 0x000b;
12pub const C99 = 0x000c;
13pub const Ada95 = 0x000d;
14pub const Fortran95 = 0x000e;
15pub const PLI = 0x000f;
16pub const ObjC = 0x0010;
17pub const ObjC_plus_plus = 0x0011;
18pub const UPC = 0x0012;
19pub const D = 0x0013;
20pub const Python = 0x0014;
21pub const OpenCL = 0x0015;
22pub const Go = 0x0016;
23pub const Modula3 = 0x0017;
24pub const Haskell = 0x0018;
25pub const C_plus_plus_03 = 0x0019;
26pub const C_plus_plus_11 = 0x001a;
27pub const OCaml = 0x001b;
28pub const Rust = 0x001c;
29pub const C11 = 0x001d;
30pub const Swift = 0x001e;
31pub const Julia = 0x001f;
32pub const Dylan = 0x0020;
33pub const C_plus_plus_14 = 0x0021;
34pub const Fortran03 = 0x0022;
35pub const Fortran08 = 0x0023;
36pub const RenderScript = 0x0024;
37pub const BLISS = 0x0025;
38
39pub const lo_user = 0x8000;
40pub const hi_user = 0xffff;
41
42pub const Mips_Assembler = 0x8001;
43pub const Upc = 0x8765;
44pub const HP_Bliss = 0x8003;
45pub const HP_Basic91 = 0x8004;
46pub const HP_Pascal91 = 0x8005;
47pub const HP_IMacro = 0x8006;
48pub const HP_Assembler = 0x8007;
lib/std/dwarf/OP.zig+12
...@@ -157,6 +157,18 @@ pub const bit_piece = 0x9d;...@@ -157,6 +157,18 @@ pub const bit_piece = 0x9d;
157pub const implicit_value = 0x9e;157pub const implicit_value = 0x9e;
158pub const stack_value = 0x9f;158pub const stack_value = 0x9f;
159159
160// DWARF 5 extensions.
161pub const implicit_pointer = 0xa0;
162pub const addrx = 0xa1;
163pub const constx = 0xa2;
164pub const entry_value = 0xa3;
165pub const const_type = 0xa4;
166pub const regval_type = 0xa5;
167pub const deref_type = 0xa6;
168pub const xderef_type = 0xa7;
169pub const convert = 0xa8;
170pub const reinterpret = 0xa9;
171
160pub const lo_user = 0xe0; // Implementation-defined range start.172pub const lo_user = 0xe0; // Implementation-defined range start.
161pub const hi_user = 0xff; // Implementation-defined range end.173pub const hi_user = 0xff; // Implementation-defined range end.
162174
lib/std/dwarf/TAG.zig+10
...@@ -65,6 +65,16 @@ pub const type_unit = 0x41;...@@ -65,6 +65,16 @@ pub const type_unit = 0x41;
65pub const rvalue_reference_type = 0x42;65pub const rvalue_reference_type = 0x42;
66pub const template_alias = 0x43;66pub const template_alias = 0x43;
6767
68// DWARF 5
69pub const coarray_type = 0x44;
70pub const generic_subrange = 0x45;
71pub const dynamic_type = 0x46;
72pub const atomic_type = 0x47;
73pub const call_site = 0x48;
74pub const call_site_parameter = 0x49;
75pub const skeleton_unit = 0x4a;
76pub const immutable_type = 0x4b;
77
68pub const lo_user = 0x4080;78pub const lo_user = 0x4080;
69pub const hi_user = 0xffff;79pub const hi_user = 0xffff;
7080
src/link/MachO/Object.zig+13
...@@ -38,6 +38,7 @@ dwarf_debug_info_index: ?u16 = null,...@@ -38,6 +38,7 @@ dwarf_debug_info_index: ?u16 = null,
38dwarf_debug_abbrev_index: ?u16 = null,38dwarf_debug_abbrev_index: ?u16 = null,
39dwarf_debug_str_index: ?u16 = null,39dwarf_debug_str_index: ?u16 = null,
40dwarf_debug_line_index: ?u16 = null,40dwarf_debug_line_index: ?u16 = null,
41dwarf_debug_line_str_index: ?u16 = null,
41dwarf_debug_ranges_index: ?u16 = null,42dwarf_debug_ranges_index: ?u16 = null,
4243
43symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},44symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
...@@ -68,6 +69,7 @@ const DebugInfo = struct {...@@ -68,6 +69,7 @@ const DebugInfo = struct {
68 debug_abbrev: []u8,69 debug_abbrev: []u8,
69 debug_str: []u8,70 debug_str: []u8,
70 debug_line: []u8,71 debug_line: []u8,
72 debug_line_str: []u8,
71 debug_ranges: []u8,73 debug_ranges: []u8,
7274
73 pub fn parseFromObject(allocator: Allocator, object: *const Object) !?DebugInfo {75 pub fn parseFromObject(allocator: Allocator, object: *const Object) !?DebugInfo {
...@@ -87,6 +89,12 @@ const DebugInfo = struct {...@@ -87,6 +89,12 @@ const DebugInfo = struct {
87 const index = object.dwarf_debug_line_index orelse return null;89 const index = object.dwarf_debug_line_index orelse return null;
88 break :blk try object.readSection(allocator, index);90 break :blk try object.readSection(allocator, index);
89 };91 };
92 var debug_line_str = blk: {
93 if (object.dwarf_debug_line_str_index) |ind| {
94 break :blk try object.readSection(allocator, ind);
95 }
96 break :blk try allocator.alloc(u8, 0);
97 };
90 var debug_ranges = blk: {98 var debug_ranges = blk: {
91 if (object.dwarf_debug_ranges_index) |ind| {99 if (object.dwarf_debug_ranges_index) |ind| {
92 break :blk try object.readSection(allocator, ind);100 break :blk try object.readSection(allocator, ind);
...@@ -100,6 +108,7 @@ const DebugInfo = struct {...@@ -100,6 +108,7 @@ const DebugInfo = struct {
100 .debug_abbrev = debug_abbrev,108 .debug_abbrev = debug_abbrev,
101 .debug_str = debug_str,109 .debug_str = debug_str,
102 .debug_line = debug_line,110 .debug_line = debug_line,
111 .debug_line_str = debug_line_str,
103 .debug_ranges = debug_ranges,112 .debug_ranges = debug_ranges,
104 };113 };
105 try dwarf.openDwarfDebugInfo(&inner, allocator);114 try dwarf.openDwarfDebugInfo(&inner, allocator);
...@@ -110,6 +119,7 @@ const DebugInfo = struct {...@@ -110,6 +119,7 @@ const DebugInfo = struct {
110 .debug_abbrev = debug_abbrev,119 .debug_abbrev = debug_abbrev,
111 .debug_str = debug_str,120 .debug_str = debug_str,
112 .debug_line = debug_line,121 .debug_line = debug_line,
122 .debug_line_str = debug_line_str,
113 .debug_ranges = debug_ranges,123 .debug_ranges = debug_ranges,
114 };124 };
115 }125 }
...@@ -119,6 +129,7 @@ const DebugInfo = struct {...@@ -119,6 +129,7 @@ const DebugInfo = struct {
119 allocator.free(self.debug_abbrev);129 allocator.free(self.debug_abbrev);
120 allocator.free(self.debug_str);130 allocator.free(self.debug_str);
121 allocator.free(self.debug_line);131 allocator.free(self.debug_line);
132 allocator.free(self.debug_line_str);
122 allocator.free(self.debug_ranges);133 allocator.free(self.debug_ranges);
123 self.inner.abbrev_table_list.deinit();134 self.inner.abbrev_table_list.deinit();
124 self.inner.compile_unit_list.deinit();135 self.inner.compile_unit_list.deinit();
...@@ -285,6 +296,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -285,6 +296,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
285 self.dwarf_debug_str_index = index;296 self.dwarf_debug_str_index = index;
286 } else if (mem.eql(u8, sectname, "__debug_line")) {297 } else if (mem.eql(u8, sectname, "__debug_line")) {
287 self.dwarf_debug_line_index = index;298 self.dwarf_debug_line_index = index;
299 } else if (mem.eql(u8, sectname, "__debug_line_str")) {
300 self.dwarf_debug_line_str_index = index;
288 } else if (mem.eql(u8, sectname, "__debug_ranges")) {301 } else if (mem.eql(u8, sectname, "__debug_ranges")) {
289 self.dwarf_debug_ranges_index = index;302 self.dwarf_debug_ranges_index = index;
290 }303 }