gitlab.com/Raven-IO/raven-delve@v1.22.4/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  	"gitlab.com/Raven-IO/raven-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  		if err == sys.ESRCH {
    26  			return
    27  		}
    28  		err = fmt.Errorf("stop err %s on thread %d", err, t.ID)
    29  		return
    30  	}
    31  	return
    32  }
    33  
    34  // Stopped returns whether the thread is stopped at
    35  // the operating system level.
    36  func (t *nativeThread) Stopped() bool {
    37  	state := status(t.ID, t.dbp.os.comm)
    38  	return state == statusTraceStop || state == statusTraceStopT
    39  }
    40  
    41  func (t *nativeThread) resume() error {
    42  	sig := t.os.delayedSignal
    43  	t.os.delayedSignal = 0
    44  	return t.resumeWithSig(sig)
    45  }
    46  
    47  func (t *nativeThread) resumeWithSig(sig int) (err error) {
    48  	t.os.running = true
    49  	t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
    50  	return
    51  }
    52  
    53  func (procgrp *processGroup) singleStep(t *nativeThread) (err error) {
    54  	sig := 0
    55  	for {
    56  		t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID, sig) })
    57  		sig = 0
    58  		if err != nil {
    59  			return err
    60  		}
    61  		wpid, status, err := t.dbp.waitFast(t.ID)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		if (status == nil || status.Exited()) && wpid == t.dbp.pid {
    66  			t.dbp.postExit()
    67  			rs := 0
    68  			if status != nil {
    69  				rs = status.ExitStatus()
    70  			}
    71  			return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
    72  		}
    73  		if wpid == t.ID {
    74  			switch s := status.StopSignal(); s {
    75  			case sys.SIGTRAP:
    76  				return nil
    77  			case sys.SIGSTOP:
    78  				// delayed SIGSTOP, ignore it
    79  			case sys.SIGILL, sys.SIGBUS, sys.SIGFPE, sys.SIGSEGV, sys.SIGSTKFLT:
    80  				// propagate signals that can have been caused by the current instruction
    81  				sig = int(s)
    82  			default:
    83  				// delay propagation of all other signals
    84  				t.os.delayedSignal = int(s)
    85  			}
    86  		}
    87  	}
    88  }
    89  
    90  func (t *nativeThread) WriteMemory(addr uint64, data []byte) (written int, err error) {
    91  	if ok, err := t.dbp.Valid(); !ok {
    92  		return 0, err
    93  	}
    94  	if len(data) == 0 {
    95  		return
    96  	}
    97  	// ProcessVmWrite can't poke read-only memory like ptrace, so don't
    98  	// even bother for small writes -- likely breakpoints and such.
    99  	if len(data) > sys.SizeofPtr {
   100  		written, _ = processVmWrite(t.ID, uintptr(addr), data)
   101  	}
   102  	if written == 0 {
   103  		t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, uintptr(addr), data) })
   104  	}
   105  	return
   106  }
   107  
   108  func (t *nativeThread) ReadMemory(data []byte, addr uint64) (n int, err error) {
   109  	if ok, err := t.dbp.Valid(); !ok {
   110  		return 0, err
   111  	}
   112  	if len(data) == 0 {
   113  		return
   114  	}
   115  	n, _ = processVmRead(t.ID, uintptr(addr), data)
   116  	if n == 0 {
   117  		t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, uintptr(addr), data) })
   118  	}
   119  	return
   120  }
   121  
   122  // SoftExc returns true if this thread received a software exception during the last resume.
   123  func (t *nativeThread) SoftExc() bool {
   124  	return t.os.setbp
   125  }