mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge pull request #25493 from alexrp/std-debug-mips-ppc
`std.debug`: MIPS and PowerPC unwind support + some other stuff
This commit is contained in:
commit
2aea7a42b0
@ -623,7 +623,7 @@ pub const StackUnwindOptions = struct {
|
||||
/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.
|
||||
///
|
||||
/// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it.
|
||||
pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
|
||||
pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
|
||||
const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
|
||||
if (!std.options.allow_stack_tracing) return empty_trace;
|
||||
var it = StackIterator.init(options.context) catch return empty_trace;
|
||||
@ -661,7 +661,7 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
|
||||
/// Write the current stack trace to `writer`, annotated with source locations.
|
||||
///
|
||||
/// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing.
|
||||
pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
|
||||
pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
|
||||
if (!std.options.allow_stack_tracing) {
|
||||
tty_config.setColor(writer, .dim) catch {};
|
||||
try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});
|
||||
|
||||
@ -1432,8 +1432,10 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 {
|
||||
.aarch64, .aarch64_be => 32,
|
||||
.arm, .armeb, .thumb, .thumbeb => 15,
|
||||
.hexagon => 76,
|
||||
.loongarch32, .loongarch64 => 32,
|
||||
.riscv32, .riscv32be, .riscv64, .riscv64be => 32,
|
||||
.loongarch32, .loongarch64 => 64,
|
||||
.mips, .mipsel, .mips64, .mips64el => 66,
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => 67,
|
||||
.riscv32, .riscv32be, .riscv64, .riscv64be => 65,
|
||||
.s390x => 65,
|
||||
.x86 => 8,
|
||||
.x86_64 => 16,
|
||||
@ -1447,6 +1449,8 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 {
|
||||
.arm, .armeb, .thumb, .thumbeb => 11,
|
||||
.hexagon => 30,
|
||||
.loongarch32, .loongarch64 => 22,
|
||||
.mips, .mipsel, .mips64, .mips64el => 30,
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
|
||||
.riscv32, .riscv32be, .riscv64, .riscv64be => 8,
|
||||
.s390x => 11,
|
||||
.x86 => 5,
|
||||
@ -1461,6 +1465,8 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 {
|
||||
.arm, .armeb, .thumb, .thumbeb => 13,
|
||||
.hexagon => 29,
|
||||
.loongarch32, .loongarch64 => 3,
|
||||
.mips, .mipsel, .mips64, .mips64el => 29,
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
|
||||
.riscv32, .riscv32be, .riscv64, .riscv64be => 2,
|
||||
.s390x => 15,
|
||||
.x86 => 4,
|
||||
|
||||
@ -229,8 +229,10 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
|
||||
} = switch (rule) {
|
||||
.default => val: {
|
||||
// The default rule is typically equivalent to `.undefined`, but ABIs may override it.
|
||||
if (builtin.cpu.arch.isAARCH64() and register >= 19 and register <= 28) {
|
||||
break :val .same;
|
||||
switch (builtin.target.cpu.arch) {
|
||||
.aarch64, .aarch64_be => if (register >= 19 and register <= 28) break :val .same,
|
||||
.s390x => if (register >= 6 and register <= 15) break :val .same,
|
||||
else => {},
|
||||
}
|
||||
break :val .undefined;
|
||||
},
|
||||
|
||||
@ -1160,22 +1160,19 @@ test "basics" {
|
||||
|
||||
mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
|
||||
(try regNative(&cpu_context, fp_reg_num)).* = 1;
|
||||
(try regNative(&cpu_context, sp_reg_num)).* = 2;
|
||||
(try regNative(&cpu_context, ip_reg_num)).* = 3;
|
||||
(try regNative(&cpu_context, ip_reg_num)).* = 2;
|
||||
|
||||
try b.writeBreg(writer, fp_reg_num, @as(usize, 100));
|
||||
try b.writeBreg(writer, sp_reg_num, @as(usize, 200));
|
||||
try b.writeBregx(writer, ip_reg_num, @as(usize, 300));
|
||||
try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
|
||||
try b.writeBregx(writer, ip_reg_num, @as(usize, 200));
|
||||
try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 300));
|
||||
|
||||
_ = try stack_machine.run(program.written(), allocator, context, 0);
|
||||
|
||||
const regval_type = stack_machine.stack.pop().?.regval_type;
|
||||
try testing.expectEqual(@as(usize, 400), regval_type.type_offset);
|
||||
try testing.expectEqual(@as(usize, 300), regval_type.type_offset);
|
||||
try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size);
|
||||
try testing.expectEqual(@as(usize, 0xee), regval_type.value);
|
||||
|
||||
try testing.expectEqual(@as(usize, 303), stack_machine.stack.pop().?.generic);
|
||||
try testing.expectEqual(@as(usize, 202), stack_machine.stack.pop().?.generic);
|
||||
try testing.expectEqual(@as(usize, 101), stack_machine.stack.pop().?.generic);
|
||||
}
|
||||
|
||||
@ -99,6 +99,14 @@ pub const can_unwind: bool = s: {
|
||||
.aarch64_be,
|
||||
.hexagon,
|
||||
.loongarch64,
|
||||
.mips,
|
||||
.mipsel,
|
||||
.mips64,
|
||||
.mips64el,
|
||||
.powerpc,
|
||||
.powerpcle,
|
||||
.powerpc64,
|
||||
.powerpc64le,
|
||||
.riscv32,
|
||||
.riscv64,
|
||||
.s390x,
|
||||
|
||||
@ -8,6 +8,8 @@ else switch (native_arch) {
|
||||
.arm, .armeb, .thumb, .thumbeb => Arm,
|
||||
.hexagon => Hexagon,
|
||||
.loongarch32, .loongarch64 => LoongArch,
|
||||
.mips, .mipsel, .mips64, .mips64el => Mips,
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
|
||||
.riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
|
||||
.s390x => S390x,
|
||||
.x86 => X86,
|
||||
@ -196,6 +198,33 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
|
||||
},
|
||||
else => null,
|
||||
},
|
||||
.mips, .mipsel => switch (builtin.os.tag) {
|
||||
// The O32 kABI uses 64-bit fields for some reason...
|
||||
.linux => .{
|
||||
.r = s: {
|
||||
var regs: [32]Mips.Gpr = undefined;
|
||||
for (uc.mcontext.regs, 0..) |r, i| regs[i] = @truncate(r); // includes r0 (hardwired zero)
|
||||
break :s regs;
|
||||
},
|
||||
.pc = @truncate(uc.mcontext.pc),
|
||||
},
|
||||
else => null,
|
||||
},
|
||||
.mips64, .mips64el => switch (builtin.os.tag) {
|
||||
.linux => .{
|
||||
.r = uc.mcontext.regs, // includes r0 (hardwired zero)
|
||||
.pc = uc.mcontext.pc,
|
||||
},
|
||||
else => null,
|
||||
},
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => switch (builtin.os.tag) {
|
||||
.linux => .{
|
||||
.r = uc.mcontext.gp_regs[0..32].*,
|
||||
.pc = uc.mcontext.gp_regs[32],
|
||||
.lr = uc.mcontext.gp_regs[36],
|
||||
},
|
||||
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
|
||||
@ -210,7 +239,6 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
|
||||
.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,
|
||||
@ -269,7 +297,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
|
||||
};
|
||||
}
|
||||
|
||||
pub const X86 = struct {
|
||||
const X86 = struct {
|
||||
/// The first 8 registers here intentionally match the order of registers in the x86 instruction
|
||||
/// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
|
||||
/// among other things.
|
||||
@ -313,7 +341,7 @@ pub const X86 = struct {
|
||||
// x86-macos is a deprecated target which is not supported by the Zig Standard Library.
|
||||
0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
|
||||
|
||||
9 => return error.UnsupportedRegister, // rflags
|
||||
9 => return error.UnsupportedRegister, // eflags
|
||||
11...18 => return error.UnsupportedRegister, // st0 - st7
|
||||
21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
|
||||
29...36 => return error.UnsupportedRegister, // mm0 - mm7
|
||||
@ -321,14 +349,14 @@ pub const X86 = struct {
|
||||
40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
|
||||
48 => return error.UnsupportedRegister, // tr
|
||||
49 => return error.UnsupportedRegister, // ldtr
|
||||
93...94 => return error.UnsupportedRegister, // fs.base, gs.base
|
||||
93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const X86_64 = struct {
|
||||
const X86_64 = struct {
|
||||
/// The order here intentionally matches the order of the DWARF register mappings. It's unclear
|
||||
/// where those mappings actually originated from---the ordering of the first 4 registers seems
|
||||
/// quite unusual---but it is currently convenient for us to match DWARF.
|
||||
@ -389,13 +417,16 @@ pub const X86_64 = struct {
|
||||
64 => return error.UnsupportedRegister, // mxcsr
|
||||
65 => return error.UnsupportedRegister, // fcw
|
||||
66 => return error.UnsupportedRegister, // fsw
|
||||
67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
|
||||
118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
|
||||
130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Arm = struct {
|
||||
const Arm = struct {
|
||||
/// The numbered general-purpose registers R0 - R15.
|
||||
r: [16]u32,
|
||||
|
||||
@ -449,7 +480,7 @@ pub const Arm = struct {
|
||||
};
|
||||
|
||||
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
|
||||
pub const Aarch64 = extern struct {
|
||||
const Aarch64 = extern struct {
|
||||
/// The numbered general-purpose registers X0 - X30.
|
||||
x: [31]u64,
|
||||
sp: u64,
|
||||
@ -492,13 +523,13 @@ pub const Aarch64 = extern struct {
|
||||
31 => return @ptrCast(&ctx.sp),
|
||||
32 => return @ptrCast(&ctx.pc),
|
||||
|
||||
33 => return error.UnsupportedRegister, // ELF_mode
|
||||
33 => return error.UnsupportedRegister, // ELR_mode
|
||||
34 => return error.UnsupportedRegister, // RA_SIGN_STATE
|
||||
35 => return error.UnsupportedRegister, // TPIDRRO_ELO
|
||||
36 => return error.UnsupportedRegister, // RPIDR_ELO
|
||||
37 => return error.UnsupportedRegister, // RPIDR_EL1
|
||||
38 => return error.UnsupportedRegister, // RPIDR_EL2
|
||||
39 => return error.UnsupportedRegister, // RPIDR_EL3
|
||||
36 => return error.UnsupportedRegister, // TPIDR_ELO
|
||||
37 => return error.UnsupportedRegister, // TPIDR_EL1
|
||||
38 => return error.UnsupportedRegister, // TPIDR_EL2
|
||||
39 => return error.UnsupportedRegister, // TPIDR_EL3
|
||||
46 => return error.UnsupportedRegister, // VG
|
||||
47 => return error.UnsupportedRegister, // FFR
|
||||
48...63 => return error.UnsupportedRegister, // P0 - P15
|
||||
@ -511,7 +542,7 @@ pub const Aarch64 = extern struct {
|
||||
};
|
||||
|
||||
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
|
||||
pub const Hexagon = extern struct {
|
||||
const Hexagon = extern struct {
|
||||
/// The numbered general-purpose registers r0 - r31.
|
||||
r: [32]u32,
|
||||
pc: u32,
|
||||
@ -579,14 +610,16 @@ pub const Hexagon = extern struct {
|
||||
};
|
||||
|
||||
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
|
||||
pub const LoongArch = extern struct {
|
||||
const LoongArch = extern struct {
|
||||
/// The numbered general-purpose registers r0 - r31. r0 must be zero.
|
||||
r: [32]usize,
|
||||
pc: usize,
|
||||
r: [32]Gpr,
|
||||
pc: Gpr,
|
||||
|
||||
pub const Gpr = if (builtin.target.cpu.arch == .loongarch64) u64 else u32;
|
||||
|
||||
pub inline fn current() LoongArch {
|
||||
var ctx: LoongArch = undefined;
|
||||
asm volatile (if (@sizeOf(usize) == 8)
|
||||
asm volatile (if (Gpr == u64)
|
||||
\\ st.d $zero, $t0, 0
|
||||
\\ st.d $ra, $t0, 8
|
||||
\\ st.d $tp, $t0, 16
|
||||
@ -669,7 +702,9 @@ pub const LoongArch = extern struct {
|
||||
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),
|
||||
64 => return @ptrCast(&ctx.pc),
|
||||
|
||||
32...63 => return error.UnsupportedRegister, // f0 - f31
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
@ -677,14 +712,294 @@ 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 {
|
||||
const Mips = extern struct {
|
||||
/// The numbered general-purpose registers r0 - r31. r0 must be zero.
|
||||
r: [32]usize,
|
||||
pc: usize,
|
||||
r: [32]Gpr,
|
||||
pc: Gpr,
|
||||
|
||||
pub const Gpr = if (builtin.target.cpu.arch.isMIPS64()) u64 else u32;
|
||||
|
||||
pub inline fn current() Mips {
|
||||
var ctx: Mips = undefined;
|
||||
asm volatile (if (Gpr == u64)
|
||||
\\ .set push
|
||||
\\ .set noat
|
||||
\\ .set noreorder
|
||||
\\ .set nomacro
|
||||
\\ sd $zero, 0($t0)
|
||||
\\ sd $at, 8($t0)
|
||||
\\ sd $v0, 16($t0)
|
||||
\\ sd $v1, 24($t0)
|
||||
\\ sd $a0, 32($t0)
|
||||
\\ sd $a1, 40($t0)
|
||||
\\ sd $a2, 48($t0)
|
||||
\\ sd $a3, 56($t0)
|
||||
\\ sd $a4, 64($t0)
|
||||
\\ sd $a5, 72($t0)
|
||||
\\ sd $a6, 80($t0)
|
||||
\\ sd $a7, 88($t0)
|
||||
\\ sd $t0, 96($t0)
|
||||
\\ sd $t1, 104($t0)
|
||||
\\ sd $t2, 112($t0)
|
||||
\\ sd $t3, 120($t0)
|
||||
\\ sd $s0, 128($t0)
|
||||
\\ sd $s1, 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 $t8, 192($t0)
|
||||
\\ sd $t9, 200($t0)
|
||||
\\ sd $k0, 208($t0)
|
||||
\\ sd $k1, 216($t0)
|
||||
\\ sd $gp, 224($t0)
|
||||
\\ sd $sp, 232($t0)
|
||||
\\ sd $fp, 240($t0)
|
||||
\\ sd $ra, 248($t0)
|
||||
\\ bal 1f
|
||||
\\1:
|
||||
\\ sd $ra, 256($t0)
|
||||
\\ ld $ra, 248($t0)
|
||||
\\ .set pop
|
||||
else
|
||||
\\ .set push
|
||||
\\ .set noat
|
||||
\\ .set noreorder
|
||||
\\ .set nomacro
|
||||
\\ sw $zero, 0($t4)
|
||||
\\ sw $at, 4($t4)
|
||||
\\ sw $v0, 8($t4)
|
||||
\\ sw $v1, 12($t4)
|
||||
\\ sw $a0, 16($t4)
|
||||
\\ sw $a1, 20($t4)
|
||||
\\ sw $a2, 24($t4)
|
||||
\\ sw $a3, 28($t4)
|
||||
\\ sw $t0, 32($t4)
|
||||
\\ sw $t1, 36($t4)
|
||||
\\ sw $t2, 40($t4)
|
||||
\\ sw $t3, 44($t4)
|
||||
\\ sw $t4, 48($t4)
|
||||
\\ sw $t5, 52($t4)
|
||||
\\ sw $t6, 56($t4)
|
||||
\\ sw $t7, 60($t4)
|
||||
\\ sw $s0, 64($t4)
|
||||
\\ sw $s1, 68($t4)
|
||||
\\ sw $s2, 72($t4)
|
||||
\\ sw $s3, 76($t4)
|
||||
\\ sw $s4, 80($t4)
|
||||
\\ sw $s5, 84($t4)
|
||||
\\ sw $s6, 88($t4)
|
||||
\\ sw $s7, 92($t4)
|
||||
\\ sw $t8, 96($t4)
|
||||
\\ sw $t9, 100($t4)
|
||||
\\ sw $k0, 104($t4)
|
||||
\\ sw $k1, 108($t4)
|
||||
\\ sw $gp, 112($t4)
|
||||
\\ sw $sp, 116($t4)
|
||||
\\ sw $fp, 120($t4)
|
||||
\\ sw $ra, 124($t4)
|
||||
\\ bal 1f
|
||||
\\1:
|
||||
\\ sw $ra, 128($t4)
|
||||
\\ lw $ra, 124($t4)
|
||||
\\ .set pop
|
||||
:
|
||||
: [gprs] "{$12}" (&ctx),
|
||||
: .{ .memory = true });
|
||||
return ctx;
|
||||
}
|
||||
|
||||
pub fn dwarfRegisterBytes(ctx: *Mips, register_num: u16) DwarfRegisterError![]u8 {
|
||||
switch (register_num) {
|
||||
0...31 => return @ptrCast(&ctx.r[register_num]),
|
||||
66 => return @ptrCast(&ctx.pc),
|
||||
|
||||
// Who the hell knows what numbers exist for this architecture? What's an ABI
|
||||
// specification anyway? We don't need that nonsense.
|
||||
32...63 => return error.UnsupportedRegister, // f0 - f31, w0 - w31
|
||||
64 => return error.UnsupportedRegister, // hi0 (ac0)
|
||||
65 => return error.UnsupportedRegister, // lo0 (ac0)
|
||||
176 => return error.UnsupportedRegister, // hi1 (ac1)
|
||||
177 => return error.UnsupportedRegister, // lo1 (ac1)
|
||||
178 => return error.UnsupportedRegister, // hi2 (ac2)
|
||||
179 => return error.UnsupportedRegister, // lo2 (ac2)
|
||||
180 => return error.UnsupportedRegister, // hi3 (ac3)
|
||||
181 => return error.UnsupportedRegister, // lo3 (ac3)
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
|
||||
const Powerpc = extern struct {
|
||||
/// The numbered general-purpose registers r0 - r31.
|
||||
r: [32]Gpr,
|
||||
pc: Gpr,
|
||||
lr: Gpr,
|
||||
|
||||
pub const Gpr = if (builtin.target.cpu.arch.isPowerPC64()) u64 else u32;
|
||||
|
||||
pub inline fn current() Powerpc {
|
||||
var ctx: Powerpc = undefined;
|
||||
asm volatile (if (Gpr == u64)
|
||||
\\ std 0, 0(10)
|
||||
\\ std 1, 8(10)
|
||||
\\ std 2, 16(10)
|
||||
\\ std 3, 24(10)
|
||||
\\ std 4, 32(10)
|
||||
\\ std 5, 40(10)
|
||||
\\ std 6, 48(10)
|
||||
\\ std 7, 56(10)
|
||||
\\ std 8, 64(10)
|
||||
\\ std 9, 72(10)
|
||||
\\ std 10, 80(10)
|
||||
\\ std 11, 88(10)
|
||||
\\ std 12, 96(10)
|
||||
\\ std 13, 104(10)
|
||||
\\ std 14, 112(10)
|
||||
\\ std 15, 120(10)
|
||||
\\ std 16, 128(10)
|
||||
\\ std 17, 136(10)
|
||||
\\ std 18, 144(10)
|
||||
\\ std 19, 152(10)
|
||||
\\ std 20, 160(10)
|
||||
\\ std 21, 168(10)
|
||||
\\ std 22, 176(10)
|
||||
\\ std 23, 184(10)
|
||||
\\ std 24, 192(10)
|
||||
\\ std 25, 200(10)
|
||||
\\ std 26, 208(10)
|
||||
\\ std 27, 216(10)
|
||||
\\ std 28, 224(10)
|
||||
\\ std 29, 232(10)
|
||||
\\ std 30, 240(10)
|
||||
\\ std 31, 248(10)
|
||||
\\ mflr 8
|
||||
\\ std 8, 264(10)
|
||||
\\ bl 1f
|
||||
\\1:
|
||||
\\ mflr 8
|
||||
\\ std 8, 256(10)
|
||||
\\ ld 8, 64(10)
|
||||
else
|
||||
\\ stw 0, 0(10)
|
||||
\\ stw 1, 4(10)
|
||||
\\ stw 2, 8(10)
|
||||
\\ stw 3, 12(10)
|
||||
\\ stw 4, 16(10)
|
||||
\\ stw 5, 20(10)
|
||||
\\ stw 6, 24(10)
|
||||
\\ stw 7, 28(10)
|
||||
\\ stw 8, 32(10)
|
||||
\\ stw 9, 36(10)
|
||||
\\ stw 10, 40(10)
|
||||
\\ stw 11, 44(10)
|
||||
\\ stw 12, 48(10)
|
||||
\\ stw 13, 52(10)
|
||||
\\ stw 14, 56(10)
|
||||
\\ stw 15, 60(10)
|
||||
\\ stw 16, 64(10)
|
||||
\\ stw 17, 68(10)
|
||||
\\ stw 18, 72(10)
|
||||
\\ stw 19, 76(10)
|
||||
\\ stw 20, 80(10)
|
||||
\\ stw 21, 84(10)
|
||||
\\ stw 22, 88(10)
|
||||
\\ stw 23, 92(10)
|
||||
\\ stw 24, 96(10)
|
||||
\\ stw 25, 100(10)
|
||||
\\ stw 26, 104(10)
|
||||
\\ stw 27, 108(10)
|
||||
\\ stw 28, 112(10)
|
||||
\\ stw 29, 116(10)
|
||||
\\ stw 30, 120(10)
|
||||
\\ stw 31, 124(10)
|
||||
\\ mflr 8
|
||||
\\ stw 8, 132(10)
|
||||
\\ bl 1f
|
||||
\\1:
|
||||
\\ mflr 8
|
||||
\\ stw 8, 128(10)
|
||||
\\ lwz 8, 32(10)
|
||||
:
|
||||
: [gprs] "{r10}" (&ctx),
|
||||
: .{ .lr = true, .memory = true });
|
||||
return ctx;
|
||||
}
|
||||
|
||||
pub fn dwarfRegisterBytes(ctx: *Powerpc, register_num: u16) DwarfRegisterError![]u8 {
|
||||
// References:
|
||||
//
|
||||
// * System V Application Binary Interface - PowerPC Processor Supplement §3-46
|
||||
// * Power Architecture 32-bit Application Binary Interface Supplement 1.0 - Linux & Embedded §3.4
|
||||
// * 64-bit ELF V2 ABI Specification - Power Architecture Revision 1.5 §2.4
|
||||
// * ??? AIX?
|
||||
//
|
||||
// Are we having fun yet?
|
||||
|
||||
if (Gpr == u64) switch (register_num) {
|
||||
65 => return @ptrCast(&ctx.lr), // lr
|
||||
|
||||
66 => return error.UnsupportedRegister, // ctr
|
||||
68...75 => return error.UnsupportedRegister, // cr0 - cr7
|
||||
76 => return error.UnsupportedRegister, // xer
|
||||
77...108 => return error.UnsupportedRegister, // vr0 - vr31
|
||||
109 => return error.UnsupportedRegister, // vrsave (LLVM)
|
||||
110 => return error.UnsupportedRegister, // vscr
|
||||
114 => return error.UnsupportedRegister, // tfhar
|
||||
115 => return error.UnsupportedRegister, // tfiar
|
||||
116 => return error.UnsupportedRegister, // texasr
|
||||
|
||||
else => {},
|
||||
} else switch (register_num) {
|
||||
65 => return @ptrCast(&ctx.lr), // fpscr (SVR4 / EABI), or lr if you ask LLVM
|
||||
108 => return @ptrCast(&ctx.lr),
|
||||
|
||||
64 => return error.UnsupportedRegister, // cr
|
||||
66 => return error.UnsupportedRegister, // msr (SVR4 / EABI), or ctr if you ask LLVM
|
||||
68...75 => return error.UnsupportedRegister, // cr0 - cr7 if you ask LLVM
|
||||
76 => return error.UnsupportedRegister, // xer if you ask LLVM
|
||||
99 => return error.UnsupportedRegister, // acc
|
||||
100 => return error.UnsupportedRegister, // mq
|
||||
101 => return error.UnsupportedRegister, // xer
|
||||
102...107 => return error.UnsupportedRegister, // SPRs
|
||||
109 => return error.UnsupportedRegister, // ctr
|
||||
110...111 => return error.UnsupportedRegister, // SPRs
|
||||
112 => return error.UnsupportedRegister, // spefscr
|
||||
113...1123 => return error.UnsupportedRegister, // SPRs
|
||||
1124...1155 => return error.UnsupportedRegister, // SPE v0 - v31
|
||||
1200...1231 => return error.UnsupportedRegister, // SPE upper r0 - r31
|
||||
3072...4095 => return error.UnsupportedRegister, // DCRs
|
||||
4096...5120 => return error.UnsupportedRegister, // PMRs
|
||||
|
||||
else => {},
|
||||
}
|
||||
|
||||
switch (register_num) {
|
||||
0...31 => return @ptrCast(&ctx.r[register_num]),
|
||||
67 => return @ptrCast(&ctx.pc),
|
||||
|
||||
32...63 => return error.UnsupportedRegister, // f0 - f31
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
|
||||
const Riscv = extern struct {
|
||||
/// The numbered general-purpose registers r0 - r31. r0 must be zero.
|
||||
r: [32]Gpr,
|
||||
pc: Gpr,
|
||||
|
||||
pub const Gpr = if (builtin.target.cpu.arch.isRiscv64()) u64 else u32;
|
||||
|
||||
pub inline fn current() Riscv {
|
||||
var ctx: Riscv = undefined;
|
||||
asm volatile (if (@sizeOf(usize) == 8)
|
||||
asm volatile (if (Gpr == u64)
|
||||
\\ sd zero, 0(t0)
|
||||
\\ sd ra, 8(t0)
|
||||
\\ sd sp, 16(t0)
|
||||
@ -767,7 +1082,13 @@ pub const Riscv = extern struct {
|
||||
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),
|
||||
65 => return @ptrCast(&ctx.pc),
|
||||
|
||||
32...63 => return error.UnsupportedRegister, // f0 - f31
|
||||
64 => return error.UnsupportedRegister, // Alternate Frame Return Column
|
||||
96...127 => return error.UnsupportedRegister, // v0 - v31
|
||||
3072...4095 => return error.UnsupportedRegister, // Custom extensions
|
||||
4096...8191 => return error.UnsupportedRegister, // CSRs
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
}
|
||||
@ -775,11 +1096,9 @@ 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 {
|
||||
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,
|
||||
@ -790,26 +1109,10 @@ pub const S390x = extern struct {
|
||||
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)
|
||||
\\ stm %%r0, %%r1, 128(%%r2)
|
||||
\\ larl %%r0, .
|
||||
\\ stg %%r0, 264(%%r2)
|
||||
\\ stg %%r0, 136(%%r2)
|
||||
\\ lg %%r0, 0(%%r2)
|
||||
\\ lg %%r1, 8(%%r2)
|
||||
:
|
||||
@ -821,27 +1124,13 @@ pub const S390x = extern struct {
|
||||
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),
|
||||
|
||||
16...31 => return error.UnsupportedRegister, // f0 - f15
|
||||
32...47 => return error.UnsupportedRegister, // cr0 - cr15
|
||||
48...63 => return error.UnsupportedRegister, // a0 - a15
|
||||
66...67 => return error.UnsupportedRegister, // z/OS stuff???
|
||||
68...83 => return error.UnsupportedRegister, // v16 - v31
|
||||
|
||||
else => return error.InvalidRegister,
|
||||
|
||||
@ -254,13 +254,13 @@ pub const mcontext_t = extern struct {
|
||||
badva: u32,
|
||||
cs0: u32,
|
||||
cs1: u32,
|
||||
_pad2: u32,
|
||||
_pad1: u32,
|
||||
};
|
||||
|
||||
pub const ucontext_t = extern struct {
|
||||
flags: usize,
|
||||
flags: u32,
|
||||
link: ?*ucontext_t,
|
||||
stack: stack_t,
|
||||
mcontext: mcontext_t,
|
||||
sigmask: [2]u32,
|
||||
sigmask: sigset_t,
|
||||
};
|
||||
|
||||
@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
|
||||
const uid_t = linux.uid_t;
|
||||
const gid_t = linux.gid_t;
|
||||
const pid_t = linux.pid_t;
|
||||
const stack_t = linux.stack_t;
|
||||
const sigset_t = linux.sigset_t;
|
||||
const sockaddr = linux.sockaddr;
|
||||
const timespec = linux.timespec;
|
||||
|
||||
@ -347,5 +349,31 @@ pub const timezone = extern struct {
|
||||
|
||||
pub const Elf_Symndx = u32;
|
||||
|
||||
/// TODO
|
||||
pub const ucontext_t = void;
|
||||
pub const mcontext_t = extern struct {
|
||||
_regmask: u32,
|
||||
_status: u32,
|
||||
pc: u64,
|
||||
regs: [32]u64,
|
||||
fpregs: [32]f64,
|
||||
acx: u32,
|
||||
fpc_csr: u32,
|
||||
_fpc_eir: u32,
|
||||
used_math: u32,
|
||||
dsp: u32,
|
||||
mdhi: u64,
|
||||
mdlo: u64,
|
||||
hi1: u32,
|
||||
lo1: u32,
|
||||
hi2: u32,
|
||||
lo2: u32,
|
||||
hi3: u32,
|
||||
lo3: u32,
|
||||
};
|
||||
|
||||
pub const ucontext_t = extern struct {
|
||||
flags: u32,
|
||||
link: ?*ucontext_t,
|
||||
stack: stack_t,
|
||||
mcontext: mcontext_t,
|
||||
sigmask: sigset_t,
|
||||
};
|
||||
|
||||
@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
|
||||
const uid_t = linux.uid_t;
|
||||
const gid_t = linux.gid_t;
|
||||
const pid_t = linux.pid_t;
|
||||
const stack_t = linux.stack_t;
|
||||
const sigset_t = linux.sigset_t;
|
||||
const sockaddr = linux.sockaddr;
|
||||
const timespec = linux.timespec;
|
||||
|
||||
@ -326,5 +328,28 @@ pub const timezone = extern struct {
|
||||
|
||||
pub const Elf_Symndx = u32;
|
||||
|
||||
/// TODO
|
||||
pub const ucontext_t = void;
|
||||
pub const mcontext_t = extern struct {
|
||||
regs: [32]u64,
|
||||
fpregs: [32]f64,
|
||||
mdhi: u64,
|
||||
hi1: u64,
|
||||
hi2: u64,
|
||||
hi3: u64,
|
||||
mdlo: u64,
|
||||
lo1: u64,
|
||||
lo2: u64,
|
||||
lo3: u64,
|
||||
pc: u64,
|
||||
fpc_csr: u32,
|
||||
used_math: u32,
|
||||
dsp: u32,
|
||||
_reserved: u32,
|
||||
};
|
||||
|
||||
pub const ucontext_t = extern struct {
|
||||
flags: u32,
|
||||
link: ?*ucontext_t,
|
||||
stack: stack_t,
|
||||
mcontext: mcontext_t,
|
||||
sigmask: sigset_t,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user