mirror of
https://github.com/beego/bee.git
synced 2024-11-16 15:20:55 +00:00
364 lines
9.8 KiB
Go
364 lines
9.8 KiB
Go
package proc
|
||
|
||
// #include "threads_darwin.h"
|
||
import "C"
|
||
import (
|
||
"encoding/binary"
|
||
"fmt"
|
||
"rsc.io/x86/x86asm"
|
||
"unsafe"
|
||
)
|
||
|
||
// Regs represents CPU registers on an AMD64 processor.
|
||
type Regs struct {
|
||
rax uint64
|
||
rbx uint64
|
||
rcx uint64
|
||
rdx uint64
|
||
rdi uint64
|
||
rsi uint64
|
||
rbp uint64
|
||
rsp uint64
|
||
r8 uint64
|
||
r9 uint64
|
||
r10 uint64
|
||
r11 uint64
|
||
r12 uint64
|
||
r13 uint64
|
||
r14 uint64
|
||
r15 uint64
|
||
rip uint64
|
||
rflags uint64
|
||
cs uint64
|
||
fs uint64
|
||
gs uint64
|
||
gsBase uint64
|
||
fpregs []Register
|
||
}
|
||
|
||
func (r *Regs) Slice() []Register {
|
||
var regs = []struct {
|
||
k string
|
||
v uint64
|
||
}{
|
||
{"Rip", r.rip},
|
||
{"Rsp", r.rsp},
|
||
{"Rax", r.rax},
|
||
{"Rbx", r.rbx},
|
||
{"Rcx", r.rcx},
|
||
{"Rdx", r.rdx},
|
||
{"Rdi", r.rdi},
|
||
{"Rsi", r.rsi},
|
||
{"Rbp", r.rbp},
|
||
{"R8", r.r8},
|
||
{"R9", r.r9},
|
||
{"R10", r.r10},
|
||
{"R11", r.r11},
|
||
{"R12", r.r12},
|
||
{"R13", r.r13},
|
||
{"R14", r.r14},
|
||
{"R15", r.r15},
|
||
{"Rflags", r.rflags},
|
||
{"Cs", r.cs},
|
||
{"Fs", r.fs},
|
||
{"Gs", r.gs},
|
||
{"Gs_base", r.gsBase},
|
||
}
|
||
out := make([]Register, 0, len(regs)+len(r.fpregs))
|
||
for _, reg := range regs {
|
||
if reg.k == "Rflags" {
|
||
out = appendFlagReg(out, reg.k, reg.v, eflagsDescription, 64)
|
||
} else {
|
||
out = appendQwordReg(out, reg.k, reg.v)
|
||
}
|
||
}
|
||
out = append(out, r.fpregs...)
|
||
return out
|
||
}
|
||
|
||
// PC returns the current program counter
|
||
// i.e. the RIP CPU register.
|
||
func (r *Regs) PC() uint64 {
|
||
return r.rip
|
||
}
|
||
|
||
// SP returns the stack pointer location,
|
||
// i.e. the RSP register.
|
||
func (r *Regs) SP() uint64 {
|
||
return r.rsp
|
||
}
|
||
|
||
// CX returns the value of the RCX register.
|
||
func (r *Regs) CX() uint64 {
|
||
return r.rcx
|
||
}
|
||
|
||
// TLS returns the value of the register
|
||
// that contains the location of the thread
|
||
// local storage segment.
|
||
func (r *Regs) TLS() uint64 {
|
||
return r.gsBase
|
||
}
|
||
|
||
// SetPC sets the RIP register to the value specified by `pc`.
|
||
func (r *Regs) SetPC(thread *Thread, pc uint64) error {
|
||
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
|
||
if kret != C.KERN_SUCCESS {
|
||
return fmt.Errorf("could not set pc")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (r *Regs) Get(n int) (uint64, error) {
|
||
reg := x86asm.Reg(n)
|
||
const (
|
||
mask8 = 0x000f
|
||
mask16 = 0x00ff
|
||
mask32 = 0xffff
|
||
)
|
||
|
||
switch reg {
|
||
// 8-bit
|
||
case x86asm.AL:
|
||
return r.rax & mask8, nil
|
||
case x86asm.CL:
|
||
return r.rcx & mask8, nil
|
||
case x86asm.DL:
|
||
return r.rdx & mask8, nil
|
||
case x86asm.BL:
|
||
return r.rbx & mask8, nil
|
||
case x86asm.AH:
|
||
return (r.rax >> 8) & mask8, nil
|
||
case x86asm.CH:
|
||
return (r.rax >> 8) & mask8, nil
|
||
case x86asm.DH:
|
||
return (r.rdx >> 8) & mask8, nil
|
||
case x86asm.BH:
|
||
return (r.rbx >> 8) & mask8, nil
|
||
case x86asm.SPB:
|
||
return r.rsp & mask8, nil
|
||
case x86asm.BPB:
|
||
return r.rbp & mask8, nil
|
||
case x86asm.SIB:
|
||
return r.rsi & mask8, nil
|
||
case x86asm.DIB:
|
||
return r.rdi & mask8, nil
|
||
case x86asm.R8B:
|
||
return r.r8 & mask8, nil
|
||
case x86asm.R9B:
|
||
return r.r9 & mask8, nil
|
||
case x86asm.R10B:
|
||
return r.r10 & mask8, nil
|
||
case x86asm.R11B:
|
||
return r.r11 & mask8, nil
|
||
case x86asm.R12B:
|
||
return r.r12 & mask8, nil
|
||
case x86asm.R13B:
|
||
return r.r13 & mask8, nil
|
||
case x86asm.R14B:
|
||
return r.r14 & mask8, nil
|
||
case x86asm.R15B:
|
||
return r.r15 & mask8, nil
|
||
|
||
// 16-bit
|
||
case x86asm.AX:
|
||
return r.rax & mask16, nil
|
||
case x86asm.CX:
|
||
return r.rcx & mask16, nil
|
||
case x86asm.DX:
|
||
return r.rdx & mask16, nil
|
||
case x86asm.BX:
|
||
return r.rbx & mask16, nil
|
||
case x86asm.SP:
|
||
return r.rsp & mask16, nil
|
||
case x86asm.BP:
|
||
return r.rbp & mask16, nil
|
||
case x86asm.SI:
|
||
return r.rsi & mask16, nil
|
||
case x86asm.DI:
|
||
return r.rdi & mask16, nil
|
||
case x86asm.R8W:
|
||
return r.r8 & mask16, nil
|
||
case x86asm.R9W:
|
||
return r.r9 & mask16, nil
|
||
case x86asm.R10W:
|
||
return r.r10 & mask16, nil
|
||
case x86asm.R11W:
|
||
return r.r11 & mask16, nil
|
||
case x86asm.R12W:
|
||
return r.r12 & mask16, nil
|
||
case x86asm.R13W:
|
||
return r.r13 & mask16, nil
|
||
case x86asm.R14W:
|
||
return r.r14 & mask16, nil
|
||
case x86asm.R15W:
|
||
return r.r15 & mask16, nil
|
||
|
||
// 32-bit
|
||
case x86asm.EAX:
|
||
return r.rax & mask32, nil
|
||
case x86asm.ECX:
|
||
return r.rcx & mask32, nil
|
||
case x86asm.EDX:
|
||
return r.rdx & mask32, nil
|
||
case x86asm.EBX:
|
||
return r.rbx & mask32, nil
|
||
case x86asm.ESP:
|
||
return r.rsp & mask32, nil
|
||
case x86asm.EBP:
|
||
return r.rbp & mask32, nil
|
||
case x86asm.ESI:
|
||
return r.rsi & mask32, nil
|
||
case x86asm.EDI:
|
||
return r.rdi & mask32, nil
|
||
case x86asm.R8L:
|
||
return r.r8 & mask32, nil
|
||
case x86asm.R9L:
|
||
return r.r9 & mask32, nil
|
||
case x86asm.R10L:
|
||
return r.r10 & mask32, nil
|
||
case x86asm.R11L:
|
||
return r.r11 & mask32, nil
|
||
case x86asm.R12L:
|
||
return r.r12 & mask32, nil
|
||
case x86asm.R13L:
|
||
return r.r13 & mask32, nil
|
||
case x86asm.R14L:
|
||
return r.r14 & mask32, nil
|
||
case x86asm.R15L:
|
||
return r.r15 & mask32, nil
|
||
|
||
// 64-bit
|
||
case x86asm.RAX:
|
||
return r.rax, nil
|
||
case x86asm.RCX:
|
||
return r.rcx, nil
|
||
case x86asm.RDX:
|
||
return r.rdx, nil
|
||
case x86asm.RBX:
|
||
return r.rbx, nil
|
||
case x86asm.RSP:
|
||
return r.rsp, nil
|
||
case x86asm.RBP:
|
||
return r.rbp, nil
|
||
case x86asm.RSI:
|
||
return r.rsi, nil
|
||
case x86asm.RDI:
|
||
return r.rdi, nil
|
||
case x86asm.R8:
|
||
return r.r8, nil
|
||
case x86asm.R9:
|
||
return r.r9, nil
|
||
case x86asm.R10:
|
||
return r.r10, nil
|
||
case x86asm.R11:
|
||
return r.r11, nil
|
||
case x86asm.R12:
|
||
return r.r12, nil
|
||
case x86asm.R13:
|
||
return r.r13, nil
|
||
case x86asm.R14:
|
||
return r.r14, nil
|
||
case x86asm.R15:
|
||
return r.r15, nil
|
||
}
|
||
|
||
return 0, UnknownRegisterError
|
||
}
|
||
|
||
func registers(thread *Thread, floatingPoint bool) (Registers, error) {
|
||
var state C.x86_thread_state64_t
|
||
var identity C.thread_identifier_info_data_t
|
||
kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)
|
||
if kret != C.KERN_SUCCESS {
|
||
return nil, fmt.Errorf("could not get registers")
|
||
}
|
||
kret = C.get_identity(C.mach_port_name_t(thread.os.threadAct), &identity)
|
||
if kret != C.KERN_SUCCESS {
|
||
return nil, fmt.Errorf("could not get thread identity informations")
|
||
}
|
||
/*
|
||
thread_identifier_info::thread_handle contains the base of the
|
||
thread-specific data area, which on x86 and x86_64 is the thread’s base
|
||
address of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c
|
||
thread_info_internal() gets the value from
|
||
machine_thread::cthread_self, which is the same value used to set the
|
||
%gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c
|
||
act_machine_switch_pcb().
|
||
--
|
||
comment copied from chromium's crashpad
|
||
https://chromium.googlesource.com/crashpad/crashpad/+/master/snapshot/mac/process_reader.cc
|
||
*/
|
||
regs := &Regs{
|
||
rax: uint64(state.__rax),
|
||
rbx: uint64(state.__rbx),
|
||
rcx: uint64(state.__rcx),
|
||
rdx: uint64(state.__rdx),
|
||
rdi: uint64(state.__rdi),
|
||
rsi: uint64(state.__rsi),
|
||
rbp: uint64(state.__rbp),
|
||
rsp: uint64(state.__rsp),
|
||
r8: uint64(state.__r8),
|
||
r9: uint64(state.__r9),
|
||
r10: uint64(state.__r10),
|
||
r11: uint64(state.__r11),
|
||
r12: uint64(state.__r12),
|
||
r13: uint64(state.__r13),
|
||
r14: uint64(state.__r14),
|
||
r15: uint64(state.__r15),
|
||
rip: uint64(state.__rip),
|
||
rflags: uint64(state.__rflags),
|
||
cs: uint64(state.__cs),
|
||
fs: uint64(state.__fs),
|
||
gs: uint64(state.__gs),
|
||
gsBase: uint64(identity.thread_handle),
|
||
}
|
||
|
||
if floatingPoint {
|
||
// https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt
|
||
var fpstate C.x86_float_state64_t
|
||
kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate)
|
||
if kret != C.KERN_SUCCESS {
|
||
return nil, fmt.Errorf("could not get floating point registers")
|
||
}
|
||
|
||
regs.fpregs = appendWordReg(regs.fpregs, "CW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw))))
|
||
regs.fpregs = appendWordReg(regs.fpregs, "SW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw))))
|
||
regs.fpregs = appendWordReg(regs.fpregs, "TW", uint16(fpstate.__fpu_ftw))
|
||
regs.fpregs = appendWordReg(regs.fpregs, "FOP", uint16(fpstate.__fpu_fop))
|
||
regs.fpregs = appendQwordReg(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
|
||
regs.fpregs = appendQwordReg(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
|
||
|
||
for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} {
|
||
stb := C.GoBytes(unsafe.Pointer(st), 10)
|
||
mantissa := binary.LittleEndian.Uint64(stb[:8])
|
||
exponent := binary.LittleEndian.Uint16(stb[8:])
|
||
regs.fpregs = appendX87Reg(regs.fpregs, i, exponent, mantissa)
|
||
}
|
||
|
||
regs.fpregs = appendFlagReg(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr), mxcsrDescription, 32)
|
||
regs.fpregs = appendDwordReg(regs.fpregs, "MXCSR_MASK", uint32(fpstate.__fpu_mxcsrmask))
|
||
|
||
for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} {
|
||
regs.fpregs = appendSSEReg(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
|
||
}
|
||
}
|
||
return regs, nil
|
||
}
|
||
|
||
func (thread *Thread) saveRegisters() (Registers, error) {
|
||
kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &thread.os.registers)
|
||
if kret != C.KERN_SUCCESS {
|
||
return nil, fmt.Errorf("could not save register contents")
|
||
}
|
||
return &Regs{rip: uint64(thread.os.registers.__rip), rsp: uint64(thread.os.registers.__rsp)}, nil
|
||
}
|
||
|
||
func (thread *Thread) restoreRegisters() error {
|
||
kret := C.set_registers(C.mach_port_name_t(thread.os.threadAct), &thread.os.registers)
|
||
if kret != C.KERN_SUCCESS {
|
||
return fmt.Errorf("could not save register contents")
|
||
}
|
||
return nil
|
||
}
|