// Returns a new Process struct. func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) { if attach { var err error dbp.execPtraceFunc(func() { err = sys.PtraceAttach(dbp.Pid) }) if err != nil { return nil, err } _, _, err = wait(dbp.Pid, dbp.Pid, 0) if err != nil { return nil, err } } proc, err := os.FindProcess(dbp.Pid) if err != nil { return nil, err } dbp.Process = proc err = dbp.LoadInformation(path) if err != nil { return nil, err } if err := dbp.updateThreadList(); err != nil { return nil, err } switch runtime.GOARCH { case "amd64": dbp.arch = AMD64Arch() } return dbp, nil }
// Attach to a newly created thread, and store that thread in our list of // known threads. func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) { if thread, ok := dbp.Threads[tid]; ok { return thread, nil } var err error if attach { dbp.execPtraceFunc(func() { err = sys.PtraceAttach(tid) }) if err != nil && err != sys.EPERM { // Do not return err if err == EPERM, // we may already be tracing this thread due to // PTRACE_O_TRACECLONE. We will surely blow up later // if we truly don't have permissions. return nil, fmt.Errorf("could not attach to new thread %d %s", tid, err) } pid, status, err := wait(tid, dbp.Pid, 0) if err != nil { return nil, err } if status.Exited() { return nil, fmt.Errorf("thread already exited %d", pid) } } dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) }) if err == syscall.ESRCH { _, _, err = wait(tid, dbp.Pid, 0) if err != nil { return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err) } dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) }) if err != nil { return nil, fmt.Errorf("could not set options for new traced thread %d %s", tid, err) } } dbp.Threads[tid] = &Thread{ Id: tid, dbp: dbp, os: new(OSSpecificDetails), } if dbp.CurrentThread == nil { dbp.CurrentThread = dbp.Threads[tid] } return dbp.Threads[tid], nil }
// Returns a new Process struct. func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) { if attach { var err error dbp.execPtraceFunc(func() { err = sys.PtraceAttach(dbp.Pid) }) if err != nil { return nil, err } _, _, err = dbp.wait(dbp.Pid, 0) if err != nil { return nil, err } } proc, err := os.FindProcess(dbp.Pid) if err != nil { return nil, err } dbp.Process = proc err = dbp.LoadInformation(path) if err != nil { return nil, err } switch runtime.GOARCH { case "amd64": dbp.arch = AMD64Arch() } if err := dbp.updateThreadList(); err != nil { return nil, err } ver, isextld, err := dbp.getGoInformation() if err != nil { return nil, err } dbp.arch.SetGStructOffset(ver, isextld) // SelectedGoroutine can not be set correctly by the call to updateThreadList // because without calling SetGStructOffset we can not read the G struct of CurrentThread // but without calling updateThreadList we can not examine memory to determine // the offset of g struct inside TLS dbp.SelectedGoroutine, _ = dbp.CurrentThread.GetG() return dbp, nil }
// PtraceAttach executes the sys.PtraceAttach call. func PtraceAttach(pid int) error { return sys.PtraceAttach(pid) }