提交 684dc92c 编写于 作者: D Derek Parker

Improve handling of process natural death (OS X)

上级 6b3d724f
......@@ -105,11 +105,15 @@ func Run(args []string) {
}
cmdstr, args := parseCommand(cmdstr)
if cmdstr == "exit" {
handleExit(dbp, t, 0)
}
if dbp.Exited() && cmdstr != "help" {
fmt.Fprintf(os.Stderr, "Process has already exited.\n")
continue
}
cmd := cmds.Find(cmdstr)
if err := cmd(dbp, args...); err != nil {
switch err.(type) {
......@@ -132,39 +136,41 @@ func handleExit(dbp *proctl.DebuggedProcess, t *Term, status int) {
f.Close()
}
answer, err := t.line.Prompt("Would you like to kill the process? [y/n]")
if err != nil {
t.die(2, io.EOF)
}
answer = strings.TrimSuffix(answer, "\n")
for _, bp := range dbp.HWBreakPoints {
if bp == nil {
continue
if !dbp.Exited() {
for _, bp := range dbp.HWBreakPoints {
if bp == nil {
continue
}
if _, err := dbp.Clear(bp.Addr); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", bp.Addr, err)
}
}
if _, err := dbp.Clear(bp.Addr); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", bp.Addr, err)
for pc := range dbp.BreakPoints {
if _, err := dbp.Clear(pc); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", pc, err)
}
}
}
for pc := range dbp.BreakPoints {
if _, err := dbp.Clear(pc); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", pc, err)
answer, err := t.line.Prompt("Would you like to kill the process? [y/n]")
if err != nil {
t.die(2, io.EOF)
}
}
answer = strings.TrimSuffix(answer, "\n")
fmt.Println("Detaching from process...")
err = sys.PtraceDetach(dbp.Process.Pid)
if err != nil {
t.die(2, "Could not detach", err)
}
fmt.Println("Detaching from process...")
err = sys.PtraceDetach(dbp.Process.Pid)
if err != nil {
t.die(2, "Could not detach", err)
}
if answer == "y" {
fmt.Println("Killing process", dbp.Process.Pid)
if answer == "y" {
fmt.Println("Killing process", dbp.Process.Pid)
err := dbp.Process.Kill()
if err != nil {
fmt.Println("Could not kill process", err)
err := dbp.Process.Kill()
if err != nil {
fmt.Println("Could not kill process", err)
}
}
}
......
......@@ -35,6 +35,7 @@ type DebuggedProcess struct {
breakpointIDCounter int
running bool
halt bool
exited bool
}
// A ManualStopError happens when the user triggers a
......@@ -87,6 +88,12 @@ func Launch(cmd []string) (*DebuggedProcess, error) {
return newDebugProcess(proc.Process.Pid, false)
}
// Returns whether or not Delve thinks the debugged
// process has exited.
func (dbp *DebuggedProcess) Exited() bool {
return dbp.exited
}
// Returns whether or not Delve thinks the debugged
// process is currently executing.
func (dbp *DebuggedProcess) Running() bool {
......@@ -242,6 +249,7 @@ func (dbp *DebuggedProcess) Continue() error {
if err != nil {
return err
}
thread, ok := dbp.Threads[wpid]
if !ok {
return fmt.Errorf("could not find thread for %d", wpid)
......@@ -380,6 +388,9 @@ func newDebugProcess(pid int, attach bool) (*DebuggedProcess, error) {
}
func (dbp *DebuggedProcess) run(fn func() error) error {
if dbp.exited {
return fmt.Errorf("process has already exited")
}
dbp.running = true
dbp.halt = false
defer func() { dbp.running = false }()
......
......@@ -122,14 +122,14 @@ mach_port_wait(mach_port_t port_set) {
// Wait for mach msg.
kret = mach_msg(&msg.hdr, MACH_RCV_MSG|MACH_RCV_INTERRUPT,
0, sizeof(msg.data), port_set, 0, MACH_PORT_NULL);
if (kret == MACH_RCV_INTERRUPTED || kret != MACH_MSG_SUCCESS) return 0;
if (kret == MACH_RCV_INTERRUPTED) return kret;
if (kret != MACH_MSG_SUCCESS) return 0;
mach_msg_body_t *bod = (mach_msg_body_t*)(&msg.hdr + 1);
mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1);
thread = desc[0].name;
// Exception
switch (msg.hdr.msgh_id) {
case 2401: // Exception
kret = thread_suspend(thread);
......
......@@ -177,20 +177,31 @@ func (dbp *DebuggedProcess) findExecutable() (*macho.File, error) {
func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
port := C.mach_port_wait(dbp.os.portSet)
switch port {
case C.MACH_RCV_INTERRUPTED:
return -1, ManualStopError{}
case dbp.os.notificationPort:
_, status, err := wait(dbp.Pid, 0)
if err != nil {
return -1, err
}
dbp.exited = true
return -1, ProcessExitedError{Pid: dbp.Pid, Status: status.ExitStatus()}
case C.MACH_RCV_INTERRUPTED:
if !dbp.halt {
// Call trapWait again, it seems
// MACH_RCV_INTERRUPTED is emitted before
// process natural death _sometimes_.
return trapWait(dbp, pid)
}
return -1, ManualStopError{}
case 0:
return -1, fmt.Errorf("error while waiting for task")
}
// Since we cannot be notified of new threads on OS X
// this is as good a time as any to check for them.
dbp.updateThreadList()
return int(port), nil
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册