mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	 a4df01e105
			
		
	
	a4df01e105
	
	
	
		
			
			The condition that causes waitFast to fail can not happen in addThread and halt so we don't need to call the slower wait.
		
			
				
	
	
		
			120 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package native
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	sys "golang.org/x/sys/unix"
 | |
| 
 | |
| 	"github.com/derekparker/delve/pkg/proc"
 | |
| )
 | |
| 
 | |
| type WaitStatus sys.WaitStatus
 | |
| 
 | |
| // OSSpecificDetails hold Linux specific
 | |
| // process details.
 | |
| type OSSpecificDetails struct {
 | |
| 	registers sys.PtraceRegs
 | |
| }
 | |
| 
 | |
| func (t *Thread) halt() (err error) {
 | |
| 	err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP)
 | |
| 	if err != nil {
 | |
| 		err = fmt.Errorf("halt err %s on thread %d", err, t.ID)
 | |
| 		return
 | |
| 	}
 | |
| 	_, _, err = t.dbp.waitFast(t.ID)
 | |
| 	if err != nil {
 | |
| 		err = fmt.Errorf("wait err %s on thread %d", err, t.ID)
 | |
| 		return
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (t *Thread) stopped() bool {
 | |
| 	state := status(t.ID, t.dbp.os.comm)
 | |
| 	return state == StatusTraceStop || state == StatusTraceStopT
 | |
| }
 | |
| 
 | |
| func (t *Thread) resume() error {
 | |
| 	return t.resumeWithSig(0)
 | |
| }
 | |
| 
 | |
| func (t *Thread) resumeWithSig(sig int) (err error) {
 | |
| 	t.running = true
 | |
| 	t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) })
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (t *Thread) singleStep() (err error) {
 | |
| 	for {
 | |
| 		t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) })
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		wpid, status, err := t.dbp.waitFast(t.ID)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if (status == nil || status.Exited()) && wpid == t.dbp.pid {
 | |
| 			t.dbp.postExit()
 | |
| 			rs := 0
 | |
| 			if status != nil {
 | |
| 				rs = status.ExitStatus()
 | |
| 			}
 | |
| 			return proc.ProcessExitedError{Pid: t.dbp.pid, Status: rs}
 | |
| 		}
 | |
| 		if wpid == t.ID && status.StopSignal() == sys.SIGTRAP {
 | |
| 			return nil
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (t *Thread) Blocked() bool {
 | |
| 	regs, err := t.Registers(false)
 | |
| 	if err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	pc := regs.PC()
 | |
| 	fn := t.BinInfo().PCToFunc(pc)
 | |
| 	if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) {
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (t *Thread) saveRegisters() (proc.Registers, error) {
 | |
| 	var err error
 | |
| 	t.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(t.ID, &t.os.registers) })
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("could not save register contents")
 | |
| 	}
 | |
| 	return &Regs{&t.os.registers, nil}, nil
 | |
| }
 | |
| 
 | |
| func (t *Thread) restoreRegisters() (err error) {
 | |
| 	t.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(t.ID, &t.os.registers) })
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) {
 | |
| 	if t.dbp.exited {
 | |
| 		return 0, proc.ProcessExitedError{Pid: t.dbp.pid}
 | |
| 	}
 | |
| 	if len(data) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) })
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
 | |
| 	if t.dbp.exited {
 | |
| 		return 0, proc.ProcessExitedError{Pid: t.dbp.pid}
 | |
| 	}
 | |
| 	if len(data) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) })
 | |
| 	return
 | |
| }
 |