Commit 97bda56306

kcbanner <kcbanner@gmail.com>
2023-07-17 16:22:01
macho: don't scan all eh_frame entries, instead follow the offset from the __unwind_info directly
1 parent 774dc2f
Changed files (3)
lib/std/debug.zig
@@ -642,7 +642,7 @@ pub const StackIterator = struct {
                 // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding
                 // via DWARF before attempting to use the compact unwind info will produce incorrect results.
                 if (module.unwind_info) |unwind_info| {
-                    if (macho.unwindFrame(&unwind_state.dwarf_context, unwind_info, module.base_address)) |return_address| {
+                    if (macho.unwindFrame(&unwind_state.dwarf_context, unwind_info, module.eh_frame, module.base_address)) |return_address| {
                         return return_address;
                     } else |err| {
                         if (err != error.RequiresDWARFUnwind) return err;
@@ -2026,10 +2026,6 @@ pub const ModuleDebugInfo = switch (native_os) {
             };
 
             try DW.openDwarfDebugInfo(&di, allocator);
-
-            // TODO: Don't actually scan everything, search on demand
-            di.scanAllUnwindInfo(allocator, self.base_address) catch {};
-
             var info = OFileInfo{
                 .di = di,
                 .addr_table = addr_table,
lib/std/dwarf.zig
@@ -686,7 +686,8 @@ pub const DwarfInfo = struct {
     pub const null_section_array = [_]?Section{null} ** num_sections;
 
     endian: std.builtin.Endian,
-    sections: SectionArray,
+    sections: SectionArray = null_section_array,
+    is_macho: bool,
 
     // Filled later by the initializer
     abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
@@ -699,8 +700,6 @@ pub const DwarfInfo = struct {
     // Sorted by start_pc
     fde_list: std.ArrayListUnmanaged(FrameDescriptionEntry) = .{},
 
-    is_macho: bool,
-
     pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 {
         return if (di.sections[@intFromEnum(dwarf_section)]) |s| s.data else null;
     }
@@ -1672,6 +1671,8 @@ pub const DwarfInfo = struct {
             if (fde_offset >= frame_section.len) return error.MissingFDE;
 
             var stream = io.fixedBufferStream(frame_section);
+            try stream.seekTo(fde_offset);
+
             const fde_entry_header = try EntryHeader.read(&stream, dwarf_section, di.endian);
             if (fde_entry_header.type != .fde) return error.MissingFDE;
 
@@ -1701,8 +1702,6 @@ pub const DwarfInfo = struct {
                 builtin.cpu.arch.endian(),
             );
         } else if (di.eh_frame_hdr) |header| {
-            std.debug.print("EH_FRAME_HDR\n", .{});
-
             const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;
             try header.findEntry(
                 context.isValidMemory,
lib/std/macho.zig
@@ -2142,7 +2142,7 @@ fn dwarfRegNumber(unwind_reg_number: u3) !u8 {
 const dwarf = std.dwarf;
 const abi = dwarf.abi;
 
-pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, module_base_address: usize) !usize {
+pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, eh_frame: ?[]const u8, module_base_address: usize) !usize {
     const header = mem.bytesAsValue(
         unwind_info_section_header,
         unwind_info[0..@sizeOf(unwind_info_section_header)],
@@ -2396,7 +2396,9 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul
 
                 break :blk new_ip;
             },
-            .DWARF => return error.RequiresDWARFUnwind,
+            .DWARF => {
+                return unwindFrameDwarf(context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf));
+            },
         },
         .aarch64 => switch (encoding.mode.arm64) {
             .OLD => return error.UnimplementedUnwindEncoding,
@@ -2408,8 +2410,10 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul
                 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).* = new_sp;
                 break :blk new_ip;
             },
-            .DWARF => return error.RequiresDWARFUnwind,
-            .FRAME => {
+            .DWARF => {
+                return unwindFrameDwarf(context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf));
+            },
+            .FRAME => blk: {
                 const fp = (try abi.regValueNative(usize, context.thread_context, abi.fpRegNum(reg_context), reg_context)).*;
                 const new_sp = fp + 16;
                 const ip_ptr = fp + @sizeOf(usize);
@@ -2453,7 +2457,7 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul
                 (try abi.regValueNative(usize, context.thread_context, abi.fpRegNum(reg_context), reg_context)).* = new_fp;
                 (try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), reg_context)).* = new_ip;
 
-                return error.UnimplementedUnwindEncoding;
+                break :blk new_ip;
             },
         },
         else => return error.UnimplementedArch,
@@ -2463,3 +2467,18 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul
     if (context.pc > 0) context.pc -= 1;
     return new_ip;
 }
+
+fn unwindFrameDwarf(context: *dwarf.UnwindContext, eh_frame: []const u8, fde_offset: usize) !usize {
+    var di = dwarf.DwarfInfo{
+        .endian = builtin.cpu.arch.endian(),
+        .is_macho = true,
+    };
+    defer di.deinit(context.allocator);
+
+    di.sections[@intFromEnum(dwarf.DwarfSection.eh_frame)] = .{
+        .data = eh_frame,
+        .owned = false,
+    };
+
+    return di.unwindFrame(context, fde_offset);
+}