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 }