/* Darwin support for GDB, the GNU debugger.
- Copyright (C) 2008-2014 Free Software Foundation, Inc.
+ Copyright (C) 2008-2015 Free Software Foundation, Inc.
Contributed by AdaCore.
#include "event-top.h"
#include "inf-loop.h"
#include <sys/stat.h>
-#include "exceptions.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/sysctl.h>
#include <sys/proc.h>
#define PTRACE(CMD, PID, ADDR, SIG) \
darwin_ptrace(#CMD, CMD, (PID), (ADDR), (SIG))
-static void darwin_stop (struct target_ops *self, 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);
"</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;
}
}
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)
{
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;
}
}
task_port = desc[1].name;
thread_port = desc[0].name;
- /* We got new rights to the task and the thread. Get rid of them. */
+ /* 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);
- 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);
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,
message can be deallocated. */
darwin_check_new_threads (inf);
+ /* 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);
+
thread = darwin_find_thread (inf, thread_port);
if (thread == NULL)
return -1;
MACH_PORT_NULL);
MACH_CHECK_ERROR (kret);
- inf->private->pending_messages--;
+ inf->priv->pending_messages--;
}
static void
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). */
}
*pinf = inf;
*pthread = thread;
- inf->private->pending_messages++;
+ inf->priv->pending_messages++;
status->kind = TARGET_WAITKIND_STOPPED;
thread->msg_state = DARWIN_MESSAGE;
inf = darwin_find_inferior_by_notify (hdr->msgh_local_port);
if (inf != NULL)
{
- if (!inf->private->no_ptrace)
+ if (!inf->priv->no_ptrace)
{
pid_t res;
int wstatus;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR pc;
- pc = regcache_read_pc (regcache) - target_decr_pc_after_break (gdbarch);
+ 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 0x%x\n",
ptid_get_tid (ptid));
/* Back up the PC if necessary. */
- if (target_decr_pc_after_break (gdbarch))
+ if (gdbarch_decr_pc_after_break (gdbarch))
regcache_write_pc (regcache, pc);
return 1;
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);
}
}
static void
-darwin_stop (struct target_ops *self, 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);
+ 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=0x%x, prev=0x%x, notify_port=0x%x\n",
- inf->private->task, prev, inf->private->notify_port);
+ 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);
mach_port_t prev_not;
exception_mask_t mask;
- inf->private = XCNEW (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 be notified when the child task terminates. */
kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
- &inf->private->notify_port);
+ &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);
+ 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);
if (kret != KERN_SUCCESS)
impact on the debugging session."));
}
- kret = darwin_save_exception_ports (inf->private);
+ kret = darwin_save_exception_ports (inf->priv);
if (kret != KERN_SUCCESS)
error (_("Unable to save exception ports, task_get_exception_ports"
"returned: %d"),
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);
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. */
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);
+ 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));
darwin_setup_fake_stop_event (inf);
- inf->private->no_ptrace = 1;
+ inf->priv->no_ptrace = 1;
}
/* Take a program previously attached to and detaches it.
}
/* 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);
{
case TARGET_OBJECT_MEMORY:
{
- int l = darwin_read_write_inferior (inf->private->task, offset,
+ int l = darwin_read_write_inferior (inf->priv->task, offset,
readbuf, writebuf, len);
if (l == 0)
/* Support only read. */
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:
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);
}
/* 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)
{
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;