Fix: Improve handling of soft signals on darwin
Fixes a bug on OSX where, if the debugged process spawned a child, when that process received a SIGCHLD it would cause Delve to hang. Fixes #197
This commit is contained in:
parent
3f4476da02
commit
a336c92a8b
25
_fixtures/sigchldprog.go
Normal file
25
_fixtures/sigchldprog.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("date")
|
||||||
|
reader, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
go func() {
|
||||||
|
for scanner.Scan() {
|
||||||
|
fmt.Println(scanner.Text())
|
||||||
|
}
|
||||||
|
reader.Close()
|
||||||
|
}()
|
||||||
|
cmd.Start()
|
||||||
|
cmd.Wait()
|
||||||
|
}
|
@ -113,6 +113,8 @@ mach_port_t
|
|||||||
mach_port_wait(mach_port_t port_set) {
|
mach_port_wait(mach_port_t port_set) {
|
||||||
kern_return_t kret;
|
kern_return_t kret;
|
||||||
thread_act_t thread;
|
thread_act_t thread;
|
||||||
|
NDR_record_t *ndr;
|
||||||
|
integer_t *data;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
mach_msg_header_t hdr;
|
mach_msg_header_t hdr;
|
||||||
@ -128,28 +130,21 @@ mach_port_wait(mach_port_t port_set) {
|
|||||||
mach_msg_body_t *bod = (mach_msg_body_t*)(&msg.hdr + 1);
|
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);
|
mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1);
|
||||||
thread = desc[0].name;
|
thread = desc[0].name;
|
||||||
|
ndr = (NDR_record_t *)(desc + 2);
|
||||||
|
data = (integer_t *)(ndr + 1);
|
||||||
|
|
||||||
switch (msg.hdr.msgh_id) {
|
switch (msg.hdr.msgh_id) {
|
||||||
case 2401: // Exception
|
case 2401: // Exception
|
||||||
kret = thread_suspend(thread);
|
if (thread_suspend(thread) != KERN_SUCCESS) return 0;
|
||||||
if (kret != KERN_SUCCESS) return 0;
|
|
||||||
|
|
||||||
// Send our reply back so the kernel knows this exception has been handled.
|
// Send our reply back so the kernel knows this exception has been handled.
|
||||||
mig_reply_error_t reply;
|
kret = mach_send_reply(msg.hdr);
|
||||||
mach_msg_header_t *rh = &reply.Head;
|
|
||||||
rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg.hdr.msgh_bits), 0);
|
|
||||||
rh->msgh_remote_port = msg.hdr.msgh_remote_port;
|
|
||||||
rh->msgh_size = (mach_msg_size_t) sizeof(mig_reply_error_t);
|
|
||||||
rh->msgh_local_port = MACH_PORT_NULL;
|
|
||||||
rh->msgh_id = msg.hdr.msgh_id + 100;
|
|
||||||
|
|
||||||
reply.NDR = NDR_record;
|
|
||||||
reply.RetCode = KERN_SUCCESS;
|
|
||||||
|
|
||||||
kret = mach_msg(&reply.Head, MACH_SEND_MSG|MACH_SEND_INTERRUPT, rh->msgh_size, 0,
|
|
||||||
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
||||||
|
|
||||||
if (kret != MACH_MSG_SUCCESS) return 0;
|
if (kret != MACH_MSG_SUCCESS) return 0;
|
||||||
|
if (data[2] == EXC_SOFT_SIGNAL) {
|
||||||
|
if (data[3] != SIGTRAP) {
|
||||||
|
if (thread_resume(thread) != KERN_SUCCESS) return 0;
|
||||||
|
return mach_port_wait(port_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 72: // Death
|
case 72: // Death
|
||||||
@ -159,6 +154,23 @@ mach_port_wait(mach_port_t port_set) {
|
|||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kern_return_t
|
||||||
|
mach_send_reply(mach_msg_header_t hdr) {
|
||||||
|
mig_reply_error_t reply;
|
||||||
|
mach_msg_header_t *rh = &reply.Head;
|
||||||
|
rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr.msgh_bits), 0);
|
||||||
|
rh->msgh_remote_port = hdr.msgh_remote_port;
|
||||||
|
rh->msgh_size = (mach_msg_size_t) sizeof(mig_reply_error_t);
|
||||||
|
rh->msgh_local_port = MACH_PORT_NULL;
|
||||||
|
rh->msgh_id = hdr.msgh_id + 100;
|
||||||
|
|
||||||
|
reply.NDR = NDR_record;
|
||||||
|
reply.RetCode = KERN_SUCCESS;
|
||||||
|
|
||||||
|
return mach_msg(&reply.Head, MACH_SEND_MSG|MACH_SEND_INTERRUPT, rh->msgh_size, 0,
|
||||||
|
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
kern_return_t
|
kern_return_t
|
||||||
raise_exception(mach_port_t task, mach_port_t thread, mach_port_t exception_port, exception_type_t exception) {
|
raise_exception(mach_port_t task, mach_port_t thread, mach_port_t exception_port, exception_type_t exception) {
|
||||||
return exception_raise(exception_port, thread, task, exception, 0, 0);
|
return exception_raise(exception_port, thread, task, exception, 0, 0);
|
||||||
|
@ -301,26 +301,25 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
|||||||
dbp.updateThreadList()
|
dbp.updateThreadList()
|
||||||
th, err = dbp.handleBreakpointOnThread(int(port))
|
th, err = dbp.handleBreakpointOnThread(int(port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(NoBreakpointError); ok {
|
if _, ok := err.(NoBreakpointError); !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
thread := dbp.Threads[int(port)]
|
||||||
if dbp.halt {
|
if dbp.halt {
|
||||||
dbp.halt = false
|
dbp.halt = false
|
||||||
return dbp.Threads[int(port)], nil
|
return thread, nil
|
||||||
}
|
}
|
||||||
th := dbp.Threads[int(port)]
|
if dbp.firstStart || thread.singleStepping {
|
||||||
if dbp.firstStart || th.singleStepping {
|
|
||||||
dbp.firstStart = false
|
dbp.firstStart = false
|
||||||
return dbp.Threads[int(port)], nil
|
return thread, nil
|
||||||
}
|
}
|
||||||
if err := th.Continue(); err != nil {
|
if err := thread.Continue(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return th, nil
|
return th, nil
|
||||||
}
|
}
|
||||||
return th, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func wait(pid, tgid, options int) (int, *sys.WaitStatus, error) {
|
func wait(pid, tgid, options int) (int, *sys.WaitStatus, error) {
|
||||||
|
@ -38,6 +38,9 @@ thread_count(task_t task);
|
|||||||
mach_port_t
|
mach_port_t
|
||||||
mach_port_wait(mach_port_t);
|
mach_port_wait(mach_port_t);
|
||||||
|
|
||||||
|
kern_return_t
|
||||||
|
mach_send_reply(mach_msg_header_t);
|
||||||
|
|
||||||
kern_return_t
|
kern_return_t
|
||||||
raise_exception(mach_port_t, mach_port_t, mach_port_t, exception_type_t);
|
raise_exception(mach_port_t, mach_port_t, mach_port_t, exception_type_t);
|
||||||
|
|
||||||
|
@ -694,3 +694,13 @@ func TestBreakpointOnFunctionEntry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessReceivesSIGCHLD(t *testing.T) {
|
||||||
|
withTestProcess("sigchldprog", t, func(p *Process, fixture protest.Fixture) {
|
||||||
|
err := p.Continue()
|
||||||
|
_, ok := err.(ProcessExitedError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Continue() returned unexpected error type %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user