authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-02 23:31:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-07 00:48:32-07:00
log1792258dc813cde7083fd7860442e6ec92afd4ba
treee338b76af71a6124bc67a6877659d1634d2ff5e1
parent66954e833051872308641b3a1af12aa865d5d59a

std.debug.Dwarf: precompute .debug_line table

yields a 60x speedup for resolveSourceLocations in debug builds

3 files changed, 150 insertions(+), 166 deletions(-)

lib/std/debug.zig+1-1
...@@ -762,7 +762,7 @@ pub fn writeCurrentStackTrace(...@@ -762,7 +762,7 @@ pub fn writeCurrentStackTrace(
762 // an overflow. We do not need to signal `StackIterator` as it will correctly detect this762 // an overflow. We do not need to signal `StackIterator` as it will correctly detect this
763 // condition on the subsequent iteration and return `null` thus terminating the loop.763 // condition on the subsequent iteration and return `null` thus terminating the loop.
764 // same behaviour for x86-windows-msvc764 // same behaviour for x86-windows-msvc
765 const address = if (return_address == 0) return_address else return_address - 1;765 const address = return_address -| 1;
766 try printSourceAtAddress(debug_info, out_stream, address, tty_config);766 try printSourceAtAddress(debug_info, out_stream, address, tty_config);
767 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);767 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);
768}768}
lib/std/debug/Dwarf.zig+146-164
...@@ -138,6 +138,29 @@ pub const CompileUnit = struct {...@@ -138,6 +138,29 @@ pub const CompileUnit = struct {
138 rnglists_base: usize,138 rnglists_base: usize,
139 loclists_base: usize,139 loclists_base: usize,
140 frame_base: ?*const FormValue,140 frame_base: ?*const FormValue,
141
142 src_loc_cache: ?SrcLocCache,
143
144 pub const SrcLocCache = struct {
145 line_table: LineTable,
146 directories: []const FileEntry,
147 files: []FileEntry,
148 version: u16,
149
150 pub const LineTable = std.AutoArrayHashMapUnmanaged(u64, LineEntry);
151
152 pub const LineEntry = struct {
153 line: u32,
154 column: u32,
155 file: u32,
156 };
157
158 pub fn findSource(slc: *const SrcLocCache, address: u64) !LineEntry {
159 const index = std.sort.upperBound(u64, address, slc.line_table.keys(), {}, std.sort.asc(u64));
160 if (index == 0) return missing();
161 return slc.line_table.values()[index - 1];
162 }
163 };
141};164};
142165
143pub const FormValue = union(enum) {166pub const FormValue = union(enum) {
...@@ -760,6 +783,11 @@ pub fn deinit(di: *Dwarf, gpa: Allocator) void {...@@ -760,6 +783,11 @@ pub fn deinit(di: *Dwarf, gpa: Allocator) void {
760 }783 }
761 di.abbrev_table_list.deinit(gpa);784 di.abbrev_table_list.deinit(gpa);
762 for (di.compile_unit_list.items) |*cu| {785 for (di.compile_unit_list.items) |*cu| {
786 if (cu.src_loc_cache) |*slc| {
787 slc.line_table.deinit(gpa);
788 gpa.free(slc.directories);
789 gpa.free(slc.files);
790 }
763 cu.die.deinit(gpa);791 cu.die.deinit(gpa);
764 }792 }
765 di.compile_unit_list.deinit(gpa);793 di.compile_unit_list.deinit(gpa);
...@@ -846,6 +874,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void {...@@ -846,6 +874,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void {
846 .rnglists_base = 0,874 .rnglists_base = 0,
847 .loclists_base = 0,875 .loclists_base = 0,
848 .frame_base = null,876 .frame_base = null,
877 .src_loc_cache = null,
849 };878 };
850879
851 while (true) {880 while (true) {
...@@ -1032,6 +1061,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator) ScanError!void {...@@ -1032,6 +1061,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator) ScanError!void {
1032 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,1061 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
1033 .loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,1062 .loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
1034 .frame_base = compile_unit_die.getAttr(AT.frame_base),1063 .frame_base = compile_unit_die.getAttr(AT.frame_base),
1064 .src_loc_cache = null,
1035 };1065 };
10361066
1037 compile_unit.pc_range = x: {1067 compile_unit.pc_range = x: {
...@@ -1242,7 +1272,7 @@ const DebugRangeIterator = struct {...@@ -1242,7 +1272,7 @@ const DebugRangeIterator = struct {
1242};1272};
12431273
1244/// TODO: change this to binary searching the sorted compile unit list1274/// TODO: change this to binary searching the sorted compile unit list
1245pub fn findCompileUnit(di: *const Dwarf, target_address: u64) !*const CompileUnit {1275pub fn findCompileUnit(di: *const Dwarf, target_address: u64) !*CompileUnit {
1246 for (di.compile_unit_list.items) |*compile_unit| {1276 for (di.compile_unit_list.items) |*compile_unit| {
1247 if (compile_unit.pc_range) |range| {1277 if (compile_unit.pc_range) |range| {
1248 if (target_address >= range.start and target_address < range.end) return compile_unit;1278 if (target_address >= range.start and target_address < range.end) return compile_unit;
...@@ -1352,34 +1382,36 @@ fn parseDie(...@@ -1352,34 +1382,36 @@ fn parseDie(
1352 };1382 };
1353}1383}
13541384
1355pub fn getLineNumberInfo(1385fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) !CompileUnit.SrcLocCache {
1356 di: *Dwarf,1386 const compile_unit_cwd = try compile_unit.die.getAttrString(d, AT.comp_dir, d.section(.debug_line_str), compile_unit.*);
1357 allocator: Allocator,
1358 compile_unit: CompileUnit,
1359 target_address: u64,
1360) !std.debug.SourceLocation {
1361 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit);
1362 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);1387 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
13631388
1364 var fbr: FixedBufferReader = .{ .buf = di.section(.debug_line).?, .endian = di.endian };1389 var fbr: FixedBufferReader = .{
1390 .buf = d.section(.debug_line).?,
1391 .endian = d.endian,
1392 };
1365 try fbr.seekTo(line_info_offset);1393 try fbr.seekTo(line_info_offset);
13661394
1367 const unit_header = try readUnitHeader(&fbr, null);1395 const unit_header = try readUnitHeader(&fbr, null);
1368 if (unit_header.unit_length == 0) return missing();1396 if (unit_header.unit_length == 0) return missing();
1397
1369 const next_offset = unit_header.header_length + unit_header.unit_length;1398 const next_offset = unit_header.header_length + unit_header.unit_length;
13701399
1371 const version = try fbr.readInt(u16);1400 const version = try fbr.readInt(u16);
1372 if (version < 2) return bad();1401 if (version < 2) return bad();
13731402
1374 var addr_size: u8 = switch (unit_header.format) {1403 const addr_size: u8, const seg_size: u8 = if (version >= 5) .{
1375 .@"32" => 4,1404 try fbr.readByte(),
1376 .@"64" => 8,1405 try fbr.readByte(),
1406 } else .{
1407 switch (unit_header.format) {
1408 .@"32" => 4,
1409 .@"64" => 8,
1410 },
1411 0,
1377 };1412 };
1378 var seg_size: u8 = 0;1413 _ = addr_size;
1379 if (version >= 5) {1414 _ = seg_size;
1380 addr_size = try fbr.readByte();
1381 seg_size = try fbr.readByte();
1382 }
13831415
1384 const prologue_length = try fbr.readAddress(unit_header.format);1416 const prologue_length = try fbr.readAddress(unit_header.format);
1385 const prog_start_offset = fbr.pos + prologue_length;1417 const prog_start_offset = fbr.pos + prologue_length;
...@@ -1388,8 +1420,8 @@ pub fn getLineNumberInfo(...@@ -1388,8 +1420,8 @@ pub fn getLineNumberInfo(
1388 if (minimum_instruction_length == 0) return bad();1420 if (minimum_instruction_length == 0) return bad();
13891421
1390 if (version >= 4) {1422 if (version >= 4) {
1391 // maximum_operations_per_instruction1423 const maximum_operations_per_instruction = try fbr.readByte();
1392 _ = try fbr.readByte();1424 _ = maximum_operations_per_instruction;
1393 }1425 }
13941426
1395 const default_is_stmt = (try fbr.readByte()) != 0;1427 const default_is_stmt = (try fbr.readByte()) != 0;
...@@ -1402,18 +1434,18 @@ pub fn getLineNumberInfo(...@@ -1402,18 +1434,18 @@ pub fn getLineNumberInfo(
14021434
1403 const standard_opcode_lengths = try fbr.readBytes(opcode_base - 1);1435 const standard_opcode_lengths = try fbr.readBytes(opcode_base - 1);
14041436
1405 var include_directories = std.ArrayList(FileEntry).init(allocator);1437 var directories: std.ArrayListUnmanaged(FileEntry) = .{};
1406 defer include_directories.deinit();1438 defer directories.deinit(gpa);
1407 var file_entries = std.ArrayList(FileEntry).init(allocator);1439 var file_entries: std.ArrayListUnmanaged(FileEntry) = .{};
1408 defer file_entries.deinit();1440 defer file_entries.deinit(gpa);
14091441
1410 if (version < 5) {1442 if (version < 5) {
1411 try include_directories.append(.{ .path = compile_unit_cwd });1443 try directories.append(gpa, .{ .path = compile_unit_cwd });
14121444
1413 while (true) {1445 while (true) {
1414 const dir = try fbr.readBytesTo(0);1446 const dir = try fbr.readBytesTo(0);
1415 if (dir.len == 0) break;1447 if (dir.len == 0) break;
1416 try include_directories.append(.{ .path = dir });1448 try directories.append(gpa, .{ .path = dir });
1417 }1449 }
14181450
1419 while (true) {1451 while (true) {
...@@ -1422,7 +1454,7 @@ pub fn getLineNumberInfo(...@@ -1422,7 +1454,7 @@ pub fn getLineNumberInfo(
1422 const dir_index = try fbr.readUleb128(u32);1454 const dir_index = try fbr.readUleb128(u32);
1423 const mtime = try fbr.readUleb128(u64);1455 const mtime = try fbr.readUleb128(u64);
1424 const size = try fbr.readUleb128(u64);1456 const size = try fbr.readUleb128(u64);
1425 try file_entries.append(.{1457 try file_entries.append(gpa, .{
1426 .path = file_name,1458 .path = file_name,
1427 .dir_index = dir_index,1459 .dir_index = dir_index,
1428 .mtime = mtime,1460 .mtime = mtime,
...@@ -1446,52 +1478,10 @@ pub fn getLineNumberInfo(...@@ -1446,52 +1478,10 @@ pub fn getLineNumberInfo(
1446 }1478 }
14471479
1448 const directories_count = try fbr.readUleb128(usize);1480 const directories_count = try fbr.readUleb128(usize);
1449 try include_directories.ensureUnusedCapacity(directories_count);
1450 {
1451 var i: usize = 0;
1452 while (i < directories_count) : (i += 1) {
1453 var e: FileEntry = .{ .path = &.{} };
1454 for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| {
1455 const form_value = try parseFormValue(
1456 &fbr,
1457 ent_fmt.form_code,
1458 unit_header.format,
1459 null,
1460 );
1461 switch (ent_fmt.content_type_code) {
1462 DW.LNCT.path => e.path = try form_value.getString(di.*),
1463 DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
1464 DW.LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
1465 DW.LNCT.size => e.size = try form_value.getUInt(u64),
1466 DW.LNCT.MD5 => e.md5 = switch (form_value) {
1467 .data16 => |data16| data16.*,
1468 else => return bad(),
1469 },
1470 else => continue,
1471 }
1472 }
1473 include_directories.appendAssumeCapacity(e);
1474 }
1475 }
1476 }
14771481
1478 var file_ent_fmt_buf: [10]FileEntFmt = undefined;1482 for (try directories.addManyAsSlice(gpa, directories_count)) |*e| {
1479 const file_name_entry_format_count = try fbr.readByte();1483 e.* = .{ .path = &.{} };
1480 if (file_name_entry_format_count > file_ent_fmt_buf.len) return bad();1484 for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| {
1481 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| {
1482 ent_fmt.* = .{
1483 .content_type_code = try fbr.readUleb128(u8),
1484 .form_code = try fbr.readUleb128(u16),
1485 };
1486 }
1487
1488 const file_names_count = try fbr.readUleb128(usize);
1489 try file_entries.ensureUnusedCapacity(file_names_count);
1490 {
1491 var i: usize = 0;
1492 while (i < file_names_count) : (i += 1) {
1493 var e: FileEntry = .{ .path = &.{} };
1494 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| {
1495 const form_value = try parseFormValue(1485 const form_value = try parseFormValue(
1496 &fbr,1486 &fbr,
1497 ent_fmt.form_code,1487 ent_fmt.form_code,
...@@ -1499,7 +1489,7 @@ pub fn getLineNumberInfo(...@@ -1499,7 +1489,7 @@ pub fn getLineNumberInfo(
1499 null,1489 null,
1500 );1490 );
1501 switch (ent_fmt.content_type_code) {1491 switch (ent_fmt.content_type_code) {
1502 DW.LNCT.path => e.path = try form_value.getString(di.*),1492 DW.LNCT.path => e.path = try form_value.getString(d.*),
1503 DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),1493 DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
1504 DW.LNCT.timestamp => e.mtime = try form_value.getUInt(u64),1494 DW.LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
1505 DW.LNCT.size => e.size = try form_value.getUInt(u64),1495 DW.LNCT.size => e.size = try form_value.getUInt(u64),
...@@ -1510,17 +1500,49 @@ pub fn getLineNumberInfo(...@@ -1510,17 +1500,49 @@ pub fn getLineNumberInfo(
1510 else => continue,1500 else => continue,
1511 }1501 }
1512 }1502 }
1513 file_entries.appendAssumeCapacity(e);1503 }
1504 }
1505
1506 var file_ent_fmt_buf: [10]FileEntFmt = undefined;
1507 const file_name_entry_format_count = try fbr.readByte();
1508 if (file_name_entry_format_count > file_ent_fmt_buf.len) return bad();
1509 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| {
1510 ent_fmt.* = .{
1511 .content_type_code = try fbr.readUleb128(u8),
1512 .form_code = try fbr.readUleb128(u16),
1513 };
1514 }
1515
1516 const file_names_count = try fbr.readUleb128(usize);
1517 try file_entries.ensureUnusedCapacity(gpa, file_names_count);
1518
1519 for (try file_entries.addManyAsSlice(gpa, file_names_count)) |*e| {
1520 e.* = .{ .path = &.{} };
1521 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| {
1522 const form_value = try parseFormValue(
1523 &fbr,
1524 ent_fmt.form_code,
1525 unit_header.format,
1526 null,
1527 );
1528 switch (ent_fmt.content_type_code) {
1529 DW.LNCT.path => e.path = try form_value.getString(d.*),
1530 DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
1531 DW.LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
1532 DW.LNCT.size => e.size = try form_value.getUInt(u64),
1533 DW.LNCT.MD5 => e.md5 = switch (form_value) {
1534 .data16 => |data16| data16.*,
1535 else => return bad(),
1536 },
1537 else => continue,
1538 }
1514 }1539 }
1515 }1540 }
1516 }1541 }
15171542
1518 var prog = LineNumberProgram.init(1543 var prog = LineNumberProgram.init(default_is_stmt, version);
1519 default_is_stmt,1544 var line_table: CompileUnit.SrcLocCache.LineTable = .{};
1520 include_directories.items,1545 errdefer line_table.deinit(gpa);
1521 target_address,
1522 version,
1523 );
15241546
1525 try fbr.seekTo(prog_start_offset);1547 try fbr.seekTo(prog_start_offset);
15261548
...@@ -1536,7 +1558,7 @@ pub fn getLineNumberInfo(...@@ -1536,7 +1558,7 @@ pub fn getLineNumberInfo(
1536 switch (sub_op) {1558 switch (sub_op) {
1537 DW.LNE.end_sequence => {1559 DW.LNE.end_sequence => {
1538 prog.end_sequence = true;1560 prog.end_sequence = true;
1539 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;1561 try prog.addRow(gpa, &line_table);
1540 prog.reset();1562 prog.reset();
1541 },1563 },
1542 DW.LNE.set_address => {1564 DW.LNE.set_address => {
...@@ -1548,7 +1570,7 @@ pub fn getLineNumberInfo(...@@ -1548,7 +1570,7 @@ pub fn getLineNumberInfo(
1548 const dir_index = try fbr.readUleb128(u32);1570 const dir_index = try fbr.readUleb128(u32);
1549 const mtime = try fbr.readUleb128(u64);1571 const mtime = try fbr.readUleb128(u64);
1550 const size = try fbr.readUleb128(u64);1572 const size = try fbr.readUleb128(u64);
1551 try file_entries.append(.{1573 try file_entries.append(gpa, .{
1552 .path = path,1574 .path = path,
1553 .dir_index = dir_index,1575 .dir_index = dir_index,
1554 .mtime = mtime,1576 .mtime = mtime,
...@@ -1564,12 +1586,12 @@ pub fn getLineNumberInfo(...@@ -1564,12 +1586,12 @@ pub fn getLineNumberInfo(
1564 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);1586 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
1565 prog.line += inc_line;1587 prog.line += inc_line;
1566 prog.address += inc_addr;1588 prog.address += inc_addr;
1567 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;1589 try prog.addRow(gpa, &line_table);
1568 prog.basic_block = false;1590 prog.basic_block = false;
1569 } else {1591 } else {
1570 switch (opcode) {1592 switch (opcode) {
1571 DW.LNS.copy => {1593 DW.LNS.copy => {
1572 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;1594 try prog.addRow(gpa, &line_table);
1573 prog.basic_block = false;1595 prog.basic_block = false;
1574 },1596 },
1575 DW.LNS.advance_pc => {1597 DW.LNS.advance_pc => {
...@@ -1611,7 +1633,35 @@ pub fn getLineNumberInfo(...@@ -1611,7 +1633,35 @@ pub fn getLineNumberInfo(
1611 }1633 }
1612 }1634 }
16131635
1614 return missing();1636 return .{
1637 .line_table = line_table,
1638 .directories = try directories.toOwnedSlice(gpa),
1639 .files = try file_entries.toOwnedSlice(gpa),
1640 .version = version,
1641 };
1642}
1643
1644pub fn getLineNumberInfo(
1645 d: *Dwarf,
1646 gpa: Allocator,
1647 compile_unit: *CompileUnit,
1648 target_address: u64,
1649) !std.debug.SourceLocation {
1650 if (compile_unit.src_loc_cache == null)
1651 compile_unit.src_loc_cache = try runLineNumberProgram(d, gpa, compile_unit);
1652 const slc = &compile_unit.src_loc_cache.?;
1653 const entry = try slc.findSource(target_address);
1654 const file_index = entry.file - @intFromBool(slc.version < 5);
1655 if (file_index >= slc.files.len) return bad();
1656 const file_entry = &slc.files[file_index];
1657 if (file_entry.dir_index >= slc.directories.len) return bad();
1658 const dir_name = slc.directories[file_entry.dir_index].path;
1659 const file_name = try std.fs.path.join(gpa, &.{ dir_name, file_entry.path });
1660 return .{
1661 .line = entry.line,
1662 .column = entry.column,
1663 .file_name = file_name,
1664 };
1615}1665}
16161666
1617fn getString(di: Dwarf, offset: u64) ![:0]const u8 {1667fn getString(di: Dwarf, offset: u64) ![:0]const u8 {
...@@ -1826,17 +1876,6 @@ const LineNumberProgram = struct {...@@ -1826,17 +1876,6 @@ const LineNumberProgram = struct {
1826 end_sequence: bool,1876 end_sequence: bool,
18271877
1828 default_is_stmt: bool,1878 default_is_stmt: bool,
1829 target_address: u64,
1830 include_dirs: []const FileEntry,
1831
1832 prev_valid: bool,
1833 prev_address: u64,
1834 prev_file: usize,
1835 prev_line: i64,
1836 prev_column: u64,
1837 prev_is_stmt: bool,
1838 prev_basic_block: bool,
1839 prev_end_sequence: bool,
18401879
1841 // Reset the state machine following the DWARF specification1880 // Reset the state machine following the DWARF specification
1842 pub fn reset(self: *LineNumberProgram) void {1881 pub fn reset(self: *LineNumberProgram) void {
...@@ -1847,24 +1886,10 @@ const LineNumberProgram = struct {...@@ -1847,24 +1886,10 @@ const LineNumberProgram = struct {
1847 self.is_stmt = self.default_is_stmt;1886 self.is_stmt = self.default_is_stmt;
1848 self.basic_block = false;1887 self.basic_block = false;
1849 self.end_sequence = false;1888 self.end_sequence = false;
1850 // Invalidate all the remaining fields
1851 self.prev_valid = false;
1852 self.prev_address = 0;
1853 self.prev_file = undefined;
1854 self.prev_line = undefined;
1855 self.prev_column = undefined;
1856 self.prev_is_stmt = undefined;
1857 self.prev_basic_block = undefined;
1858 self.prev_end_sequence = undefined;
1859 }1889 }
18601890
1861 pub fn init(1891 pub fn init(is_stmt: bool, version: u16) LineNumberProgram {
1862 is_stmt: bool,1892 return .{
1863 include_dirs: []const FileEntry,
1864 target_address: u64,
1865 version: u16,
1866 ) LineNumberProgram {
1867 return LineNumberProgram{
1868 .address = 0,1893 .address = 0,
1869 .file = 1,1894 .file = 1,
1870 .line = 1,1895 .line = 1,
...@@ -1873,60 +1898,17 @@ const LineNumberProgram = struct {...@@ -1873,60 +1898,17 @@ const LineNumberProgram = struct {
1873 .is_stmt = is_stmt,1898 .is_stmt = is_stmt,
1874 .basic_block = false,1899 .basic_block = false,
1875 .end_sequence = false,1900 .end_sequence = false,
1876 .include_dirs = include_dirs,
1877 .default_is_stmt = is_stmt,1901 .default_is_stmt = is_stmt,
1878 .target_address = target_address,
1879 .prev_valid = false,
1880 .prev_address = 0,
1881 .prev_file = undefined,
1882 .prev_line = undefined,
1883 .prev_column = undefined,
1884 .prev_is_stmt = undefined,
1885 .prev_basic_block = undefined,
1886 .prev_end_sequence = undefined,
1887 };1902 };
1888 }1903 }
18891904
1890 pub fn checkLineMatch(1905 pub fn addRow(prog: *LineNumberProgram, gpa: Allocator, table: *CompileUnit.SrcLocCache.LineTable) !void {
1891 self: *LineNumberProgram,1906 if (prog.line == 0) return; // garbage data
1892 allocator: Allocator,1907 try table.put(gpa, prog.address, .{
1893 file_entries: []const FileEntry,1908 .line = cast(u32, prog.line) orelse maxInt(u32),
1894 ) !?std.debug.SourceLocation {1909 .column = cast(u32, prog.column) orelse maxInt(u32),
1895 if (self.prev_valid and1910 .file = cast(u32, prog.file) orelse return bad(),
1896 self.target_address >= self.prev_address and1911 });
1897 self.target_address < self.address)
1898 {
1899 const file_index = if (self.version >= 5) self.prev_file else i: {
1900 if (self.prev_file == 0) return missing();
1901 break :i self.prev_file - 1;
1902 };
1903
1904 if (file_index >= file_entries.len) return bad();
1905 const file_entry = &file_entries[file_index];
1906
1907 if (file_entry.dir_index >= self.include_dirs.len) return bad();
1908 const dir_name = self.include_dirs[file_entry.dir_index].path;
1909
1910 const file_name = try std.fs.path.join(allocator, &[_][]const u8{
1911 dir_name, file_entry.path,
1912 });
1913
1914 return std.debug.SourceLocation{
1915 .line = if (self.prev_line >= 0) @as(u64, @intCast(self.prev_line)) else 0,
1916 .column = self.prev_column,
1917 .file_name = file_name,
1918 };
1919 }
1920
1921 self.prev_valid = true;
1922 self.prev_address = self.address;
1923 self.prev_file = self.file;
1924 self.prev_line = self.line;
1925 self.prev_column = self.column;
1926 self.prev_is_stmt = self.is_stmt;
1927 self.prev_basic_block = self.basic_block;
1928 self.prev_end_sequence = self.end_sequence;
1929 return null;
1930 }1912 }
1931};1913};
19321914
...@@ -2381,7 +2363,7 @@ pub fn resolveSourceLocations(...@@ -2381,7 +2363,7 @@ pub fn resolveSourceLocations(
2381 defer prog_node.end();2363 defer prog_node.end();
23822364
2383 var cu_i: usize = 0;2365 var cu_i: usize = 0;
2384 var cu: *const CompileUnit = &d.compile_unit_list.items[0];2366 var cu: *CompileUnit = &d.compile_unit_list.items[0];
2385 var range = cu.pc_range.?;2367 var range = cu.pc_range.?;
2386 next_pc: for (sorted_pc_addrs, output) |pc, *out| {2368 next_pc: for (sorted_pc_addrs, output) |pc, *out| {
2387 defer prog_node.completeOne();2369 defer prog_node.completeOne();
...@@ -2403,7 +2385,7 @@ pub fn resolveSourceLocations(...@@ -2403,7 +2385,7 @@ pub fn resolveSourceLocations(
2403 }2385 }
2404 // TODO: instead of calling this function, break the function up into one that parses the2386 // TODO: instead of calling this function, break the function up into one that parses the
2405 // information once and prepares a context that can be reused for the entire batch.2387 // information once and prepares a context that can be reused for the entire batch.
2406 if (getLineNumberInfo(d, gpa, cu.*, pc)) |src_loc| {2388 if (getLineNumberInfo(d, gpa, cu, pc)) |src_loc| {
2407 out.* = src_loc;2389 out.* = src_loc;
2408 } else |err| switch (err) {2390 } else |err| switch (err) {
2409 error.MissingDebugInfo, error.InvalidDebugInfo => out.* = std.debug.SourceLocation.invalid,2391 error.MissingDebugInfo, error.InvalidDebugInfo => out.* = std.debug.SourceLocation.invalid,
...@@ -2419,7 +2401,7 @@ fn getSymbol(di: *Dwarf, allocator: Allocator, address: u64) !std.debug.Symbol {...@@ -2419,7 +2401,7 @@ fn getSymbol(di: *Dwarf, allocator: Allocator, address: u64) !std.debug.Symbol {
2419 .compile_unit_name = compile_unit.die.getAttrString(di, std.dwarf.AT.name, di.section(.debug_str), compile_unit.*) catch |err| switch (err) {2401 .compile_unit_name = compile_unit.die.getAttrString(di, std.dwarf.AT.name, di.section(.debug_str), compile_unit.*) catch |err| switch (err) {
2420 error.MissingDebugInfo, error.InvalidDebugInfo => "???",2402 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
2421 },2403 },
2422 .source_location = di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {2404 .source_location = di.getLineNumberInfo(allocator, compile_unit, address) catch |err| switch (err) {
2423 error.MissingDebugInfo, error.InvalidDebugInfo => null,2405 error.MissingDebugInfo, error.InvalidDebugInfo => null,
2424 else => return err,2406 else => return err,
2425 },2407 },
lib/std/debug/FixedBufferReader.zig+3-1
...@@ -1,4 +1,6 @@...@@ -1,4 +1,6 @@
1const std = @import("std.zig");1//! Optimized for performance in debug builds.
2
3const std = @import("../std.zig");
2const MemoryAccessor = std.debug.MemoryAccessor;4const MemoryAccessor = std.debug.MemoryAccessor;
35
4const FixedBufferReader = @This();6const FixedBufferReader = @This();