2015-06-12 19:49:23 +00:00
|
|
|
|
package proc
|
2015-01-14 02:37:10 +00:00
|
|
|
|
|
|
|
|
|
// #include "threads_darwin.h"
|
|
|
|
|
import "C"
|
2015-06-19 07:20:10 +00:00
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
)
|
2015-01-14 02:37:10 +00:00
|
|
|
|
|
|
|
|
|
type Regs struct {
|
2015-07-28 05:33:07 +00:00
|
|
|
|
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
|
|
|
|
|
gs_base uint64
|
2015-06-19 07:20:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Regs) String() string {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
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},
|
2015-07-28 05:33:07 +00:00
|
|
|
|
{"Gs_base", r.gs_base},
|
2015-06-19 07:20:10 +00:00
|
|
|
|
}
|
|
|
|
|
for _, reg := range regs {
|
2015-09-02 05:00:48 +00:00
|
|
|
|
fmt.Fprintf(&buf, "%8s = %0#16x\n", reg.k, reg.v)
|
2015-06-19 07:20:10 +00:00
|
|
|
|
}
|
|
|
|
|
return buf.String()
|
2015-01-14 02:37:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Regs) PC() uint64 {
|
2015-06-19 07:20:10 +00:00
|
|
|
|
return r.rip
|
2015-01-14 02:37:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Regs) SP() uint64 {
|
2015-06-19 07:20:10 +00:00
|
|
|
|
return r.rsp
|
2015-01-14 02:37:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-11 20:17:56 +00:00
|
|
|
|
func (r *Regs) CX() uint64 {
|
2015-06-19 07:20:10 +00:00
|
|
|
|
return r.rcx
|
2015-06-11 20:17:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-28 05:33:07 +00:00
|
|
|
|
func (r *Regs) TLS() uint64 {
|
|
|
|
|
return r.gs_base
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-12 19:51:23 +00:00
|
|
|
|
func (r *Regs) SetPC(thread *Thread, pc uint64) error {
|
2015-02-28 16:41:05 +00:00
|
|
|
|
kret := C.set_pc(thread.os.thread_act, C.uint64_t(pc))
|
|
|
|
|
if kret != C.KERN_SUCCESS {
|
2015-05-04 22:31:13 +00:00
|
|
|
|
return fmt.Errorf("could not set pc")
|
2015-02-28 16:41:05 +00:00
|
|
|
|
}
|
2015-01-14 02:37:10 +00:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-12 19:51:23 +00:00
|
|
|
|
func registers(thread *Thread) (Registers, error) {
|
2015-02-28 16:39:21 +00:00
|
|
|
|
var state C.x86_thread_state64_t
|
2015-07-28 05:33:07 +00:00
|
|
|
|
var identity C.thread_identifier_info_data_t
|
2015-02-28 16:39:21 +00:00
|
|
|
|
kret := C.get_registers(C.mach_port_name_t(thread.os.thread_act), &state)
|
|
|
|
|
if kret != C.KERN_SUCCESS {
|
2015-05-04 22:31:13 +00:00
|
|
|
|
return nil, fmt.Errorf("could not get registers")
|
2015-02-28 16:39:21 +00:00
|
|
|
|
}
|
2015-07-28 05:33:07 +00:00
|
|
|
|
kret = C.get_identity(C.mach_port_name_t(thread.os.thread_act), &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
|
|
|
|
|
*/
|
2015-06-19 07:20:10 +00:00
|
|
|
|
regs := &Regs{
|
2015-07-28 05:33:07 +00:00
|
|
|
|
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),
|
|
|
|
|
gs_base: uint64(identity.thread_handle),
|
2015-06-19 07:20:10 +00:00
|
|
|
|
}
|
2015-01-14 02:37:10 +00:00
|
|
|
|
return regs, nil
|
|
|
|
|
}
|
2015-06-19 07:20:10 +00:00
|
|
|
|
|
|
|
|
|
func (thread *Thread) saveRegisters() (Registers, error) {
|
|
|
|
|
kret := C.get_registers(C.mach_port_name_t(thread.os.thread_act), &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.thread_act), &thread.os.registers)
|
|
|
|
|
if kret != C.KERN_SUCCESS {
|
|
|
|
|
return fmt.Errorf("could not save register contents")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|