macosx-nat-inferior.c [plain text]
#include "defs.h"
#include "top.h"
#include "inferior.h"
#include "target.h"
#include "symfile.h"
#include "symtab.h"
#include "objfiles.h"
#include "gdb.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "regcache.h"
#include "environ.h"
#include "event-top.h"
#include "event-loop.h"
#include "inf-loop.h"
#include "gdb_stat.h"
#include "exceptions.h"
#include "checkpoint.h"
#include "value.h"
#include "gdb_regex.h"
#include "bfd.h"
#include <sys/ptrace.h>
#include <sys/signal.h>
#include <machine/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 <mach/mach_error.h>
#include "macosx-nat-dyld.h"
#include "macosx-nat-inferior.h"
#include "macosx-nat-infthread.h"
#include "macosx-nat-inferior-debug.h"
#include "macosx-nat-mutils.h"
#include "macosx-nat-excthread.h"
#include "macosx-nat-sigthread.h"
#include "macosx-nat-threads.h"
#include "macosx-xdep.h"
#include "macosx-nat.h"
#include "macosx-nat-inferior-util.h"
#include "macosx-nat-dyld-process.h"
#if WITH_CFM
#include "macosx-nat-cfm.h"
#endif
#include <mach/mach_vm.h>
#ifndef EXC_SOFT_SIGNAL
#define EXC_SOFT_SIGNAL 0
#endif
#if defined (TARGET_I386)
#define SINGLE_STEP EXC_I386_SGL
#elif defined (TARGET_POWERPC)
#define SINGLE_STEP 5
#elif defined (TARGET_ARM)
#define SINGLE_STEP 5
#else
#error "unknown architecture"
#endif
#define _dyld_debug_make_runnable(a, b) DYLD_FAILURE
#define _dyld_debug_restore_runnable(a, b) DYLD_FAILURE
#define _dyld_debug_module_name(a, b, c, d, e) DYLD_FAILURE
#define _dyld_debug_set_error_func(a) DYLD_FAILURE
#define _dyld_debug_add_event_subscriber(a, b, c, d, e) DYLD_FAILURE
extern int standard_is_async_p (void);
extern int standard_can_async_p (void);
extern bfd *exec_bfd;
extern struct target_ops deprecated_child_ops;
extern struct target_ops macosx_child_ops;
extern struct target_ops exec_ops;
extern struct target_ops macosx_exec_ops;
macosx_inferior_status *macosx_status = NULL;
extern macosx_dyld_thread_status macosx_dyld_status;
int inferior_ptrace_flag = 1;
int inferior_ptrace_on_attach_flag = 1;
int inferior_bind_exception_port_flag = 1;
struct target_ops macosx_child_ops;
struct target_ops macosx_exec_ops;
extern void init_child_ops (void);
extern void init_exec_ops (void);
extern int inferior_auto_start_dyld_flag;
int macosx_fake_resume = 0;
enum macosx_source_type
{
NEXT_SOURCE_NONE = 0x0,
NEXT_SOURCE_EXCEPTION = 0x1,
NEXT_SOURCE_SIGNAL = 0x2,
NEXT_SOURCE_CFM = 0x4,
NEXT_SOURCE_ERROR = 0x8,
NEXT_SOURCE_ALL = 0xf,
};
struct macosx_pending_event
{
enum macosx_source_type type;
unsigned char *buf;
struct macosx_pending_event *next;
struct macosx_pending_event *prev;
};
struct macosx_pending_event *pending_event_chain, *pending_event_tail;
static void (*async_client_callback) (enum inferior_event_type event_type,
void *context);
static void *async_client_context;
static enum macosx_source_type macosx_fetch_event (struct
macosx_inferior_status
*inferior,
unsigned char *buf,
size_t len,
unsigned int flags,
int timeout);
static int macosx_service_event (enum macosx_source_type source,
unsigned char *buf,
struct target_waitstatus *status);
static void macosx_handle_signal (macosx_signal_thread_message *msg,
struct target_waitstatus *status);
static void macosx_handle_exception (macosx_exception_thread_message *msg,
struct target_waitstatus *status);
static int macosx_process_events (struct macosx_inferior_status *ns,
struct target_waitstatus *status,
int timeout, int service_first_event);
static struct macosx_pending_event * macosx_add_to_pending_events (enum macosx_source_type,
unsigned char *buf);
static int macosx_post_pending_event (void);
static void macosx_pending_event_handler (void *data);
static ptid_t macosx_process_pending_event (struct macosx_inferior_status *ns,
struct target_waitstatus *status,
gdb_client_data client_data);
static void macosx_clear_pending_events ();
static void macosx_child_stop (void);
static void macosx_child_resume (ptid_t ptid, int step,
enum target_signal signal);
static ptid_t macosx_child_wait (ptid_t ptid,
struct target_waitstatus *status,
gdb_client_data client_data);
static void macosx_mourn_inferior ();
static int macosx_lookup_task (char *args, task_t * ptask, int *ppid);
static void macosx_child_attach (char *args, int from_tty);
static void macosx_child_detach (char *args, int from_tty);
static int macosx_kill_inferior (void *);
static void macosx_kill_inferior_safe ();
static void macosx_ptrace_me ();
static void macosx_ptrace_him (int pid);
static void macosx_child_create_inferior (char *exec_file, char *allargs,
char **env, int from_tty);
static void macosx_child_files_info (struct target_ops *ops);
static char *macosx_pid_to_str (ptid_t tpid);
static int macosx_child_thread_alive (ptid_t tpid);
static void
macosx_handle_signal (macosx_signal_thread_message *msg,
struct target_waitstatus *status)
{
kern_return_t kret;
CHECK_FATAL (macosx_status != NULL);
CHECK_FATAL (macosx_status->attached_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_ptrace);
if (inferior_debug_flag)
{
macosx_signal_thread_debug_status (stderr, msg->status);
}
if (msg->pid != macosx_status->pid)
{
warning ("macosx_handle_signal: signal message was for pid %d, "
"not for inferior process (pid %d)\n",
msg->pid, macosx_status->pid);
return;
}
if (WIFEXITED (msg->status))
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = WEXITSTATUS (msg->status);
return;
}
if (!WIFSTOPPED (msg->status))
{
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.sig = target_signal_from_host (WTERMSIG (msg->status));
return;
}
macosx_status->stopped_in_ptrace = 1;
kret = macosx_inferior_suspend_mach (macosx_status);
MACH_CHECK_ERROR (kret);
prepare_threads_after_stop (macosx_status);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = target_signal_from_host (WSTOPSIG (msg->status));
}
static void
macosx_handle_exception (macosx_exception_thread_message *msg,
struct target_waitstatus *status)
{
kern_return_t kret;
CHECK_FATAL (status != NULL);
CHECK_FATAL (macosx_status != NULL);
if (inferior_ptrace_flag)
{
CHECK_FATAL (macosx_status->attached_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_ptrace);
}
inferior_debug (2, "macosx_handle_exception: received exception message\n");
if (msg->task_port != macosx_status->task)
{
inferior_debug (2,
"macosx_handle_exception: exception was for child of process being debugged\n");
kret =
macosx_restore_exception_ports (msg->task_port,
&macosx_status->exception_status.
saved_exceptions);
MACH_WARN_ERROR (kret);
macosx_inferior_resume_mach (macosx_status, 0);
status->kind = TARGET_WAITKIND_SPURIOUS;
return;
}
macosx_status->last_thread = msg->thread_port;
kret = macosx_inferior_suspend_mach (macosx_status);
MACH_CHECK_ERROR (kret);
prepare_threads_after_stop (macosx_status);
status->kind = TARGET_WAITKIND_STOPPED;
switch (msg->exception_type)
{
case EXC_BAD_ACCESS:
status->value.sig = TARGET_EXC_BAD_ACCESS;
status->code = msg->exception_data[0];
if (sizeof (msg->exception_data[1]) < sizeof (CORE_ADDR))
status->address = (CORE_ADDR) ((unsigned int) msg->exception_data[1]);
else
status->address = (CORE_ADDR) msg->exception_data[1];
break;
case EXC_BAD_INSTRUCTION:
status->value.sig = TARGET_EXC_BAD_INSTRUCTION;
break;
case EXC_ARITHMETIC:
status->value.sig = TARGET_EXC_ARITHMETIC;
break;
case EXC_EMULATION:
status->value.sig = TARGET_EXC_EMULATION;
break;
case EXC_SOFTWARE:
{
switch (msg->exception_data[0])
{
case EXC_SOFT_SIGNAL:
status->value.sig =
target_signal_from_host ((unsigned int) msg->exception_data[1]);
macosx_status->stopped_in_softexc = 1;
break;
default:
status->value.sig = TARGET_EXC_SOFTWARE;
break;
}
}
break;
case EXC_BREAKPOINT:
status->value.sig = TARGET_SIGNAL_TRAP;
break;
default:
status->value.sig = TARGET_SIGNAL_UNKNOWN;
break;
}
}
static void
macosx_add_to_port_set (struct macosx_inferior_status *inferior,
fd_set * fds, int flags)
{
FD_ZERO (fds);
if ((flags & NEXT_SOURCE_EXCEPTION)
&& inferior->exception_status.receive_from_fd > 0)
{
FD_SET (inferior->exception_status.receive_from_fd, fds);
}
if ((flags & NEXT_SOURCE_ERROR)
&& inferior->exception_status.error_receive_fd > 0)
{
FD_SET (inferior->exception_status.error_receive_fd, fds);
}
if ((flags & NEXT_SOURCE_SIGNAL)
&& inferior->signal_status.receive_fd > 0)
{
FD_SET (inferior->signal_status.receive_fd, fds);
}
}
static enum macosx_source_type
macosx_fetch_event (struct macosx_inferior_status *inferior,
unsigned char *buf, size_t len,
unsigned int flags, int timeout)
{
fd_set fds;
int fd, ret;
struct timeval tv;
CHECK_FATAL (len >= sizeof (macosx_exception_thread_message));
CHECK_FATAL (len >= sizeof (macosx_signal_thread_message));
tv.tv_sec = 0;
tv.tv_usec = timeout;
macosx_add_to_port_set (inferior, &fds, flags);
for (;;)
{
if (timeout == -1)
{
ret = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
}
else
{
ret = select (FD_SETSIZE, &fds, NULL, NULL, &tv);
}
if ((ret < 0) && (errno == EINTR))
{
continue;
}
if (ret < 0)
{
internal_error (__FILE__, __LINE__, "unable to select: %s",
strerror (errno));
}
if (ret == 0)
{
return NEXT_SOURCE_NONE;
}
break;
}
fd = inferior->exception_status.error_receive_fd;
if (fd > 0 && FD_ISSET (fd, &fds))
{
read (fd, buf, 1);
return NEXT_SOURCE_ERROR;
}
fd = inferior->exception_status.receive_from_fd;
if (fd > 0 && FD_ISSET (fd, &fds))
{
read (fd, buf, sizeof (macosx_exception_thread_message));
return NEXT_SOURCE_EXCEPTION;
}
fd = inferior->signal_status.receive_fd;
if (fd > 0 && FD_ISSET (fd, &fds))
{
read (fd, buf, sizeof (macosx_signal_thread_message));
return NEXT_SOURCE_SIGNAL;
}
return NEXT_SOURCE_NONE;
}
static struct macosx_pending_event *
macosx_add_to_pending_events (enum macosx_source_type type,
unsigned char *buf)
{
struct macosx_pending_event *new_event;
new_event = (struct macosx_pending_event *)
xmalloc (sizeof (struct macosx_pending_event));
new_event->type = type;
if (type == NEXT_SOURCE_SIGNAL)
{
macosx_signal_thread_message *mssg;
mssg = (macosx_signal_thread_message *)
xmalloc (sizeof (macosx_signal_thread_message));
memcpy (mssg, buf, sizeof (macosx_signal_thread_message));
inferior_debug (1,
"macosx_add_to_pending_events: adding a signal event "
"to the pending events.\n");
new_event->buf = (void *) mssg;
}
else if (type == NEXT_SOURCE_EXCEPTION)
{
macosx_exception_thread_message *mssg;
mssg = (macosx_exception_thread_message *)
xmalloc (sizeof (macosx_exception_thread_message));
memcpy (mssg, buf, sizeof (macosx_exception_thread_message));
inferior_debug (1,
"macosx_add_to_pending_events: adding an exception event "
"to the pending events.\n");
new_event->buf = (void *) mssg;
}
new_event->next = NULL;
if (pending_event_chain == NULL)
{
pending_event_chain = new_event;
pending_event_tail = new_event;
new_event->prev = NULL;
}
else
{
new_event->prev = pending_event_tail;
pending_event_tail->next = new_event;
pending_event_tail = new_event;
}
return new_event;
}
static void
macosx_free_pending_event (struct macosx_pending_event *event_ptr)
{
xfree (event_ptr->buf);
xfree (event_ptr);
}
static int
macosx_count_pending_events ()
{
int counter = 0;
struct macosx_pending_event *event_ptr;
for (event_ptr = pending_event_chain; event_ptr != NULL; event_ptr = event_ptr->next)
counter++;
return counter;
}
static void
macosx_remove_pending_event (struct macosx_pending_event *event_ptr, int delete)
{
if (event_ptr == pending_event_chain)
pending_event_chain = event_ptr->next;
if (event_ptr == pending_event_tail)
pending_event_tail = event_ptr->prev;
if (event_ptr->prev != NULL)
event_ptr->prev->next = event_ptr->next;
if (event_ptr->next != NULL)
event_ptr->next->prev = event_ptr->prev;
if (delete)
macosx_free_pending_event (event_ptr);
}
static void
macosx_clear_pending_events ()
{
struct macosx_pending_event *event_ptr = pending_event_chain;
while (event_ptr != NULL)
{
pending_event_chain = event_ptr->next;
macosx_free_pending_event (event_ptr);
event_ptr = pending_event_chain;
}
}
static int
macosx_post_pending_event (void)
{
struct macosx_pending_event *event;
if (pending_event_chain == NULL)
{
inferior_debug (1, "macosx_post_pending_event: no events to post\n");
return 0;
}
else
{
event = pending_event_chain;
macosx_remove_pending_event (event, 0);
inferior_debug (1,
"macosx_post_pending_event: consuming event off queue\n");
gdb_queue_event (macosx_pending_event_handler, (void *) event, HEAD);
return 1;
}
}
static void
macosx_pending_event_handler (void *data)
{
inferior_debug (4, "Called in macosx_pending_event_handler\n");
async_client_callback (INF_REG_EVENT, data);
}
static int
macosx_service_event (enum macosx_source_type source,
unsigned char *buf, struct target_waitstatus *status)
{
status->code = -1;
if (source == NEXT_SOURCE_EXCEPTION)
{
macosx_exception_thread_message *msg =
(macosx_exception_thread_message *) buf;
inferior_debug (1,
"macosx_service_events: got exception message 0x%lx\n",
msg->exception_type);
CHECK_FATAL (inferior_bind_exception_port_flag);
macosx_handle_exception ((macosx_exception_thread_message *) buf,
status);
if (status->kind != TARGET_WAITKIND_SPURIOUS)
return 1;
}
else if (source == NEXT_SOURCE_SIGNAL)
{
inferior_debug (1, "macosx_service_events: got signal message\n");
macosx_handle_signal ((macosx_signal_thread_message *) buf, status);
CHECK_FATAL (status->kind != TARGET_WAITKIND_SPURIOUS);
return 1;
}
else if (source == NEXT_SOURCE_ERROR)
{
inferior_debug (1, "macosx_service_events: got an error\n");
target_mourn_inferior ();
return 0;
}
else
{
error ("got message from unknown source: 0x%08x\n", source);
return 0;
}
return 1;
}
enum bp_ss_or_other {
bp_event = 0,
ss_event,
sig_event,
other_event
};
static enum bp_ss_or_other
get_event_type (struct macosx_exception_thread_message *msg)
{
if (msg->exception_type == EXC_BREAKPOINT)
{
if (msg->data_count == 2
&& msg->exception_data[0] == SINGLE_STEP)
return ss_event;
else
return bp_event;
}
else if (msg->exception_type == EXC_SOFTWARE
&& (msg->data_count == 2)
&& (msg->exception_data[0] == EXC_SOFT_SIGNAL))
return sig_event;
else
return other_event;
}
int
macosx_service_one_other_event (struct target_waitstatus *status)
{
struct macosx_pending_event *event;
int count = 0;
event = pending_event_chain;
while (event != NULL)
{
struct macosx_pending_event *next_event = event->next;
macosx_exception_thread_message *msg =
(macosx_exception_thread_message *) event->buf;
if (event->type != NEXT_SOURCE_EXCEPTION
|| get_event_type (msg) == other_event
|| get_event_type (msg) == sig_event)
{
count++;
if (count == 1)
{
macosx_service_event (event->type, event->buf, status);
macosx_remove_pending_event (event, 1);
}
}
else
{
macosx_remove_pending_event (event, 1);
}
event = next_event;
}
return count;
}
struct macosx_pending_event *
macosx_backup_before_break (int ignore)
{
int count = 0;
struct macosx_pending_event *ret_event = NULL, *event;
for (event = pending_event_chain; event != NULL ; event = event->next) {
if (event->type == NEXT_SOURCE_EXCEPTION)
{
macosx_exception_thread_message *msg =
(macosx_exception_thread_message *) event->buf;
ptid_t ptid = ptid_build (macosx_status->pid, 0, msg->thread_port);
if (get_event_type(msg) == bp_event
&& breakpoint_here_p (read_pc_pid (ptid) -
DECR_PC_AFTER_BREAK))
{
if (count == ignore)
{
ret_event = event;
}
else
{
if (DECR_PC_AFTER_BREAK)
{
CORE_ADDR new_pc = read_pc_pid (ptid) - DECR_PC_AFTER_BREAK;
write_pc_pid (new_pc, ptid);
inferior_debug (6, "backup_before_break: setting PID for thread: 0x%lx to %s\n",
msg->thread_port, paddr_nz (new_pc));
}
}
}
}
count++;
}
if (DECR_PC_AFTER_BREAK)
{
if (ret_event)
inferior_debug (6, "Backing up all breakpoint hits except thread 0x%lx\n",
((macosx_exception_thread_message *) ret_event->buf)->thread_port);
else
inferior_debug (6, "Backing up all breakpoint hits\n");
}
return ret_event;
}
static int
macosx_process_events (struct macosx_inferior_status *inferior,
struct target_waitstatus *status,
int timeout, int service_first_event)
{
enum macosx_source_type source;
unsigned char buf[1024];
int event_count = 0;
int breakpoint_count = 0;
int other_count = 0;
int scheduler_bp = -1;
enum bp_ss_or_other event_type;
int hand_call_function_bp = -1;
struct macosx_pending_event *event = NULL, *single_step = NULL,
*hand_call_function_thread_event = NULL,
*signal_event = NULL;
int first_time_through = 1;
CHECK_FATAL (status->kind == TARGET_WAITKIND_SPURIOUS);
event_count = macosx_count_pending_events ();
if (event_count != 0)
return event_count;
for (;;)
{
source = macosx_fetch_event (inferior, buf, sizeof (buf),
NEXT_SOURCE_ALL, timeout);
if (first_time_through)
{
first_time_through = 0;
macosx_exception_get_write_lock (&inferior->exception_status);
}
if (source == NEXT_SOURCE_NONE)
{
break;
}
event_count++;
if (source == NEXT_SOURCE_ERROR)
{
inferior_debug (2, "Got NEXT_SOURCE_ERROR from macosx_fetch_event\n");
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
return 0;
}
else if (source == NEXT_SOURCE_SIGNAL)
{
event = macosx_add_to_pending_events (source, buf);
signal_event = event;
other_count++;
}
else
{
struct ptid this_ptid;
this_ptid = ptid_build (macosx_status->pid, 0,
((macosx_exception_thread_message *) buf)->thread_port);
event = macosx_add_to_pending_events (source, buf);
event_type = get_event_type ((macosx_exception_thread_message *) buf);
extern ptid_t get_hand_call_ptid (void);
if (ptid_equal (this_ptid, get_hand_call_ptid ()))
{
hand_call_function_thread_event = event;
if (event_type == bp_event)
hand_call_function_bp = breakpoint_count;
}
if (event_type == ss_event)
single_step = event;
else if (event_type == bp_event)
{
if (scheduler_lock_on_p ())
{
if (ptid_equal (get_scheduler_lock_ptid (), this_ptid))
scheduler_bp = breakpoint_count;
}
breakpoint_count += 1;
}
else if (event_type == sig_event)
{
signal_event = event;
other_count += 1;
}
else
other_count += 1;
}
timeout = 0;
}
macosx_exception_release_write_lock (&inferior->exception_status);
if (event_count == 0)
return 0;
inferior_debug (2,
"macosx_process_events: returning with (status->kind == %d)\n",
status->kind);
if (event_count == 1)
{
int retval;
if (macosx_service_event (event->type,
event->buf, status) == 0)
retval = 0;
else
retval = 1;
macosx_clear_pending_events ();
return retval;
}
else
{
if (single_step != NULL)
{
inferior_debug (2, "macosx_process_events: found a single step "
"event, and %d breakpoint events\n", breakpoint_count);
macosx_backup_before_break (-1);
event_count = macosx_service_event (single_step->type, single_step->buf,
status);
}
else if (signal_event != NULL)
{
inferior_debug (2, "macosx_process_events: forwarding signal event");
macosx_backup_before_break (-1);
event_count = macosx_service_event (signal_event->type,
signal_event->buf,
status);
}
else if (hand_call_function_thread_event != NULL)
{
inferior_debug (2, "macosx_process_events: found an event for "
"the hand-call function thread "
", and %d breakpoint events\n", breakpoint_count);
macosx_backup_before_break (hand_call_function_bp);
event_count = macosx_service_event (hand_call_function_thread_event->type,
hand_call_function_thread_event->buf,
status);
}
else if (breakpoint_count != event_count)
{
inferior_debug (2, "macosx_process_events: found %d breakpoint events out of "
"%d total events\n", breakpoint_count, event_count);
macosx_backup_before_break (-1);
event_count = macosx_service_one_other_event (status);
}
else
{
struct macosx_pending_event *chosen_break;
int random_selector;
if (scheduler_bp != -1)
{
inferior_debug (6, "macosx_process_events: Choosing scheduler "
"breakpoint thread index: %d\n", scheduler_bp);
random_selector = scheduler_bp;
}
else
{
random_selector = (int)
((breakpoint_count * (double) rand ()) / (RAND_MAX + 1.0));
inferior_debug (6, "macosx_process_events: Choosing random "
"selector index %d\n", random_selector);
}
chosen_break = macosx_backup_before_break (random_selector);
event_count = macosx_service_event (chosen_break->type, chosen_break->buf,
status);
}
macosx_clear_pending_events ();
}
return event_count;
}
void
macosx_check_new_threads (thread_array_t thread_list, unsigned int nthreads)
{
kern_return_t kret;
unsigned int i;
int dealloc_thread_list = (thread_list == NULL);
if (thread_list == NULL)
{
kret = task_threads (macosx_status->task, &thread_list, &nthreads);
MACH_CHECK_ERROR (kret);
}
for (i = 0; i < nthreads; i++)
{
ptid_t ptid = ptid_build (macosx_status->pid, 0, thread_list[i]);
if (!in_thread_list (ptid))
{
struct thread_info *tp;
tp = add_thread (ptid);
if (create_private_thread_info (tp))
tp->private->app_thread_port =
get_application_thread_port (thread_list[i]);
}
}
if (dealloc_thread_list)
{
kret =
vm_deallocate (mach_task_self (), (vm_address_t) thread_list,
(nthreads * sizeof (int)));
MACH_CHECK_ERROR (kret);
}
}
static void
macosx_child_stop (void)
{
extern pid_t inferior_process_group;
int ret;
ret = kill (inferior_process_group, SIGINT);
}
static void
macosx_child_resume (ptid_t ptid, int step, enum target_signal signal)
{
int nsignal = target_signal_to_host (signal);
struct target_waitstatus status;
int stop_others = 1;
int pid;
thread_t thread;
status.code = -1;
if (ptid_equal (ptid, minus_one_ptid))
{
ptid = inferior_ptid;
stop_others = 0;
}
pid = ptid_get_pid (ptid);
thread = ptid_get_tid (ptid);
CHECK_FATAL (macosx_status != NULL);
macosx_inferior_check_stopped (macosx_status);
if (!macosx_inferior_valid (macosx_status))
return;
inferior_debug (2, "macosx_child_resume: checking for pending events\n");
status.kind = TARGET_WAITKIND_SPURIOUS;
macosx_process_events (macosx_status, &status, 0, 0);
inferior_debug (1, "macosx_child_resume: %s process with signal %d\n",
step ? "stepping" : "continuing", nsignal);
if (macosx_post_pending_event ())
{
macosx_fake_resume = 1;
if (target_is_async_p ())
target_executing = 1;
return;
}
if (macosx_status->stopped_in_ptrace || macosx_status->stopped_in_softexc)
{
macosx_inferior_resume_ptrace (macosx_status, thread, nsignal,
PTRACE_CONT);
}
if (!macosx_inferior_valid (macosx_status))
return;
if (step)
prepare_threads_before_run (macosx_status, step, thread, 1);
else
prepare_threads_before_run (macosx_status, 0, thread, stop_others);
macosx_inferior_resume_mach (macosx_status, -1);
if (target_can_async_p ())
target_async (inferior_event_handler, 0);
if (target_is_async_p ())
target_executing = 1;
}
static ptid_t
macosx_process_pending_event (struct macosx_inferior_status *ns,
struct target_waitstatus *status,
gdb_client_data client_data)
{
struct macosx_pending_event *event
= (struct macosx_pending_event *) client_data;
inferior_debug (1, "Processing pending event type: %d\n", event->type);
macosx_service_event (event->type, (unsigned char *) event->buf, status);
return ptid_build (macosx_status->pid, 0, macosx_status->last_thread);
}
ptid_t
macosx_wait (struct macosx_inferior_status *ns,
struct target_waitstatus * status, gdb_client_data client_data)
{
CHECK_FATAL (ns != NULL);
if (client_data != NULL)
return macosx_process_pending_event (ns, status, client_data);
set_sigint_trap ();
set_sigio_trap ();
status->kind = TARGET_WAITKIND_SPURIOUS;
while (status->kind == TARGET_WAITKIND_SPURIOUS)
macosx_process_events (ns, status, -1, 1);
clear_sigio_trap ();
clear_sigint_trap ();
if ((status->kind == TARGET_WAITKIND_EXITED)
|| (status->kind == TARGET_WAITKIND_SIGNALLED))
return null_ptid;
macosx_check_new_threads (NULL, 0);
if (!macosx_thread_valid (macosx_status->task, macosx_status->last_thread))
{
if (macosx_task_valid (macosx_status->task))
{
warning ("Currently selected thread no longer alive; "
"selecting initial thread");
macosx_status->last_thread =
macosx_primary_thread_of_task (macosx_status->task);
}
}
return ptid_build (macosx_status->pid, 0, macosx_status->last_thread);
}
static ptid_t
macosx_child_wait (ptid_t pid, struct target_waitstatus *status,
gdb_client_data client_data)
{
CHECK_FATAL (macosx_status != NULL);
return macosx_wait (macosx_status, status, client_data);
}
static void
macosx_mourn_inferior ()
{
unpush_target (&macosx_child_ops);
deprecated_child_ops.to_mourn_inferior ();
macosx_inferior_destroy (macosx_status);
inferior_ptid = null_ptid;
attach_flag = 0;
macosx_dyld_mourn_inferior ();
macosx_clear_pending_events ();
}
void
macosx_fetch_task_info (struct kinfo_proc **info, size_t * count)
{
struct kinfo_proc *proc;
int control[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t length;
CHECK_FATAL (info != NULL);
CHECK_FATAL (count != NULL);
sysctl (control, 3, NULL, &length, NULL, 0);
proc = (struct kinfo_proc *) xmalloc (length);
sysctl (control, 3, proc, &length, NULL, 0);
*count = length / sizeof (struct kinfo_proc);
*info = proc;
}
char **
macosx_process_completer_quoted (char *text, char *word, int quote)
{
struct kinfo_proc *proc = NULL;
size_t count, i, found = 0;
char **procnames = NULL;
char **ret = NULL;
int quoted = 0;
if (text[0] == '"')
{
quoted = 1;
}
macosx_fetch_task_info (&proc, &count);
procnames = (char **) xmalloc ((count + 1) * sizeof (char *));
for (i = 0; i < count; i++)
{
if (!can_attach (proc[i].kp_proc.p_pid))
continue;
char *temp =
(char *) xmalloc (strlen (proc[i].kp_proc.p_comm) + 1 + 16);
sprintf (temp, "%s.%d", proc[i].kp_proc.p_comm, proc[i].kp_proc.p_pid);
procnames[found] = (char *) xmalloc (strlen (temp) * 2 + 2 + 1);
if (quote)
{
if (quoted)
{
sprintf (procnames[found], "\"%s\"", temp);
}
else
{
char *s = temp;
char *t = procnames[found];
while (*s != '\0')
{
if (strchr ("\" ", *s) != NULL)
{
*t++ = '\\';
*t++ = *s++;
}
else
{
*t++ = *s++;
}
}
*t++ = '\0';
}
}
else
{
sprintf (procnames[found], "%s", temp);
}
found++;
}
procnames[found] = NULL;
ret = complete_on_enum ((const char **) procnames, text, word);
xfree (proc);
return ret;
}
char **
macosx_process_completer (char *text, char *word)
{
return macosx_process_completer_quoted (text, word, 1);
}
static void
macosx_lookup_task_local (char *pid_str, int pid, task_t * ptask, int *ppid)
{
CHECK_FATAL (ptask != NULL);
CHECK_FATAL (ppid != NULL);
if (pid_str == NULL)
{
task_t itask;
kern_return_t kret;
kret = task_for_pid (mach_task_self (), pid, &itask);
if (kret != KERN_SUCCESS)
{
error ("Unable to access task for process-id %d: %s.", pid,
MACH_ERROR_STRING (kret));
}
*ptask = itask;
*ppid = pid;
}
else
{
struct cleanup *cleanups = NULL;
char **ret = macosx_process_completer_quoted (pid_str, pid_str, 0);
char *tmp = NULL;
char *tmp2 = NULL;
unsigned long lpid = 0;
task_t itask;
kern_return_t kret;
cleanups = make_cleanup (free, ret);
if ((ret == NULL) || (ret[0] == NULL))
{
error ("Unable to locate process named \"%s\".", pid_str);
}
if (ret[1] != NULL)
{
error ("Multiple processes exist with the name \"%s\".", pid_str);
}
tmp = strrchr (ret[0], '.');
if (tmp == NULL)
{
error
("Unable to parse process-specifier \"%s\" (does not contain process-id)",
ret[0]);
}
tmp++;
lpid = strtoul (tmp, &tmp2, 10);
if (!isdigit (*tmp) || (*tmp2 != '\0'))
{
error
("Unable to parse process-specifier \"%s\" (does not contain process-id)",
ret[0]);
}
if ((lpid > INT_MAX) || ((lpid == ULONG_MAX) && (errno == ERANGE)))
{
error ("Unable to parse process-id \"%s\" (integer overflow).",
ret[0]);
}
pid = lpid;
kret = task_for_pid (mach_task_self (), pid, &itask);
if (kret != KERN_SUCCESS)
{
error ("Unable to locate task for process-id %d: %s.", pid,
MACH_ERROR_STRING (kret));
}
*ptask = itask;
*ppid = pid;
do_cleanups (cleanups);
}
}
static void
wait_for_process_by_name (const char *procname)
{
struct kinfo_proc *proc = NULL;
size_t count, i;
if (procname == NULL || procname[0] == '\0')
return;
printf_filtered ("Waiting for process '%s' to launch.\n", procname);
while (1)
{
QUIT;
macosx_fetch_task_info (&proc, &count);
for (i = 0; i < count; i++)
{
if (strncmp (proc[i].kp_proc.p_comm, procname, MAXCOMLEN) == 0)
{
xfree (proc);
return;
}
}
usleep (400);
xfree (proc);
}
}
static int
macosx_lookup_task (char *args, task_t * ptask, int *ppid)
{
char *pid_str = NULL;
char *tmp = NULL;
struct cleanup *cleanups = NULL;
char **argv = NULL;
unsigned int argc;
unsigned long lpid = 0;
int pid = 0;
CHECK_FATAL (ptask != NULL);
CHECK_FATAL (ppid != NULL);
*ptask = TASK_NULL;
*ppid = 0;
if (args == NULL)
{
return 0;
}
argv = buildargv (args);
if (argv == NULL)
{
nomem (0);
}
cleanups = make_cleanup_freeargv (argv);
for (argc = 0; argv[argc] != NULL; argc++);
switch (argc)
{
case 1:
pid_str = argv[0];
break;
case 2:
if (strcmp ("-waitfor", argv[0]) == 0
|| strcmp ("--waitfor", argv[0]) == 0)
{
pid_str = argv[1];
if (strlen (pid_str) > MAXCOMLEN)
pid_str[MAXCOMLEN] = '\0';
wait_for_process_by_name (pid_str);
break;
}
default:
error ("Usage: attach <-waitfor procname>|<pid>|<procname>.");
break;
}
CHECK_FATAL (pid_str != NULL);
lpid = strtoul (pid_str, &tmp, 10);
if (isdigit (*pid_str) && (*tmp == '\0'))
{
if ((lpid > INT_MAX) || ((lpid == ULONG_MAX) && (errno == ERANGE)))
{
error ("Unable to locate pid \"%s\" (integer overflow).", pid_str);
}
pid_str = NULL;
pid = lpid;
}
macosx_lookup_task_local (pid_str, pid, ptask, ppid);
do_cleanups (cleanups);
return 0;
}
static void
macosx_child_attach (char *args, int from_tty)
{
task_t itask;
int pid;
int ret;
kern_return_t kret;
char *exec_file = NULL;
if (args == NULL)
{
error_no_arg ("process-id to attach");
}
macosx_lookup_task (args, &itask, &pid);
if (itask == TASK_NULL)
{
error ("unable to locate task");
}
if (itask == mach_task_self ())
{
error ("unable to debug self");
}
CHECK_FATAL (macosx_status != NULL);
macosx_inferior_destroy (macosx_status);
exec_file = get_exec_file (0);
if (exec_file)
printf_filtered ("Attaching to program: `%s', %s.\n",
exec_file, target_pid_to_str (pid_to_ptid (pid)));
else
printf_filtered ("Attaching to %s.\n",
target_pid_to_str (pid_to_ptid (pid)));
if (attaching_to_classic_process_p (pid))
{
attach_to_classic_process (pid);
return;
}
macosx_create_inferior_for_task (macosx_status, itask, pid);
macosx_exception_thread_create (&macosx_status->exception_status,
macosx_status->task);
if (inferior_ptrace_on_attach_flag)
{
ret = call_ptrace (PTRACE_ATTACHEXC, pid, 0, 0);
if (ret != 0)
{
macosx_inferior_destroy (macosx_status);
if (errno == EPERM)
{
error ("Unable to attach to process-id %d: %s (%d).\n"
"This request requires that the target process be neither setuid nor "
"setgid and have the same real userid as the debugger, or that the "
"debugger be running with administrator privileges.",
pid, strerror (errno), errno);
}
else
{
error ("Unable to attach to process-id %d: %s (%d)",
pid, strerror (errno), errno);
}
}
macosx_status->attached_in_ptrace = 1;
macosx_status->stopped_in_ptrace = 0;
macosx_status->stopped_in_softexc = 0;
macosx_status->suspend_count = 0;
}
else if (inferior_bind_exception_port_flag)
{
kret = macosx_inferior_suspend_mach (macosx_status);
if (kret != KERN_SUCCESS)
{
macosx_inferior_destroy (macosx_status);
MACH_CHECK_ERROR (kret);
}
}
macosx_check_new_threads (NULL, 0);
inferior_ptid = ptid_build (pid, 0, macosx_status->last_thread);
attach_flag = 1;
push_target (&macosx_child_ops);
if (macosx_status->attached_in_ptrace)
{
enum macosx_source_type source;
unsigned char buf[1024];
stop_soon = STOP_QUIETLY;
wait_for_inferior ();
macosx_signal_thread_create (&macosx_status->signal_status,
macosx_status->pid);
source = macosx_fetch_event (macosx_status, buf, sizeof (buf),
NEXT_SOURCE_SIGNAL, 100000);
if (source == NEXT_SOURCE_SIGNAL)
{
unsigned int signo;
macosx_signal_thread_message *msg
= (macosx_signal_thread_message *) buf;
signo = target_signal_from_host (WSTOPSIG (msg->status));
if (signo != SIGSTOP)
{
inferior_debug (2,"Attach returned signal: %d\n", signo);
}
else
inferior_debug (2, "Got SIGSTOP from signal thread.");
}
else if (source == NEXT_SOURCE_NONE)
{
inferior_debug (2, "No signal event on stop after attach.");
}
}
macosx_set_malloc_inited (1);
if (inferior_auto_start_dyld_flag)
{
macosx_solib_add (NULL, 0, NULL, 0);
}
}
static void
macosx_child_detach (char *args, int from_tty)
{
kern_return_t kret;
CHECK_FATAL (macosx_status != NULL);
if (ptid_equal (inferior_ptid, null_ptid))
{
return;
}
if (from_tty)
{
char *exec_file = get_exec_file (0);
if (exec_file)
printf_filtered ("Detaching from program: `%s', %s.\n",
exec_file, target_pid_to_str (inferior_ptid));
else
printf_filtered ("Detaching from %s.\n",
target_pid_to_str (inferior_ptid));
}
if (!macosx_inferior_valid (macosx_status))
{
target_mourn_inferior ();
return;
}
macosx_inferior_check_stopped (macosx_status);
CHECK (macosx_inferior_valid (macosx_status));
if (macosx_status->attached_in_ptrace
&& (!macosx_status->stopped_in_ptrace)
&& (!macosx_status->stopped_in_softexc))
{
macosx_inferior_suspend_ptrace (macosx_status);
CHECK_FATAL (macosx_status->stopped_in_ptrace
|| macosx_status->stopped_in_softexc);
}
if (inferior_bind_exception_port_flag)
{
kret =
macosx_restore_exception_ports (macosx_status->task,
&macosx_status->exception_status.
saved_exceptions);
MACH_CHECK_ERROR (kret);
}
if (macosx_status->attached_in_ptrace)
{
macosx_inferior_resume_ptrace (macosx_status, 0, 0, PTRACE_DETACH);
}
if (!macosx_inferior_valid (macosx_status))
{
target_mourn_inferior ();
return;
}
macosx_inferior_suspend_mach (macosx_status);
if (!macosx_inferior_valid (macosx_status))
{
target_mourn_inferior ();
return;
}
prepare_threads_before_run (macosx_status, 0, THREAD_NULL, 0);
macosx_inferior_resume_mach (macosx_status, -1);
target_mourn_inferior ();
return;
}
static int
macosx_kill_inferior (void *arg)
{
kern_return_t *errval = (kern_return_t *) arg;
int status;
CHECK_FATAL (macosx_status != NULL);
*errval = KERN_SUCCESS;
if (ptid_equal (inferior_ptid, null_ptid))
{
return 1;
}
if (!macosx_inferior_valid (macosx_status))
{
target_mourn_inferior ();
return 1;
}
macosx_inferior_check_stopped (macosx_status);
CHECK (macosx_inferior_valid (macosx_status));
if (macosx_status->attached_in_ptrace
&& (!macosx_status->stopped_in_ptrace)
&& (!macosx_status->stopped_in_softexc))
{
macosx_inferior_suspend_ptrace (macosx_status);
CHECK_FATAL ((macosx_status->stopped_in_ptrace
|| macosx_status->stopped_in_softexc));
}
macosx_inferior_suspend_mach (macosx_status);
prepare_threads_before_run (macosx_status, 0, THREAD_NULL, 0);
if (macosx_status->attached_in_ptrace)
{
CHECK_FATAL (macosx_status->stopped_in_ptrace
|| macosx_status->stopped_in_softexc);
if (call_ptrace (PTRACE_KILL, macosx_status->pid, 0, 0) != 0)
{
error ("macosx_child_detach: ptrace (%d, %d, %d, %d): %s",
PTRACE_KILL, macosx_status->pid, 0, 0, strerror (errno));
}
macosx_status->stopped_in_ptrace = 0;
macosx_status->stopped_in_softexc = 0;
}
if (!macosx_inferior_valid (macosx_status))
{
target_mourn_inferior ();
return 1;
}
macosx_inferior_resume_mach (macosx_status, -1);
sched_yield ();
wait (&status);
target_mourn_inferior ();
return 1;
}
static void
macosx_kill_inferior_safe ()
{
kern_return_t kret;
int ret;
ret = catch_errors (macosx_kill_inferior, &kret,
"error while killing target (killing anyway): ",
RETURN_MASK_ALL);
if (ret == 0)
{
kret = task_terminate (macosx_status->task);
MACH_WARN_ERROR (kret);
sched_yield ();
target_mourn_inferior ();
}
}
static void
macosx_ptrace_me ()
{
call_ptrace (PTRACE_TRACEME, 0, 0, 0);
call_ptrace (PTRACE_SIGEXC, 0, 0, 0);
}
static void
macosx_ptrace_him (int pid)
{
task_t itask;
kern_return_t kret;
int traps_expected;
CHECK_FATAL (!macosx_status->attached_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_softexc);
CHECK_FATAL (macosx_status->suspend_count == 0);
kret = task_for_pid (mach_task_self (), pid, &itask);
{
char buf[64];
sprintf (buf, "%s=%d", "TASK", itask);
putenv (buf);
}
if (kret != KERN_SUCCESS)
{
error ("Unable to find Mach task port for process-id %d: %s (0x%lx).",
pid, MACH_ERROR_STRING (kret), (unsigned long) kret);
}
inferior_debug (2, "inferior task: 0x%08x, pid: %d\n", itask, pid);
push_target (&macosx_child_ops);
macosx_create_inferior_for_task (macosx_status, itask, pid);
macosx_signal_thread_create (&macosx_status->signal_status,
macosx_status->pid);
macosx_exception_thread_create (&macosx_status->exception_status,
macosx_status->task);
macosx_status->attached_in_ptrace = 1;
macosx_status->stopped_in_ptrace = 0;
macosx_status->stopped_in_softexc = 0;
macosx_status->suspend_count = 0;
#ifdef USE_ARCH_FOR_EXEC
traps_expected = (start_with_shell_flag ? 3 : 1);
#else
traps_expected = (start_with_shell_flag ? 2 : 1);
#endif
startup_inferior (traps_expected);
if (ptid_equal (inferior_ptid, null_ptid))
{
return;
}
if (!macosx_task_valid (macosx_status->task))
{
target_mourn_inferior ();
return;
}
macosx_inferior_check_stopped (macosx_status);
CHECK (macosx_inferior_valid (macosx_status));
if (inferior_ptrace_flag)
{
CHECK_FATAL (macosx_status->attached_in_ptrace);
CHECK_FATAL (macosx_status->stopped_in_ptrace
|| macosx_status->stopped_in_softexc);
}
else
{
macosx_inferior_resume_ptrace (macosx_status, 0, 0, PTRACE_DETACH);
CHECK_FATAL (!macosx_status->attached_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_ptrace);
CHECK_FATAL (!macosx_status->stopped_in_softexc);
}
}
static void
macosx_child_create_inferior (char *exec_file, char *allargs, char **env,
int from_tty)
{
if ((exec_bfd != NULL) &&
(exec_bfd->xvec->flavour == bfd_target_pef_flavour
|| exec_bfd->xvec->flavour == bfd_target_pef_xlib_flavour))
{
error
("Can't run a PEF binary - use LaunchCFMApp as the executable file.");
}
macosx_set_malloc_inited (0);
fork_inferior (exec_file, allargs, env, macosx_ptrace_me, macosx_ptrace_him,
NULL, NULL);
if (ptid_equal (inferior_ptid, null_ptid))
return;
macosx_dyld_create_inferior_hook ();
attach_flag = 0;
if (target_can_async_p ())
target_async (inferior_event_handler, 0);
clear_proceed_status ();
proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
}
static void
macosx_child_files_info (struct target_ops *ops)
{
CHECK_FATAL (macosx_status != NULL);
macosx_debug_inferior_status (macosx_status);
}
static char *
macosx_pid_to_str (ptid_t ptid)
{
static char buf[128];
int pid = ptid_get_pid (ptid);
struct thread_info *tp;
tp = find_thread_pid (ptid);
if (tp->private == NULL || tp->private->app_thread_port == 0)
{
thread_t thread = ptid_get_tid (ptid);
sprintf (buf, "process %d local thread 0x%lx", pid,
(unsigned long) thread);
}
else
sprintf (buf, "process %d thread 0x%lx", pid,
(unsigned long) tp->private->app_thread_port);
return buf;
}
static int
macosx_child_thread_alive (ptid_t ptid)
{
return macosx_thread_valid (macosx_status->task, ptid_get_tid (ptid));
}
void
macosx_create_inferior_for_task (struct macosx_inferior_status *inferior,
task_t task, int pid)
{
CHECK_FATAL (inferior != NULL);
macosx_inferior_destroy (inferior);
macosx_inferior_reset (inferior);
inferior->task = task;
inferior->pid = pid;
inferior->attached_in_ptrace = 0;
inferior->stopped_in_ptrace = 0;
inferior->stopped_in_softexc = 0;
inferior->suspend_count = 0;
inferior->last_thread = macosx_primary_thread_of_task (inferior->task);
}
static int remote_async_terminal_ours_p = 1;
static void (*ofunc) (int);
static PTR sigint_remote_twice_token;
static PTR sigint_remote_token;
static void remote_interrupt_twice (int signo);
static void remote_interrupt (int signo);
static void handle_remote_sigint_twice (int sig);
static void handle_remote_sigint (int sig);
static void async_remote_interrupt_twice (gdb_client_data arg);
static void async_remote_interrupt (gdb_client_data arg);
static void
interrupt_query (void)
{
target_terminal_ours ();
if (query ("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? "))
{
target_mourn_inferior ();
deprecated_throw_reason (RETURN_QUIT);
}
target_terminal_inferior ();
}
static void
remote_interrupt_twice (int signo)
{
signal (signo, ofunc);
interrupt_query ();
signal (signo, remote_interrupt);
}
static void
remote_interrupt (int signo)
{
signal (signo, remote_interrupt_twice);
target_stop ();
}
static void
handle_remote_sigint_twice (int sig)
{
signal (sig, handle_sigint);
sigint_remote_twice_token =
create_async_signal_handler (inferior_event_handler_wrapper, NULL);
mark_async_signal_handler_wrapper (sigint_remote_twice_token);
}
static void
handle_remote_sigint (int sig)
{
signal (sig, handle_remote_sigint_twice);
sigint_remote_twice_token =
create_async_signal_handler (async_remote_interrupt_twice, NULL);
mark_async_signal_handler_wrapper (sigint_remote_token);
}
static void
async_remote_interrupt_twice (gdb_client_data arg)
{
if (target_executing)
{
interrupt_query ();
signal (SIGINT, handle_remote_sigint);
}
}
static void
async_remote_interrupt (gdb_client_data arg)
{
target_stop ();
}
static void
cleanup_sigint_signal_handler (void *dummy)
{
signal (SIGINT, handle_sigint);
if (sigint_remote_twice_token)
delete_async_signal_handler ((struct async_signal_handler **)
&sigint_remote_twice_token);
if (sigint_remote_token)
delete_async_signal_handler ((struct async_signal_handler **)
&sigint_remote_token);
}
static void
initialize_sigint_signal_handler (void)
{
sigint_remote_token =
create_async_signal_handler (async_remote_interrupt, NULL);
signal (SIGINT, handle_remote_sigint);
}
static void
macosx_terminal_inferior (void)
{
terminal_inferior ();
if (!sync_execution)
return;
if (!remote_async_terminal_ours_p)
return;
CHECK_FATAL (sync_execution);
CHECK_FATAL (remote_async_terminal_ours_p);
delete_file_handler (input_fd);
remote_async_terminal_ours_p = 0;
initialize_sigint_signal_handler ();
}
static void
macosx_terminal_ours (void)
{
terminal_ours ();
if (!sync_execution)
return;
if (remote_async_terminal_ours_p)
return;
CHECK_FATAL (sync_execution);
CHECK_FATAL (!remote_async_terminal_ours_p);
cleanup_sigint_signal_handler (NULL);
add_file_handler (input_fd, stdin_event_handler, 0);
remote_async_terminal_ours_p = 1;
}
static void
macosx_file_handler (int error, gdb_client_data client_data)
{
async_client_callback (INF_REG_EVENT, async_client_context);
}
static void
macosx_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context)
{
if (current_target.to_async_mask_value == 0)
internal_error (__FILE__, __LINE__,
"Calling remote_async when async is masked");
if (callback != NULL)
{
async_client_callback = callback;
async_client_context = context;
if (macosx_status->exception_status.error_receive_fd > 0)
add_file_handler (macosx_status->exception_status.error_receive_fd,
macosx_file_handler, NULL);
if (macosx_status->exception_status.receive_from_fd > 0)
add_file_handler (macosx_status->exception_status.receive_from_fd,
macosx_file_handler, NULL);
if (macosx_status->signal_status.receive_fd > 0)
add_file_handler (macosx_status->signal_status.receive_fd,
macosx_file_handler, NULL);
}
else
{
if (macosx_status->exception_status.error_receive_fd > 0)
delete_file_handler (macosx_status->exception_status.error_receive_fd);
if (macosx_status->exception_status.receive_from_fd > 0)
delete_file_handler (macosx_status->exception_status.receive_from_fd);
if (macosx_status->signal_status.receive_fd > 0)
delete_file_handler (macosx_status->signal_status.receive_fd);
}
}
static char *macosx_unsafe_functions[] = {
"malloc",
"free",
"szone_malloc",
"szone_free",
"_class_lookupMethodAndLoadCache"
};
static regex_t *macosx_unsafe_patterns = NULL;
static int num_unsafe_patterns;
int
macosx_check_safe_call (void)
{
if (macosx_get_malloc_inited () == 0)
return 0;
if (macosx_unsafe_patterns == NULL)
{
int i;
num_unsafe_patterns = sizeof (macosx_unsafe_functions) / sizeof (char *);
macosx_unsafe_patterns = (regex_t *)
xcalloc (num_unsafe_patterns, sizeof (regex_t));
for (i = 0; i < num_unsafe_patterns; i++)
{
int err_code;
err_code = regcomp (macosx_unsafe_patterns + i,
macosx_unsafe_functions[i],
REG_EXTENDED|REG_NOSUB);
if (err_code != 0)
{
char err_str[512];
regerror (err_code, macosx_unsafe_patterns + i,
err_str, 512);
internal_error (__FILE__, __LINE__,
"Couldn't compile unsafe call pattern %s, error %s",
macosx_unsafe_functions[i], err_str);
}
}
}
return check_safe_call (macosx_unsafe_patterns, num_unsafe_patterns, 5,
CHECK_SCHEDULER_VALUE);
}
void
macosx_print_extra_stop_info (int code, CORE_ADDR address)
{
ui_out_text (uiout, "Reason: ");
switch (code)
{
case KERN_PROTECTION_FAILURE:
ui_out_field_string (uiout, "access-reason", "KERN_PROTECTION_FAILURE");
break;
case KERN_INVALID_ADDRESS:
ui_out_field_string (uiout, "access-reason", "KERN_INVALID_ADDRESS");
break;
default:
ui_out_field_int (uiout, "access-reason", code);
}
ui_out_text (uiout, " at address: ");
ui_out_field_core_addr (uiout, "address", address);
ui_out_text (uiout, "\n");
}
void
cpfork_info (char *args, int from_tty)
{
task_t itask;
int pid;
int total = 0;
if (args == NULL)
{
pid = ptid_get_pid (inferior_ptid);
}
macosx_lookup_task (args, &itask, &pid);
if (itask == TASK_NULL)
{
error ("unable to locate task with pid %d", pid);
return;
}
{
vm_address_t address = 0;
vm_size_t size = 0;
kern_return_t err = 0;
while (1) {
mach_msg_type_number_t count;
struct vm_region_submap_info_64 info;
natural_t nestingDepth;
count = VM_REGION_SUBMAP_INFO_COUNT_64;
err = vm_region_recurse_64(itask, &address, &size, &nestingDepth,
(vm_region_info_64_t)&info,&count);
if (err == KERN_INVALID_ADDRESS) {
break;
} else if (err) {
mach_error("vm_region",err);
break; }
++total;
if (info.protection & VM_PROT_WRITE)
{
printf("addr 0x%x size 0x%x (", address, size);
{
int rslt;
vm_offset_t mempointer;
mach_msg_type_number_t memcopied;
rslt = mach_vm_read (itask, address, 16, &mempointer, &memcopied);
if (rslt == KERN_SUCCESS)
{
int i;
for (i = 0; i < 16; ++i)
printf("%x ", ((unsigned char *) mempointer)[i]);
}
}
printf(")\n");
}
if (info.is_submap) { nestingDepth++;
} else {
address = address+size;
}
}
}
printf ("%d regions total.\n", total);
}
void
direct_memcache_get (struct checkpoint *cp)
{
task_t itask;
int kret;
int pid = cp->pid;
vm_address_t address = 0;
vm_size_t size = 0;
kern_return_t err = 0;
kret = task_for_pid (mach_task_self (), pid, &itask);
if (kret != KERN_SUCCESS)
{
error ("Unable to locate task for process-id %d: %s.", pid,
MACH_ERROR_STRING (kret));
}
if (itask == TASK_NULL)
{
error ("unable to locate task");
return;
}
while (1)
{
mach_msg_type_number_t count;
struct vm_region_submap_info_64 info;
natural_t nesting_depth;
count = VM_REGION_SUBMAP_INFO_COUNT_64;
err = vm_region_recurse_64 (itask, &address, &size, &nesting_depth,
(vm_region_info_64_t) &info, &count);
if (err == KERN_INVALID_ADDRESS)
{
break;
}
else if (err)
{
mach_error ("vm_region",err);
break; }
if (info.protection & VM_PROT_WRITE)
{
memcache_get (cp, address, size);
}
if (info.is_submap)
nesting_depth++;
else
address += size;
}
}
void
fork_memcache_put (struct checkpoint *cp)
{
task_t itask;
int kret;
int pid = cp->pid;
vm_address_t address = 0;
vm_size_t size = 0;
kern_return_t err = 0;
kret = task_for_pid (mach_task_self (), pid, &itask);
if (kret != KERN_SUCCESS)
{
error ("Unable to locate task for process-id %d: %s.", pid,
MACH_ERROR_STRING (kret));
}
if (itask == TASK_NULL)
{
error ("unable to locate task");
return;
}
while (1)
{
mach_msg_type_number_t count;
struct vm_region_submap_info_64 info;
natural_t nesting_depth;
count = VM_REGION_SUBMAP_INFO_COUNT_64;
err = vm_region_recurse_64 (itask, &address, &size, &nesting_depth,
(vm_region_info_64_t) &info, &count);
if (err == KERN_INVALID_ADDRESS)
{
break;
}
else if (err)
{
mach_error ("vm_region",err);
break; }
if (info.protection & VM_PROT_WRITE)
{
int rslt;
vm_offset_t mempointer;
mach_msg_type_number_t memcopied;
if (0)
printf("count now %d addr 0x%x size 0x%x\n", count, address, size);
rslt = mach_vm_read (itask, address, size, &mempointer, &memcopied);
if (0)
printf("rslt is %d, copied %d\n", rslt, memcopied);
if (rslt == KERN_SUCCESS)
{
target_write (¤t_target, TARGET_OBJECT_MEMORY, NULL,
(bfd_byte *) mempointer, address, memcopied);
}
}
if (info.is_submap)
nesting_depth++;
else
address += size;
}
}
void
_initialize_macosx_inferior ()
{
CHECK_FATAL (macosx_status == NULL);
macosx_status = (struct macosx_inferior_status *)
xmalloc (sizeof (struct macosx_inferior_status));
macosx_inferior_reset (macosx_status);
dyld_init_paths (&macosx_dyld_status.path_info);
dyld_objfile_info_init (&macosx_dyld_status.current_info);
init_child_ops ();
macosx_child_ops = deprecated_child_ops;
deprecated_child_ops.to_can_run = NULL;
init_exec_ops ();
macosx_exec_ops = exec_ops;
exec_ops.to_can_run = NULL;
macosx_exec_ops.to_shortname = "macos-exec";
macosx_exec_ops.to_longname = "Mac OS X executable";
macosx_exec_ops.to_doc = "Mac OS X executable";
macosx_exec_ops.to_can_async_p = standard_can_async_p;
macosx_exec_ops.to_is_async_p = standard_is_async_p;
macosx_exec_ops.to_has_thread_control = tc_schedlock | tc_switch;
macosx_exec_ops.to_find_exception_catchpoints
= macosx_find_exception_catchpoints;
macosx_exec_ops.to_enable_exception_callback
= macosx_enable_exception_callback;
macosx_exec_ops.to_get_current_exception_event
= macosx_get_current_exception_event;
macosx_complete_child_target (&macosx_exec_ops);
exec_ops = macosx_exec_ops;
macosx_exec_ops.to_can_run = NULL;
macosx_child_ops.to_shortname = "macos-child";
macosx_child_ops.to_longname = "Mac OS X child process";
macosx_child_ops.to_doc =
"Mac OS X child process (started by the \"run\" command).";
macosx_child_ops.to_attach = macosx_child_attach;
macosx_child_ops.to_detach = macosx_child_detach;
macosx_child_ops.to_create_inferior = macosx_child_create_inferior;
macosx_child_ops.to_files_info = macosx_child_files_info;
macosx_child_ops.to_wait = macosx_child_wait;
macosx_child_ops.to_mourn_inferior = macosx_mourn_inferior;
macosx_child_ops.to_kill = macosx_kill_inferior_safe;
macosx_child_ops.to_stop = macosx_child_stop;
macosx_child_ops.to_resume = macosx_child_resume;
macosx_child_ops.to_thread_alive = macosx_child_thread_alive;
macosx_child_ops.to_pid_to_str = macosx_pid_to_str;
macosx_child_ops.to_load = NULL;
macosx_child_ops.deprecated_xfer_memory = mach_xfer_memory;
macosx_child_ops.to_xfer_partial = mach_xfer_partial;
macosx_child_ops.to_can_async_p = standard_can_async_p;
macosx_child_ops.to_is_async_p = standard_is_async_p;
macosx_child_ops.to_terminal_inferior = macosx_terminal_inferior;
macosx_child_ops.to_terminal_ours = macosx_terminal_ours;
macosx_child_ops.to_async = macosx_async;
macosx_child_ops.to_async_mask_value = 1;
macosx_child_ops.to_bind_function = dyld_lookup_and_bind_function;
macosx_child_ops.to_check_safe_call = macosx_check_safe_call;
macosx_child_ops.to_allocate_memory = macosx_allocate_space_in_inferior;
macosx_child_ops.to_check_is_objfile_loaded = dyld_is_objfile_loaded;
macosx_child_ops.to_has_thread_control = tc_schedlock | tc_switch;
macosx_child_ops.to_find_exception_catchpoints
= macosx_find_exception_catchpoints;
macosx_child_ops.to_enable_exception_callback
= macosx_enable_exception_callback;
macosx_child_ops.to_get_current_exception_event
= macosx_get_current_exception_event;
macosx_child_ops.to_find_exception_catchpoints
= macosx_find_exception_catchpoints;
macosx_child_ops.to_enable_exception_callback
= macosx_enable_exception_callback;
macosx_child_ops.to_get_current_exception_event
= macosx_get_current_exception_event;
macosx_complete_child_target (&macosx_child_ops);
add_target (&macosx_exec_ops);
add_target (&macosx_child_ops);
inferior_stderr = fdopen (fileno (stderr), "w");
inferior_debug (2, "GDB task: 0x%lx, pid: %d\n", mach_task_self (),
getpid ());
add_setshow_boolean_cmd ("inferior-bind-exception-port", class_obscure,
&inferior_bind_exception_port_flag, _("\
Set if GDB should bind the task exception port."), _("\
Show if GDB should bind the task exception port."), NULL,
NULL, NULL,
&setlist, &showlist);
add_setshow_boolean_cmd ("inferior-ptrace", class_obscure,
&inferior_ptrace_flag, _("\
Set if GDB should attach to the subprocess using ptrace ()."), _("\
Show if GDB should attach to the subprocess using ptrace ()."), NULL,
NULL, NULL,
&setlist, &showlist);
add_setshow_boolean_cmd ("inferior-ptrace-on-attach", class_obscure,
&inferior_ptrace_on_attach_flag, _("\
Set if GDB should attach to the subprocess using ptrace ()."), _("\
Show if GDB should attach to the subprocess using ptrace ()."), NULL,
NULL, NULL,
&setlist, &showlist);
add_info ("fork", cpfork_info, "help");
}