From 59633e54a235ce8811cfb33d719595e1bd6f7334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 04:31:47 +0200 Subject: [PATCH 1/7] std.debug: select SelfInfo using ObjectFormat.default() --- lib/std/debug.zig | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7e2ec0509291..f2c3a5606ba8 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -61,28 +61,12 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// ``` pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) root.debug.SelfInfo -else switch (native_os) { - .linux, - .netbsd, - .freebsd, - .dragonfly, - .openbsd, - .solaris, - .illumos, - => @import("debug/SelfInfo/Elf.zig"), - - .macos, - .ios, - .watchos, - .tvos, - .visionos, - => @import("debug/SelfInfo/Darwin.zig"), - - .uefi, - .windows, - => @import("debug/SelfInfo/Windows.zig"), - - else => void, +else switch (std.Target.ObjectFormat.default(native_os, native_arch)) { + .coff => @import("debug/SelfInfo/Windows.zig"), + .elf => @import("debug/SelfInfo/Elf.zig"), + .macho => @import("debug/SelfInfo/Darwin.zig"), + .goff, .plan9, .spirv, .wasm, .xcoff => void, + .c, .hex, .raw => unreachable, }; pub const SelfInfoError = error{ From e1fb662f600a7e134661d3c46d12e7ead83dd799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 15:33:50 +0200 Subject: [PATCH 2/7] std.debug: don't use SelfInfo.Windows for UEFI It is, in fact, Windows-only. --- lib/std/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index f2c3a5606ba8..54e99762d8df 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -62,7 +62,7 @@ pub const cpu_context = @import("debug/cpu_context.zig"); pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) root.debug.SelfInfo else switch (std.Target.ObjectFormat.default(native_os, native_arch)) { - .coff => @import("debug/SelfInfo/Windows.zig"), + .coff => if (native_os == .windows) @import("debug/SelfInfo/Windows.zig") else void, .elf => @import("debug/SelfInfo/Elf.zig"), .macho => @import("debug/SelfInfo/Darwin.zig"), .goff, .plan9, .spirv, .wasm, .xcoff => void, From 771410cbf231e1a2b20e25f9d70c13d4ffeace9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 15:34:32 +0200 Subject: [PATCH 3/7] std.debug.SelfInfo: rename Darwin to MachO --- lib/std/debug.zig | 2 +- lib/std/debug/SelfInfo/{Darwin.zig => MachO.zig} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/std/debug/SelfInfo/{Darwin.zig => MachO.zig} (100%) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 54e99762d8df..2b1ea3492fc2 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -64,7 +64,7 @@ pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfI else switch (std.Target.ObjectFormat.default(native_os, native_arch)) { .coff => if (native_os == .windows) @import("debug/SelfInfo/Windows.zig") else void, .elf => @import("debug/SelfInfo/Elf.zig"), - .macho => @import("debug/SelfInfo/Darwin.zig"), + .macho => @import("debug/SelfInfo/MachO.zig"), .goff, .plan9, .spirv, .wasm, .xcoff => void, .c, .hex, .raw => unreachable, }; diff --git a/lib/std/debug/SelfInfo/Darwin.zig b/lib/std/debug/SelfInfo/MachO.zig similarity index 100% rename from lib/std/debug/SelfInfo/Darwin.zig rename to lib/std/debug/SelfInfo/MachO.zig From b46867848e4a2e8ba9965d579d4474fba1ab3b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 15:34:46 +0200 Subject: [PATCH 4/7] std.debug: some adjustments to target handling * driverkit handling missing in a few places. * x86-solaris is a dead target. * aarch64_be does not exist on Darwin, FreeBSD, Windows. --- lib/std/debug/SelfInfo/Elf.zig | 32 ++++++++++++++++++++++++------ lib/std/debug/SelfInfo/MachO.zig | 2 +- lib/std/debug/SelfInfo/Windows.zig | 2 +- lib/std/debug/cpu_context.zig | 12 +++++------ 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 4f9389f2d543..36acdb54e367 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -84,12 +84,32 @@ pub const can_unwind: bool = s: { // Notably, we are yet to support unwinding on ARM. There, unwinding is not done through // `.eh_frame`, but instead with the `.ARM.exidx` section, which has a different format. const archs: []const std.Target.Cpu.Arch = switch (builtin.target.os.tag) { - .linux => &.{ .x86, .x86_64, .aarch64, .aarch64_be }, - .netbsd => &.{ .x86, .x86_64, .aarch64, .aarch64_be }, - .freebsd => &.{ .x86_64, .aarch64, .aarch64_be }, - .openbsd => &.{.x86_64}, - .solaris => &.{ .x86, .x86_64 }, - .illumos => &.{ .x86, .x86_64 }, + .linux => &.{ + .aarch64, + .aarch64_be, + .x86, + .x86_64, + }, + .netbsd => &.{ + .aarch64, + .aarch64_be, + .x86, + .x86_64, + }, + .freebsd => &.{ + .x86_64, + .aarch64, + }, + .openbsd => &.{ + .x86_64, + }, + .solaris => &.{ + .x86_64, + }, + .illumos => &.{ + .x86, + .x86_64, + }, else => unreachable, }; for (archs) |a| { diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index a43f279f39b7..eb4d0854d842 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -371,7 +371,7 @@ fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usi return context.next(gpa, &rules); }, }, - .aarch64, .aarch64_be => switch (encoding.mode.arm64) { + .aarch64 => switch (encoding.mode.arm64) { .OLD => return error.UnsupportedDebugInfo, .FRAMELESS => ip: { const sp = (try dwarfRegNative(&context.cpu_state, sp_reg_num)).*; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index ffa99a27f24f..f84836a6d4d9 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -88,7 +88,7 @@ pub const UnwindContext = struct { .R15 = ctx.gprs.get(.r15), .Rip = ctx.gprs.get(.rip), }), - .aarch64, .aarch64_be => .{ + .aarch64 => .{ .ContextFlags = 0, .Cpsr = 0, .DUMMYUNIONNAME = .{ .X = ctx.x }, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 1089e74aa639..e8fb50d93a76 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -21,7 +21,7 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { const uc: *const signal_ucontext_t = @ptrCast(@alignCast(ctx_ptr)); return switch (native_arch) { .x86 => switch (native_os) { - .linux, .netbsd, .solaris, .illumos => .{ .gprs = .init(.{ + .linux, .netbsd, .illumos => .{ .gprs = .init(.{ .eax = uc.mcontext.gregs[std.posix.REG.EAX], .ecx = uc.mcontext.gregs[std.posix.REG.ECX], .edx = uc.mcontext.gregs[std.posix.REG.EDX], @@ -92,7 +92,7 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { .r15 = @bitCast(uc.sc_r15), .rip = @bitCast(uc.sc_rip), }) }, - .macos, .ios => .{ .gprs = .init(.{ + .driverkit, .macos, .ios => .{ .gprs = .init(.{ .rax = uc.mcontext.ss.rax, .rdx = uc.mcontext.ss.rdx, .rcx = uc.mcontext.ss.rcx, @@ -137,7 +137,7 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { else => null, }, .aarch64, .aarch64_be => switch (builtin.os.tag) { - .macos, .ios, .tvos, .watchos, .visionos => .{ + .driverkit, .macos, .ios, .tvos, .watchos, .visionos => .{ .x = uc.mcontext.ss.regs ++ @as([2]u64, .{ uc.mcontext.ss.fp, // x29 = fp uc.mcontext.ss.lr, // x30 = lr @@ -209,7 +209,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native { .r15 = ctx.R15, .rip = ctx.Rip, }) }, - .aarch64, .aarch64_be => .{ + .aarch64 => .{ .x = ctx.DUMMYUNIONNAME.X[0..31].*, .sp = ctx.Sp, .pc = ctx.Pc, @@ -371,7 +371,6 @@ pub const Arm = struct { pub fn dwarfRegisterBytes(ctx: *Arm, register_num: u16) DwarfRegisterError![]u8 { // DWARF for the Arm(r) Architecture § 4.1 "DWARF register names" switch (register_num) { - // The order of `Gpr` intentionally matches DWARF's mappings. 0...15 => return @ptrCast(&ctx.r[register_num]), 64...95 => return error.UnsupportedRegister, // S0 - S31 @@ -444,7 +443,6 @@ pub const Aarch64 = extern struct { pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 { // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names" switch (register_num) { - // The order of `Gpr` intentionally matches DWARF's mappings. 0...30 => return @ptrCast(&ctx.x[register_num]), 31 => return @ptrCast(&ctx.sp), 32 => return @ptrCast(&ctx.pc), @@ -471,7 +469,7 @@ const signal_ucontext_t = switch (native_os) { .linux => std.os.linux.ucontext_t, .emscripten => std.os.emscripten.ucontext_t, .freebsd => std.os.freebsd.ucontext_t, - .macos, .ios, .tvos, .watchos, .visionos => extern struct { + .driverkit, .macos, .ios, .tvos, .watchos, .visionos => extern struct { onstack: c_int, sigmask: std.c.sigset_t, stack: std.c.stack_t, From 8520e9312eed3b3b8d7f95d4844c83105c91ead1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 23:24:43 +0200 Subject: [PATCH 5/7] std.debug: add loongarch64-linux unwind support --- lib/std/debug/Dwarf.zig | 15 +++-- lib/std/debug/SelfInfo/Elf.zig | 1 + lib/std/debug/cpu_context.zig | 110 ++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 8 deletions(-) diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 7af76d02a1db..3283e59aea82 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1429,30 +1429,33 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u16 { /// Returns `null` for CPU architectures without an instruction pointer register. pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 { return switch (arch) { + .aarch64, .aarch64_be => 32, + .arm, .armeb, .thumb, .thumbeb => 15, + .loongarch32, .loongarch64 => 32, .x86 => 8, .x86_64 => 16, - .arm, .armeb, .thumb, .thumbeb => 15, - .aarch64, .aarch64_be => 32, else => null, }; } pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 { return switch (arch) { + .aarch64, .aarch64_be => 29, + .arm, .armeb, .thumb, .thumbeb => 11, + .loongarch32, .loongarch64 => 22, .x86 => 5, .x86_64 => 6, - .arm, .armeb, .thumb, .thumbeb => 11, - .aarch64, .aarch64_be => 29, else => unreachable, }; } pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 { return switch (arch) { + .aarch64, .aarch64_be => 31, + .arm, .armeb, .thumb, .thumbeb => 13, + .loongarch32, .loongarch64 => 3, .x86 => 4, .x86_64 => 7, - .arm, .armeb, .thumb, .thumbeb => 13, - .aarch64, .aarch64_be => 31, else => unreachable, }; } diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 36acdb54e367..7a7a0a2c57f8 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -87,6 +87,7 @@ pub const can_unwind: bool = s: { .linux => &.{ .aarch64, .aarch64_be, + .loongarch64, .x86, .x86_64, }, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index e8fb50d93a76..9b0af9019855 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -4,10 +4,11 @@ pub const Native = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "CpuContext")) root.debug.CpuContext else switch (native_arch) { + .aarch64, .aarch64_be => Aarch64, + .arm, .armeb, .thumb, .thumbeb => Arm, + .loongarch32, .loongarch64 => LoongArch, .x86 => X86, .x86_64 => X86_64, - .arm, .armeb, .thumb, .thumbeb => Arm, - .aarch64, .aarch64_be => Aarch64, else => noreturn, }; @@ -173,6 +174,13 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { }, else => null, }, + .loongarch64 => switch (builtin.os.tag) { + .linux => .{ + .r = uc.mcontext.regs, // includes r0 (hardwired zero) + .pc = uc.mcontext.pc, + }, + else => null, + }, else => null, }; } @@ -465,6 +473,104 @@ pub const Aarch64 = extern struct { } }; +/// This is an `extern struct` so that inline assembly in `current` can use field offsets. +pub const LoongArch = extern struct { + /// The numbered general-purpose registers r0 - r31. r0 must be zero. + r: [32]usize, + pc: usize, + + pub inline fn current() LoongArch { + var ctx: LoongArch = undefined; + asm volatile (if (@sizeOf(usize) == 8) + \\ st.d $zero, $t0, 0 + \\ st.d $ra, $t0, 8 + \\ st.d $tp, $t0, 16 + \\ st.d $sp, $t0, 24 + \\ st.d $a0, $t0, 32 + \\ st.d $a1, $t0, 40 + \\ st.d $a2, $t0, 48 + \\ st.d $a3, $t0, 56 + \\ st.d $a4, $t0, 64 + \\ st.d $a5, $t0, 72 + \\ st.d $a6, $t0, 80 + \\ st.d $a7, $t0, 88 + \\ st.d $t0, $t0, 96 + \\ st.d $t1, $t0, 104 + \\ st.d $t2, $t0, 112 + \\ st.d $t3, $t0, 120 + \\ st.d $t4, $t0, 128 + \\ st.d $t5, $t0, 136 + \\ st.d $t6, $t0, 144 + \\ st.d $t7, $t0, 152 + \\ st.d $t8, $t0, 160 + \\ st.d $r21, $t0, 168 + \\ st.d $fp, $t0, 176 + \\ st.d $s0, $t0, 184 + \\ st.d $s1, $t0, 192 + \\ st.d $s2, $t0, 200 + \\ st.d $s3, $t0, 208 + \\ st.d $s4, $t0, 216 + \\ st.d $s5, $t0, 224 + \\ st.d $s6, $t0, 232 + \\ st.d $s7, $t0, 240 + \\ st.d $s8, $t0, 248 + \\ bl 1f + \\1: + \\ st.d $ra, $t0, 256 + \\ ld.d $ra, $t0, 8 + else + \\ st.w $zero, $t0, 0 + \\ st.w $ra, $t0, 4 + \\ st.w $tp, $t0, 8 + \\ st.w $sp, $t0, 12 + \\ st.w $a0, $t0, 16 + \\ st.w $a1, $t0, 20 + \\ st.w $a2, $t0, 24 + \\ st.w $a3, $t0, 28 + \\ st.w $a4, $t0, 32 + \\ st.w $a5, $t0, 36 + \\ st.w $a6, $t0, 40 + \\ st.w $a7, $t0, 44 + \\ st.w $t0, $t0, 48 + \\ st.w $t1, $t0, 52 + \\ st.w $t2, $t0, 56 + \\ st.w $t3, $t0, 60 + \\ st.w $t4, $t0, 64 + \\ st.w $t5, $t0, 68 + \\ st.w $t6, $t0, 72 + \\ st.w $t7, $t0, 76 + \\ st.w $t8, $t0, 80 + \\ st.w $r21, $t0, 84 + \\ st.w $fp, $t0, 88 + \\ st.w $s0, $t0, 92 + \\ st.w $s1, $t0, 96 + \\ st.w $s2, $t0, 100 + \\ st.w $s3, $t0, 104 + \\ st.w $s4, $t0, 108 + \\ st.w $s5, $t0, 112 + \\ st.w $s6, $t0, 116 + \\ st.w $s7, $t0, 120 + \\ st.w $s8, $t0, 124 + \\ bl 1f + \\1: + \\ st.w $ra, $t0, 128 + \\ ld.w $ra, $t0, 4 + : + : [gprs] "{$r12}" (&ctx), + : .{ .memory = true }); + return ctx; + } + + pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 { + switch (register_num) { + 0...31 => return @ptrCast(&ctx.r[register_num]), + 32 => return @ptrCast(&ctx.pc), + + else => return error.InvalidRegister, + } + } +}; + const signal_ucontext_t = switch (native_os) { .linux => std.os.linux.ucontext_t, .emscripten => std.os.emscripten.ucontext_t, From 97de46dc16b584f5bd7aa2ae9afb2bb77970cd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 1 Oct 2025 23:24:53 +0200 Subject: [PATCH 6/7] std.debug: add riscv32-linux and riscv64-linux unwind support --- lib/std/debug/Dwarf.zig | 7 +-- lib/std/debug/SelfInfo/Elf.zig | 2 + lib/std/debug/cpu_context.zig | 106 +++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 3283e59aea82..ab064617eaf2 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1432,6 +1432,7 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 { .aarch64, .aarch64_be => 32, .arm, .armeb, .thumb, .thumbeb => 15, .loongarch32, .loongarch64 => 32, + .riscv32, .riscv32be, .riscv64, .riscv64be => 32, .x86 => 8, .x86_64 => 16, else => null, @@ -1443,6 +1444,7 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 { .aarch64, .aarch64_be => 29, .arm, .armeb, .thumb, .thumbeb => 11, .loongarch32, .loongarch64 => 22, + .riscv32, .riscv32be, .riscv64, .riscv64be => 8, .x86 => 5, .x86_64 => 6, else => unreachable, @@ -1454,6 +1456,7 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 { .aarch64, .aarch64_be => 31, .arm, .armeb, .thumb, .thumbeb => 13, .loongarch32, .loongarch64 => 3, + .riscv32, .riscv32be, .riscv64, .riscv64be => 2, .x86 => 4, .x86_64 => 7, else => unreachable, @@ -1473,10 +1476,6 @@ pub fn supportsUnwinding(target: *const std.Target) bool { .spirv64, => false, - // Enabling this causes relocation errors such as: - // error: invalid relocation type R_RISCV_SUB32 at offset 0x20 - .riscv64, .riscv64be, .riscv32, .riscv32be => false, - // Conservative guess. Feel free to update this logic with any targets // that are known to not support Dwarf unwinding. else => true, diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 7a7a0a2c57f8..ebb19c2a7bad 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -88,6 +88,8 @@ pub const can_unwind: bool = s: { .aarch64, .aarch64_be, .loongarch64, + .riscv32, + .riscv64, .x86, .x86_64, }, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 9b0af9019855..981174e95472 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -7,6 +7,7 @@ else switch (native_arch) { .aarch64, .aarch64_be => Aarch64, .arm, .armeb, .thumb, .thumbeb => Arm, .loongarch32, .loongarch64 => LoongArch, + .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv, .x86 => X86, .x86_64 => X86_64, else => noreturn, @@ -181,6 +182,13 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { }, else => null, }, + .riscv32, .riscv64 => switch (builtin.os.tag) { + .linux => .{ + .r = [1]usize{0} ++ uc.mcontext.gregs[1..].*, // r0 position is used for pc; replace with zero + .pc = uc.mcontext.gregs[0], + }, + else => null, + }, else => null, }; } @@ -571,6 +579,104 @@ pub const LoongArch = extern struct { } }; +/// This is an `extern struct` so that inline assembly in `current` can use field offsets. +pub const Riscv = extern struct { + /// The numbered general-purpose registers r0 - r31. r0 must be zero. + r: [32]usize, + pc: usize, + + pub inline fn current() Riscv { + var ctx: Riscv = undefined; + asm volatile (if (@sizeOf(usize) == 8) + \\ sd zero, 0(t0) + \\ sd ra, 8(t0) + \\ sd sp, 16(t0) + \\ sd gp, 24(t0) + \\ sd tp, 32(t0) + \\ sd t0, 40(t0) + \\ sd t1, 48(t0) + \\ sd t2, 56(t0) + \\ sd s0, 64(t0) + \\ sd s1, 72(t0) + \\ sd a0, 80(t0) + \\ sd a1, 88(t0) + \\ sd a2, 96(t0) + \\ sd a3, 104(t0) + \\ sd a4, 112(t0) + \\ sd a5, 120(t0) + \\ sd a6, 128(t0) + \\ sd a7, 136(t0) + \\ sd s2, 144(t0) + \\ sd s3, 152(t0) + \\ sd s4, 160(t0) + \\ sd s5, 168(t0) + \\ sd s6, 176(t0) + \\ sd s7, 184(t0) + \\ sd s8, 192(t0) + \\ sd s9, 200(t0) + \\ sd s10, 208(t0) + \\ sd s11, 216(t0) + \\ sd t3, 224(t0) + \\ sd t4, 232(t0) + \\ sd t5, 240(t0) + \\ sd t6, 248(t0) + \\ jal ra, 1f + \\1: + \\ sd ra, 256(t0) + \\ ld ra, 8(t0) + else + \\ sw zero, 0(t0) + \\ sw ra, 4(t0) + \\ sw sp, 8(t0) + \\ sw gp, 12(t0) + \\ sw tp, 16(t0) + \\ sw t0, 20(t0) + \\ sw t1, 24(t0) + \\ sw t2, 28(t0) + \\ sw s0, 32(t0) + \\ sw s1, 36(t0) + \\ sw a0, 40(t0) + \\ sw a1, 44(t0) + \\ sw a2, 48(t0) + \\ sw a3, 52(t0) + \\ sw a4, 56(t0) + \\ sw a5, 60(t0) + \\ sw a6, 64(t0) + \\ sw a7, 68(t0) + \\ sw s2, 72(t0) + \\ sw s3, 76(t0) + \\ sw s4, 80(t0) + \\ sw s5, 84(t0) + \\ sw s6, 88(t0) + \\ sw s7, 92(t0) + \\ sw s8, 96(t0) + \\ sw s9, 100(t0) + \\ sw s10, 104(t0) + \\ sw s11, 108(t0) + \\ sw t3, 112(t0) + \\ sw t4, 116(t0) + \\ sw t5, 120(t0) + \\ sw t6, 124(t0) + \\ jal ra, 1f + \\1: + \\ sw ra, 128(t0) + \\ lw ra, 4(t0) + : + : [gprs] "{t0}" (&ctx), + : .{ .memory = true }); + return ctx; + } + + pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 { + switch (register_num) { + 0...31 => return @ptrCast(&ctx.r[register_num]), + 32 => return @ptrCast(&ctx.pc), + + else => return error.InvalidRegister, + } + } +}; + const signal_ucontext_t = switch (native_os) { .linux => std.os.linux.ucontext_t, .emscripten => std.os.emscripten.ucontext_t, From a4f95b1e619656b0306744177dc4f8662ae4879b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 2 Oct 2025 03:05:33 +0200 Subject: [PATCH 7/7] std.debug.Dwarf.Unwind: deal with invalid def_cfa_reg by GNU toolchains --- lib/std/debug/Dwarf/Unwind/VirtualMachine.zig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/std/debug/Dwarf/Unwind/VirtualMachine.zig b/lib/std/debug/Dwarf/Unwind/VirtualMachine.zig index 319841ea7f18..ccb674b56560 100644 --- a/lib/std/debug/Dwarf/Unwind/VirtualMachine.zig +++ b/lib/std/debug/Dwarf/Unwind/VirtualMachine.zig @@ -256,7 +256,18 @@ fn evalInstructions( .offset = cfa.offset_sf * cie.data_alignment_factor, } }, .def_cfa_reg => |register| switch (vm.current_row.cfa) { - .none, .expression => return error.InvalidOperation, + .none => { + // According to the DWARF specification, this is not valid, because this + // instruction can only be used to replace the register if the rule is already a + // `.reg_off`. However, this is emitted in practice by GNU toolchains for some + // targets, and so by convention is interpreted as equivalent to `.def_cfa` with + // an offset of 0. + vm.current_row.cfa = .{ .reg_off = .{ + .register = register, + .offset = 0, + } }; + }, + .expression => return error.InvalidOperation, .reg_off => |*ro| ro.register = register, }, .def_cfa_offset => |offset| switch (vm.current_row.cfa) {