github.com/undoio/delve@v1.9.0/pkg/proc/native/threads_linux.go (about)

     1  package native
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sys "golang.org/x/sys/unix"
     7  
     8  	"github.com/undoio/delve/pkg/proc"
     9  )
    10  
    11  type waitStatus sys.WaitStatus
    12  
    13  // osSpecificDetails hold Linux specific
    14  // process details.
    15  type osSpecificDetails struct {
    16  	delayedSignal       int
    17  	running             bool
    18  	setbp               bool
    19  	phantomBreakpointPC uint64
    20  }
    21  
    22  func (t *nativeThread) stop() (err error) {
    23  	err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP)
    24  	if err != nil {
    25  		err = fmt.Errorf("stop err %s on thread %d", err, t.ID)
    26  		return
    27  	}
    28  	return
    29  }
    30  
    31  // Stopped returns whether the thread is stopped at
    32  // the operating system level.
    33  func (t *nativeThread) Stopped() bool {
    34  	state := status(t.ID, t.dbp.os.comm)
    35  	return state == statusTraceStop || state == statusTraceStopT
    36  }
    37  
    38  func (t *nativeThread) resume() error {
    39  	sig := t.os.delayedSignal
    40  	t.os.delayedSignal = 0
    41  	return t.resumeWithSig(sig)
    42  }
    43  
    44  func (t *nativeThread) resumeWithSig(sig int) (err error) {
    45  	t.os.running = true
    46  	t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
    47  	return
    48  }
    49  
    50  func (t *nativeThread) singleStep() (err error) {
    51  	sig := 0
    52  	for {
    53  		t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID, sig) })
    54  		sig = 0
    55  		if err != nil {
    56  			return err
    57  		}
    58  		wpid, status, err := t.dbp.waitFast(t.ID)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		if (status == nil || status.Exited()) && wpid == t.dbp.pid {
    63  			t.dbp.postExit()
    64  			rs := 0
    65  			if status != nil {
    66  				rs = status.ExitStatus()
    67  			}
    68  			return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
    69  		}
    70  		if wpid == t.ID {
    71  			switch s := status.StopSignal(); s {
    72  			case sys.SIGTRAP:
    73  				return nil
    74  			case sys.SIGSTOP:
    75  				// delayed SIGSTOP, ignore it
    76  			case sys.SIGILL, sys.SIGBUS, sys.SIGFPE, sys.SIGSEGV, sys.SIGSTKFLT:
    77  				// propagate signals that can have been caused by the current instruction
    78  				sig = int(s)
    79  			default:
    80  				// delay propagation of all other signals
    81  				t.os.delayedSignal = int(s)
    82  			}
    83  		}
    84  	}
    85  }
    86  
    87  func (t *nativeThread) WriteMemory(addr uint64, data []byte) (written int, err error) {
    88  	if t.dbp.exited {
    89  		return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
    90  	}
    91  	if len(data) == 0 {
    92  		return
    93  	}
    94  	// ProcessVmWrite can't poke read-only memory like ptrace, so don't
    95  	// even bother for small writes -- likely breakpoints and such.
    96  	if len(data) > sys.SizeofPtr {
    97  		written, _ = processVmWrite(t.ID, uintptr(addr), data)
    98  	}
    99  	if written == 0 {
   100  		t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, uintptr(addr), data) })
   101  	}
   102  	return
   103  }
   104  
   105  func (t *nativeThread) ReadMemory(data []byte, addr uint64) (n int, err error) {
   106  	if t.dbp.exited {
   107  		return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
   108  	}
   109  	if len(data) == 0 {
   110  		return
   111  	}
   112  	n, _ = processVmRead(t.ID, uintptr(addr), data)
   113  	if n == 0 {
   114  		t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, uintptr(addr), data) })
   115  	}
   116  	return
   117  }
   118  
   119  // SoftExc returns true if this thread received a software exception during the last resume.
   120  func (t *nativeThread) SoftExc() bool {
   121  	return t.os.setbp
   122  }