GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "top.h"
#include <mach/port.h>
#include "darwin-nat.h"
+#include "common/filestuff.h"
/* Quick overview.
Darwin kernel is Mach + BSD derived kernel. Note that they share the
thread_t old_id = old ? old->gdb_port : THREAD_NULL;
inferior_debug
- (12, _(" new_ix:%d/%d, old_ix:%d/%d, new_id:%x old_id:%x\n"),
+ (12, _(" new_ix:%d/%d, old_ix:%d/%d, new_id:0x%x old_id:0x%x\n"),
new_ix, new_nbr, old_ix, old_nbr, new_id, old_id);
if (old_id == new_id)
/* Set or reset single step. */
if (step != thread->single_step)
{
- inferior_debug (4, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
+ inferior_debug (4, _("darwin_set_sstep (thread=0x%x, enable=%d)\n"),
thread->gdb_port, step);
darwin_set_sstep (thread->gdb_port, step);
thread->single_step = step;
if (res < 0)
{
/* Should not happen... */
- printf_unfiltered (_("darwin_wait: ill-formatted message (id=%x)\n"),
- hdr->msgh_id);
+ printf_unfiltered
+ (_("darwin_wait: ill-formatted message (id=0x%x)\n"), hdr->msgh_id);
/* FIXME: send a failure reply? */
status->kind = TARGET_WAITKIND_SPURIOUS;
return minus_one_ptid;
status->kind = TARGET_WAITKIND_STOPPED;
thread->msg_state = DARWIN_MESSAGE;
- inferior_debug (4, _("darwin_wait: thread=%x, got %s\n"),
+ inferior_debug (4, _("darwin_wait: thread=0x%x, got %s\n"),
thread->gdb_port,
unparse_exception_type (thread->event.ex_type));
status->value.sig = WTERMSIG (wstatus);
}
- inferior_debug (4, _("darwin_wait: pid=%d exit, status=%x\n"),
+ inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
res, wstatus);
/* Looks necessary on Leopard and harmless... */
}
}
- printf_unfiltered (_("Bad local-port: %x\n"), hdr->msgh_local_port);
+ printf_unfiltered (_("Bad local-port: 0x%x\n"), hdr->msgh_local_port);
status->kind = TARGET_WAITKIND_SPURIOUS;
return minus_one_ptid;
}
pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
{
- inferior_debug (4, "cancel_breakpoint for thread %x\n",
+ inferior_debug (4, "cancel_breakpoint for thread 0x%x\n",
ptid_get_tid (ptid));
/* Back up the PC if necessary. */
if (kret != MACH_MSG_SUCCESS)
{
- inferior_debug (5, _("mach_msg: ret=%x\n"), kret);
+ inferior_debug (5, _("mach_msg: ret=0x%x\n"), kret);
status->kind = TARGET_WAITKIND_SPURIOUS;
return minus_one_ptid;
}
if (kret != MACH_MSG_SUCCESS)
{
inferior_debug
- (5, _("darwin_wait: mach_msg(pending) ret=%x\n"), kret);
+ (5, _("darwin_wait: mach_msg(pending) ret=0x%x\n"), kret);
break;
}
}
else
inferior_debug
- (3, _("darwin_wait: thread %x hit a non-gdb breakpoint\n"),
+ (3, _("darwin_wait: thread 0x%x hit a non-gdb breakpoint\n"),
thread->gdb_port);
}
else
kret = mach_port_move_member (gdb_task,
inf->private->notify_port, MACH_PORT_NULL);
- gdb_assert (kret == KERN_SUCCESS);
+ MACH_CHECK_ERROR (kret);
kret = mach_port_request_notification (gdb_task, inf->private->task,
MACH_NOTIFY_DEAD_NAME, 0,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&prev);
/* This can fail if the task is dead. */
- inferior_debug (4, "task=%x, prev=%x, notify_port=%x\n",
+ inferior_debug (4, "task=0x%x, prev=0x%x, notify_port=0x%x\n",
inf->private->task, prev, inf->private->notify_port);
if (kret == KERN_SUCCESS)
/* Create a port to get exceptions. */
kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
&darwin_ex_port);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to create exception port, mach_port_allocate "
+ "returned: %d"),
+ kret);
kret = mach_port_insert_right (gdb_task, darwin_ex_port, darwin_ex_port,
MACH_MSG_TYPE_MAKE_SEND);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to create exception port, mach_port_insert_right "
+ "returned: %d"),
+ kret);
/* Create a port set and put ex_port in it. */
kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_PORT_SET,
&darwin_port_set);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to create port set, mach_port_allocate "
+ "returned: %d"),
+ kret);
kret = mach_port_move_member (gdb_task, darwin_ex_port, darwin_port_set);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to move exception port into new port set, "
+ "mach_port_move_member\n"
+ "returned: %d"),
+ kret);
}
/* Create a port to be notified when the child task terminates. */
kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
&inf->private->notify_port);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to create notification port, mach_port_allocate "
+ "returned: %d"),
+ kret);
kret = mach_port_move_member (gdb_task,
inf->private->notify_port, darwin_port_set);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to move notification port into new port set, "
+ "mach_port_move_member\n"
+ "returned: %d"),
+ kret);
kret = mach_port_request_notification (gdb_task, inf->private->task,
MACH_NOTIFY_DEAD_NAME, 0,
inf->private->notify_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&prev_not);
- gdb_assert (kret == KERN_SUCCESS);
- gdb_assert (prev_not == MACH_PORT_NULL);
+ if (kret != KERN_SUCCESS)
+ error (_("Termination notification request failed, "
+ "mach_port_request_notification\n"
+ "returned: %d"),
+ kret);
+ if (prev_not != MACH_PORT_NULL)
+ {
+ /* This is unexpected, as there should not be any previously
+ registered notification request. But this is not a fatal
+ issue, so just emit a warning. */
+ warning (_("\
+A task termination request was registered before the debugger registered\n\
+its own. This is unexpected, but should otherwise not have any actual\n\
+impact on the debugging session."));
+ }
kret = darwin_save_exception_ports (inf->private);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to save exception ports, task_get_exception_ports"
+ "returned: %d"),
+ kret);
/* Set exception port. */
if (enable_mach_exceptions)
mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
kret = task_set_exception_ports (inf->private->task, mask, darwin_ex_port,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
- gdb_assert (kret == KERN_SUCCESS);
+ if (kret != KERN_SUCCESS)
+ error (_("Unable to set exception ports, task_set_exception_ports"
+ "returned: %d"),
+ kret);
push_target (darwin_ops);
}
/* Wait until gdb is ready. */
res = read (ptrace_fds[0], &c, 1);
- gdb_assert (res == 0);
+ if (res != 0)
+ error (_("unable to read from pipe, read returned: %d"), res);
close (ptrace_fds[0]);
/* Get rid of privileges. */
ptrace_fds[1] = -1;
error (_("unable to create a pipe: %s"), safe_strerror (errno));
}
+
+ mark_fd_no_cloexec (ptrace_fds[0]);
+ mark_fd_no_cloexec (ptrace_fds[1]);
}
static void
close (ptrace_fds[0]);
close (ptrace_fds[1]);
+ unmark_fd_no_cloexec (ptrace_fds[0]);
+ unmark_fd_no_cloexec (ptrace_fds[1]);
+
darwin_init_thread_list (inf);
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
}
\f
+/* Set things up such that the next call to darwin_wait will immediately
+ return a fake stop event for inferior INF.
+
+ This assumes that the inferior's thread list has been initialized,
+ as it will suspend the inferior's first thread. */
+
+static void
+darwin_setup_fake_stop_event (struct inferior *inf)
+{
+ darwin_thread_t *thread;
+ kern_return_t kret;
+
+ gdb_assert (darwin_inf_fake_stop == NULL);
+ darwin_inf_fake_stop = inf;
+
+ /* When detecting a fake pending stop event, darwin_wait returns
+ an event saying that the first thread is in a DARWIN_STOPPED
+ state. To make that accurate, we need to suspend that thread
+ as well. Otherwise, we'll try resuming it when resuming the
+ inferior, and get a warning because the thread's suspend count
+ is already zero, making the resume request useless. */
+ thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
+ kret = thread_suspend (thread->gdb_port);
+ MACH_CHECK_ERROR (kret);
+}
+
/* Attach to process PID, then initialize for debugging it
and wait for the trace-trap that results from attaching. */
static void
darwin_check_osabi (inf->private, ptid_get_tid (inferior_ptid));
- gdb_assert (darwin_inf_fake_stop == NULL);
- darwin_inf_fake_stop = inf;
+ darwin_setup_fake_stop_event (inf);
+
inf->private->no_ptrace = 1;
}
mach_vm_address_t region_address;
mach_vm_size_t region_length;
- inferior_debug (8, _("darwin_read_write_inferior(task=%x, %s, len=%d)\n"),
+ inferior_debug (8, _("darwin_read_write_inferior(task=0x%x, %s, len=%d)\n"),
task, core_addr_to_string (addr), length);
/* Get memory from inferior with page aligned addresses. */