
Process is an incorrect name for the DebuggedProcess struct that the thread is "a part" of. Also, no need to export that field.
101 lines
2.6 KiB
Go
101 lines
2.6 KiB
Go
package proctl
|
|
|
|
// #include "threads_darwin.h"
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
type OSSpecificDetails struct {
|
|
thread_act C.thread_act_t
|
|
registers C.x86_thread_state64_t
|
|
}
|
|
|
|
func (t *ThreadContext) Halt() error {
|
|
var kret C.kern_return_t
|
|
kret = C.thread_suspend(t.os.thread_act)
|
|
if kret != C.KERN_SUCCESS {
|
|
return fmt.Errorf("could not suspend thread %d", t.Id)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *ThreadContext) singleStep() error {
|
|
kret := C.single_step(t.os.thread_act)
|
|
if kret != C.KERN_SUCCESS {
|
|
return fmt.Errorf("could not single step")
|
|
}
|
|
t.dbp.trapWait(0)
|
|
kret = C.clear_trap_flag(t.os.thread_act)
|
|
if kret != C.KERN_SUCCESS {
|
|
return fmt.Errorf("could not clear CPU trap flag")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *ThreadContext) resume() error {
|
|
// TODO(dp) set flag for ptrace stops
|
|
if PtraceCont(t.dbp.Pid, 0) == nil {
|
|
return nil
|
|
}
|
|
kret := C.resume_thread(t.os.thread_act)
|
|
if kret != C.KERN_SUCCESS {
|
|
return fmt.Errorf("could not continue thread")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *ThreadContext) blocked() bool {
|
|
// TODO(dp) cache the func pc to remove this lookup
|
|
pc, _ := t.PC()
|
|
fn := t.dbp.goSymTable.PCToFunc(pc)
|
|
if fn != nil && (fn.Name == "runtime.mach_semaphore_wait" || fn.Name == "runtime.usleep") {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func writeMemory(thread *ThreadContext, addr uintptr, data []byte) (int, error) {
|
|
var (
|
|
vm_data = unsafe.Pointer(&data[0])
|
|
vm_addr = C.mach_vm_address_t(addr)
|
|
length = C.mach_msg_type_number_t(len(data))
|
|
)
|
|
|
|
if ret := C.write_memory(thread.dbp.os.task, vm_addr, vm_data, length); ret < 0 {
|
|
return 0, fmt.Errorf("could not write memory")
|
|
}
|
|
return len(data), nil
|
|
}
|
|
|
|
func readMemory(thread *ThreadContext, addr uintptr, data []byte) (int, error) {
|
|
var (
|
|
vm_data = unsafe.Pointer(&data[0])
|
|
vm_addr = C.mach_vm_address_t(addr)
|
|
length = C.mach_msg_type_number_t(len(data))
|
|
)
|
|
|
|
ret := C.read_memory(thread.dbp.os.task, vm_addr, vm_data, length)
|
|
if ret < 0 {
|
|
return 0, fmt.Errorf("could not read memory")
|
|
}
|
|
return len(data), nil
|
|
}
|
|
|
|
func (thread *ThreadContext) 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{pc: uint64(thread.os.registers.__rip), sp: uint64(thread.os.registers.__rsp)}, nil
|
|
}
|
|
|
|
func (thread *ThreadContext) 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
|
|
}
|