diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-10-03 03:27:02 +0200 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-10-03 03:29:20 +0200 |
| commit | 8263f55ab271c499a8a2133ef52e615850846bd1 (patch) | |
| tree | 7f49b910e6b87acf922a6bae899ed4e7b36710fd /lib/std/debug | |
| parent | 006bc5a8ca815e5c20438fa747bfbb336a6b5066 (diff) | |
| download | zig-8263f55ab271c499a8a2133ef52e615850846bd1.tar.gz zig-8263f55ab271c499a8a2133ef52e615850846bd1.zip | |
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 | 6 | ||||
| -rw-r--r-- | lib/std/debug/SelfInfo/Elf.zig | 1 | ||||
| -rw-r--r-- | lib/std/debug/cpu_context.zig | 87 |
4 files changed, 96 insertions, 1 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..c0a44b6a09 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, .{ 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, |
