gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/threads_darwin.go (about)

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