| ... | ... | @@ -3,56 +3,87 @@ const std = @import("../std.zig"); |
| 3 | 3 | const os = std.os; |
| 4 | 4 | const mem = std.mem; |
| 5 | 5 | |
| 6 | | /// Maps register names to their DWARF register number. |
| 7 | | /// `bp`, `ip`, and `sp` are provided as aliases. |
| 8 | | pub const Register = switch (builtin.cpu.arch) { |
| 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 {}, |
| 6 | pub const RegisterContext = struct { |
| 7 | eh_frame: bool, |
| 8 | is_macho: bool, |
| 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 | 87 | fn RegBytesReturnType(comptime ContextPtrType: type) type { |
| 57 | 88 | const info = @typeInfo(ContextPtrType); |
| 58 | 89 | if (info != .Pointer or info.Pointer.child != os.ucontext_t) { |
| ... | ... | @@ -62,36 +93,132 @@ fn RegBytesReturnType(comptime ContextPtrType: type) type { |
| 62 | 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` |
| 66 | | pub fn regBytes(ucontext_ptr: anytype, reg_number: u8) !RegBytesReturnType(@TypeOf(ucontext_ptr)) { |
| 96 | /// Returns a slice containing the backing storage for `reg_number`. |
| 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 | 102 | var m = &ucontext_ptr.mcontext; |
| 68 | 103 | |
| 69 | 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 | 138 | .x86_64 => switch (builtin.os.tag) { |
| 71 | 139 | .linux, .netbsd, .solaris => switch (reg_number) { |
| 72 | | 0 => mem.asBytes(&m.gregs[os.REG.RAX]), |
| 73 | | 1 => mem.asBytes(&m.gregs[os.REG.RDX]), |
| 74 | | 2 => mem.asBytes(&m.gregs[os.REG.RCX]), |
| 75 | | 3 => mem.asBytes(&m.gregs[os.REG.RBX]), |
| 76 | | 4 => mem.asBytes(&m.gregs[os.REG.RSI]), |
| 77 | | 5 => mem.asBytes(&m.gregs[os.REG.RDI]), |
| 78 | | 6 => mem.asBytes(&m.gregs[os.REG.RBP]), |
| 79 | | 7 => mem.asBytes(&m.gregs[os.REG.RSP]), |
| 80 | | 8 => mem.asBytes(&m.gregs[os.REG.R8]), |
| 81 | | 9 => mem.asBytes(&m.gregs[os.REG.R9]), |
| 82 | | 10 => mem.asBytes(&m.gregs[os.REG.R10]), |
| 83 | | 11 => mem.asBytes(&m.gregs[os.REG.R11]), |
| 84 | | 12 => mem.asBytes(&m.gregs[os.REG.R12]), |
| 85 | | 13 => mem.asBytes(&m.gregs[os.REG.R13]), |
| 86 | | 14 => mem.asBytes(&m.gregs[os.REG.R14]), |
| 87 | | 15 => mem.asBytes(&m.gregs[os.REG.R15]), |
| 88 | | 16 => mem.asBytes(&m.gregs[os.REG.RIP]), |
| 140 | 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RAX]), |
| 141 | 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDX]), |
| 142 | 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RCX]), |
| 143 | 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBX]), |
| 144 | 4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSI]), |
| 145 | 5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDI]), |
| 146 | 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBP]), |
| 147 | 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSP]), |
| 148 | 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R8]), |
| 149 | 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R9]), |
| 150 | 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R10]), |
| 151 | 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R11]), |
| 152 | 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R12]), |
| 153 | 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R13]), |
| 154 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]), |
| 155 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]), |
| 156 | 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]), |
| 89 | 157 | 17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]), |
| 90 | 158 | else => error.InvalidRegister, |
| 91 | 159 | }, |
| 92 | | //.freebsd => @intCast(usize, ctx.mcontext.rip), |
| 93 | | //.openbsd => @intCast(usize, ctx.sc_rip), |
| 94 | | //.macos => @intCast(usize, ctx.mcontext.ss.rip), |
| 160 | .freebsd => switch (reg_number) { |
| 161 | 0 => mem.asBytes(&ucontext_ptr.mcontext.rax), |
| 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 | 222 | else => error.UnimplementedOs, |
| 96 | 223 | }, |
| 97 | 224 | else => error.UnimplementedArch, |