/* Darwin support for GDB, the GNU debugger.
- Copyright (C) 2008-2012 Free Software Foundation, Inc.
+ Copyright (C) 2008-2013 Free Software Foundation, Inc.
Contributed by AdaCore.
#include "value.h"
#include "arch-utils.h"
#include "bfd.h"
+#include "bfd/mach-o.h"
#include <sys/ptrace.h>
#include <sys/signal.h>
static void darwin_stop (ptid_t);
static void darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
- enum target_signal signal);
+ enum gdb_signal signal);
static void darwin_resume (ptid_t ptid, int step,
- enum target_signal signal);
+ enum gdb_signal signal);
static ptid_t darwin_wait_to (struct target_ops *ops, ptid_t ptid,
struct target_waitstatus *status, int options);
#define PAGE_ROUND(x) PAGE_TRUNC((x) + mach_page_size - 1)
/* This controls output of inferior debugging. */
-static int darwin_debug_flag = 0;
+static unsigned int darwin_debug_flag = 0;
/* Create a __TEXT __info_plist section in the executable so that gdb could
be signed. This is required to get an authorization for task_for_pid.
thread->signaled = 1;
}
- /* Set single step. */
- inferior_debug (4, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
- thread->gdb_port, step);
- darwin_set_sstep (thread->gdb_port, step);
- thread->single_step = step;
+ /* Set or reset single step. */
+ if (step != thread->single_step)
+ {
+ inferior_debug (4, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
+ thread->gdb_port, step);
+ darwin_set_sstep (thread->gdb_port, step);
+ thread->single_step = step;
+ }
darwin_send_reply (inf, thread);
thread->msg_state = DARWIN_RUNNING;
}
static void
-darwin_resume (ptid_t ptid, int step, enum target_signal signal)
+darwin_resume (ptid_t ptid, int step, enum gdb_signal signal)
{
struct target_waitstatus status;
int pid;
(2, _("darwin_resume: pid=%d, tid=0x%x, step=%d, signal=%d\n"),
ptid_get_pid (ptid), ptid_get_tid (ptid), step, signal);
- if (signal == TARGET_SIGNAL_0)
+ if (signal == GDB_SIGNAL_0)
nsignal = 0;
else
- nsignal = target_signal_to_host (signal);
+ nsignal = gdb_signal_to_host (signal);
/* Don't try to single step all threads. */
if (step)
static void
darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
- enum target_signal signal)
+ enum gdb_signal signal)
{
return darwin_resume (ptid, step, signal);
}
if (thread->event.ex_data[0] == EXC_SOFT_SIGNAL)
{
status->value.sig =
- target_signal_from_host (thread->event.ex_data[1]);
+ gdb_signal_from_host (thread->event.ex_data[1]);
inferior_debug (5, _(" (signal %d: %s)\n"),
thread->event.ex_data[1],
- target_signal_to_name (status->value.sig));
+ gdb_signal_to_name (status->value.sig));
/* If the thread is stopped because it has received a signal
that gdb has just sent, continue. */
break;
case EXC_BREAKPOINT:
/* Many internal GDB routines expect breakpoints to be reported
- as TARGET_SIGNAL_TRAP, and will report TARGET_EXC_BREAKPOINT
+ as GDB_SIGNAL_TRAP, and will report TARGET_EXC_BREAKPOINT
as a spurious signal. */
- status->value.sig = TARGET_SIGNAL_TRAP;
+ status->value.sig = GDB_SIGNAL_TRAP;
break;
default:
- status->value.sig = TARGET_SIGNAL_UNKNOWN;
+ status->value.sig = GDB_SIGNAL_UNKNOWN;
break;
}
darwin_inf_fake_stop = NULL;
status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = TARGET_SIGNAL_TRAP;
+ status->value.sig = GDB_SIGNAL_TRAP;
thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
thread->msg_state = DARWIN_STOPPED;
return ptid_build (inf->pid, 0, thread->gdb_port);
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,
{
ptid = darwin_wait (inferior_ptid, &wstatus);
if (wstatus.kind == TARGET_WAITKIND_STOPPED
- && wstatus.value.sig == TARGET_SIGNAL_STOP)
+ && wstatus.value.sig == GDB_SIGNAL_STOP)
break;
}
}
gdb_assert (inf != NULL);
- if (!inf->private->no_ptrace)
- {
- darwin_stop_inferior (inf);
-
- res = PTRACE (PT_KILL, inf->pid, 0, 0);
- if (res != 0)
- warning (_("Failed to kill inferior: ptrace returned %d "
- "[%s] (pid=%d)"),
- res, safe_strerror (errno), inf->pid);
+ kret = darwin_restore_exception_ports (inf->private);
+ MACH_CHECK_ERROR (kret);
- darwin_reply_to_all_pending_messages (inf);
+ darwin_reply_to_all_pending_messages (inf);
- darwin_resume_inferior (inf);
+ res = kill (inf->pid, 9);
- ptid = darwin_wait (inferior_ptid, &wstatus);
- }
- else
+ if (res == 0)
{
- kret = darwin_restore_exception_ports (inf->private);
- MACH_CHECK_ERROR (kret);
-
- darwin_reply_to_all_pending_messages (inf);
-
darwin_resume_inferior (inf);
-
- res = kill (inf->pid, 9);
-
+
ptid = darwin_wait (inferior_ptid, &wstatus);
}
+ else if (errno != ESRCH)
+ warning (_("Failed to kill inferior: kill (%d, 9) returned [%s]"),
+ inf->pid, safe_strerror (errno));
target_mourn_inferior ();
}
/* 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. */
Return 0 on failure; number of bytes read / writen otherwise. */
static int
darwin_read_write_inferior (task_t task, CORE_ADDR addr,
- char *rdaddr, const char *wraddr, int length)
+ gdb_byte *rdaddr, const gdb_byte *wraddr,
+ int length)
{
kern_return_t kret;
mach_vm_address_t offset = addr & (mach_page_size - 1);
mach_vm_address_t low_address = (mach_vm_address_t) (addr - offset);
mach_vm_size_t aligned_length = (mach_vm_size_t) PAGE_ROUND (offset + length);
pointer_t copied;
- int copy_count;
+ mach_msg_type_number_t copy_count;
mach_vm_size_t remaining_length;
mach_vm_address_t region_address;
mach_vm_size_t region_length;
/* Read LENGTH bytes at offset ADDR of task_dyld_info for TASK, and copy them
to RDADDR.
- Return 0 on failure; number of bytes read / writen otherwise. */
+ Return 0 on failure; number of bytes read / written otherwise. */
+#ifdef TASK_DYLD_INFO_COUNT
+/* This is not available in Darwin 9. */
static int
-darwin_read_dyld_info (task_t task, CORE_ADDR addr, char *rdaddr, int length)
+darwin_read_dyld_info (task_t task, CORE_ADDR addr, gdb_byte *rdaddr,
+ int length)
{
struct task_dyld_info task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
memcpy (rdaddr, (char *)&task_dyld_info + addr, length);
return length;
}
+#endif
\f
/* Return 0 on failure, number of bytes handled otherwise. TARGET
case TARGET_OBJECT_MEMORY:
return darwin_read_write_inferior (inf->private->task, offset,
readbuf, writebuf, len);
+#ifdef TASK_DYLD_INFO_COUNT
case TARGET_OBJECT_DARWIN_DYLD_INFO:
if (writebuf != NULL || readbuf == NULL)
{
return -1;
}
return darwin_read_dyld_info (inf->private->task, offset, readbuf, len);
+#endif
default:
return -1;
}
return 1;
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_darwin_inferior;
+
void
_initialize_darwin_inferior (void)
{
inferior_debug (2, _("GDB task: 0x%lx, pid: %d\n"), mach_task_self (),
getpid ());
- add_setshow_zinteger_cmd ("darwin", class_obscure,
- &darwin_debug_flag, _("\
+ add_setshow_zuinteger_cmd ("darwin", class_obscure,
+ &darwin_debug_flag, _("\
Set if printing inferior communication debugging statements."), _("\
Show if printing inferior communication debugging statements."), NULL,
- NULL, NULL,
- &setdebuglist, &showdebuglist);
+ NULL, NULL,
+ &setdebuglist, &showdebuglist);
add_setshow_boolean_cmd ("mach-exceptions", class_support,
&enable_mach_exceptions, _("\