
For hardware breakpoints we have to set them on every thread. It could be the case that another thread is running. Stop it first, set the breakpoint, then continue it.
94 lines
2.1 KiB
Go
94 lines
2.1 KiB
Go
package proc
|
|
|
|
// #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 *Thread) 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)
|
|
}
|
|
t.running = false
|
|
return nil
|
|
}
|
|
|
|
func (t *Thread) 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 *Thread) resume() error {
|
|
t.running = true
|
|
// TODO(dp) set flag for ptrace stops
|
|
var err error
|
|
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.Pid, 0) })
|
|
if err == 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 *Thread) 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 *Thread, addr uintptr, data []byte) (int, error) {
|
|
if len(data) == 0 {
|
|
return 0, nil
|
|
}
|
|
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 *Thread, addr uintptr, data []byte) (int, error) {
|
|
if len(data) == 0 {
|
|
return 0, nil
|
|
}
|
|
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
|
|
}
|