diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 66dfdc1838..0bbc2b511d 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -532,6 +532,8 @@ pub const StackIterator = struct { if (self.next_dwarf()) |_| { return self.dwarf_context.pc; } else |err| { + if (err != error.MissingFDE) print("DWARF unwind error: {}\n", .{err}); + // Fall back to fp unwinding on the first failure, // as the register context won't be updated @@ -540,9 +542,6 @@ pub const StackIterator = struct { self.fp = self.dwarf_context.getFp() catch 0; self.debug_info = null; - - // TODO: Remove - print("\ndwarf unwind error {}, placing fp at 0x{x}\n\n", .{err, self.fp}); } } @@ -1570,7 +1569,6 @@ pub const ModuleDebugInfo = switch (native_os) { .macos, .ios, .watchos, .tvos => struct { base_address: usize, mapped_memory: []align(mem.page_size) const u8, - external_mapped_memory: ?[]align(mem.page_size) const u8, symbols: []const MachoSymbol, strings: [:0]const u8, ofiles: OFileTable, @@ -1591,7 +1589,6 @@ pub const ModuleDebugInfo = switch (native_os) { self.ofiles.deinit(); allocator.free(self.symbols); os.munmap(self.mapped_memory); - if (self.external_mapped_memory) |m| os.munmap(m); } fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo { @@ -1637,102 +1634,37 @@ pub const ModuleDebugInfo = switch (native_os) { addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value); } - var opt_debug_line: ?macho.section_64 = null; - var opt_debug_info: ?macho.section_64 = null; - var opt_debug_abbrev: ?macho.section_64 = null; - var opt_debug_str: ?macho.section_64 = null; - var opt_debug_str_offsets: ?macho.section_64 = null; - var opt_debug_line_str: ?macho.section_64 = null; - var opt_debug_ranges: ?macho.section_64 = null; - var opt_debug_loclists: ?macho.section_64 = null; - var opt_debug_rnglists: ?macho.section_64 = null; - var opt_debug_addr: ?macho.section_64 = null; - var opt_debug_names: ?macho.section_64 = null; - var opt_debug_frame: ?macho.section_64 = null; - + var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array; for (segcmd.?.getSections()) |sect| { const name = sect.sectName(); - if (mem.eql(u8, name, "__debug_line")) { - opt_debug_line = sect; - } else if (mem.eql(u8, name, "__debug_info")) { - opt_debug_info = sect; - } else if (mem.eql(u8, name, "__debug_abbrev")) { - opt_debug_abbrev = sect; - } else if (mem.eql(u8, name, "__debug_str")) { - opt_debug_str = sect; - } else if (mem.eql(u8, name, "__debug_str_offsets")) { - opt_debug_str_offsets = sect; - } else if (mem.eql(u8, name, "__debug_line_str")) { - opt_debug_line_str = sect; - } else if (mem.eql(u8, name, "__debug_ranges")) { - opt_debug_ranges = sect; - } else if (mem.eql(u8, name, "__debug_loclists")) { - opt_debug_loclists = sect; - } else if (mem.eql(u8, name, "__debug_rnglists")) { - opt_debug_rnglists = sect; - } else if (mem.eql(u8, name, "__debug_addr")) { - opt_debug_addr = sect; - } else if (mem.eql(u8, name, "__debug_names")) { - opt_debug_names = sect; - } else if (mem.eql(u8, name, "__debug_frame")) { - opt_debug_frame = sect; + + var section_index: ?usize = null; + inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| { + if (mem.eql(u8, "__" ++ section.name, name)) section_index = i; } + if (section_index == null) continue; + + const section_bytes = try chopSlice(mapped_mem, sect.offset, sect.size); + sections[section_index.?] = .{ + .data = section_bytes, + .owned = false, + }; } - const debug_line = opt_debug_line orelse - return error.MissingDebugInfo; - const debug_info = opt_debug_info orelse - return error.MissingDebugInfo; - const debug_str = opt_debug_str orelse - return error.MissingDebugInfo; - const debug_abbrev = opt_debug_abbrev orelse - return error.MissingDebugInfo; + const missing_debug_info = + sections[@enumToInt(DW.DwarfSection.debug_info)] == null or + sections[@enumToInt(DW.DwarfSection.debug_abbrev)] == null or + sections[@enumToInt(DW.DwarfSection.debug_str)] == null or + sections[@enumToInt(DW.DwarfSection.debug_line)] == null; + if (missing_debug_info) return error.MissingDebugInfo; var di = DW.DwarfInfo{ .endian = .Little, + .sections = sections, .is_macho = true, - - // TODO: Get this compiling - - .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size), - .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size), - .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size), - .debug_str_offsets = if (opt_debug_str_offsets) |debug_str_offsets| - try chopSlice(mapped_mem, debug_str_offsets.offset, debug_str_offsets.size) - else - null, - .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size), - .debug_line_str = if (opt_debug_line_str) |debug_line_str| - try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size) - else - null, - .debug_ranges = if (opt_debug_ranges) |debug_ranges| - try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size) - else - null, - .debug_loclists = if (opt_debug_loclists) |debug_loclists| - try chopSlice(mapped_mem, debug_loclists.offset, debug_loclists.size) - else - null, - .debug_rnglists = if (opt_debug_rnglists) |debug_rnglists| - try chopSlice(mapped_mem, debug_rnglists.offset, debug_rnglists.size) - else - null, - .debug_addr = if (opt_debug_addr) |debug_addr| - try chopSlice(mapped_mem, debug_addr.offset, debug_addr.size) - else - null, - .debug_names = if (opt_debug_names) |debug_names| - try chopSlice(mapped_mem, debug_names.offset, debug_names.size) - else - null, - .debug_frame = if (opt_debug_frame) |debug_frame| - try chopSlice(mapped_mem, debug_frame.offset, debug_frame.size) - else - null, }; - try DW.openDwarfDebugInfo(&di, allocator); + try DW.openDwarfDebugInfo(&di, allocator, mapped_mem); var info = OFileInfo{ .di = di, .addr_table = addr_table, @@ -1784,7 +1716,7 @@ pub const ModuleDebugInfo = switch (native_os) { .compile_unit_name = compile_unit.die.getAttrString( o_file_di, DW.AT.name, - o_file_di.debug_str, + o_file_di.section(.debug_str), compile_unit.*, ) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => "???", diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 99c26051c8..b5294b5987 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -1626,7 +1626,7 @@ pub const DwarfInfo = struct { context.ucontext = next_ucontext; if (has_next_ip) { - context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.ipRegNum(), context.reg_ctx)); + context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, comptime abi.ipRegNum(), context.reg_ctx)); } else { context.pc = 0; } diff --git a/lib/std/dwarf/abi.zig b/lib/std/dwarf/abi.zig index 35f805bbf4..869993c8e8 100644 --- a/lib/std/dwarf/abi.zig +++ b/lib/std/dwarf/abi.zig @@ -12,23 +12,8 @@ pub fn ipRegNum() u8 { return switch (builtin.cpu.arch) { .x86 => 8, .x86_64 => 16, - .arm => error.InvalidRegister, // TODO - .aarch64 => error.InvalidRegister, // TODO - - // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); - // const ip = switch (native_os) { - // .macos => @intCast(usize, ctx.mcontext.ss.pc), - // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]), - // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr), - // else => @intCast(usize, ctx.mcontext.pc), - // }; - // // x29 is the ABI-designated frame pointer - // const bp = switch (native_os) { - // .macos => @intCast(usize, ctx.mcontext.ss.fp), - // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]), - // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]), - // else => @intCast(usize, ctx.mcontext.regs[29]), - // }; + .arm => 15, + .aarch64 => 32, else => unreachable, }; } @@ -38,8 +23,8 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 { // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5, .x86_64 => 6, - .arm => error.InvalidRegister, // TODO - .aarch64 => error.InvalidRegister, // TODO + .arm => 11, + .aarch64 => 29, // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); // const ip = switch (native_os) { @@ -63,23 +48,8 @@ pub fn spRegNum(reg_ctx: RegisterContext) u8 { return switch (builtin.cpu.arch) { .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4, .x86_64 => 7, - .arm => error.InvalidRegister, // TODO - .aarch64 => error.InvalidRegister, // TODO - - // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); - // const ip = switch (native_os) { - // .macos => @intCast(usize, ctx.mcontext.ss.pc), - // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]), - // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr), - // else => @intCast(usize, ctx.mcontext.pc), - // }; - // // x29 is the ABI-designated frame pointer - // const bp = switch (native_os) { - // .macos => @intCast(usize, ctx.mcontext.ss.fp), - // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]), - // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]), - // else => @intCast(usize, ctx.mcontext.regs[29]), - // }; + .arm => 13, + .aarch64 => 31, else => unreachable, }; } @@ -221,6 +191,56 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext }, else => error.UnimplementedOs, }, + .arm => switch (builtin.os.tag) { + .linux => switch (reg_number) { + 0 => mem.asBytes(&ucontext_ptr.mcontext.arm_r0), + 1 => mem.asBytes(&ucontext_ptr.mcontext.arm_r1), + 2 => mem.asBytes(&ucontext_ptr.mcontext.arm_r2), + 3 => mem.asBytes(&ucontext_ptr.mcontext.arm_r3), + 4 => mem.asBytes(&ucontext_ptr.mcontext.arm_r4), + 5 => mem.asBytes(&ucontext_ptr.mcontext.arm_r5), + 6 => mem.asBytes(&ucontext_ptr.mcontext.arm_r6), + 7 => mem.asBytes(&ucontext_ptr.mcontext.arm_r7), + 8 => mem.asBytes(&ucontext_ptr.mcontext.arm_r8), + 9 => mem.asBytes(&ucontext_ptr.mcontext.arm_r9), + 10 => mem.asBytes(&ucontext_ptr.mcontext.arm_r10), + 11 => mem.asBytes(&ucontext_ptr.mcontext.arm_fp), + 12 => mem.asBytes(&ucontext_ptr.mcontext.arm_ip), + 13 => mem.asBytes(&ucontext_ptr.mcontext.arm_sp), + 14 => mem.asBytes(&ucontext_ptr.mcontext.arm_lr), + 15 => mem.asBytes(&ucontext_ptr.mcontext.arm_pc), + // CPSR is not allocated a register number (See: https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst, Section 4.1) + else => error.InvalidRegister, + }, + else => error.UnimplementedOs, + }, + .aarch64 => switch (builtin.os.tag) { + .macos => switch (reg_number) { + 0...28 => mem.asBytes(&ucontext_ptr.mcontext.ss.regs[reg_number]), + 29 => mem.asBytes(&ucontext_ptr.mcontext.ss.fp), + 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr), + 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp), + 32 => mem.asBytes(&ucontext_ptr.mcontext.ss.pc), + else => error.InvalidRegister, + }, + .netbsd => switch (reg_number) { + 0...34 => mem.asBytes(&ucontext_ptr.mcontext.gregs[reg_number]), + else => error.InvalidRegister, + }, + .freebsd => switch (reg_number) { + 0...29 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.x[reg_number]), + 30 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.lr), + 31 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.sp), + 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 + else => error.InvalidRegister, + }, + else => switch (reg_number) { + 0...30 => mem.asBytes(&ucontext_ptr.mcontext.regs[reg_number]), + 31 => mem.asBytes(&ucontext_ptr.mcontext.sp), + 32 => mem.asBytes(&ucontext_ptr.mcontext.pc), + else => error.InvalidRegister, + }, + }, else => error.UnimplementedArch, }; }