From a41f2563d040d86954ccda7faa4a8ad7bdbcae88 Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Fri, 21 Mar 2014 16:56:39 +0100 Subject: [PATCH] darwin-nat: avoid crash while debugging gdb. it is possible that gdb gets mach exceptions from an unknown inferior. This happens when an inferior creates a child and that child gets a signal. So instead of reporting messages with unknown origins, simply reply to these notifications. The kernel will then post the unix signal. gdb/ * darwin-nat.c (darwin_encode_reply): Add prototype. (darwin_decode_exception_message): Reply to unknown inferiors. (darwin_decode_message): Handle message by id. Ignore message to unknown inferior. (darwin_wait): Discard unknown messages, add debug trace. --- gdb/ChangeLog | 8 ++++ gdb/darwin-nat.c | 144 ++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 98 insertions(+), 54 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5ff3b59..c8d4ab5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2014-04-01 Tristan Gingold + + * darwin-nat.c (darwin_encode_reply): Add prototype. + (darwin_decode_exception_message): Reply to unknown inferiors. + (darwin_decode_message): Handle message by id. Ignore message + to unknown inferior. + (darwin_wait): Discard unknown messages, add debug trace. + 2014-03-31 Doug Evans * dwarf2read.c (read_cutu_die_from_dwo): Delete unused local diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c index 3ea9696..7d2508e 100644 --- a/gdb/darwin-nat.c +++ b/gdb/darwin-nat.c @@ -113,6 +113,9 @@ static char *darwin_pid_to_str (struct target_ops *ops, ptid_t tpid); static int darwin_thread_alive (struct target_ops *ops, ptid_t tpid); +static void darwin_encode_reply (mig_reply_error_t *reply, + mach_msg_header_t *hdr, integer_t code); + /* Target operations for Darwin. */ static struct target_ops *darwin_ops; @@ -557,8 +560,8 @@ darwin_decode_exception_message (mach_msg_header_t *hdr, kern_return_t kret; int i; - /* Check message identifier. 2401 == 0x961 is exc. */ - if (hdr->msgh_id != 2401) + /* Check message destination. */ + if (hdr->msgh_local_port != darwin_ex_port) return -1; /* Check message header. */ @@ -588,25 +591,42 @@ darwin_decode_exception_message (mach_msg_header_t *hdr, /* Ok, the hard work. */ data = (integer_t *)(ndr + 1); - /* Find process by port. */ task_port = desc[1].name; thread_port = desc[0].name; + + /* We got new rights to the task and the thread. Get rid of them. */ + kret = mach_port_deallocate (mach_task_self (), task_port); + MACH_CHECK_ERROR (kret); + kret = mach_port_deallocate (mach_task_self (), thread_port); + MACH_CHECK_ERROR (kret); + + /* Find process by port. */ inf = darwin_find_inferior_by_task (task_port); - if (inf == NULL) - return -1; *pinf = inf; + if (inf == NULL) + { + /* Not a known inferior. This could happen if the child fork, as + the created process will inherit its exception port. + FIXME: should the exception port be restored ? */ + kern_return_t kret; + mig_reply_error_t reply; + + darwin_encode_reply (&reply, hdr, KERN_SUCCESS); + + kret = mach_msg (&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT, + reply.Head.msgh_size, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + MACH_CHECK_ERROR (kret); + + return 0; + } /* Find thread by port. */ /* Check for new threads. Do it early so that the port in the exception message can be deallocated. */ darwin_check_new_threads (inf); - /* We got new rights to the task and the thread. Get rid of them. */ - kret = mach_port_deallocate (mach_task_self (), task_port); - MACH_CHECK_ERROR (kret); - kret = mach_port_deallocate (mach_task_self (), thread_port); - MACH_CHECK_ERROR (kret); - thread = darwin_find_thread (inf, thread_port); if (thread == NULL) return -1; @@ -863,8 +883,8 @@ darwin_decode_message (mach_msg_header_t *hdr, darwin_thread_t *thread; struct inferior *inf; - /* Exception message. */ - if (hdr->msgh_local_port == darwin_ex_port) + /* Exception message. 2401 == 0x961 is exc. */ + if (hdr->msgh_id == 2401) { int res; @@ -877,7 +897,12 @@ darwin_decode_message (mach_msg_header_t *hdr, printf_unfiltered (_("darwin_wait: ill-formatted message (id=0x%x)\n"), hdr->msgh_id); /* FIXME: send a failure reply? */ - status->kind = TARGET_WAITKIND_SPURIOUS; + status->kind = TARGET_WAITKIND_IGNORE; + return minus_one_ptid; + } + if (inf == NULL) + { + status->kind = TARGET_WAITKIND_IGNORE; return minus_one_ptid; } *pinf = inf; @@ -940,56 +965,60 @@ darwin_decode_message (mach_msg_header_t *hdr, return ptid_build (inf->pid, 0, thread->gdb_port); } - - *pinf = NULL; - *pthread = NULL; - - inf = darwin_find_inferior_by_notify (hdr->msgh_local_port); - if (inf != NULL) + else if (hdr->msgh_id == 0x48) { - if (!inf->private->no_ptrace) - { - pid_t res; - int wstatus; + /* MACH_NOTIFY_DEAD_NAME: notification for exit. */ + *pinf = NULL; + *pthread = NULL; - res = wait4 (inf->pid, &wstatus, 0, NULL); - if (res < 0 || res != inf->pid) - { - printf_unfiltered (_("wait4: res=%d: %s\n"), - res, safe_strerror (errno)); - status->kind = TARGET_WAITKIND_SPURIOUS; - return minus_one_ptid; - } - if (WIFEXITED (wstatus)) + inf = darwin_find_inferior_by_notify (hdr->msgh_local_port); + if (inf != NULL) + { + if (!inf->private->no_ptrace) { - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = WEXITSTATUS (wstatus); + pid_t res; + int wstatus; + + res = wait4 (inf->pid, &wstatus, 0, NULL); + if (res < 0 || res != inf->pid) + { + printf_unfiltered (_("wait4: res=%d: %s\n"), + res, safe_strerror (errno)); + status->kind = TARGET_WAITKIND_IGNORE; + return minus_one_ptid; + } + if (WIFEXITED (wstatus)) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = WEXITSTATUS (wstatus); + } + else + { + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = WTERMSIG (wstatus); + } + + inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"), + res, wstatus); + + /* Looks necessary on Leopard and harmless... */ + wait4 (inf->pid, &wstatus, 0, NULL); + + return ptid_build (inf->pid, 0, 0); } else { - status->kind = TARGET_WAITKIND_SIGNALLED; - status->value.sig = WTERMSIG (wstatus); + inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid); + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; /* Don't know. */ + return ptid_build (inf->pid, 0, 0); } - - inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"), - res, wstatus); - - /* Looks necessary on Leopard and harmless... */ - wait4 (inf->pid, &wstatus, 0, NULL); - - return ptid_build (inf->pid, 0, 0); - } - else - { - inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid); - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = 0; /* Don't know. */ - return ptid_build (inf->pid, 0, 0); } } - printf_unfiltered (_("Bad local-port: 0x%x\n"), hdr->msgh_local_port); - status->kind = TARGET_WAITKIND_SPURIOUS; + /* Unknown message. */ + warning (_("darwin: got unknown message, id: 0x%x\n"), hdr->msgh_id); + status->kind = TARGET_WAITKIND_IGNORE; return minus_one_ptid; } @@ -1082,7 +1111,10 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status) darwin_dump_message (hdr, darwin_debug_flag > 11); res = darwin_decode_message (hdr, &thread, &inf, status); + if (ptid_equal (res, minus_one_ptid)) + continue; + /* Early return in case an inferior has exited. */ if (inf == NULL) return res; } @@ -1110,6 +1142,10 @@ darwin_wait (ptid_t ptid, struct target_waitstatus *status) break; } + /* Debug: display message. */ + if (darwin_debug_flag > 10) + darwin_dump_message (hdr, darwin_debug_flag > 11); + ptid2 = darwin_decode_message (hdr, &thread, &inf, &status2); if (inf != NULL && thread != NULL -- 2.7.4