| ... | ... | @@ -200,12 +200,10 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, |
| 200 | 200 | |
| 201 | 201 | pub const StackIterator = struct { |
| 202 | 202 | first_addr: ?usize, |
| 203 | | debug_info: *DebugInfo, |
| 204 | 203 | fp: usize, |
| 205 | 204 | |
| 206 | | pub fn init(debug_info: *DebugInfo, first_addr: ?usize) StackIterator { |
| 205 | pub fn init(first_addr: ?usize) StackIterator { |
| 207 | 206 | return StackIterator{ |
| 208 | | .debug_info = debug_info, |
| 209 | 207 | .first_addr = first_addr, |
| 210 | 208 | .fp = @ptrToInt(@frameAddress()), |
| 211 | 209 | }; |
| ... | ... | @@ -236,7 +234,7 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color |
| 236 | 234 | builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), |
| 237 | 235 | else => {}, |
| 238 | 236 | } |
| 239 | | var it = StackIterator.init(debug_info, start_addr); |
| 237 | var it = StackIterator.init(start_addr); |
| 240 | 238 | while (it.next()) |return_address| { |
| 241 | 239 | try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); |
| 242 | 240 | } |
| ... | ... | @@ -596,7 +594,6 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt |
| 596 | 594 | if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { |
| 597 | 595 | defer line_info.deinit(); |
| 598 | 596 | try printLineInfo( |
| 599 | | di, |
| 600 | 597 | out_stream, |
| 601 | 598 | line_info, |
| 602 | 599 | address, |
| ... | ... | @@ -620,7 +617,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt |
| 620 | 617 | /// This function works in freestanding mode. |
| 621 | 618 | /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void |
| 622 | 619 | pub fn printSourceAtAddressDwarf( |
| 623 | | debug_info: *DebugInfo, |
| 620 | debug_info: *DwarfInfo, |
| 624 | 621 | out_stream: var, |
| 625 | 622 | address: usize, |
| 626 | 623 | tty_color: bool, |
| ... | ... | @@ -639,7 +636,6 @@ pub fn printSourceAtAddressDwarf( |
| 639 | 636 | defer line_info.deinit(); |
| 640 | 637 | const symbol_name = "???"; |
| 641 | 638 | try printLineInfo( |
| 642 | | debug_info, |
| 643 | 639 | out_stream, |
| 644 | 640 | line_info, |
| 645 | 641 | address, |
| ... | ... | @@ -665,7 +661,6 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres |
| 665 | 661 | } |
| 666 | 662 | |
| 667 | 663 | fn printLineInfo( |
| 668 | | debug_info: *DebugInfo, |
| 669 | 664 | out_stream: var, |
| 670 | 665 | line_info: LineInfo, |
| 671 | 666 | address: usize, |
| ... | ... | @@ -900,36 +895,50 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { |
| 900 | 895 | return list.toOwnedSlice(); |
| 901 | 896 | } |
| 902 | 897 | |
| 903 | | pub fn openDwarfDebugInfo( |
| 898 | fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { |
| 899 | const elf_header = (try elf_file.findSection(name)) orelse return null; |
| 900 | return DwarfInfo.Section{ |
| 901 | .offset = elf_header.offset, |
| 902 | .size = elf_header.size, |
| 903 | }; |
| 904 | } |
| 905 | |
| 906 | /// Initialize DWARF info. The caller has the responsibility to initialize most |
| 907 | /// the DwarfInfo fields before calling. These fields can be left undefined: |
| 908 | /// * abbrev_table_list |
| 909 | /// * compile_unit_list |
| 910 | pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { |
| 911 | di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); |
| 912 | di.compile_unit_list = ArrayList(CompileUnit).init(allocator); |
| 913 | try scanAllCompileUnits(di); |
| 914 | } |
| 915 | |
| 916 | pub fn openElfDebugInfo( |
| 904 | 917 | allocator: *mem.Allocator, |
| 905 | | dwarf_seekable_stream: *DwarfSeekableStream, |
| 906 | | dwarf_in_stream: *DwarfInStream, |
| 907 | | ) !DebugInfo { |
| 908 | | var di = DebugInfo{ |
| 909 | | .dwarf_seekable_stream = dwarf_seekable_stream, |
| 910 | | .dwarf_in_stream = dwarf_in_stream, |
| 911 | | .elf = undefined, |
| 912 | | .debug_info = undefined, |
| 913 | | .debug_abbrev = undefined, |
| 914 | | .debug_str = undefined, |
| 915 | | .debug_line = undefined, |
| 916 | | .debug_ranges = null, |
| 917 | | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), |
| 918 | | .compile_unit_list = ArrayList(CompileUnit).init(allocator), |
| 918 | elf_seekable_stream: *DwarfSeekableStream, |
| 919 | elf_in_stream: *DwarfInStream, |
| 920 | ) !DwarfInfo { |
| 921 | var efile: elf.Elf = undefined; |
| 922 | try efile.openStream(allocator, elf_seekable_stream, elf_in_stream); |
| 923 | errdefer efile.close(); |
| 924 | |
| 925 | var di = DwarfInfo{ |
| 926 | .dwarf_seekable_stream = elf_seekable_stream, |
| 927 | .dwarf_in_stream = elf_in_stream, |
| 928 | .endian = efile.endian, |
| 929 | .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo, |
| 930 | .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo, |
| 931 | .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo, |
| 932 | .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo, |
| 933 | .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), |
| 934 | .abbrev_table_list = undefined, |
| 935 | .compile_unit_list = undefined, |
| 919 | 936 | }; |
| 920 | | try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream); |
| 921 | | errdefer di.elf.close(); |
| 922 | | |
| 923 | | di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; |
| 924 | | di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; |
| 925 | | di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; |
| 926 | | di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; |
| 927 | | di.debug_ranges = (try di.elf.findSection(".debug_ranges")); |
| 928 | | try scanAllCompileUnits(&di); |
| 937 | try openDwarfDebugInfo(&di, allocator); |
| 929 | 938 | return di; |
| 930 | 939 | } |
| 931 | 940 | |
| 932 | | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { |
| 941 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo { |
| 933 | 942 | const S = struct { |
| 934 | 943 | var self_exe_file: os.File = undefined; |
| 935 | 944 | var self_exe_seekable_stream: os.File.SeekableStream = undefined; |
| ... | ... | @@ -941,7 +950,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { |
| 941 | 950 | S.self_exe_seekable_stream = S.self_exe_file.seekableStream(); |
| 942 | 951 | S.self_exe_in_stream = S.self_exe_file.inStream(); |
| 943 | 952 | |
| 944 | | return openDwarfDebugInfo( |
| 953 | return openElfDebugInfo( |
| 945 | 954 | allocator, |
| 946 | 955 | // TODO https://github.com/ziglang/zig/issues/764 |
| 947 | 956 | @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream), |
| ... | ... | @@ -1086,26 +1095,27 @@ pub const DwarfInStream = io.InStream(anyerror); |
| 1086 | 1095 | pub const DwarfInfo = struct { |
| 1087 | 1096 | dwarf_seekable_stream: *DwarfSeekableStream, |
| 1088 | 1097 | dwarf_in_stream: *DwarfInStream, |
| 1089 | | elf: elf.Elf, |
| 1090 | | debug_info: *elf.SectionHeader, |
| 1091 | | debug_abbrev: *elf.SectionHeader, |
| 1092 | | debug_str: *elf.SectionHeader, |
| 1093 | | debug_line: *elf.SectionHeader, |
| 1094 | | debug_ranges: ?*elf.SectionHeader, |
| 1098 | endian: builtin.Endian, |
| 1099 | debug_info: Section, |
| 1100 | debug_abbrev: Section, |
| 1101 | debug_str: Section, |
| 1102 | debug_line: Section, |
| 1103 | debug_ranges: ?Section, |
| 1095 | 1104 | abbrev_table_list: ArrayList(AbbrevTableHeader), |
| 1096 | 1105 | compile_unit_list: ArrayList(CompileUnit), |
| 1097 | 1106 | |
| 1098 | | pub fn allocator(self: DebugInfo) *mem.Allocator { |
| 1107 | pub const Section = struct { |
| 1108 | offset: usize, |
| 1109 | size: usize, |
| 1110 | }; |
| 1111 | |
| 1112 | pub fn allocator(self: DwarfInfo) *mem.Allocator { |
| 1099 | 1113 | return self.abbrev_table_list.allocator; |
| 1100 | 1114 | } |
| 1101 | 1115 | |
| 1102 | | pub fn readString(self: *DebugInfo) ![]u8 { |
| 1116 | pub fn readString(self: *DwarfInfo) ![]u8 { |
| 1103 | 1117 | return readStringRaw(self.allocator(), self.dwarf_in_stream); |
| 1104 | 1118 | } |
| 1105 | | |
| 1106 | | pub fn close(self: *DebugInfo) void { |
| 1107 | | self.elf.close(); |
| 1108 | | } |
| 1109 | 1119 | }; |
| 1110 | 1120 | |
| 1111 | 1121 | pub const DebugInfo = switch (builtin.os) { |
| ... | ... | @@ -1236,7 +1246,7 @@ const Die = struct { |
| 1236 | 1246 | }; |
| 1237 | 1247 | } |
| 1238 | 1248 | |
| 1239 | | fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 { |
| 1249 | fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 { |
| 1240 | 1250 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 1241 | 1251 | return switch (form_value.*) { |
| 1242 | 1252 | FormValue.String => |value| value, |
| ... | ... | @@ -1253,7 +1263,7 @@ const FileEntry = struct { |
| 1253 | 1263 | len_bytes: usize, |
| 1254 | 1264 | }; |
| 1255 | 1265 | |
| 1256 | | const LineInfo = struct { |
| 1266 | pub const LineInfo = struct { |
| 1257 | 1267 | line: usize, |
| 1258 | 1268 | column: usize, |
| 1259 | 1269 | file_name: []const u8, |
| ... | ... | @@ -1352,7 +1362,7 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { |
| 1352 | 1362 | return buf.toSlice(); |
| 1353 | 1363 | } |
| 1354 | 1364 | |
| 1355 | | fn getString(di: *DebugInfo, offset: u64) ![]u8 { |
| 1365 | fn getString(di: *DwarfInfo, offset: u64) ![]u8 { |
| 1356 | 1366 | const pos = di.debug_str.offset + offset; |
| 1357 | 1367 | try di.dwarf_seekable_stream.seekTo(pos); |
| 1358 | 1368 | return di.readString(); |
| ... | ... | @@ -1452,7 +1462,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 |
| 1452 | 1462 | }; |
| 1453 | 1463 | } |
| 1454 | 1464 | |
| 1455 | | fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable { |
| 1465 | fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { |
| 1456 | 1466 | var result = AbbrevTable.init(di.allocator()); |
| 1457 | 1467 | while (true) { |
| 1458 | 1468 | const abbrev_code = try readULeb128(di.dwarf_in_stream); |
| ... | ... | @@ -1479,7 +1489,7 @@ fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable { |
| 1479 | 1489 | |
| 1480 | 1490 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 1481 | 1491 | /// seeks in the stream and parses it. |
| 1482 | | fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 1492 | fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 1483 | 1493 | for (di.abbrev_table_list.toSlice()) |*header| { |
| 1484 | 1494 | if (header.offset == abbrev_offset) { |
| 1485 | 1495 | return &header.table; |
| ... | ... | @@ -1500,7 +1510,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con |
| 1500 | 1510 | return null; |
| 1501 | 1511 | } |
| 1502 | 1512 | |
| 1503 | | fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { |
| 1513 | fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { |
| 1504 | 1514 | const abbrev_code = try readULeb128(di.dwarf_in_stream); |
| 1505 | 1515 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; |
| 1506 | 1516 | |
| ... | ... | @@ -1717,7 +1727,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 1717 | 1727 | return error.MissingDebugInfo; |
| 1718 | 1728 | } |
| 1719 | 1729 | |
| 1720 | | fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { |
| 1730 | fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { |
| 1721 | 1731 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); |
| 1722 | 1732 | |
| 1723 | 1733 | const debug_line_end = di.debug_line.offset + di.debug_line.size; |
| ... | ... | @@ -1737,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr |
| 1737 | 1747 | continue; |
| 1738 | 1748 | } |
| 1739 | 1749 | |
| 1740 | | const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); |
| 1750 | const version = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1741 | 1751 | // TODO support 3 and 5 |
| 1742 | 1752 | if (version != 2 and version != 4) return error.InvalidDebugInfo; |
| 1743 | 1753 | |
| 1744 | | const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); |
| 1754 | const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); |
| 1745 | 1755 | const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; |
| 1746 | 1756 | |
| 1747 | 1757 | const minimum_instruction_length = try di.dwarf_in_stream.readByte(); |
| ... | ... | @@ -1810,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr |
| 1810 | 1820 | return error.MissingDebugInfo; |
| 1811 | 1821 | }, |
| 1812 | 1822 | DW.LNE_set_address => { |
| 1813 | | const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize); |
| 1823 | const addr = try di.dwarf_in_stream.readInt(di.endian, usize); |
| 1814 | 1824 | prog.address = addr; |
| 1815 | 1825 | }, |
| 1816 | 1826 | DW.LNE_define_file => { |
| ... | ... | @@ -1872,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr |
| 1872 | 1882 | prog.address += inc_addr; |
| 1873 | 1883 | }, |
| 1874 | 1884 | DW.LNS_fixed_advance_pc => { |
| 1875 | | const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16); |
| 1885 | const arg = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1876 | 1886 | prog.address += arg; |
| 1877 | 1887 | }, |
| 1878 | 1888 | DW.LNS_set_prologue_end => {}, |
| ... | ... | @@ -1891,7 +1901,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr |
| 1891 | 1901 | return error.MissingDebugInfo; |
| 1892 | 1902 | } |
| 1893 | 1903 | |
| 1894 | | fn scanAllCompileUnits(di: *DebugInfo) !void { |
| 1904 | fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 1895 | 1905 | const debug_info_end = di.debug_info.offset + di.debug_info.size; |
| 1896 | 1906 | var this_unit_offset = di.debug_info.offset; |
| 1897 | 1907 | var cu_index: usize = 0; |
| ... | ... | @@ -1904,10 +1914,10 @@ fn scanAllCompileUnits(di: *DebugInfo) !void { |
| 1904 | 1914 | if (unit_length == 0) return; |
| 1905 | 1915 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| 1906 | 1916 | |
| 1907 | | const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); |
| 1917 | const version = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1908 | 1918 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 1909 | 1919 | |
| 1910 | | const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); |
| 1920 | const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); |
| 1911 | 1921 | |
| 1912 | 1922 | const address_size = try di.dwarf_in_stream.readByte(); |
| 1913 | 1923 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| ... | ... | @@ -1958,7 +1968,7 @@ fn scanAllCompileUnits(di: *DebugInfo) !void { |
| 1958 | 1968 | } |
| 1959 | 1969 | } |
| 1960 | 1970 | |
| 1961 | | fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit { |
| 1971 | fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { |
| 1962 | 1972 | for (di.compile_unit_list.toSlice()) |*compile_unit| { |
| 1963 | 1973 | if (compile_unit.pc_range) |range| { |
| 1964 | 1974 | if (target_address >= range.start and target_address < range.end) return compile_unit; |