Commit d99b40d38b

kcbanner <kcbanner@gmail.com>
2023-07-18 07:21:45
dwarf: fix the unwinder using the incorrect row from the FDE in certain cases
1 parent 1a2bb70
Changed files (2)
lib/std/dwarf/call_frame.zig
@@ -395,9 +395,7 @@ pub const VirtualMachine = struct {
     }
 
     /// Runs the CIE instructions, then the FDE instructions. Execution halts
-    /// once the row that corresponds to `pc` is known (and set as `current_row`).
-    ///
-    /// The state of the row prior to the last execution step is returned.
+    /// once the row that corresponds to `pc` is known, and the row is returned.
     pub fn runTo(
         self: *VirtualMachine,
         allocator: std.mem.Allocator,
@@ -419,17 +417,15 @@ pub const VirtualMachine = struct {
             &fde_stream,
         };
 
-        outer: for (&streams, 0..) |stream, i| {
+        for (&streams, 0..) |stream, i| {
             while (stream.pos < stream.buffer.len) {
                 const instruction = try dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);
                 prev_row = try self.step(allocator, cie, i == 0, instruction);
-                if (pc < fde.pc_begin + self.current_row.offset) {
-                    break :outer;
-                }
+                if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
             }
         }
 
-        return prev_row;
+        return self.current_row;
     }
 
     pub fn runToNative(
lib/std/dwarf.zig
@@ -1740,8 +1740,20 @@ pub const DwarfInfo = struct {
         context.reg_context.eh_frame = cie.version != 4;
         context.reg_context.is_macho = di.is_macho;
 
-        _ = try context.vm.runToNative(context.allocator, context.pc, cie, fde);
-        const row = &context.vm.current_row;
+        if (comptime builtin.target.isDarwin()) {
+            std.debug.print("  state before:\n", .{});
+            std.debug.print("    cfa {?x}:\n", .{context.cfa});
+            for (context.thread_context.mcontext.ss.regs, 0..) |reg, i| {
+                std.debug.print("    {}:0x{x}\n", .{i, reg});
+            }
+            std.debug.print("    fp:0x{x}\n", .{context.thread_context.mcontext.ss.fp});
+            std.debug.print("    lr:0x{x}\n", .{context.thread_context.mcontext.ss.lr});
+            std.debug.print("    sp:0x{x}\n", .{context.thread_context.mcontext.ss.sp});
+            std.debug.print("    pc:0x{x}\n", .{context.thread_context.mcontext.ss.pc});
+        }
+
+        const row = try context.vm.runToNative(context.allocator, context.pc, cie, fde);
+        std.debug.print("     ran to 0x{x}\n", .{row.offset + fde.pc_begin});
 
         context.cfa = switch (row.cfa.rule) {
             .val_offset => |offset| blk: {
@@ -1785,7 +1797,7 @@ pub const DwarfInfo = struct {
 
         var update_tail: ?*RegisterUpdate = null;
         var has_next_ip = false;
-        for (context.vm.rowColumns(row.*)) |column| {
+        for (context.vm.rowColumns(row)) |column| {
             if (column.register) |register| {
                 if (register == cie.return_address_register) {
                     has_next_ip = column.rule != .undefined;