github.com/undoio/delve@v1.9.0/pkg/proc/native/threads_darwin.go (about) 1 //go:build darwin && macnative 2 // +build darwin,macnative 3 4 package native 5 6 // #include "threads_darwin.h" 7 // #include "proc_darwin.h" 8 import "C" 9 import ( 10 "errors" 11 "fmt" 12 "unsafe" 13 14 sys "golang.org/x/sys/unix" 15 16 "github.com/undoio/delve/pkg/proc" 17 "github.com/undoio/delve/pkg/proc/amd64util" 18 ) 19 20 // waitStatus is a synonym for the platform-specific WaitStatus 21 type waitStatus sys.WaitStatus 22 23 // osSpecificDetails holds information specific to the OSX/Darwin 24 // operating system / kernel. 25 type osSpecificDetails struct { 26 threadAct C.thread_act_t 27 registers C.x86_thread_state64_t 28 exists bool 29 } 30 31 // ErrContinueThread is the error returned when a thread could not 32 // be continued. 33 var ErrContinueThread = fmt.Errorf("could not continue thread") 34 35 func (t *nativeThread) stop() (err error) { 36 kret := C.thread_suspend(t.os.threadAct) 37 if kret != C.KERN_SUCCESS { 38 errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret))) 39 // check that the thread still exists before complaining 40 err2 := t.dbp.updateThreadList() 41 if err2 != nil { 42 err = fmt.Errorf("could not suspend thread %d %s (additionally could not update thread list: %v)", t.ID, errStr, err2) 43 return 44 } 45 46 if _, ok := t.dbp.threads[t.ID]; ok { 47 err = fmt.Errorf("could not suspend thread %d %s", t.ID, errStr) 48 return 49 } 50 } 51 return 52 } 53 54 func (t *nativeThread) singleStep() error { 55 kret := C.single_step(t.os.threadAct) 56 if kret != C.KERN_SUCCESS { 57 return fmt.Errorf("could not single step") 58 } 59 for { 60 twthread, err := t.dbp.trapWait(t.dbp.pid) 61 if err != nil { 62 return err 63 } 64 if twthread.ID == t.ID { 65 break 66 } 67 } 68 69 kret = C.clear_trap_flag(t.os.threadAct) 70 if kret != C.KERN_SUCCESS { 71 return fmt.Errorf("could not clear CPU trap flag") 72 } 73 return nil 74 } 75 76 func (t *nativeThread) resume() error { 77 // TODO(dp) set flag for ptrace stops 78 var err error 79 t.dbp.execPtraceFunc(func() { err = ptraceCont(t.dbp.pid, 0) }) 80 if err == nil { 81 return nil 82 } 83 kret := C.resume_thread(t.os.threadAct) 84 if kret != C.KERN_SUCCESS { 85 return ErrContinueThread 86 } 87 return nil 88 } 89 90 // Stopped returns whether the thread is stopped at 91 // the operating system level. 92 func (t *nativeThread) Stopped() bool { 93 return C.thread_blocked(t.os.threadAct) > C.int(0) 94 } 95 96 func (t *nativeThread) WriteMemory(addr uint64, data []byte) (int, error) { 97 if t.dbp.exited { 98 return 0, proc.ErrProcessExited{Pid: t.dbp.pid} 99 } 100 if len(data) == 0 { 101 return 0, nil 102 } 103 var ( 104 vmData = unsafe.Pointer(&data[0]) 105 vmAddr = C.mach_vm_address_t(addr) 106 length = C.mach_msg_type_number_t(len(data)) 107 ) 108 if ret := C.write_memory(t.dbp.os.task, vmAddr, vmData, length); ret < 0 { 109 return 0, fmt.Errorf("could not write memory") 110 } 111 return len(data), nil 112 } 113 114 func (t *nativeThread) ReadMemory(buf []byte, addr uint64) (int, error) { 115 if t.dbp.exited { 116 return 0, proc.ErrProcessExited{Pid: t.dbp.pid} 117 } 118 if len(buf) == 0 { 119 return 0, nil 120 } 121 var ( 122 vmData = unsafe.Pointer(&buf[0]) 123 vmAddr = C.mach_vm_address_t(addr) 124 length = C.mach_msg_type_number_t(len(buf)) 125 ) 126 127 ret := C.read_memory(t.dbp.os.task, vmAddr, vmData, length) 128 if ret < 0 { 129 return 0, fmt.Errorf("could not read memory") 130 } 131 return len(buf), nil 132 } 133 134 func (t *nativeThread) restoreRegisters(sr proc.Registers) error { 135 return errors.New("not implemented") 136 } 137 138 func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error { 139 return proc.ErrHWBreakUnsupported 140 } 141 142 // SoftExc returns true if this thread received a software exception during the last resume. 143 func (t *nativeThread) SoftExc() bool { 144 return false 145 }