| ... | @@ -26,7 +26,6 @@ const cast = std.math.cast; | ... | @@ -26,7 +26,6 @@ const cast = std.math.cast; |
| 26 | const maxInt = std.math.maxInt; | 26 | const maxInt = std.math.maxInt; |
| 27 | const MemoryAccessor = std.debug.MemoryAccessor; | 27 | const MemoryAccessor = std.debug.MemoryAccessor; |
| 28 | const Path = std.Build.Cache.Path; | 28 | const Path = std.Build.Cache.Path; |
| 29 | | | |
| 30 | const FixedBufferReader = std.debug.FixedBufferReader; | 29 | const FixedBufferReader = std.debug.FixedBufferReader; |
| 31 | | 30 | |
| 32 | const Dwarf = @This(); | 31 | const Dwarf = @This(); |
| ... | @@ -35,6 +34,9 @@ pub const expression = @import("Dwarf/expression.zig"); | ... | @@ -35,6 +34,9 @@ pub const expression = @import("Dwarf/expression.zig"); |
| 35 | pub const abi = @import("Dwarf/abi.zig"); | 34 | pub const abi = @import("Dwarf/abi.zig"); |
| 36 | pub const call_frame = @import("Dwarf/call_frame.zig"); | 35 | pub const call_frame = @import("Dwarf/call_frame.zig"); |
| 37 | | 36 | |
| | 37 | /// Useful to temporarily enable while working on this file. |
| | 38 | const debug_debug_mode = false; |
| | 39 | |
| 38 | endian: std.builtin.Endian, | 40 | endian: std.builtin.Endian, |
| 39 | sections: SectionArray = null_section_array, | 41 | sections: SectionArray = null_section_array, |
| 40 | is_macho: bool, | 42 | is_macho: bool, |
| ... | @@ -165,6 +167,16 @@ pub const CompileUnit = struct { | ... | @@ -165,6 +167,16 @@ pub const CompileUnit = struct { |
| 165 | column: u32, | 167 | column: u32, |
| 166 | /// Offset by 1 depending on whether Dwarf version is >= 5. | 168 | /// Offset by 1 depending on whether Dwarf version is >= 5. |
| 167 | file: u32, | 169 | file: u32, |
| | 170 | |
| | 171 | pub const invalid: LineEntry = .{ |
| | 172 | .line = undefined, |
| | 173 | .column = undefined, |
| | 174 | .file = std.math.maxInt(u32), |
| | 175 | }; |
| | 176 | |
| | 177 | pub fn isInvalid(le: LineEntry) bool { |
| | 178 | return le.file == invalid.file; |
| | 179 | } |
| 168 | }; | 180 | }; |
| 169 | | 181 | |
| 170 | pub fn findSource(slc: *const SrcLocCache, address: u64) !LineEntry { | 182 | pub fn findSource(slc: *const SrcLocCache, address: u64) !LineEntry { |
| ... | @@ -1400,6 +1412,7 @@ fn parseDie( | ... | @@ -1400,6 +1412,7 @@ fn parseDie( |
| 1400 | }; | 1412 | }; |
| 1401 | } | 1413 | } |
| 1402 | | 1414 | |
| | 1415 | /// Ensures that addresses in the returned LineTable are monotonically increasing. |
| 1403 | fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) !CompileUnit.SrcLocCache { | 1416 | fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) !CompileUnit.SrcLocCache { |
| 1404 | const compile_unit_cwd = try compile_unit.die.getAttrString(d, AT.comp_dir, d.section(.debug_line_str), compile_unit.*); | 1417 | const compile_unit_cwd = try compile_unit.die.getAttrString(d, AT.comp_dir, d.section(.debug_line_str), compile_unit.*); |
| 1405 | const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); | 1418 | const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); |
| ... | @@ -1575,8 +1588,19 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! | ... | @@ -1575,8 +1588,19 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! |
| 1575 | const sub_op = try fbr.readByte(); | 1588 | const sub_op = try fbr.readByte(); |
| 1576 | switch (sub_op) { | 1589 | switch (sub_op) { |
| 1577 | DW.LNE.end_sequence => { | 1590 | DW.LNE.end_sequence => { |
| 1578 | prog.end_sequence = true; | 1591 | // The row being added here is an "end" address, meaning |
| 1579 | try prog.addRow(gpa, &line_table); | 1592 | // that it does not map to the source location here - |
| | 1593 | // rather it marks the previous address as the last address |
| | 1594 | // that maps to this source location. |
| | 1595 | |
| | 1596 | // In this implementation we don't mark end of addresses. |
| | 1597 | // This is a performance optimization based on the fact |
| | 1598 | // that we don't need to know if an address is missing |
| | 1599 | // source location info; we are only interested in being |
| | 1600 | // able to look up source location info for addresses that |
| | 1601 | // are known to have debug info. |
| | 1602 | //if (debug_debug_mode) assert(!line_table.contains(prog.address)); |
| | 1603 | //try line_table.put(gpa, prog.address, CompileUnit.SrcLocCache.LineEntry.invalid); |
| 1580 | prog.reset(); | 1604 | prog.reset(); |
| 1581 | }, | 1605 | }, |
| 1582 | DW.LNE.set_address => { | 1606 | DW.LNE.set_address => { |
| ... | @@ -1651,6 +1675,17 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! | ... | @@ -1651,6 +1675,17 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! |
| 1651 | } | 1675 | } |
| 1652 | } | 1676 | } |
| 1653 | | 1677 | |
| | 1678 | // Dwarf standard v5, 6.2.5 says |
| | 1679 | // > Within a sequence, addresses and operation pointers may only increase. |
| | 1680 | // However, this is empirically not the case in reality, so we sort here. |
| | 1681 | line_table.sortUnstable(struct { |
| | 1682 | keys: []const u64, |
| | 1683 | |
| | 1684 | pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { |
| | 1685 | return ctx.keys[a_index] < ctx.keys[b_index]; |
| | 1686 | } |
| | 1687 | }{ .keys = line_table.keys() }); |
| | 1688 | |
| 1654 | return .{ | 1689 | return .{ |
| 1655 | .line_table = line_table, | 1690 | .line_table = line_table, |
| 1656 | .directories = try directories.toOwnedSlice(gpa), | 1691 | .directories = try directories.toOwnedSlice(gpa), |
| ... | @@ -1895,7 +1930,6 @@ const LineNumberProgram = struct { | ... | @@ -1895,7 +1930,6 @@ const LineNumberProgram = struct { |
| 1895 | version: u16, | 1930 | version: u16, |
| 1896 | is_stmt: bool, | 1931 | is_stmt: bool, |
| 1897 | basic_block: bool, | 1932 | basic_block: bool, |
| 1898 | end_sequence: bool, | | |
| 1899 | | 1933 | |
| 1900 | default_is_stmt: bool, | 1934 | default_is_stmt: bool, |
| 1901 | | 1935 | |
| ... | @@ -1907,7 +1941,6 @@ const LineNumberProgram = struct { | ... | @@ -1907,7 +1941,6 @@ const LineNumberProgram = struct { |
| 1907 | self.column = 0; | 1941 | self.column = 0; |
| 1908 | self.is_stmt = self.default_is_stmt; | 1942 | self.is_stmt = self.default_is_stmt; |
| 1909 | self.basic_block = false; | 1943 | self.basic_block = false; |
| 1910 | self.end_sequence = false; | | |
| 1911 | } | 1944 | } |
| 1912 | | 1945 | |
| 1913 | pub fn init(is_stmt: bool, version: u16) LineNumberProgram { | 1946 | pub fn init(is_stmt: bool, version: u16) LineNumberProgram { |
| ... | @@ -1919,13 +1952,16 @@ const LineNumberProgram = struct { | ... | @@ -1919,13 +1952,16 @@ const LineNumberProgram = struct { |
| 1919 | .version = version, | 1952 | .version = version, |
| 1920 | .is_stmt = is_stmt, | 1953 | .is_stmt = is_stmt, |
| 1921 | .basic_block = false, | 1954 | .basic_block = false, |
| 1922 | .end_sequence = false, | | |
| 1923 | .default_is_stmt = is_stmt, | 1955 | .default_is_stmt = is_stmt, |
| 1924 | }; | 1956 | }; |
| 1925 | } | 1957 | } |
| 1926 | | 1958 | |
| 1927 | pub fn addRow(prog: *LineNumberProgram, gpa: Allocator, table: *CompileUnit.SrcLocCache.LineTable) !void { | 1959 | pub fn addRow(prog: *LineNumberProgram, gpa: Allocator, table: *CompileUnit.SrcLocCache.LineTable) !void { |
| 1928 | if (prog.line == 0) return; // garbage data | 1960 | if (prog.line == 0) { |
| | 1961 | //if (debug_debug_mode) @panic("garbage line data"); |
| | 1962 | return; |
| | 1963 | } |
| | 1964 | if (debug_debug_mode) assert(!table.contains(prog.address)); |
| 1929 | try table.put(gpa, prog.address, .{ | 1965 | try table.put(gpa, prog.address, .{ |
| 1930 | .line = cast(u32, prog.line) orelse maxInt(u32), | 1966 | .line = cast(u32, prog.line) orelse maxInt(u32), |
| 1931 | .column = cast(u32, prog.column) orelse maxInt(u32), | 1967 | .column = cast(u32, prog.column) orelse maxInt(u32), |
| ... | @@ -1972,12 +2008,12 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 { | ... | @@ -1972,12 +2008,12 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 { |
| 1972 | /// This function is to make it handy to comment out the return and make it | 2008 | /// This function is to make it handy to comment out the return and make it |
| 1973 | /// into a crash when working on this file. | 2009 | /// into a crash when working on this file. |
| 1974 | pub fn bad() error{InvalidDebugInfo} { | 2010 | pub fn bad() error{InvalidDebugInfo} { |
| 1975 | //if (true) @panic("bad dwarf"); // can be handy to uncomment when working on this file | 2011 | if (debug_debug_mode) @panic("bad dwarf"); |
| 1976 | return error.InvalidDebugInfo; | 2012 | return error.InvalidDebugInfo; |
| 1977 | } | 2013 | } |
| 1978 | | 2014 | |
| 1979 | fn missing() error{MissingDebugInfo} { | 2015 | fn missing() error{MissingDebugInfo} { |
| 1980 | //if (true) @panic("missing dwarf"); // can be handy to uncomment when working on this file | 2016 | if (debug_debug_mode) @panic("missing dwarf"); |
| 1981 | return error.MissingDebugInfo; | 2017 | return error.MissingDebugInfo; |
| 1982 | } | 2018 | } |
| 1983 | | 2019 | |