| ... | @@ -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 | }; |
| 142 | | 165 | |
| 143 | pub const FormValue = union(enum) { | 166 | pub 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 | }; |
| 850 | | 879 | |
| 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 | }; |
| 1036 | | 1066 | |
| 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 | }; |
| 1243 | | 1273 | |
| 1244 | /// TODO: change this to binary searching the sorted compile unit list | 1274 | /// TODO: change this to binary searching the sorted compile unit list |
| 1245 | pub fn findCompileUnit(di: *const Dwarf, target_address: u64) !*const CompileUnit { | 1275 | pub 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 | } |
| 1354 | | 1384 | |
| 1355 | pub fn getLineNumberInfo( | 1385 | fn 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); |
| 1363 | | 1388 | |
| 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); |
| 1366 | | 1394 | |
| 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; |
| 1370 | | 1399 | |
| 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(); |
| 1373 | | 1402 | |
| 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 | } | | |
| 1383 | | 1415 | |
| 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(); |
| 1389 | | 1421 | |
| 1390 | if (version >= 4) { | 1422 | if (version >= 4) { |
| 1391 | // maximum_operations_per_instruction | 1423 | const maximum_operations_per_instruction = try fbr.readByte(); |
| 1392 | _ = try fbr.readByte(); | 1424 | _ = maximum_operations_per_instruction; |
| 1393 | } | 1425 | } |
| 1394 | | 1426 | |
| 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( |
| 1402 | | 1434 | |
| 1403 | const standard_opcode_lengths = try fbr.readBytes(opcode_base - 1); | 1435 | const standard_opcode_lengths = try fbr.readBytes(opcode_base - 1); |
| 1404 | | 1436 | |
| 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); |
| 1409 | | 1441 | |
| 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 }); |
| 1412 | | 1444 | |
| 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 | } |
| 1418 | | 1450 | |
| 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 | } |
| 1447 | | 1479 | |
| 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 | } | | |
| 1477 | | 1481 | |
| 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 | } |
| 1517 | | 1542 | |
| 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 | ); | | |
| 1524 | | 1546 | |
| 1525 | try fbr.seekTo(prog_start_offset); | 1547 | try fbr.seekTo(prog_start_offset); |
| 1526 | | 1548 | |
| ... | @@ -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 | } |
| 1613 | | 1635 | |
| 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 | |
| | 1644 | pub 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 | } |
| 1616 | | 1666 | |
| 1617 | fn getString(di: Dwarf, offset: u64) ![:0]const u8 { | 1667 | fn 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, |
| 1827 | | 1877 | |
| 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, | | |
| 1840 | | 1879 | |
| 1841 | // Reset the state machine following the DWARF specification | 1880 | // 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 | } |
| 1860 | | 1890 | |
| 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 | } |
| 1889 | | 1904 | |
| 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 and | 1910 | .file = cast(u32, prog.file) orelse return bad(), |
| 1896 | self.target_address >= self.prev_address and | 1911 | }); |
| 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 | }; |
| 1932 | | 1914 | |
| ... | @@ -2381,7 +2363,7 @@ pub fn resolveSourceLocations( | ... | @@ -2381,7 +2363,7 @@ pub fn resolveSourceLocations( |
| 2381 | defer prog_node.end(); | 2363 | defer prog_node.end(); |
| 2382 | | 2364 | |
| 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 the | 2386 | // 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 | }, |