authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-22 12:05:50+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-02-22 12:05:50+01:00
log41bca1ce760f415df5bc89acb0f609659e9bdad8
treebeefcbbccc4141edc2674d1db63a797dcde655f0
parentc060cae3ce1a47032b36bd295a3725760145e811

unification: windows debug info


1 files changed, 155 insertions(+), 5 deletions(-)

lib/std/debug.zig+155-5
...@@ -393,9 +393,9 @@ pub fn writeCurrentStackTraceWindows(...@@ -393,9 +393,9 @@ pub fn writeCurrentStackTraceWindows(
393/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,393/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
394/// make this `noasync fn` and remove the individual noasync calls.394/// make this `noasync fn` and remove the individual noasync calls.
395pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {395pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
396 if (builtin.os == .windows) {396 // if (builtin.os == .windows) {
397 return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config);397 // return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config);
398 }398 // }
399 return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);399 return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);
400}400}
401401
...@@ -1516,8 +1516,6 @@ pub const ModuleDebugInfo = switch (builtin.os) {...@@ -1516,8 +1516,6 @@ pub const ModuleDebugInfo = switch (builtin.os) {
1516 assert(symbol.ofile.?.n_strx < self.strings.len);1516 assert(symbol.ofile.?.n_strx < self.strings.len);
1517 const o_file_path = mem.toSliceConst(u8, self.strings.ptr + symbol.ofile.?.n_strx);1517 const o_file_path = mem.toSliceConst(u8, self.strings.ptr + symbol.ofile.?.n_strx);
15181518
1519 warn("Loading .o file: {s}\n", .{o_file_path});
1520
1521 // Check if its debug infos are already in the cache1519 // Check if its debug infos are already in the cache
1522 var o_file_di = self.ofiles.getValue(o_file_path) orelse1520 var o_file_di = self.ofiles.getValue(o_file_path) orelse
1523 (self.loadOFile(o_file_path) catch |err| switch (err) {1521 (self.loadOFile(o_file_path) catch |err| switch (err) {
...@@ -1560,6 +1558,158 @@ pub const ModuleDebugInfo = switch (builtin.os) {...@@ -1560,6 +1558,158 @@ pub const ModuleDebugInfo = switch (builtin.os) {
1560 coff: *coff.Coff,1558 coff: *coff.Coff,
1561 sect_contribs: []pdb.SectionContribEntry,1559 sect_contribs: []pdb.SectionContribEntry,
1562 modules: []Module,1560 modules: []Module,
1561
1562 pub fn allocator(self: @This()) *mem.Allocator {
1563 return self.coff.allocator;
1564 }
1565
1566 fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1567 // Translate the VA into an address into this object
1568 const relocated_address = address - self.base_address;
1569
1570 var coff_section: *coff.Section = undefined;
1571 const mod_index = for (self.sect_contribs) |sect_contrib| {
1572 if (sect_contrib.Section > self.coff.sections.len) continue;
1573 // Remember that SectionContribEntry.Section is 1-based.
1574 coff_section = &self.coff.sections.toSlice()[sect_contrib.Section - 1];
1575
1576 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
1577 const vaddr_end = vaddr_start + sect_contrib.Size;
1578 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
1579 break sect_contrib.ModuleIndex;
1580 }
1581 } else {
1582 // we have no information to add to the address
1583 return SymbolInfo{};
1584 };
1585
1586 const mod = &self.modules[mod_index];
1587 try populateModule(self, mod);
1588 const obj_basename = fs.path.basename(mod.obj_file_name);
1589
1590 var symbol_i: usize = 0;
1591 const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
1592 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
1593 if (prefix.RecordLen < 2)
1594 return error.InvalidDebugInfo;
1595 switch (prefix.RecordKind) {
1596 .S_LPROC32, .S_GPROC32 => {
1597 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
1598 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
1599 const vaddr_end = vaddr_start + proc_sym.CodeSize;
1600 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
1601 break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym));
1602 }
1603 },
1604 else => {},
1605 }
1606 symbol_i += prefix.RecordLen + @sizeOf(u16);
1607 if (symbol_i > mod.symbols.len)
1608 return error.InvalidDebugInfo;
1609 } else "???";
1610
1611 const subsect_info = mod.subsect_info;
1612
1613 var sect_offset: usize = 0;
1614 var skip_len: usize = undefined;
1615 const opt_line_info = subsections: {
1616 const checksum_offset = mod.checksum_offset orelse break :subsections null;
1617 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
1618 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
1619 skip_len = subsect_hdr.Length;
1620 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
1621
1622 switch (subsect_hdr.Kind) {
1623 pdb.DebugSubsectionKind.Lines => {
1624 var line_index = sect_offset;
1625
1626 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
1627 if (line_hdr.RelocSegment == 0)
1628 return error.MissingDebugInfo;
1629 line_index += @sizeOf(pdb.LineFragmentHeader);
1630 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
1631 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
1632
1633 if (relocated_address >= frag_vaddr_start and relocated_address < frag_vaddr_end) {
1634 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
1635 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
1636 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
1637 const subsection_end_index = sect_offset + subsect_hdr.Length;
1638
1639 while (line_index < subsection_end_index) {
1640 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
1641 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
1642 const start_line_index = line_index;
1643
1644 const has_column = line_hdr.Flags.LF_HaveColumns;
1645
1646 // All line entries are stored inside their line block by ascending start address.
1647 // Heuristic: we want to find the last line entry
1648 // that has a vaddr_start <= relocated_address.
1649 // This is done with a simple linear search.
1650 var line_i: u32 = 0;
1651 while (line_i < block_hdr.NumLines) : (line_i += 1) {
1652 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
1653 line_index += @sizeOf(pdb.LineNumberEntry);
1654
1655 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
1656 if (relocated_address < vaddr_start) {
1657 break;
1658 }
1659 }
1660
1661 // line_i == 0 would mean that no matching LineNumberEntry was found.
1662 if (line_i > 0) {
1663 const subsect_index = checksum_offset + block_hdr.NameIndex;
1664 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
1665 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
1666 try self.pdb.string_table.seekTo(strtab_offset);
1667 const source_file_name = try self.pdb.string_table.readNullTermString(self.allocator());
1668
1669 const line_entry_idx = line_i - 1;
1670
1671 const column = if (has_column) blk: {
1672 const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
1673 const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
1674 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
1675 break :blk col_num_entry.StartColumn;
1676 } else 0;
1677
1678 const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
1679 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
1680 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
1681
1682 break :subsections LineInfo{
1683 .allocator = self.allocator(),
1684 .file_name = source_file_name,
1685 .line = flags.Start,
1686 .column = column,
1687 };
1688 }
1689 }
1690
1691 // Checking that we are not reading garbage after the (possibly) multiple block fragments.
1692 if (line_index != subsection_end_index) {
1693 return error.InvalidDebugInfo;
1694 }
1695 }
1696 },
1697 else => {},
1698 }
1699
1700 if (sect_offset > subsect_info.len)
1701 return error.InvalidDebugInfo;
1702 } else {
1703 break :subsections null;
1704 }
1705 };
1706
1707 return SymbolInfo{
1708 .symbol_name = symbol_name,
1709 .compile_unit_name = obj_basename,
1710 .line_info = opt_line_info,
1711 };
1712 }
1563 },1713 },
1564 .linux, .freebsd => struct {1714 .linux, .freebsd => struct {
1565 base_address: usize,1715 base_address: usize,