authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-05-22 15:56:04-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:13-04:00
loge72e762d1e81b06c38902348a3f6625a85e1dce0
tree46c4e3dbfcb8adf49283a98076f4de37062cbc9d
parent9145ff7da073966ace27151f7a0921b20c7860f4

dwarf: implement more register mappings, fix up macos compile


3 files changed, 80 insertions(+), 128 deletions(-)

lib/std/debug.zig+23-91
...@@ -532,6 +532,8 @@ pub const StackIterator = struct {...@@ -532,6 +532,8 @@ pub const StackIterator = struct {
532 if (self.next_dwarf()) |_| {532 if (self.next_dwarf()) |_| {
533 return self.dwarf_context.pc;533 return self.dwarf_context.pc;
534 } else |err| {534 } else |err| {
535 if (err != error.MissingFDE) print("DWARF unwind error: {}\n", .{err});
536
535 // Fall back to fp unwinding on the first failure,537 // Fall back to fp unwinding on the first failure,
536 // as the register context won't be updated538 // as the register context won't be updated
537539
...@@ -540,9 +542,6 @@ pub const StackIterator = struct {...@@ -540,9 +542,6 @@ pub const StackIterator = struct {
540542
541 self.fp = self.dwarf_context.getFp() catch 0;543 self.fp = self.dwarf_context.getFp() catch 0;
542 self.debug_info = null;544 self.debug_info = null;
543
544 // TODO: Remove
545 print("\ndwarf unwind error {}, placing fp at 0x{x}\n\n", .{err, self.fp});
546 }545 }
547 }546 }
548547
...@@ -1570,7 +1569,6 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1570,7 +1569,6 @@ pub const ModuleDebugInfo = switch (native_os) {
1570 .macos, .ios, .watchos, .tvos => struct {1569 .macos, .ios, .watchos, .tvos => struct {
1571 base_address: usize,1570 base_address: usize,
1572 mapped_memory: []align(mem.page_size) const u8,1571 mapped_memory: []align(mem.page_size) const u8,
1573 external_mapped_memory: ?[]align(mem.page_size) const u8,
1574 symbols: []const MachoSymbol,1572 symbols: []const MachoSymbol,
1575 strings: [:0]const u8,1573 strings: [:0]const u8,
1576 ofiles: OFileTable,1574 ofiles: OFileTable,
...@@ -1591,7 +1589,6 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1591,7 +1589,6 @@ pub const ModuleDebugInfo = switch (native_os) {
1591 self.ofiles.deinit();1589 self.ofiles.deinit();
1592 allocator.free(self.symbols);1590 allocator.free(self.symbols);
1593 os.munmap(self.mapped_memory);1591 os.munmap(self.mapped_memory);
1594 if (self.external_mapped_memory) |m| os.munmap(m);
1595 }1592 }
15961593
1597 fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo {1594 fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo {
...@@ -1637,102 +1634,37 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1637,102 +1634,37 @@ pub const ModuleDebugInfo = switch (native_os) {
1637 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);1634 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
1638 }1635 }
16391636
1640 var opt_debug_line: ?macho.section_64 = null;1637 var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array;
1641 var opt_debug_info: ?macho.section_64 = null;
1642 var opt_debug_abbrev: ?macho.section_64 = null;
1643 var opt_debug_str: ?macho.section_64 = null;
1644 var opt_debug_str_offsets: ?macho.section_64 = null;
1645 var opt_debug_line_str: ?macho.section_64 = null;
1646 var opt_debug_ranges: ?macho.section_64 = null;
1647 var opt_debug_loclists: ?macho.section_64 = null;
1648 var opt_debug_rnglists: ?macho.section_64 = null;
1649 var opt_debug_addr: ?macho.section_64 = null;
1650 var opt_debug_names: ?macho.section_64 = null;
1651 var opt_debug_frame: ?macho.section_64 = null;
1652
1653 for (segcmd.?.getSections()) |sect| {1638 for (segcmd.?.getSections()) |sect| {
1654 const name = sect.sectName();1639 const name = sect.sectName();
1655 if (mem.eql(u8, name, "__debug_line")) {1640
1656 opt_debug_line = sect;1641 var section_index: ?usize = null;
1657 } else if (mem.eql(u8, name, "__debug_info")) {1642 inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
1658 opt_debug_info = sect;1643 if (mem.eql(u8, "__" ++ section.name, name)) section_index = i;
1659 } else if (mem.eql(u8, name, "__debug_abbrev")) {
1660 opt_debug_abbrev = sect;
1661 } else if (mem.eql(u8, name, "__debug_str")) {
1662 opt_debug_str = sect;
1663 } else if (mem.eql(u8, name, "__debug_str_offsets")) {
1664 opt_debug_str_offsets = sect;
1665 } else if (mem.eql(u8, name, "__debug_line_str")) {
1666 opt_debug_line_str = sect;
1667 } else if (mem.eql(u8, name, "__debug_ranges")) {
1668 opt_debug_ranges = sect;
1669 } else if (mem.eql(u8, name, "__debug_loclists")) {
1670 opt_debug_loclists = sect;
1671 } else if (mem.eql(u8, name, "__debug_rnglists")) {
1672 opt_debug_rnglists = sect;
1673 } else if (mem.eql(u8, name, "__debug_addr")) {
1674 opt_debug_addr = sect;
1675 } else if (mem.eql(u8, name, "__debug_names")) {
1676 opt_debug_names = sect;
1677 } else if (mem.eql(u8, name, "__debug_frame")) {
1678 opt_debug_frame = sect;
1679 }1644 }
1645 if (section_index == null) continue;
1646
1647 const section_bytes = try chopSlice(mapped_mem, sect.offset, sect.size);
1648 sections[section_index.?] = .{
1649 .data = section_bytes,
1650 .owned = false,
1651 };
1680 }1652 }
16811653
1682 const debug_line = opt_debug_line orelse1654 const missing_debug_info =
1683 return error.MissingDebugInfo;1655 sections[@enumToInt(DW.DwarfSection.debug_info)] == null or
1684 const debug_info = opt_debug_info orelse1656 sections[@enumToInt(DW.DwarfSection.debug_abbrev)] == null or
1685 return error.MissingDebugInfo;1657 sections[@enumToInt(DW.DwarfSection.debug_str)] == null or
1686 const debug_str = opt_debug_str orelse1658 sections[@enumToInt(DW.DwarfSection.debug_line)] == null;
1687 return error.MissingDebugInfo;1659 if (missing_debug_info) return error.MissingDebugInfo;
1688 const debug_abbrev = opt_debug_abbrev orelse
1689 return error.MissingDebugInfo;
16901660
1691 var di = DW.DwarfInfo{1661 var di = DW.DwarfInfo{
1692 .endian = .Little,1662 .endian = .Little,
1663 .sections = sections,
1693 .is_macho = true,1664 .is_macho = true,
1694
1695 // TODO: Get this compiling
1696
1697 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
1698 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
1699 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
1700 .debug_str_offsets = if (opt_debug_str_offsets) |debug_str_offsets|
1701 try chopSlice(mapped_mem, debug_str_offsets.offset, debug_str_offsets.size)
1702 else
1703 null,
1704 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
1705 .debug_line_str = if (opt_debug_line_str) |debug_line_str|
1706 try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)
1707 else
1708 null,
1709 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
1710 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
1711 else
1712 null,
1713 .debug_loclists = if (opt_debug_loclists) |debug_loclists|
1714 try chopSlice(mapped_mem, debug_loclists.offset, debug_loclists.size)
1715 else
1716 null,
1717 .debug_rnglists = if (opt_debug_rnglists) |debug_rnglists|
1718 try chopSlice(mapped_mem, debug_rnglists.offset, debug_rnglists.size)
1719 else
1720 null,
1721 .debug_addr = if (opt_debug_addr) |debug_addr|
1722 try chopSlice(mapped_mem, debug_addr.offset, debug_addr.size)
1723 else
1724 null,
1725 .debug_names = if (opt_debug_names) |debug_names|
1726 try chopSlice(mapped_mem, debug_names.offset, debug_names.size)
1727 else
1728 null,
1729 .debug_frame = if (opt_debug_frame) |debug_frame|
1730 try chopSlice(mapped_mem, debug_frame.offset, debug_frame.size)
1731 else
1732 null,
1733 };1665 };
17341666
1735 try DW.openDwarfDebugInfo(&di, allocator);1667 try DW.openDwarfDebugInfo(&di, allocator, mapped_mem);
1736 var info = OFileInfo{1668 var info = OFileInfo{
1737 .di = di,1669 .di = di,
1738 .addr_table = addr_table,1670 .addr_table = addr_table,
...@@ -1784,7 +1716,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1784,7 +1716,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1784 .compile_unit_name = compile_unit.die.getAttrString(1716 .compile_unit_name = compile_unit.die.getAttrString(
1785 o_file_di,1717 o_file_di,
1786 DW.AT.name,1718 DW.AT.name,
1787 o_file_di.debug_str,1719 o_file_di.section(.debug_str),
1788 compile_unit.*,1720 compile_unit.*,
1789 ) catch |err| switch (err) {1721 ) catch |err| switch (err) {
1790 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1722 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
lib/std/dwarf.zig+1-1
...@@ -1626,7 +1626,7 @@ pub const DwarfInfo = struct {...@@ -1626,7 +1626,7 @@ pub const DwarfInfo = struct {
1626 context.ucontext = next_ucontext;1626 context.ucontext = next_ucontext;
16271627
1628 if (has_next_ip) {1628 if (has_next_ip) {
1629 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.ipRegNum(), context.reg_ctx));1629 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, comptime abi.ipRegNum(), context.reg_ctx));
1630 } else {1630 } else {
1631 context.pc = 0;1631 context.pc = 0;
1632 }1632 }
lib/std/dwarf/abi.zig+56-36
...@@ -12,23 +12,8 @@ pub fn ipRegNum() u8 {...@@ -12,23 +12,8 @@ pub fn ipRegNum() u8 {
12 return switch (builtin.cpu.arch) {12 return switch (builtin.cpu.arch) {
13 .x86 => 8,13 .x86 => 8,
14 .x86_64 => 16,14 .x86_64 => 16,
15 .arm => error.InvalidRegister, // TODO15 .arm => 15,
16 .aarch64 => error.InvalidRegister, // TODO16 .aarch64 => 32,
17
18 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
19 // const ip = switch (native_os) {
20 // .macos => @intCast(usize, ctx.mcontext.ss.pc),
21 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
22 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
23 // else => @intCast(usize, ctx.mcontext.pc),
24 // };
25 // // x29 is the ABI-designated frame pointer
26 // const bp = switch (native_os) {
27 // .macos => @intCast(usize, ctx.mcontext.ss.fp),
28 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
29 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
30 // else => @intCast(usize, ctx.mcontext.regs[29]),
31 // };
32 else => unreachable,17 else => unreachable,
33 };18 };
34}19}
...@@ -38,8 +23,8 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 {...@@ -38,8 +23,8 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
38 // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO23 // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO
39 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5,24 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5,
40 .x86_64 => 6,25 .x86_64 => 6,
41 .arm => error.InvalidRegister, // TODO26 .arm => 11,
42 .aarch64 => error.InvalidRegister, // TODO27 .aarch64 => 29,
4328
44 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));29 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
45 // const ip = switch (native_os) {30 // const ip = switch (native_os) {
...@@ -63,23 +48,8 @@ pub fn spRegNum(reg_ctx: RegisterContext) u8 {...@@ -63,23 +48,8 @@ pub fn spRegNum(reg_ctx: RegisterContext) u8 {
63 return switch (builtin.cpu.arch) {48 return switch (builtin.cpu.arch) {
64 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4,49 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4,
65 .x86_64 => 7,50 .x86_64 => 7,
66 .arm => error.InvalidRegister, // TODO51 .arm => 13,
67 .aarch64 => error.InvalidRegister, // TODO52 .aarch64 => 31,
68
69 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
70 // const ip = switch (native_os) {
71 // .macos => @intCast(usize, ctx.mcontext.ss.pc),
72 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
73 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
74 // else => @intCast(usize, ctx.mcontext.pc),
75 // };
76 // // x29 is the ABI-designated frame pointer
77 // const bp = switch (native_os) {
78 // .macos => @intCast(usize, ctx.mcontext.ss.fp),
79 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
80 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
81 // else => @intCast(usize, ctx.mcontext.regs[29]),
82 // };
83 else => unreachable,53 else => unreachable,
84 };54 };
85}55}
...@@ -221,6 +191,56 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext...@@ -221,6 +191,56 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext
221 },191 },
222 else => error.UnimplementedOs,192 else => error.UnimplementedOs,
223 },193 },
194 .arm => switch (builtin.os.tag) {
195 .linux => switch (reg_number) {
196 0 => mem.asBytes(&ucontext_ptr.mcontext.arm_r0),
197 1 => mem.asBytes(&ucontext_ptr.mcontext.arm_r1),
198 2 => mem.asBytes(&ucontext_ptr.mcontext.arm_r2),
199 3 => mem.asBytes(&ucontext_ptr.mcontext.arm_r3),
200 4 => mem.asBytes(&ucontext_ptr.mcontext.arm_r4),
201 5 => mem.asBytes(&ucontext_ptr.mcontext.arm_r5),
202 6 => mem.asBytes(&ucontext_ptr.mcontext.arm_r6),
203 7 => mem.asBytes(&ucontext_ptr.mcontext.arm_r7),
204 8 => mem.asBytes(&ucontext_ptr.mcontext.arm_r8),
205 9 => mem.asBytes(&ucontext_ptr.mcontext.arm_r9),
206 10 => mem.asBytes(&ucontext_ptr.mcontext.arm_r10),
207 11 => mem.asBytes(&ucontext_ptr.mcontext.arm_fp),
208 12 => mem.asBytes(&ucontext_ptr.mcontext.arm_ip),
209 13 => mem.asBytes(&ucontext_ptr.mcontext.arm_sp),
210 14 => mem.asBytes(&ucontext_ptr.mcontext.arm_lr),
211 15 => mem.asBytes(&ucontext_ptr.mcontext.arm_pc),
212 // CPSR is not allocated a register number (See: https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst, Section 4.1)
213 else => error.InvalidRegister,
214 },
215 else => error.UnimplementedOs,
216 },
217 .aarch64 => switch (builtin.os.tag) {
218 .macos => switch (reg_number) {
219 0...28 => mem.asBytes(&ucontext_ptr.mcontext.ss.regs[reg_number]),
220 29 => mem.asBytes(&ucontext_ptr.mcontext.ss.fp),
221 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr),
222 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp),
223 32 => mem.asBytes(&ucontext_ptr.mcontext.ss.pc),
224 else => error.InvalidRegister,
225 },
226 .netbsd => switch (reg_number) {
227 0...34 => mem.asBytes(&ucontext_ptr.mcontext.gregs[reg_number]),
228 else => error.InvalidRegister,
229 },
230 .freebsd => switch (reg_number) {
231 0...29 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.x[reg_number]),
232 30 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.lr),
233 31 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.sp),
234 32 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.elr), // TODO: This seems wrong, but it was in the old debug.zig code for PC, check this
235 else => error.InvalidRegister,
236 },
237 else => switch (reg_number) {
238 0...30 => mem.asBytes(&ucontext_ptr.mcontext.regs[reg_number]),
239 31 => mem.asBytes(&ucontext_ptr.mcontext.sp),
240 32 => mem.asBytes(&ucontext_ptr.mcontext.pc),
241 else => error.InvalidRegister,
242 },
243 },
224 else => error.UnimplementedArch,244 else => error.UnimplementedArch,
225 };245 };
226}246}