func (pt *Ptrace) Wait(h Handler) error { if h == nil { return errors.New("nil handler") } for { status, err := pt.Proc.Wait() if err != nil { return err } if status.Exited() { break } if err := h(pt); err != nil { return err } if err := syscall.PtraceSingleStep(pt.Proc.Pid); err != nil { return err } } return nil }
func (t *thread) ptraceStep() os.Error { err := syscall.PtraceSingleStep(t.tid) return os.NewSyscallError("ptrace(SINGLESTEP)", err) }
// SingleStep is a wrapper for ptrace(PTRACE_STEP) func (p *Process) SingleStep() bool { err := syscall.PtraceSingleStep(p.Pid) return err == nil }
func run() { // If the debugger itself is multi-threaded, ptrace calls must come from // the same thread that originally attached to the remote thread. runtime.LockOSThread() f, err := os.Open(exeFilename) if err != nil { log.Printf(`%q not found. Did you run "go build ." in that directory?`, exeFilename) log.Fatalf("Open: %v", err) } defer f.Close() dwarfData, err := loadDwarfData(f) if err != nil { log.Fatalf("loadDwarfData: %v", err) } proc, err := os.StartProcess(exeFilename, []string{exeFilename}, &os.ProcAttr{ Files: []*os.File{ os.Stdin, os.Stdout, os.Stderr, }, Sys: &syscall.SysProcAttr{ Ptrace: true, Pdeathsig: syscall.SIGKILL, }, }) if err != nil { log.Fatalf("StartProcess: %v", err) } fmt.Printf("\tproc.Pid=%d\n", proc.Pid) _, status, err := wait(proc.Pid) if err != nil { log.Fatalf("wait: %v", err) } if status != 0x00057f { // 0x05=SIGTRAP, 0x7f=stopped. log.Fatalf("status: got %#x, want %#x", status, 0x57f) } err = syscall.PtraceSetOptions(proc.Pid, syscall.PTRACE_O_TRACECLONE|syscall.PTRACE_O_TRACEEXIT) if err != nil { log.Fatalf("PtraceSetOptions: %v", err) } addr, err := lookupSym(dwarfData, "fmt.Printf") if err != nil { log.Fatalf("lookupSym: %v", err) } fmt.Printf("\tfmt.Printf=%#x\n", addr) var buf [1]byte if err := peek(proc.Pid, addr, buf[:1]); err != nil { log.Fatalf("peek: %v", err) } breakpoints := map[uint64]breakpoint{ addr: {pc: addr, origInstr: buf[0]}, } buf[0] = breakpointInstr if err := poke(proc.Pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } err = syscall.PtraceCont(proc.Pid, 0) if err != nil { log.Fatalf("PtraceCont: %v", err) } for { pid, status, err := wait(-1) if err != nil { log.Fatalf("wait: %v", err) } switch status { case 0x00057f: // 0x05=SIGTRAP, 0x7f=stopped. regs := syscall.PtraceRegs{} if err := syscall.PtraceGetRegs(pid, ®s); err != nil { log.Fatalf("PtraceGetRegs: %v", err) } regs.Rip -= breakpointInstrLen if err := syscall.PtraceSetRegs(pid, ®s); err != nil { log.Fatalf("PtraceSetRegs: %v", err) } bp, ok := breakpoints[regs.Rip] if !ok { log.Fatalf("no breakpoint for address %#x\n", regs.Rip) } buf[0] = bp.origInstr if err := poke(pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } fmt.Printf("\thit breakpoint at %#x, pid=%5d\n", regs.Rip, pid) if err := syscall.PtraceSingleStep(pid); err != nil { log.Fatalf("PtraceSingleStep: %v", err) } _, status, err := wait(pid) if err != nil { log.Fatalf("wait: %v", err) } if status != 0x00057f { log.Fatalf("PtraceSingleStep: unexpected status %#x\n", status) } buf[0] = breakpointInstr if err := poke(pid, addr, buf[:1]); err != nil { log.Fatalf("poke: %v", err) } case 0x00137f: // 0x13=SIGSTOP, 0x7f=stopped. // No-op. case 0x03057f: // 0x05=SIGTRAP, 0x7f=stopped, 0x03=PTRACE_EVENT_CLONE. msg, err := syscall.PtraceGetEventMsg(pid) if err != nil { log.Fatalf("PtraceGetEventMsg: %v", err) } fmt.Printf("\tclone: new pid=%d\n", msg) default: log.Fatalf("unexpected status %#x\n", status) } err = syscall.PtraceCont(pid, 0) if err != nil { log.Fatalf("PtraceCont: %v", err) } } }
func (t *Tracer) SingleStep() error { return syscall.PtraceSingleStep(t.Process.Pid) }
func (s *Server) ptraceSingleStep(pid int) (err error) { s.fc <- func() error { return syscall.PtraceSingleStep(pid) } return <-s.ec }