/* Darwin support for GDB, the GNU debugger.
- Copyright (C) 2008-2013 Free Software Foundation, Inc.
+ Copyright (C) 2008-2015 Free Software Foundation, Inc.
Contributed by AdaCore.
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 "regcache.h"
#include "event-top.h"
#include "inf-loop.h"
-#include "gdb_stat.h"
-#include "exceptions.h"
+#include <sys/stat.h>
#include "inf-child.h"
#include "value.h"
#include "arch-utils.h"
#include <sys/ptrace.h>
#include <sys/signal.h>
-#include <machine/setjmp.h>
+#include <setjmp.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
-#include <string.h>
#include <ctype.h>
-#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
#include <libproc.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
#define PTRACE(CMD, PID, ADDR, SIG) \
darwin_ptrace(#CMD, CMD, (PID), (ADDR), (SIG))
-extern boolean_t exc_server (mach_msg_header_t *in, mach_msg_header_t *out);
-
-static void darwin_stop (ptid_t);
+static void darwin_interrupt (struct target_ops *self, ptid_t);
static void darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
enum gdb_signal signal);
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;
/* Exception port. */
mach_port_t darwin_ex_port;
-/* Port set. */
+/* Port set, to wait for answer on all ports. */
mach_port_t darwin_port_set;
/* Page size. */
/* 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.
- Once gdb is built, you can either:
- * make it setgid procmod
- * or codesign it with any system-trusted signing authority.
- See taskgated(8) for details. */
+ Once gdb is built, you must codesign it with any system-trusted signing
+ authority. See taskgated(8) for details. */
static const unsigned char info_plist[]
__attribute__ ((section ("__TEXT,__info_plist"),used)) =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"</dict>\n"
"</plist>\n";
+static void inferior_debug (int level, const char *fmt, ...)
+ ATTRIBUTE_PRINTF (2, 3);
+
static void
inferior_debug (int level, const char *fmt, ...)
{
unsigned int new_nbr;
unsigned int old_nbr;
unsigned int new_ix, old_ix;
- darwin_inferior *darwin_inf = inf->private;
+ darwin_inferior *darwin_inf = inf->priv;
VEC (darwin_thread_t) *thread_vec;
/* Get list of threads. */
break;
if (i == new_nbr)
{
+ /* Deallocate ports. */
+ for (i = 0; i < new_nbr; i++)
+ {
+ kret = mach_port_deallocate (mach_task_self (), thread_list[i]);
+ MACH_CHECK_ERROR (kret);
+ }
+
+ /* Deallocate the buffer. */
kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
new_nbr * sizeof (int));
MACH_CHECK_ERROR (kret);
+
return;
}
}
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)
new_ix++;
old_ix++;
- kret = mach_port_deallocate (gdb_task, old_id);
+ /* Deallocate the port. */
+ kret = mach_port_deallocate (gdb_task, new_id);
MACH_CHECK_ERROR (kret);
+
continue;
}
if (new_ix < new_nbr && new_id == MACH_PORT_DEAD)
struct thread_info *tp;
struct private_thread_info *pti;
- pti = XZALLOC (struct private_thread_info);
+ pti = XCNEW (struct private_thread_info);
pti->gdb_port = new_id;
pti->msg_state = DARWIN_RUNNING;
{
tp = find_thread_ptid (ptid_build (inf->pid, 0, 0));
gdb_assert (tp);
- tp->private = pti;
+ tp->priv = pti;
}
VEC_safe_push (darwin_thread_t, thread_vec, pti);
new_ix++;
VEC_free (darwin_thread_t, darwin_inf->threads);
darwin_inf->threads = thread_vec;
+ /* Deallocate the buffer. */
kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
new_nbr * sizeof (int));
MACH_CHECK_ERROR (kret);
static int
find_inferior_task_it (struct inferior *inf, void *port_ptr)
{
- return inf->private->task == *(task_t*)port_ptr;
+ return inf->priv->task == *(task_t*)port_ptr;
}
static int
find_inferior_notify_it (struct inferior *inf, void *port_ptr)
{
- return inf->private->notify_port == *(task_t*)port_ptr;
+ return inf->priv->notify_port == *(task_t*)port_ptr;
}
/* Return an inferior by task port. */
int k;
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, t);
k++)
if (t->gdb_port == thread)
return t;
static void
darwin_suspend_inferior (struct inferior *inf)
{
- if (!inf->private->suspended)
+ if (!inf->priv->suspended)
{
kern_return_t kret;
- kret = task_suspend (inf->private->task);
+ kret = task_suspend (inf->priv->task);
MACH_CHECK_ERROR (kret);
- inf->private->suspended = 1;
+ inf->priv->suspended = 1;
}
}
static void
darwin_resume_inferior (struct inferior *inf)
{
- if (inf->private->suspended)
+ if (inf->priv->suspended)
{
kern_return_t kret;
- kret = task_resume (inf->private->task);
+ kret = task_resume (inf->priv->task);
MACH_CHECK_ERROR (kret);
- inf->private->suspended = 0;
+ inf->priv->suspended = 0;
}
}
if (disp_body)
{
const unsigned char *data;
- const unsigned long *ldata;
+ const unsigned int *ldata;
int size;
int i;
}
printf_unfiltered (_(" data:"));
- ldata = (const unsigned long *)data;
- for (i = 0; i < size / sizeof (unsigned long); i++)
- printf_unfiltered (" %08lx", ldata[i]);
+ ldata = (const unsigned int *)data;
+ for (i = 0; i < size / sizeof (unsigned int); i++)
+ printf_unfiltered (" %08x", ldata[i]);
printf_unfiltered (_("\n"));
}
}
kern_return_t kret;
int i;
- /* Check message identifier. 2401 is exc. */
- if (hdr->msgh_id != 2401)
+ /* Check message destination. */
+ if (hdr->msgh_local_port != darwin_ex_port)
return -1;
/* Check message header. */
/* 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, get rid of it. Do not get rid of thread
+ right, as we will need it to find the thread. */
+ kret = mach_port_deallocate (mach_task_self (), task_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;
+
+ /* Free thread port (we don't know it). */
+ kret = mach_port_deallocate (mach_task_self (), thread_port);
+ MACH_CHECK_ERROR (kret);
+
+ 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);
+ /* Free the thread port (as gdb knows the thread, it has already has a right
+ for it, so this just decrement a reference counter). */
kret = mach_port_deallocate (mach_task_self (), thread_port);
MACH_CHECK_ERROR (kret);
return -1;
*pthread = thread;
- /* The thread should be running. However we have observed cases where a thread
- got a SIGTTIN message after being stopped. */
+ /* The thread should be running. However we have observed cases where a
+ thread got a SIGTTIN message after being stopped. */
gdb_assert (thread->msg_state != DARWIN_MESSAGE);
/* Finish decoding. */
integer_t code)
{
mach_msg_header_t *rh = &reply->Head;
- rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr->msgh_bits), 0);
+
+ 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_size = (mach_msg_size_t) sizeof (mig_reply_error_t);
rh->msgh_local_port = MACH_PORT_NULL;
rh->msgh_id = hdr->msgh_id + 100;
MACH_PORT_NULL);
MACH_CHECK_ERROR (kret);
- inf->private->pending_messages--;
+ inf->priv->pending_messages--;
}
static void
/* 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;
int k;
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, thread);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, thread);
k++)
darwin_resume_thread (inf, thread, step, nsignal);
}
int k;
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, thread);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, thread);
k++)
switch (thread->msg_state)
{
}
else
{
- struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
+ struct inferior *inf = find_inferior_ptid (ptid);
long tid = ptid_get_tid (ptid);
/* Stop the inferior (should be useless). */
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;
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;
+ status->kind = TARGET_WAITKIND_IGNORE;
+ return minus_one_ptid;
+ }
+ if (inf == NULL)
+ {
+ status->kind = TARGET_WAITKIND_IGNORE;
return minus_one_ptid;
}
*pinf = inf;
*pthread = thread;
- inf->private->pending_messages++;
+ inf->priv->pending_messages++;
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));
switch (thread->event.ex_type)
{
case EXC_BAD_ACCESS:
- status->value.sig = TARGET_EXC_BAD_ACCESS;
+ status->value.sig = GDB_EXC_BAD_ACCESS;
break;
case EXC_BAD_INSTRUCTION:
- status->value.sig = TARGET_EXC_BAD_INSTRUCTION;
+ status->value.sig = GDB_EXC_BAD_INSTRUCTION;
break;
case EXC_ARITHMETIC:
- status->value.sig = TARGET_EXC_ARITHMETIC;
+ status->value.sig = GDB_EXC_ARITHMETIC;
break;
case EXC_EMULATION:
- status->value.sig = TARGET_EXC_EMULATION;
+ status->value.sig = GDB_EXC_EMULATION;
break;
case EXC_SOFTWARE:
if (thread->event.ex_data[0] == EXC_SOFT_SIGNAL)
}
}
else
- status->value.sig = TARGET_EXC_SOFTWARE;
+ status->value.sig = GDB_EXC_SOFTWARE;
break;
case EXC_BREAKPOINT:
/* Many internal GDB routines expect breakpoints to be reported
- as GDB_SIGNAL_TRAP, and will report TARGET_EXC_BREAKPOINT
+ as GDB_SIGNAL_TRAP, and will report GDB_EXC_BREAKPOINT
as a spurious signal. */
status->value.sig = GDB_SIGNAL_TRAP;
break;
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->priv->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=%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: %x\n"), hdr->msgh_local_port);
- status->kind = TARGET_WAITKIND_SPURIOUS;
+ /* Unknown message. */
+ warning (_("darwin: got unknown message, id: 0x%x"), hdr->msgh_id);
+ status->kind = TARGET_WAITKIND_IGNORE;
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. */
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = GDB_SIGNAL_TRAP;
- thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
+ thread = VEC_index (darwin_thread_t, inf->priv->threads, 0);
thread->msg_state = DARWIN_STOPPED;
return ptid_build (inf->pid, 0, thread->gdb_port);
}
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;
}
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;
}
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;
}
+ /* 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
}
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
}
static ptid_t
-darwin_wait_to (struct target_ops *ops,
+darwin_wait_to (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *status, int options)
{
return darwin_wait (ptid, status);
}
static void
-darwin_stop (ptid_t t)
+darwin_interrupt (struct target_ops *self, ptid_t t)
{
struct inferior *inf = current_inferior ();
/* FIXME: handle in no_ptrace mode. */
- gdb_assert (!inf->private->no_ptrace);
+ gdb_assert (!inf->priv->no_ptrace);
kill (inf->pid, SIGINT);
}
mach_port_t prev;
int i;
- unpush_target (darwin_ops);
-
/* Deallocate threads. */
- if (inf->private->threads)
+ if (inf->priv->threads)
{
int k;
darwin_thread_t *t;
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, t);
k++)
{
kret = mach_port_deallocate (gdb_task, t->gdb_port);
MACH_CHECK_ERROR (kret);
}
- VEC_free (darwin_thread_t, inf->private->threads);
- inf->private->threads = NULL;
+ VEC_free (darwin_thread_t, inf->priv->threads);
+ inf->priv->threads = NULL;
}
kret = mach_port_move_member (gdb_task,
- inf->private->notify_port, MACH_PORT_NULL);
- gdb_assert (kret == KERN_SUCCESS);
+ inf->priv->notify_port, MACH_PORT_NULL);
+ MACH_CHECK_ERROR (kret);
- kret = mach_port_request_notification (gdb_task, inf->private->task,
+ kret = mach_port_request_notification (gdb_task, inf->priv->task,
MACH_NOTIFY_DEAD_NAME, 0,
MACH_PORT_NULL,
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",
- inf->private->task, prev, inf->private->notify_port);
+ inferior_debug (4, "task=0x%x, prev=0x%x, notify_port=0x%x\n",
+ inf->priv->task, prev, inf->priv->notify_port);
if (kret == KERN_SUCCESS)
{
MACH_CHECK_ERROR (kret);
}
- kret = mach_port_destroy (gdb_task, inf->private->notify_port);
+ kret = mach_port_destroy (gdb_task, inf->priv->notify_port);
MACH_CHECK_ERROR (kret);
/* Deallocate saved exception ports. */
- for (i = 0; i < inf->private->exception_info.count; i++)
+ for (i = 0; i < inf->priv->exception_info.count; i++)
{
kret = mach_port_deallocate
- (gdb_task, inf->private->exception_info.ports[i]);
+ (gdb_task, inf->priv->exception_info.ports[i]);
MACH_CHECK_ERROR (kret);
}
- inf->private->exception_info.count = 0;
+ inf->priv->exception_info.count = 0;
- kret = mach_port_deallocate (gdb_task, inf->private->task);
+ kret = mach_port_deallocate (gdb_task, inf->priv->task);
MACH_CHECK_ERROR (kret);
- xfree (inf->private);
- inf->private = NULL;
+ xfree (inf->priv);
+ inf->priv = NULL;
- generic_mourn_inferior ();
+ inf_child_mourn_inferior (ops);
}
static void
darwin_thread_t *t;
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, t);
k++)
{
if (t->msg_state == DARWIN_MESSAGE)
darwin_reply_to_all_pending_messages (inf);
- if (inf->private->no_ptrace)
+ if (inf->priv->no_ptrace)
return;
res = kill (inf->pid, SIGSTOP);
gdb_assert (inf != NULL);
- kret = darwin_restore_exception_ports (inf->private);
+ kret = darwin_restore_exception_ports (inf->priv);
MACH_CHECK_ERROR (kret);
darwin_reply_to_all_pending_messages (inf);
if (res == 0)
{
darwin_resume_inferior (inf);
-
+
ptid = darwin_wait (inferior_ptid, &wstatus);
}
else if (errno != ESRCH)
mach_port_t prev_not;
exception_mask_t mask;
- inf->private = XZALLOC (darwin_inferior);
+ inf->priv = XCNEW (darwin_inferior);
- kret = task_for_pid (gdb_task, inf->pid, &inf->private->task);
+ kret = task_for_pid (gdb_task, inf->pid, &inf->priv->task);
if (kret != KERN_SUCCESS)
{
int status;
}
inferior_debug (2, _("inferior task: 0x%x, pid: %d\n"),
- inf->private->task, inf->pid);
+ inf->priv->task, inf->pid);
if (darwin_ex_port == MACH_PORT_NULL)
{
/* 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);
+ &inf->priv->notify_port);
+ 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);
+ inf->priv->notify_port, darwin_port_set);
+ 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,
+ kret = mach_port_request_notification (gdb_task, inf->priv->task,
MACH_NOTIFY_DEAD_NAME, 0,
- inf->private->notify_port,
+ inf->priv->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);
+ kret = darwin_save_exception_ports (inf->priv);
+ 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_ALL;
else
mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
- kret = task_set_exception_ports (inf->private->task, mask, darwin_ex_port,
+ kret = task_set_exception_ports (inf->priv->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);
+ if (!target_is_pushed (darwin_ops))
+ push_target (darwin_ops);
}
static void
darwin_check_new_threads (inf);
- gdb_assert (inf->private->threads
- && VEC_length (darwin_thread_t, inf->private->threads) > 0);
- thread = VEC_index (darwin_thread_t, inf->private->threads, 0);
+ gdb_assert (inf->priv->threads
+ && VEC_length (darwin_thread_t, inf->priv->threads) > 0);
+ thread = VEC_index (darwin_thread_t, inf->priv->threads, 0);
/* Note: fork_inferior automatically add a thead but it uses a wrong ptid.
Fix up. */
/* 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->priv->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_attach (struct target_ops *ops, char *args, int from_tty)
+darwin_attach (struct target_ops *ops, const char *args, int from_tty)
{
pid_t pid;
pid_t pid2;
darwin_init_thread_list (inf);
- darwin_check_osabi (inf->private, ptid_get_tid (inferior_ptid));
+ darwin_check_osabi (inf->priv, ptid_get_tid (inferior_ptid));
- gdb_assert (darwin_inf_fake_stop == NULL);
- darwin_inf_fake_stop = inf;
- inf->private->no_ptrace = 1;
+ darwin_setup_fake_stop_event (inf);
+
+ inf->priv->no_ptrace = 1;
}
/* Take a program previously attached to and detaches it.
previously attached. It *might* work if the program was
started via fork. */
static void
-darwin_detach (struct target_ops *ops, char *args, int from_tty)
+darwin_detach (struct target_ops *ops, const char *args, int from_tty)
{
pid_t pid = ptid_get_pid (inferior_ptid);
struct inferior *inf = current_inferior ();
}
/* If ptrace() is in use, stop the process. */
- if (!inf->private->no_ptrace)
+ if (!inf->priv->no_ptrace)
darwin_stop_inferior (inf);
- kret = darwin_restore_exception_ports (inf->private);
+ kret = darwin_restore_exception_ports (inf->priv);
MACH_CHECK_ERROR (kret);
- if (!inf->private->no_ptrace)
+ if (!inf->priv->no_ptrace)
{
res = PTRACE (PT_DETACH, inf->pid, 0, 0);
if (res != 0)
/* When using ptrace, we have just performed a PT_DETACH, which
resumes the inferior. On the other hand, when we are not using
ptrace, we need to resume its execution ourselves. */
- if (inf->private->no_ptrace)
+ if (inf->priv->no_ptrace)
darwin_resume_inferior (inf);
darwin_mourn_inferior (ops);
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,
+ ULONGEST 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;
- inferior_debug (8, _("darwin_read_write_inferior(task=%x, %s, len=%d)\n"),
- task, core_addr_to_string (addr), length);
+ inferior_debug (8, _("darwin_read_write_inferior(task=0x%x, %s, len=%s)\n"),
+ task, core_addr_to_string (addr), pulongest (length));
/* Get memory from inferior with page aligned addresses. */
kret = mach_vm_read (task, low_address, aligned_length,
#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)
+static enum target_xfer_status
+darwin_read_dyld_info (task_t task, CORE_ADDR addr, gdb_byte *rdaddr,
+ ULONGEST length, ULONGEST *xfered_len)
{
struct task_dyld_info task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
kern_return_t kret;
if (addr >= sz)
- return 0;
+ return TARGET_XFER_EOF;
kret = task_info (task, TASK_DYLD_INFO, (task_info_t) &task_dyld_info, &count);
MACH_CHECK_ERROR (kret);
if (kret != KERN_SUCCESS)
- return -1;
+ return TARGET_XFER_E_IO;
/* Truncate. */
if (addr + length > sz)
length = sz - addr;
memcpy (rdaddr, (char *)&task_dyld_info + addr, length);
- return length;
+ *xfered_len = (ULONGEST) length;
+ return TARGET_XFER_OK;
}
#endif
\f
-/* Return 0 on failure, number of bytes handled otherwise. TARGET
- is ignored. */
-static int
-darwin_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
- struct mem_attrib *attrib, struct target_ops *target)
-{
- struct inferior *inf = current_inferior ();
- task_t task = inf->private->task;
-
- if (task == MACH_PORT_NULL)
- return 0;
-
- inferior_debug (8, _("darwin_xfer_memory(%s, %d, %c)\n"),
- core_addr_to_string (memaddr), len, write ? 'w' : 'r');
-
- if (write)
- return darwin_read_write_inferior (task, memaddr, NULL, myaddr, len);
- else
- return darwin_read_write_inferior (task, memaddr, myaddr, NULL, len);
-}
-static LONGEST
+static enum target_xfer_status
darwin_xfer_partial (struct target_ops *ops,
enum target_object object, const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len)
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
{
struct inferior *inf = current_inferior ();
inferior_debug
- (8, _("darwin_xfer_partial(%s, %d, rbuf=%s, wbuf=%s) pid=%u\n"),
- core_addr_to_string (offset), (int)len,
+ (8, _("darwin_xfer_partial(%s, %s, rbuf=%s, wbuf=%s) pid=%u\n"),
+ core_addr_to_string (offset), pulongest (len),
host_address_to_string (readbuf), host_address_to_string (writebuf),
inf->pid);
switch (object)
{
case TARGET_OBJECT_MEMORY:
- return darwin_read_write_inferior (inf->private->task, offset,
- readbuf, writebuf, len);
+ {
+ int l = darwin_read_write_inferior (inf->priv->task, offset,
+ readbuf, writebuf, len);
+
+ if (l == 0)
+ return TARGET_XFER_EOF;
+ else
+ {
+ gdb_assert (l > 0);
+ *xfered_len = (ULONGEST) l;
+ return TARGET_XFER_OK;
+ }
+ }
#ifdef TASK_DYLD_INFO_COUNT
case TARGET_OBJECT_DARWIN_DYLD_INFO:
if (writebuf != NULL || readbuf == NULL)
{
/* Support only read. */
- return -1;
+ return TARGET_XFER_E_IO;
}
- return darwin_read_dyld_info (inf->private->task, offset, readbuf, len);
+ return darwin_read_dyld_info (inf->priv->task, offset, readbuf, len,
+ xfered_len);
#endif
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
}
mask = EXC_MASK_ALL;
else
{
- darwin_restore_exception_ports (inf->private);
+ darwin_restore_exception_ports (inf->priv);
mask = EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT;
}
- kret = task_set_exception_ports (inf->private->task, mask, darwin_ex_port,
+ kret = task_set_exception_ports (inf->priv->task, mask, darwin_ex_port,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
MACH_CHECK_ERROR (kret);
}
}
static char *
-darwin_pid_to_exec_file (int pid)
+darwin_pid_to_exec_file (struct target_ops *self, int pid)
{
- char *path;
+ static char path[PATH_MAX];
int res;
- path = xmalloc (MAXPATHLEN);
- make_cleanup (xfree, path);
-
- res = proc_pidinfo (pid, PROC_PIDPATHINFO, 0, path, MAXPATHLEN);
+ res = proc_pidinfo (pid, PROC_PIDPATHINFO, 0, path, PATH_MAX);
if (res >= 0)
return path;
else
}
static ptid_t
-darwin_get_ada_task_ptid (long lwp, long thread)
+darwin_get_ada_task_ptid (struct target_ops *self, long lwp, long thread)
{
int i;
darwin_thread_t *t;
/* First linear search. */
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, t);
k++)
if (t->inf_port == lwp)
return ptid_build (ptid_get_pid (inferior_ptid), 0, t->gdb_port);
/* Maybe the port was never extract. Do it now. */
/* First get inferior port names. */
- kret = mach_port_names (inf->private->task, &names, &names_count, &types,
+ kret = mach_port_names (inf->priv->task, &names, &names_count, &types,
&types_count);
MACH_CHECK_ERROR (kret);
if (kret != KERN_SUCCESS)
/* We just need to know the corresponding name in gdb name space.
So extract and deallocate the right. */
- kret = mach_port_extract_right (inf->private->task, names[i],
+ kret = mach_port_extract_right (inf->priv->task, names[i],
MACH_MSG_TYPE_COPY_SEND,
&local_name, &local_type);
if (kret != KERN_SUCCESS)
mach_port_deallocate (gdb_task, local_name);
for (k = 0;
- VEC_iterate (darwin_thread_t, inf->private->threads, k, t);
+ VEC_iterate (darwin_thread_t, inf->priv->threads, k, t);
k++)
if (t->gdb_port == local_name)
{
}
static int
-darwin_supports_multi_process (void)
+darwin_supports_multi_process (struct target_ops *self)
{
return 1;
}
darwin_ops = inf_child_target ();
- darwin_ops->to_shortname = "darwin-child";
- darwin_ops->to_longname = _("Darwin child process");
- darwin_ops->to_doc =
- _("Darwin child process (started by the \"run\" command).");
darwin_ops->to_create_inferior = darwin_create_inferior;
darwin_ops->to_attach = darwin_attach;
darwin_ops->to_attach_no_wait = 0;
darwin_ops->to_wait = darwin_wait_to;
darwin_ops->to_mourn_inferior = darwin_mourn_inferior;
darwin_ops->to_kill = darwin_kill_inferior;
- darwin_ops->to_stop = darwin_stop;
+ darwin_ops->to_interrupt = darwin_interrupt;
darwin_ops->to_resume = darwin_resume_to;
darwin_ops->to_thread_alive = darwin_thread_alive;
darwin_ops->to_pid_to_str = darwin_pid_to_str;
darwin_ops->to_pid_to_exec_file = darwin_pid_to_exec_file;
darwin_ops->to_load = NULL;
- darwin_ops->deprecated_xfer_memory = darwin_xfer_memory;
darwin_ops->to_xfer_partial = darwin_xfer_partial;
darwin_ops->to_supports_multi_process = darwin_supports_multi_process;
darwin_ops->to_get_ada_task_ptid = darwin_get_ada_task_ptid;