diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-10-03 07:42:17 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-03 07:42:17 +0200 |
| commit | 1f083e9ed78f5c3c2d848d0abc58612c4ce88804 (patch) | |
| tree | 7eb2c831d2eecdd768c847c9ffe7948de7f2d24f /lib/std/debug | |
| parent | bc4da9a90743c11c7c0b3e485f46d365d57d87b7 (diff) | |
| parent | 95bdb0c1c65c128923ffac3f4be6b4619eb4a54b (diff) | |
| download | zig-1f083e9ed78f5c3c2d848d0abc58612c4ce88804.tar.gz zig-1f083e9ed78f5c3c2d848d0abc58612c4ce88804.zip | |
Merge pull request #25443 from alexrp/s390x-unwind
`std.debug`: add `s390x-linux` unwind support
Diffstat (limited to 'lib/std/debug')
| -rw-r--r-- | lib/std/debug/Dwarf.zig | 3 | ||||
| -rw-r--r-- | lib/std/debug/Dwarf/SelfUnwinder.zig | 16 | ||||
| -rw-r--r-- | lib/std/debug/SelfInfo/Elf.zig | 1 | ||||
| -rw-r--r-- | lib/std/debug/cpu_context.zig | 87 |
4 files changed, 103 insertions, 4 deletions
diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index ab064617ea..e510c84f15 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1433,6 +1433,7 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 { .arm, .armeb, .thumb, .thumbeb => 15, .loongarch32, .loongarch64 => 32, .riscv32, .riscv32be, .riscv64, .riscv64be => 32, + .s390x => 65, .x86 => 8, .x86_64 => 16, else => null, @@ -1445,6 +1446,7 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 { .arm, .armeb, .thumb, .thumbeb => 11, .loongarch32, .loongarch64 => 22, .riscv32, .riscv32be, .riscv64, .riscv64be => 8, + .s390x => 11, .x86 => 5, .x86_64 => 6, else => unreachable, @@ -1457,6 +1459,7 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 { .arm, .armeb, .thumb, .thumbeb => 13, .loongarch32, .loongarch64 => 3, .riscv32, .riscv32be, .riscv64, .riscv64be => 2, + .s390x => 15, .x86 => 4, .x86_64 => 7, else => unreachable, diff --git a/lib/std/debug/Dwarf/SelfUnwinder.zig b/lib/std/debug/Dwarf/SelfUnwinder.zig index 8ee08180dd..3a7b70b037 100644 --- a/lib/std/debug/Dwarf/SelfUnwinder.zig +++ b/lib/std/debug/Dwarf/SelfUnwinder.zig @@ -176,7 +176,11 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE break :cfa try applyOffset(ptr.*, ro.offset); }, .expression => |expr| cfa: { - // On all implemented architectures, the CFA is defined to be the previous frame's SP + // On most implemented architectures, the CFA is defined to be the previous frame's SP. + // + // On s390x, it's defined to be SP + 160 (ELF ABI s390x Supplement §1.6.3); however, + // what this actually means is that there will be a `def_cfa r15 + 160`, so nothing + // special for us to do. const prev_cfa_val = (try regNative(&unwinder.cpu_state, sp_reg_num)).*; unwinder.expr_vm.reset(); const value = try unwinder.expr_vm.run(expr, gpa, .{ @@ -193,9 +197,13 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE // If unspecified, we'll use the default rule for the return address register, which is // typically equivalent to `.undefined` (meaning there is no return address), but may be // overriden by ABIs. - var has_return_address: bool = builtin.cpu.arch.isAARCH64() and - return_address_register >= 19 and - return_address_register <= 28; + var has_return_address: bool = switch (builtin.cpu.arch) { + // DWARF for the Arm 64-bit Architecture (AArch64) §4.3, p1 + .aarch64, .aarch64_be => return_address_register >= 19 and return_address_register <= 28, + // ELF ABI s390x Supplement §1.6.4 + .s390x => return_address_register >= 6 and return_address_register <= 15, + else => false, + }; // Create a copy of the CPU state, to which we will apply the new rules. var new_cpu_state = unwinder.cpu_state; diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index ebb19c2a7b..9772ec0aac 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -90,6 +90,7 @@ pub const can_unwind: bool = s: { .loongarch64, .riscv32, .riscv64, + .s390x, .x86, .x86_64, }, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 981174e954..0e25d00480 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -8,6 +8,7 @@ else switch (native_arch) { .arm, .armeb, .thumb, .thumbeb => Arm, .loongarch32, .loongarch64 => LoongArch, .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv, + .s390x => S390x, .x86 => X86, .x86_64 => X86_64, else => noreturn, @@ -189,6 +190,17 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { }, else => null, }, + .s390x => switch (builtin.os.tag) { + .linux => .{ + .r = uc.mcontext.gregs, + .f = uc.mcontext.fregs, + .psw = .{ + .mask = uc.mcontext.psw.mask, + .addr = uc.mcontext.psw.addr, + }, + }, + else => null, + }, else => null, }; } @@ -677,6 +689,81 @@ pub const Riscv = extern struct { } }; +/// This is an `extern struct` so that inline assembly in `current` can use field offsets. +pub const S390x = extern struct { + /// The numbered general-purpose registers r0 - r15. + r: [16]u64, + /// The numbered floating-point registers f0 - f15. Yes, really - they can be used in DWARF CFI. + f: [16]f64, + /// The program counter. + psw: extern struct { + mask: u64, + addr: u64, + }, + + pub inline fn current() S390x { + var ctx: S390x = undefined; + asm volatile ( + \\ stmg %%r0, %%r15, 0(%%r2) + \\ std %%f0, 128(%%r2) + \\ std %%f1, 136(%%r2) + \\ std %%f2, 144(%%r2) + \\ std %%f3, 152(%%r2) + \\ std %%f4, 160(%%r2) + \\ std %%f5, 168(%%r2) + \\ std %%f6, 176(%%r2) + \\ std %%f7, 184(%%r2) + \\ std %%f8, 192(%%r2) + \\ std %%f9, 200(%%r2) + \\ std %%f10, 208(%%r2) + \\ std %%f11, 216(%%r2) + \\ std %%f12, 224(%%r2) + \\ std %%f13, 232(%%r2) + \\ std %%f14, 240(%%r2) + \\ std %%f15, 248(%%r2) + \\ epsw %%r0, %%r1 + \\ stm %%r0, %%r1, 256(%%r2) + \\ larl %%r0, . + \\ stg %%r0, 264(%%r2) + \\ lg %%r0, 0(%%r2) + \\ lg %%r1, 8(%%r2) + : + : [gprs] "{r2}" (&ctx), + : .{ .memory = true }); + return ctx; + } + + pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 { + switch (register_num) { + 0...15 => return @ptrCast(&ctx.r[register_num]), + // Why??? + 16 => return @ptrCast(&ctx.f[0]), + 17 => return @ptrCast(&ctx.f[2]), + 18 => return @ptrCast(&ctx.f[4]), + 19 => return @ptrCast(&ctx.f[6]), + 20 => return @ptrCast(&ctx.f[1]), + 21 => return @ptrCast(&ctx.f[3]), + 22 => return @ptrCast(&ctx.f[5]), + 23 => return @ptrCast(&ctx.f[7]), + 24 => return @ptrCast(&ctx.f[8]), + 25 => return @ptrCast(&ctx.f[10]), + 26 => return @ptrCast(&ctx.f[12]), + 27 => return @ptrCast(&ctx.f[14]), + 28 => return @ptrCast(&ctx.f[9]), + 29 => return @ptrCast(&ctx.f[11]), + 30 => return @ptrCast(&ctx.f[13]), + 31 => return @ptrCast(&ctx.f[15]), + 64 => return @ptrCast(&ctx.psw.mask), + 65 => return @ptrCast(&ctx.psw.addr), + + 48...63 => return error.UnsupportedRegister, // a0 - a15 + 68...83 => return error.UnsupportedRegister, // v16 - v31 + + else => return error.InvalidRegister, + } + } +}; + const signal_ucontext_t = switch (native_os) { .linux => std.os.linux.ucontext_t, .emscripten => std.os.emscripten.ucontext_t, |
