| ... | @@ -3,56 +3,87 @@ const std = @import("../std.zig"); | ... | @@ -3,56 +3,87 @@ const std = @import("../std.zig"); |
| 3 | const os = std.os; | 3 | const os = std.os; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | | 5 | |
| 6 | /// Maps register names to their DWARF register number. | 6 | pub const RegisterContext = struct { |
| 7 | /// `bp`, `ip`, and `sp` are provided as aliases. | 7 | eh_frame: bool, |
| 8 | pub const Register = switch (builtin.cpu.arch) { | 8 | is_macho: bool, |
| 9 | .x86 => { | | |
| 10 | | | |
| 11 | //pub const ip = Register.eip; | | |
| 12 | //pub const sp = Register. | | |
| 13 | }, | | |
| 14 | .x86_64 => enum(u8) { | | |
| 15 | rax, | | |
| 16 | rdx, | | |
| 17 | rcx, | | |
| 18 | rbx, | | |
| 19 | rsi, | | |
| 20 | rdi, | | |
| 21 | rbp, | | |
| 22 | rsp, | | |
| 23 | r8, | | |
| 24 | r9, | | |
| 25 | r10, | | |
| 26 | r11, | | |
| 27 | r12, | | |
| 28 | r13, | | |
| 29 | r14, | | |
| 30 | r15, | | |
| 31 | rip, | | |
| 32 | xmm0, | | |
| 33 | xmm1, | | |
| 34 | xmm2, | | |
| 35 | xmm3, | | |
| 36 | xmm4, | | |
| 37 | xmm5, | | |
| 38 | xmm6, | | |
| 39 | xmm7, | | |
| 40 | xmm8, | | |
| 41 | xmm9, | | |
| 42 | xmm10, | | |
| 43 | xmm11, | | |
| 44 | xmm12, | | |
| 45 | xmm13, | | |
| 46 | xmm14, | | |
| 47 | xmm15, | | |
| 48 | | | |
| 49 | pub const fp = Register.rbp; | | |
| 50 | pub const ip = Register.rip; | | |
| 51 | pub const sp = Register.rsp; | | |
| 52 | }, | | |
| 53 | else => enum {}, | | |
| 54 | }; | 9 | }; |
| 55 | | 10 | |
| | 11 | pub fn ipRegNum() u8 { |
| | 12 | return switch (builtin.cpu.arch) { |
| | 13 | .x86 => 8, |
| | 14 | .x86_64 => 16, |
| | 15 | .arm => error.InvalidRegister, // TODO |
| | 16 | .aarch64 => error.InvalidRegister, // TODO |
| | 17 | |
| | 18 | // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| | 19 | // const ip = switch (native_os) { |
| | 20 | // .macos => @intCast(usize, ctx.mcontext.ss.pc), |
| | 21 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]), |
| | 22 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr), |
| | 23 | // else => @intCast(usize, ctx.mcontext.pc), |
| | 24 | // }; |
| | 25 | // // x29 is the ABI-designated frame pointer |
| | 26 | // const bp = switch (native_os) { |
| | 27 | // .macos => @intCast(usize, ctx.mcontext.ss.fp), |
| | 28 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]), |
| | 29 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]), |
| | 30 | // else => @intCast(usize, ctx.mcontext.regs[29]), |
| | 31 | // }; |
| | 32 | else => unreachable, |
| | 33 | }; |
| | 34 | } |
| | 35 | |
| | 36 | pub fn fpRegNum(reg_ctx: RegisterContext) u8 { |
| | 37 | return switch (builtin.cpu.arch) { |
| | 38 | // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO |
| | 39 | .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5, |
| | 40 | .x86_64 => 6, |
| | 41 | .arm => error.InvalidRegister, // TODO |
| | 42 | .aarch64 => error.InvalidRegister, // TODO |
| | 43 | |
| | 44 | // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| | 45 | // const ip = switch (native_os) { |
| | 46 | // .macos => @intCast(usize, ctx.mcontext.ss.pc), |
| | 47 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]), |
| | 48 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr), |
| | 49 | // else => @intCast(usize, ctx.mcontext.pc), |
| | 50 | // }; |
| | 51 | // // x29 is the ABI-designated frame pointer |
| | 52 | // const bp = switch (native_os) { |
| | 53 | // .macos => @intCast(usize, ctx.mcontext.ss.fp), |
| | 54 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]), |
| | 55 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]), |
| | 56 | // else => @intCast(usize, ctx.mcontext.regs[29]), |
| | 57 | // }; |
| | 58 | else => unreachable, |
| | 59 | }; |
| | 60 | } |
| | 61 | |
| | 62 | pub fn spRegNum(reg_ctx: RegisterContext) u8 { |
| | 63 | return switch (builtin.cpu.arch) { |
| | 64 | .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4, |
| | 65 | .x86_64 => 7, |
| | 66 | .arm => error.InvalidRegister, // TODO |
| | 67 | .aarch64 => error.InvalidRegister, // TODO |
| | 68 | |
| | 69 | // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| | 70 | // const ip = switch (native_os) { |
| | 71 | // .macos => @intCast(usize, ctx.mcontext.ss.pc), |
| | 72 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]), |
| | 73 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr), |
| | 74 | // else => @intCast(usize, ctx.mcontext.pc), |
| | 75 | // }; |
| | 76 | // // x29 is the ABI-designated frame pointer |
| | 77 | // const bp = switch (native_os) { |
| | 78 | // .macos => @intCast(usize, ctx.mcontext.ss.fp), |
| | 79 | // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]), |
| | 80 | // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]), |
| | 81 | // else => @intCast(usize, ctx.mcontext.regs[29]), |
| | 82 | // }; |
| | 83 | else => unreachable, |
| | 84 | }; |
| | 85 | } |
| | 86 | |
| 56 | fn RegBytesReturnType(comptime ContextPtrType: type) type { | 87 | fn RegBytesReturnType(comptime ContextPtrType: type) type { |
| 57 | const info = @typeInfo(ContextPtrType); | 88 | const info = @typeInfo(ContextPtrType); |
| 58 | if (info != .Pointer or info.Pointer.child != os.ucontext_t) { | 89 | if (info != .Pointer or info.Pointer.child != os.ucontext_t) { |
| ... | @@ -62,36 +93,132 @@ fn RegBytesReturnType(comptime ContextPtrType: type) type { | ... | @@ -62,36 +93,132 @@ fn RegBytesReturnType(comptime ContextPtrType: type) type { |
| 62 | return if (info.Pointer.is_const) return []const u8 else []u8; | 93 | return if (info.Pointer.is_const) return []const u8 else []u8; |
| 63 | } | 94 | } |
| 64 | | 95 | |
| 65 | /// Returns a slice containing the backing storage for `reg_number` | 96 | /// Returns a slice containing the backing storage for `reg_number`. |
| 66 | pub fn regBytes(ucontext_ptr: anytype, reg_number: u8) !RegBytesReturnType(@TypeOf(ucontext_ptr)) { | 97 | /// |
| | 98 | /// `reg_ctx` describes in what context the register number is used, as it can have different |
| | 99 | /// meanings depending on the DWARF container. It is only required when getting the stack or |
| | 100 | /// frame pointer register on some architectures. |
| | 101 | pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext) !RegBytesReturnType(@TypeOf(ucontext_ptr)) { |
| 67 | var m = &ucontext_ptr.mcontext; | 102 | var m = &ucontext_ptr.mcontext; |
| 68 | | 103 | |
| 69 | return switch (builtin.cpu.arch) { | 104 | return switch (builtin.cpu.arch) { |
| | 105 | .x86 => switch (reg_number) { |
| | 106 | 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]), |
| | 107 | 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]), |
| | 108 | 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]), |
| | 109 | 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]), |
| | 110 | 4...5 => if (reg_ctx) |r| bytes: { |
| | 111 | if (reg_number == 4) { |
| | 112 | break :bytes if (r.eh_frame and r.is_macho) |
| | 113 | mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]) |
| | 114 | else |
| | 115 | mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]); |
| | 116 | } else { |
| | 117 | break :bytes if (r.eh_frame and r.is_macho) |
| | 118 | mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]) |
| | 119 | else |
| | 120 | mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]); |
| | 121 | } |
| | 122 | } else error.RegisterContextRequired, |
| | 123 | 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]), |
| | 124 | 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]), |
| | 125 | 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]), |
| | 126 | 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]), |
| | 127 | 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]), |
| | 128 | 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]), |
| | 129 | 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]), |
| | 130 | 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]), |
| | 131 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]), |
| | 132 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]), |
| | 133 | 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs |
| | 134 | // TODO: Map TRAPNO, ERR, UESP |
| | 135 | 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs |
| | 136 | else => error.InvalidRegister, |
| | 137 | }, |
| 70 | .x86_64 => switch (builtin.os.tag) { | 138 | .x86_64 => switch (builtin.os.tag) { |
| 71 | .linux, .netbsd, .solaris => switch (reg_number) { | 139 | .linux, .netbsd, .solaris => switch (reg_number) { |
| 72 | 0 => mem.asBytes(&m.gregs[os.REG.RAX]), | 140 | 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RAX]), |
| 73 | 1 => mem.asBytes(&m.gregs[os.REG.RDX]), | 141 | 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDX]), |
| 74 | 2 => mem.asBytes(&m.gregs[os.REG.RCX]), | 142 | 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RCX]), |
| 75 | 3 => mem.asBytes(&m.gregs[os.REG.RBX]), | 143 | 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBX]), |
| 76 | 4 => mem.asBytes(&m.gregs[os.REG.RSI]), | 144 | 4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSI]), |
| 77 | 5 => mem.asBytes(&m.gregs[os.REG.RDI]), | 145 | 5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDI]), |
| 78 | 6 => mem.asBytes(&m.gregs[os.REG.RBP]), | 146 | 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBP]), |
| 79 | 7 => mem.asBytes(&m.gregs[os.REG.RSP]), | 147 | 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSP]), |
| 80 | 8 => mem.asBytes(&m.gregs[os.REG.R8]), | 148 | 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R8]), |
| 81 | 9 => mem.asBytes(&m.gregs[os.REG.R9]), | 149 | 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R9]), |
| 82 | 10 => mem.asBytes(&m.gregs[os.REG.R10]), | 150 | 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R10]), |
| 83 | 11 => mem.asBytes(&m.gregs[os.REG.R11]), | 151 | 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R11]), |
| 84 | 12 => mem.asBytes(&m.gregs[os.REG.R12]), | 152 | 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R12]), |
| 85 | 13 => mem.asBytes(&m.gregs[os.REG.R13]), | 153 | 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R13]), |
| 86 | 14 => mem.asBytes(&m.gregs[os.REG.R14]), | 154 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]), |
| 87 | 15 => mem.asBytes(&m.gregs[os.REG.R15]), | 155 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]), |
| 88 | 16 => mem.asBytes(&m.gregs[os.REG.RIP]), | 156 | 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]), |
| 89 | 17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]), | 157 | 17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]), |
| 90 | else => error.InvalidRegister, | 158 | else => error.InvalidRegister, |
| 91 | }, | 159 | }, |
| 92 | //.freebsd => @intCast(usize, ctx.mcontext.rip), | 160 | .freebsd => switch (reg_number) { |
| 93 | //.openbsd => @intCast(usize, ctx.sc_rip), | 161 | 0 => mem.asBytes(&ucontext_ptr.mcontext.rax), |
| 94 | //.macos => @intCast(usize, ctx.mcontext.ss.rip), | 162 | 1 => mem.asBytes(&ucontext_ptr.mcontext.rdx), |
| | 163 | 2 => mem.asBytes(&ucontext_ptr.mcontext.rcx), |
| | 164 | 3 => mem.asBytes(&ucontext_ptr.mcontext.rbx), |
| | 165 | 4 => mem.asBytes(&ucontext_ptr.mcontext.rsi), |
| | 166 | 5 => mem.asBytes(&ucontext_ptr.mcontext.rdi), |
| | 167 | 6 => mem.asBytes(&ucontext_ptr.mcontext.rbp), |
| | 168 | 7 => mem.asBytes(&ucontext_ptr.mcontext.rsp), |
| | 169 | 8 => mem.asBytes(&ucontext_ptr.mcontext.r8), |
| | 170 | 9 => mem.asBytes(&ucontext_ptr.mcontext.r9), |
| | 171 | 10 => mem.asBytes(&ucontext_ptr.mcontext.r10), |
| | 172 | 11 => mem.asBytes(&ucontext_ptr.mcontext.r11), |
| | 173 | 12 => mem.asBytes(&ucontext_ptr.mcontext.r12), |
| | 174 | 13 => mem.asBytes(&ucontext_ptr.mcontext.r13), |
| | 175 | 14 => mem.asBytes(&ucontext_ptr.mcontext.r14), |
| | 176 | 15 => mem.asBytes(&ucontext_ptr.mcontext.r15), |
| | 177 | 16 => mem.asBytes(&ucontext_ptr.mcontext.rip), |
| | 178 | // TODO: Extract xmm state from mcontext.fpstate? |
| | 179 | else => error.InvalidRegister, |
| | 180 | }, |
| | 181 | .openbsd => switch (reg_number) { |
| | 182 | 0 => mem.asBytes(&ucontext_ptr.sc_rax), |
| | 183 | 1 => mem.asBytes(&ucontext_ptr.sc_rdx), |
| | 184 | 2 => mem.asBytes(&ucontext_ptr.sc_rcx), |
| | 185 | 3 => mem.asBytes(&ucontext_ptr.sc_rbx), |
| | 186 | 4 => mem.asBytes(&ucontext_ptr.sc_rsi), |
| | 187 | 5 => mem.asBytes(&ucontext_ptr.sc_rdi), |
| | 188 | 6 => mem.asBytes(&ucontext_ptr.sc_rbp), |
| | 189 | 7 => mem.asBytes(&ucontext_ptr.sc_rsp), |
| | 190 | 8 => mem.asBytes(&ucontext_ptr.sc_r8), |
| | 191 | 9 => mem.asBytes(&ucontext_ptr.sc_r9), |
| | 192 | 10 => mem.asBytes(&ucontext_ptr.sc_r10), |
| | 193 | 11 => mem.asBytes(&ucontext_ptr.sc_r11), |
| | 194 | 12 => mem.asBytes(&ucontext_ptr.sc_r12), |
| | 195 | 13 => mem.asBytes(&ucontext_ptr.sc_r13), |
| | 196 | 14 => mem.asBytes(&ucontext_ptr.sc_r14), |
| | 197 | 15 => mem.asBytes(&ucontext_ptr.sc_r15), |
| | 198 | 16 => mem.asBytes(&ucontext_ptr.sc_rip), |
| | 199 | // TODO: Extract xmm state from sc_fpstate? |
| | 200 | else => error.InvalidRegister, |
| | 201 | }, |
| | 202 | .macos => switch (reg_number) { |
| | 203 | 0 => mem.asBytes(&ucontext_ptr.mcontext.ss.rax), |
| | 204 | 1 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdx), |
| | 205 | 2 => mem.asBytes(&ucontext_ptr.mcontext.ss.rcx), |
| | 206 | 3 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbx), |
| | 207 | 4 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsi), |
| | 208 | 5 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdi), |
| | 209 | 6 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbp), |
| | 210 | 7 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsp), |
| | 211 | 8 => mem.asBytes(&ucontext_ptr.mcontext.ss.r8), |
| | 212 | 9 => mem.asBytes(&ucontext_ptr.mcontext.ss.r9), |
| | 213 | 10 => mem.asBytes(&ucontext_ptr.mcontext.ss.r10), |
| | 214 | 11 => mem.asBytes(&ucontext_ptr.mcontext.ss.r11), |
| | 215 | 12 => mem.asBytes(&ucontext_ptr.mcontext.ss.r12), |
| | 216 | 13 => mem.asBytes(&ucontext_ptr.mcontext.ss.r13), |
| | 217 | 14 => mem.asBytes(&ucontext_ptr.mcontext.ss.r14), |
| | 218 | 15 => mem.asBytes(&ucontext_ptr.mcontext.ss.r15), |
| | 219 | 16 => mem.asBytes(&ucontext_ptr.mcontext.ss.rip), |
| | 220 | else => error.InvalidRegister, |
| | 221 | }, |
| 95 | else => error.UnimplementedOs, | 222 | else => error.UnimplementedOs, |
| 96 | }, | 223 | }, |
| 97 | else => error.UnimplementedArch, | 224 | else => error.UnimplementedArch, |