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  }