2008-11-27 10:23:01 +01:00
|
|
|
|
/* Darwin support for GDB, the GNU debugger.
|
2009-01-03 06:58:08 +01:00
|
|
|
|
Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
2008-11-27 10:23:01 +01:00
|
|
|
|
|
|
|
|
|
Contributed by AdaCore.
|
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
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/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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 "event-top.h"
|
|
|
|
|
#include "inf-loop.h"
|
|
|
|
|
#include "gdb_stat.h"
|
|
|
|
|
#include "exceptions.h"
|
|
|
|
|
#include "inf-child.h"
|
|
|
|
|
#include "value.h"
|
|
|
|
|
#include "arch-utils.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 <sys/proc.h>
|
|
|
|
|
|
|
|
|
|
#include <mach/mach_error.h>
|
|
|
|
|
#include <mach/mach_vm.h>
|
|
|
|
|
#include <mach/mach_init.h>
|
|
|
|
|
#include <mach/vm_map.h>
|
|
|
|
|
#include <mach/task.h>
|
|
|
|
|
#include <mach/mach_port.h>
|
|
|
|
|
#include <mach/thread_act.h>
|
|
|
|
|
#include <mach/port.h>
|
|
|
|
|
|
|
|
|
|
#include "darwin-nat.h"
|
|
|
|
|
|
|
|
|
|
/* Quick overview.
|
|
|
|
|
Darwin kernel is Mach + BSD derived kernel. Note that they share the
|
|
|
|
|
same memory space and are linked together (ie there is no micro-kernel).
|
|
|
|
|
|
|
|
|
|
Although ptrace(2) is available on Darwin, it is not complete. We have
|
|
|
|
|
to use Mach calls to read and write memory and to modify registers. We
|
|
|
|
|
also use Mach to get inferior faults. As we cannot use select(2) or
|
|
|
|
|
signals with Mach port (the Mach communication channel), signals are
|
|
|
|
|
reported to gdb as an exception. Furthermore we detect death of the
|
|
|
|
|
inferior through a Mach notification message. This way we only wait
|
|
|
|
|
on Mach ports.
|
|
|
|
|
|
|
|
|
|
Some Mach documentation is available for Apple xnu source package or
|
|
|
|
|
from the web. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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_mourn_inferior (struct target_ops *ops);
|
|
|
|
|
|
|
|
|
|
static int darwin_lookup_task (char *args, task_t * ptask, int *ppid);
|
|
|
|
|
|
|
|
|
|
static void darwin_kill_inferior (void);
|
|
|
|
|
|
|
|
|
|
static void darwin_ptrace_me (void);
|
|
|
|
|
|
|
|
|
|
static void darwin_ptrace_him (int pid);
|
|
|
|
|
|
|
|
|
|
static void darwin_create_inferior (struct target_ops *ops, char *exec_file,
|
|
|
|
|
char *allargs, char **env, int from_tty);
|
|
|
|
|
|
|
|
|
|
static void darwin_files_info (struct target_ops *ops);
|
|
|
|
|
|
|
|
|
|
/* Current inferior. */
|
|
|
|
|
darwin_inferior *darwin_inf = NULL;
|
|
|
|
|
|
|
|
|
|
/* Target operations for Darwin. */
|
|
|
|
|
static struct target_ops *darwin_ops;
|
|
|
|
|
|
|
|
|
|
/* Task identifier of gdb. */
|
|
|
|
|
static task_t gdb_task;
|
|
|
|
|
|
|
|
|
|
/* A copy of mach_host_self (). */
|
|
|
|
|
mach_port_t darwin_host_self;
|
|
|
|
|
|
|
|
|
|
/* Exception port. */
|
|
|
|
|
mach_port_t darwin_ex_port;
|
|
|
|
|
|
|
|
|
|
/* Notification port. */
|
|
|
|
|
mach_port_t darwin_not_port;
|
|
|
|
|
|
|
|
|
|
/* Port set. */
|
|
|
|
|
mach_port_t darwin_port_set;
|
|
|
|
|
|
|
|
|
|
/* Page size. */
|
|
|
|
|
static vm_size_t mach_page_size;
|
|
|
|
|
|
|
|
|
|
/* If Set, catch all mach exceptions (before they are converted to signals
|
|
|
|
|
by the kernel). */
|
|
|
|
|
static int enable_mach_exceptions;
|
|
|
|
|
|
|
|
|
|
#define PAGE_TRUNC(x) ((x) & ~(mach_page_size - 1))
|
|
|
|
|
#define PAGE_ROUND(x) PAGE_TRUNC((x) + mach_page_size - 1)
|
|
|
|
|
|
|
|
|
|
/* Buffer containing received message and to be sent message. */
|
|
|
|
|
static union
|
|
|
|
|
{
|
|
|
|
|
mach_msg_header_t hdr;
|
|
|
|
|
char data[1024];
|
|
|
|
|
} msgin, msgout;
|
|
|
|
|
|
|
|
|
|
/* Current message state.
|
|
|
|
|
If the kernel has sent a message it expects a reply and the inferior
|
|
|
|
|
can't be killed before. */
|
|
|
|
|
static enum msg_state { NO_MESSAGE, GOT_MESSAGE, REPLY_SENT } msg_state;
|
|
|
|
|
|
|
|
|
|
/* Unmarshalled received message. */
|
|
|
|
|
static struct exc_msg
|
|
|
|
|
{
|
|
|
|
|
/* Receive port. */
|
|
|
|
|
mach_port_t port;
|
|
|
|
|
|
|
|
|
|
/* Thread and task taking the exception. */
|
|
|
|
|
mach_port_t thread_port;
|
|
|
|
|
mach_port_t task_port;
|
|
|
|
|
|
|
|
|
|
/* Type of the exception. */
|
|
|
|
|
exception_type_t ex_type;
|
|
|
|
|
|
|
|
|
|
/* Machine dependent details. */
|
|
|
|
|
mach_msg_type_number_t data_count;
|
|
|
|
|
integer_t ex_data[4];
|
|
|
|
|
} exc_msg;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This controls output of inferior debugging.
|
|
|
|
|
1 = basic exception handling
|
|
|
|
|
2 = task management
|
|
|
|
|
3 = thread management
|
|
|
|
|
4 = pending_event_handler
|
|
|
|
|
6 = most chatty level. */
|
|
|
|
|
|
|
|
|
|
static int darwin_debug_flag = 0;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
inferior_debug (int level, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
if (darwin_debug_flag < level)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
va_start (ap, fmt);
|
|
|
|
|
printf_unfiltered (_("[%d inferior]: "), getpid ());
|
|
|
|
|
vprintf_unfiltered (fmt, ap);
|
|
|
|
|
va_end (ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mach_check_error (kern_return_t ret, const char *file,
|
|
|
|
|
unsigned int line, const char *func)
|
|
|
|
|
{
|
|
|
|
|
if (ret == KERN_SUCCESS)
|
|
|
|
|
return;
|
|
|
|
|
if (func == NULL)
|
|
|
|
|
func = _("[UNKNOWN]");
|
|
|
|
|
|
|
|
|
|
error (_("error on line %u of \"%s\" in function \"%s\": %s (0x%lx)\n"),
|
|
|
|
|
line, file, func, mach_error_string (ret), (unsigned long) ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
unparse_exception_type (unsigned int i)
|
|
|
|
|
{
|
|
|
|
|
static char unknown_exception_buf[32];
|
|
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
|
{
|
|
|
|
|
case EXC_BAD_ACCESS:
|
|
|
|
|
return "EXC_BAD_ACCESS";
|
|
|
|
|
case EXC_BAD_INSTRUCTION:
|
|
|
|
|
return "EXC_BAD_INSTRUCTION";
|
|
|
|
|
case EXC_ARITHMETIC:
|
|
|
|
|
return "EXC_ARITHMETIC";
|
|
|
|
|
case EXC_EMULATION:
|
|
|
|
|
return "EXC_EMULATION";
|
|
|
|
|
case EXC_SOFTWARE:
|
|
|
|
|
return "EXC_SOFTWARE";
|
|
|
|
|
case EXC_BREAKPOINT:
|
|
|
|
|
return "EXC_BREAKPOINT";
|
|
|
|
|
case EXC_SYSCALL:
|
|
|
|
|
return "EXC_SYSCALL";
|
|
|
|
|
case EXC_MACH_SYSCALL:
|
|
|
|
|
return "EXC_MACH_SYSCALL";
|
|
|
|
|
case EXC_RPC_ALERT:
|
|
|
|
|
return "EXC_RPC_ALERT";
|
|
|
|
|
case EXC_CRASH:
|
|
|
|
|
return "EXC_CRASH";
|
|
|
|
|
default:
|
|
|
|
|
snprintf (unknown_exception_buf, 32, _("unknown (%d)"), i);
|
|
|
|
|
return unknown_exception_buf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
darwin_ptrace (const char *name,
|
|
|
|
|
int request, int pid, PTRACE_TYPE_ARG3 arg3, int arg4)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = ptrace (request, pid, (caddr_t) arg3, arg4);
|
|
|
|
|
|
|
|
|
|
inferior_debug (2, _("ptrace (%s, %d, 0x%x, %d): %d (%s)\n"),
|
|
|
|
|
name, pid, arg3, arg4, ret,
|
|
|
|
|
(ret != 0) ? strerror (errno) : _("no error"));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmp_thread_t (const void *l, const void *r)
|
|
|
|
|
{
|
|
|
|
|
thread_t lt = *(const thread_t *)l;
|
|
|
|
|
thread_t lr = *(const thread_t *)r;
|
|
|
|
|
return (int)(lr - lt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_check_new_threads (darwin_inferior *inf)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
thread_array_t thread_list;
|
|
|
|
|
unsigned int new_nbr;
|
|
|
|
|
unsigned int old_nbr;
|
|
|
|
|
unsigned int new_ix, old_ix;
|
|
|
|
|
VEC (thread_t) *thread_vec;
|
|
|
|
|
|
|
|
|
|
/* Get list of threads. */
|
|
|
|
|
kret = task_threads (inf->task, &thread_list, &new_nbr);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
if (kret != KERN_SUCCESS)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (new_nbr > 1)
|
|
|
|
|
qsort (thread_list, new_nbr, sizeof (thread_t), cmp_thread_t);
|
|
|
|
|
|
|
|
|
|
thread_vec = VEC_alloc (thread_t, new_nbr);
|
|
|
|
|
|
|
|
|
|
if (inf->threads)
|
|
|
|
|
old_nbr = VEC_length (thread_t, inf->threads);
|
|
|
|
|
else
|
|
|
|
|
old_nbr = 0;
|
|
|
|
|
|
|
|
|
|
for (new_ix = 0, old_ix = 0; new_ix < new_nbr || old_ix < old_nbr;)
|
|
|
|
|
{
|
|
|
|
|
thread_t new_id = (new_ix < new_nbr) ?
|
|
|
|
|
thread_list[new_ix] : THREAD_NULL;
|
|
|
|
|
thread_t old_id = (old_ix < old_nbr) ?
|
|
|
|
|
VEC_index (thread_t, inf->threads, old_ix) : THREAD_NULL;
|
|
|
|
|
|
|
|
|
|
if (old_id == new_id)
|
|
|
|
|
{
|
|
|
|
|
/* Thread still exist. */
|
|
|
|
|
VEC_safe_push (thread_t, thread_vec, old_id);
|
|
|
|
|
new_ix++;
|
|
|
|
|
old_ix++;
|
|
|
|
|
|
|
|
|
|
kret = mach_port_deallocate (gdb_task, old_id);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (new_id < old_id || old_ix == old_nbr)
|
|
|
|
|
{
|
|
|
|
|
/* A thread was created. */
|
|
|
|
|
struct thread_info *tp;
|
|
|
|
|
|
|
|
|
|
tp = add_thread (ptid_build (inf->pid, 0, new_id));
|
|
|
|
|
VEC_safe_push (thread_t, thread_vec, new_id);
|
|
|
|
|
new_ix++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (new_id > old_id || new_ix == new_nbr)
|
|
|
|
|
{
|
|
|
|
|
/* A thread was removed. */
|
|
|
|
|
delete_thread (ptid_build (inf->pid, 0, old_id));
|
|
|
|
|
kret = mach_port_deallocate (gdb_task, old_id);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
old_ix++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inf->threads)
|
|
|
|
|
VEC_free (thread_t, inf->threads);
|
|
|
|
|
inf->threads = thread_vec;
|
|
|
|
|
|
|
|
|
|
kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
|
|
|
|
|
new_nbr * sizeof (int));
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_stop (ptid_t t)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = kill (ptid_get_pid (inferior_ptid), SIGINT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_resume (struct target_ops *ops,
|
|
|
|
|
ptid_t ptid, int step, enum target_signal signal)
|
2008-11-27 10:23:01 +01:00
|
|
|
|
{
|
|
|
|
|
struct target_waitstatus status;
|
|
|
|
|
int pid;
|
|
|
|
|
thread_t thread;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
/* minus_one_ptid is RESUME_ALL. */
|
|
|
|
|
if (ptid_equal (ptid, minus_one_ptid))
|
|
|
|
|
ptid = inferior_ptid;
|
|
|
|
|
|
|
|
|
|
pid = ptid_get_pid (ptid);
|
|
|
|
|
thread = ptid_get_tid (ptid);
|
|
|
|
|
|
|
|
|
|
inferior_debug
|
|
|
|
|
(2, _("darwin_resume: state=%d, thread=0x%x, step=%d signal=%d\n"),
|
|
|
|
|
msg_state, thread, step, signal);
|
|
|
|
|
|
|
|
|
|
switch (msg_state)
|
|
|
|
|
{
|
|
|
|
|
case GOT_MESSAGE:
|
|
|
|
|
switch (exc_msg.ex_type)
|
|
|
|
|
{
|
|
|
|
|
case EXC_SOFTWARE:
|
|
|
|
|
if (exc_msg.ex_data[0] == EXC_SOFT_SIGNAL)
|
|
|
|
|
{
|
|
|
|
|
int nsignal = target_signal_to_host (signal);
|
|
|
|
|
res = PTRACE (PT_THUPDATE, pid,
|
|
|
|
|
(void *)exc_msg.thread_port, nsignal);
|
|
|
|
|
if (res < 0)
|
|
|
|
|
printf_unfiltered (_("ptrace THUP: res=%d\n"), res);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (thread != 0)
|
|
|
|
|
{
|
|
|
|
|
inferior_debug (2, _("darwin_set_sstep (thread=%x, enable=%d)\n"),
|
|
|
|
|
thread, step);
|
|
|
|
|
darwin_set_sstep (thread, step);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kret = mach_msg (&msgout.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
|
|
|
|
|
msgout.hdr.msgh_size, 0,
|
|
|
|
|
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
|
|
|
|
|
MACH_PORT_NULL);
|
|
|
|
|
if (kret != 0)
|
|
|
|
|
printf_unfiltered (_("mach_msg (reply) ret=%d\n"), kret);
|
|
|
|
|
|
|
|
|
|
msg_state = REPLY_SENT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NO_MESSAGE:
|
|
|
|
|
if (step)
|
|
|
|
|
res = PTRACE (PT_STEP, pid, (caddr_t)1, 0);
|
|
|
|
|
else
|
|
|
|
|
res = PTRACE (PT_CONTINUE, pid, (caddr_t)1, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
gdb_assert (0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kern_return_t
|
|
|
|
|
catch_exception_raise_state
|
|
|
|
|
(mach_port_t port,
|
|
|
|
|
exception_type_t exception_type, mach_exception_data_t exception_data,
|
|
|
|
|
mach_msg_type_number_t data_count, thread_state_flavor_t * state_flavor,
|
|
|
|
|
thread_state_t in_state, mach_msg_type_number_t in_state_count,
|
|
|
|
|
thread_state_t out_state, mach_msg_type_number_t out_state_count)
|
|
|
|
|
{
|
|
|
|
|
return KERN_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kern_return_t
|
|
|
|
|
catch_exception_raise_state_identity
|
|
|
|
|
(mach_port_t port, mach_port_t thread_port, mach_port_t task_port,
|
|
|
|
|
exception_type_t exception_type, mach_exception_data_t exception_data,
|
|
|
|
|
mach_msg_type_number_t data_count, thread_state_flavor_t * state_flavor,
|
|
|
|
|
thread_state_t in_state, mach_msg_type_number_t in_state_count,
|
|
|
|
|
thread_state_t out_state, mach_msg_type_number_t out_state_count)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
return KERN_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kern_return_t
|
|
|
|
|
catch_exception_raise (mach_port_t port,
|
|
|
|
|
mach_port_t thread_port,
|
|
|
|
|
mach_port_t task_port,
|
|
|
|
|
exception_type_t exception_type,
|
|
|
|
|
exception_data_t exception_data,
|
|
|
|
|
mach_msg_type_number_t data_count)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
int i;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
/* We got new rights to the task. Get rid of it. */
|
|
|
|
|
kret = mach_port_deallocate (mach_task_self (), task_port);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
|
|
|
|
|
inferior_debug
|
|
|
|
|
(7, _("catch_exception_raise: exception_type=%d, data_count=%d\n"),
|
|
|
|
|
exception_type, data_count);
|
|
|
|
|
if (darwin_debug_flag > 7)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < data_count; i++)
|
|
|
|
|
printf_unfiltered (" %08x", exception_data[i]);
|
|
|
|
|
printf_unfiltered ("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save the message.
|
|
|
|
|
FIXME: this should be in a per-thread variable. */
|
|
|
|
|
exc_msg.port = port;
|
|
|
|
|
exc_msg.thread_port = thread_port;
|
|
|
|
|
exc_msg.task_port = task_port;
|
|
|
|
|
exc_msg.ex_type = exception_type;
|
|
|
|
|
exc_msg.data_count = data_count;
|
|
|
|
|
for (i = 0; i < data_count && i < 4; i++)
|
|
|
|
|
exc_msg.ex_data[i] = exception_data[i];
|
|
|
|
|
|
|
|
|
|
return KERN_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ptid_t
|
* linux-nat.c (linux_nat_wait): Adjust.
(linux_nat_pid_to_str): Adjust. Remove call to thread_db_init.
* linux-nat.h (thread_db_init): Delete declaration.
* linux-thread-db.c (target_beneath): Delete.
(thread_db_init): Delete.
(thread_db_detach): Use find_target_beneath.
(thread_db_wait): Adjust interface. Use find_target_beneath.
(thread_db_mourn_inferior): Use find_target_beneath.
(thread_db_can_async_p, thread_db_is_async_p, thread_db_async)
(thread_db_async_mask): Delete.
(thread_db_pid_to_str): Adjust interface. Use
find_target_beneath.
(thread_db_get_thread_local_address): Adjust interface. Use
find_target_beneath.
(init_thread_db_ops): Delete references to delete functions.
* target.c (update_current_target): Don't inherit or default
to_wait. Don't inherit to_pid_to_str and
to_get_thread_local_address.
(target_translate_tls_address): Look for a pushed target that
implements to_get_thread_local_address, and use it instead of
checking for target_get_thread_local_address_p.
(target_wait, target_pid_to_str): Reimplement as functions.
(dummy_pid_to_str): New.
(init_dummy_target): Register it.
(debug_to_wait): Delete.
* target.h (struct target_ops): Make to_wait, to_pid_to_str and
to_get_thread_local_address accept a pointer to struct target_ops.
(target_wait): Delete macro, and declare as function.
(target_pid_to_str): Likewise.
(target_get_thread_local_address)
(target_get_thread_local_address_p): Delete.
(noprocess): Add NORETURN and ATTR_NORETURN tags.
* inf-ptrace.c (inf_ptrace_wait): Adjust.
(inf_ptrace_pid_to_str): New.
(inf_ptrace_target): Use inf_ptrace_pid_to_str.
* aix-thread.c (aix_thread_wait, aix_thread_pid_to_str): Adjust.
* bsd-kvm.c (bsd_kvm_pid_to_str): Adjust.
* bsd-uthread.c (bsd_uthread_wait, bsd_uthread_pid_to_str):
Adjust.
* corelow.c (core_pid_to_str): Adjust.
* darwin-nat.c (darwin_wait, darwin_pid_to_str): Adjust.
* dec-thread.c (dec_thread_wait, dec_thread_pid_to_str): Adjust.
* gnu-nat.c (gnu_wait, gnu_pid_to_str): Adjust.
* go32-nat.c (go32_wait, go32_pid_to_str): Adjust.
* hpux-thread.c (hpux_thread_wait): Adjust.
* inf-ttrace.c (inf_ttrace_wait, inf_ttrace_pid_to_str): Adjust.
* monitor.c (monitor_wait, monitor_pid_to_str): Adjust.
* nto-procfs.c (procfs_wait, procfs_pid_to_str): Adjust.
* procfs.c (procfs_pid_to_str): Adjust.
* remote-m32r-sdi.c (m32r_wait, m32r_pid_to_str): Adjust.
* remote-mips.c (mips_wait): Adjust.
* remote-sim.c (gdbsim_wait, gdbsim_pid_to_str): Adjust.
* remote.c (remote_wait, remote_pid_to_str)
(remote_get_thread_local_address): Adjust.
* rs6000-nat.c (rs6000_wait): Adjust.
* sol-thread.c (procfs_pid_to_str): Adjust declaration.
(sol_thread_wait, solaris_pid_to_str): Adjust.
* spu-linux-nat.c (spu_child_wait): Adjust.
* windows-nat.c (windows_wait, windows_pid_to_str): Adjust.
2009-02-06 23:21:26 +01:00
|
|
|
|
darwin_wait (struct target_ops *ops,
|
|
|
|
|
ptid_t ptid, struct target_waitstatus *status)
|
2008-11-27 10:23:01 +01:00
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
mach_msg_header_t *hdr = &msgin.hdr;
|
|
|
|
|
pid_t pid = ptid_get_pid (inferior_ptid); /* FIXME. */
|
|
|
|
|
|
|
|
|
|
gdb_assert (msg_state != GOT_MESSAGE);
|
|
|
|
|
|
|
|
|
|
inferior_debug (6, _("darwin_wait: waiting for a message\n"));
|
|
|
|
|
|
|
|
|
|
/* Wait for a message. */
|
|
|
|
|
kret = mach_msg (&msgin.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0,
|
|
|
|
|
sizeof (msgin.data), darwin_port_set, 0, MACH_PORT_NULL);
|
|
|
|
|
|
|
|
|
|
if (kret == MACH_RCV_INTERRUPTED)
|
|
|
|
|
{
|
|
|
|
|
status->kind = TARGET_WAITKIND_IGNORE;
|
|
|
|
|
return minus_one_ptid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (kret != MACH_MSG_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
inferior_debug (1, _("mach_msg: ret=%x\n"), kret);
|
|
|
|
|
status->kind = TARGET_WAITKIND_SPURIOUS;
|
|
|
|
|
return minus_one_ptid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Debug: display message. */
|
|
|
|
|
if (darwin_debug_flag > 10)
|
|
|
|
|
{
|
|
|
|
|
const unsigned long *buf = (unsigned long *) hdr;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
printf_unfiltered (_(" bits: 0x%x"), hdr->msgh_bits);
|
|
|
|
|
printf_unfiltered (_(", size: 0x%x"), hdr->msgh_size);
|
|
|
|
|
printf_unfiltered (_(", remote-port: 0x%x"), hdr->msgh_remote_port);
|
|
|
|
|
printf_unfiltered (_(", local-port: 0x%x"), hdr->msgh_local_port);
|
|
|
|
|
printf_unfiltered (_(", reserved: 0x%x"), hdr->msgh_reserved);
|
|
|
|
|
printf_unfiltered (_(", id: 0x%x\n"), hdr->msgh_id);
|
|
|
|
|
|
|
|
|
|
if (darwin_debug_flag > 11)
|
|
|
|
|
{
|
|
|
|
|
printf_unfiltered (_(" data:"));
|
|
|
|
|
for (i = 0; i < hdr->msgh_size; i++)
|
|
|
|
|
printf_unfiltered (" %08lx", buf[i]);
|
|
|
|
|
printf_unfiltered (_("\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Exception message. */
|
|
|
|
|
if (hdr->msgh_local_port == darwin_ex_port)
|
|
|
|
|
{
|
|
|
|
|
/* Handle it via the exception server. */
|
|
|
|
|
if (!exc_server (&msgin.hdr, &msgout.hdr))
|
|
|
|
|
{
|
|
|
|
|
printf_unfiltered (_("exc_server: unknown message (id=%x)\n"),
|
|
|
|
|
hdr->msgh_id);
|
|
|
|
|
status->kind = TARGET_WAITKIND_SPURIOUS;
|
|
|
|
|
return minus_one_ptid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status->kind = TARGET_WAITKIND_STOPPED;
|
|
|
|
|
|
|
|
|
|
inferior_debug (2, _("darwin_wait: thread=%x, got %s\n"),
|
|
|
|
|
exc_msg.thread_port,
|
|
|
|
|
unparse_exception_type (exc_msg.ex_type));
|
|
|
|
|
|
|
|
|
|
switch (exc_msg.ex_type)
|
|
|
|
|
{
|
|
|
|
|
case EXC_BAD_ACCESS:
|
|
|
|
|
status->value.sig = TARGET_EXC_BAD_ACCESS;
|
|
|
|
|
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:
|
|
|
|
|
if (exc_msg.ex_data[0] == EXC_SOFT_SIGNAL)
|
|
|
|
|
{
|
|
|
|
|
status->value.sig = target_signal_from_host (exc_msg.ex_data[1]);
|
|
|
|
|
inferior_debug (2, _(" (signal %d: %s)\n"),
|
|
|
|
|
exc_msg.ex_data[1],
|
|
|
|
|
target_signal_to_name (status->value.sig));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
status->value.sig = TARGET_EXC_SOFTWARE;
|
|
|
|
|
break;
|
|
|
|
|
case EXC_BREAKPOINT:
|
|
|
|
|
/* Many internal GDB routines expect breakpoints to be reported
|
|
|
|
|
as TARGET_SIGNAL_TRAP, and will report TARGET_EXC_BREAKPOINT
|
|
|
|
|
as a spurious signal. */
|
|
|
|
|
status->value.sig = TARGET_SIGNAL_TRAP;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
status->value.sig = TARGET_SIGNAL_UNKNOWN;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg_state = GOT_MESSAGE;
|
|
|
|
|
|
|
|
|
|
return ptid_build (pid, 0, exc_msg.thread_port);
|
|
|
|
|
}
|
|
|
|
|
else if (hdr->msgh_local_port == darwin_not_port)
|
|
|
|
|
{
|
|
|
|
|
pid_t res;
|
|
|
|
|
int wstatus;
|
|
|
|
|
|
|
|
|
|
/* FIXME: translate task port to pid. */
|
|
|
|
|
res = wait4 (pid, &wstatus, 0, NULL);
|
|
|
|
|
if (res != pid)
|
|
|
|
|
{
|
|
|
|
|
printf_unfiltered (_("wait4: res=%x\n"), res);
|
|
|
|
|
wstatus = 0;
|
|
|
|
|
}
|
|
|
|
|
status->kind = TARGET_WAITKIND_EXITED;
|
|
|
|
|
status->value.integer = WEXITSTATUS (wstatus);
|
|
|
|
|
|
|
|
|
|
inferior_debug (2, _("darwin_wait: pid=%d exit, status=%x\n"),
|
|
|
|
|
pid, wstatus);
|
|
|
|
|
|
|
|
|
|
msg_state = NO_MESSAGE;
|
|
|
|
|
|
|
|
|
|
return ptid;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf_unfiltered (_("Bad local-port: %x\n"), hdr->msgh_local_port);
|
|
|
|
|
status->kind = TARGET_WAITKIND_SPURIOUS;
|
|
|
|
|
return minus_one_ptid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_mourn_inferior (struct target_ops *ops)
|
|
|
|
|
{
|
|
|
|
|
struct inferior *inf = current_inferior ();
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
mach_port_t prev;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
unpush_target (darwin_ops);
|
|
|
|
|
|
|
|
|
|
/* Deallocate threads. */
|
|
|
|
|
if (darwin_inf->threads)
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
thread_t t;
|
|
|
|
|
for (k = 0; VEC_iterate (thread_t, darwin_inf->threads, k, t); k++)
|
|
|
|
|
{
|
|
|
|
|
kret = mach_port_deallocate (gdb_task, t);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
VEC_free (thread_t, darwin_inf->threads);
|
|
|
|
|
darwin_inf->threads = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kret = mach_port_request_notification (gdb_task, darwin_inf->task,
|
|
|
|
|
MACH_NOTIFY_DEAD_NAME, 0,
|
|
|
|
|
darwin_inf->prev_not_port,
|
|
|
|
|
MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
|
|
|
|
&prev);
|
|
|
|
|
/* This can fail if the task is dead. */
|
|
|
|
|
if (kret == KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
kret = mach_port_deallocate (gdb_task, prev);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Deallocate saved exception ports. */
|
|
|
|
|
for (i = 0; i < darwin_inf->exception_info.count; i++)
|
|
|
|
|
{
|
|
|
|
|
kret = mach_port_deallocate
|
|
|
|
|
(gdb_task, darwin_inf->exception_info.ports[i]);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
darwin_inf->exception_info.count = 0;
|
|
|
|
|
|
|
|
|
|
kret = mach_port_deallocate (gdb_task, darwin_inf->task);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
|
|
|
|
|
darwin_inf->task = 0;
|
|
|
|
|
darwin_inf->pid = 0;
|
|
|
|
|
|
|
|
|
|
generic_mourn_inferior ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_stop_inferior (darwin_inferior *inf)
|
|
|
|
|
{
|
|
|
|
|
struct target_waitstatus wstatus;
|
|
|
|
|
ptid_t ptid;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
int status;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
gdb_assert (inf != NULL);
|
|
|
|
|
|
|
|
|
|
kret = task_suspend (inf->task);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
|
|
|
|
|
if (msg_state == GOT_MESSAGE)
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_resume (darwin_ops, inferior_ptid, 0, 0);
|
2008-11-27 10:23:01 +01:00
|
|
|
|
|
|
|
|
|
res = kill (inf->pid, SIGSTOP);
|
|
|
|
|
if (res != 0)
|
|
|
|
|
warning (_("cannot kill: %s\n"), strerror (errno));
|
|
|
|
|
|
|
|
|
|
ptid = darwin_wait (inferior_ptid, &wstatus);
|
|
|
|
|
gdb_assert (wstatus.kind = TARGET_WAITKIND_STOPPED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_kill_inferior (struct target_ops *ops)
|
2008-11-27 10:23:01 +01:00
|
|
|
|
{
|
|
|
|
|
struct target_waitstatus wstatus;
|
|
|
|
|
ptid_t ptid;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
int status;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
gdb_assert (darwin_inf != NULL);
|
|
|
|
|
|
|
|
|
|
if (ptid_equal (inferior_ptid, null_ptid))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
darwin_stop_inferior (darwin_inf);
|
|
|
|
|
|
|
|
|
|
res = PTRACE (PT_KILL, darwin_inf->pid, 0, 0);
|
|
|
|
|
gdb_assert (res == 0);
|
|
|
|
|
|
|
|
|
|
if (msg_state == GOT_MESSAGE)
|
|
|
|
|
{
|
|
|
|
|
exc_msg.ex_type = 0;
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_resume (ops, inferior_ptid, 0, 0);
|
2008-11-27 10:23:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kret = task_resume (darwin_inf->task);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
|
|
|
|
|
ptid = darwin_wait (inferior_ptid, &wstatus);
|
|
|
|
|
|
|
|
|
|
/* This double wait seems required... */
|
|
|
|
|
res = waitpid (darwin_inf->pid, &status, 0);
|
|
|
|
|
gdb_assert (res == darwin_inf->pid);
|
|
|
|
|
|
|
|
|
|
msg_state = NO_MESSAGE;
|
|
|
|
|
|
|
|
|
|
target_mourn_inferior ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The child must synchronize with gdb: gdb must set the exception port
|
|
|
|
|
before the child call PTRACE_SIGEXC. We use a pipe to achieve this.
|
|
|
|
|
FIXME: is there a lighter way ? */
|
|
|
|
|
static int ptrace_fds[2];
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_ptrace_me (void)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
char c;
|
|
|
|
|
|
|
|
|
|
/* Close write end point. */
|
|
|
|
|
close (ptrace_fds[1]);
|
|
|
|
|
|
|
|
|
|
/* Wait until gdb is ready. */
|
|
|
|
|
res = read (ptrace_fds[0], &c, 1);
|
|
|
|
|
gdb_assert (res == 0);
|
|
|
|
|
close (ptrace_fds[0]);
|
|
|
|
|
|
|
|
|
|
/* Get rid of privileges. */
|
|
|
|
|
setegid (getgid ());
|
|
|
|
|
|
|
|
|
|
/* Set TRACEME. */
|
|
|
|
|
PTRACE (PT_TRACE_ME, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Redirect signals to exception port. */
|
|
|
|
|
PTRACE (PT_SIGEXC, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dummy function to be sure fork_inferior uses fork(2) and not vfork(2). */
|
|
|
|
|
static void
|
|
|
|
|
darwin_pre_ptrace (void)
|
|
|
|
|
{
|
|
|
|
|
if (pipe (ptrace_fds) != 0)
|
|
|
|
|
{
|
|
|
|
|
ptrace_fds[0] = -1;
|
|
|
|
|
ptrace_fds[1] = -1;
|
|
|
|
|
error (_("unable to create a pipe: %s"), safe_strerror (errno));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static kern_return_t
|
|
|
|
|
darwin_save_exception_ports (darwin_inferior *inf)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
|
|
inf->exception_info.count =
|
|
|
|
|
sizeof (inf->exception_info.ports) / sizeof (inf->exception_info.ports[0]);
|
|
|
|
|
|
|
|
|
|
kret = task_get_exception_ports
|
|
|
|
|
(inf->task, EXC_MASK_ALL, inf->exception_info.masks,
|
|
|
|
|
&inf->exception_info.count, inf->exception_info.ports,
|
|
|
|
|
inf->exception_info.behaviors, inf->exception_info.flavors);
|
|
|
|
|
return kret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static kern_return_t
|
|
|
|
|
darwin_restore_exception_ports (darwin_inferior *inf)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < inf->exception_info.count; i++)
|
|
|
|
|
{
|
|
|
|
|
kret = task_set_exception_ports
|
|
|
|
|
(inf->task, inf->exception_info.masks[i], inf->exception_info.ports[i],
|
|
|
|
|
inf->exception_info.behaviors[i], inf->exception_info.flavors[i]);
|
|
|
|
|
if (kret != KERN_SUCCESS)
|
|
|
|
|
return kret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return KERN_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_attach_pid (int pid)
|
|
|
|
|
{
|
|
|
|
|
task_t itask;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
mach_port_t prev_port;
|
|
|
|
|
int traps_expected;
|
|
|
|
|
exception_mask_t mask;
|
|
|
|
|
|
|
|
|
|
kret = task_for_pid (gdb_task, pid, &itask);
|
|
|
|
|
if (kret != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
struct inferior *inf = current_inferior ();
|
|
|
|
|
|
|
|
|
|
if (!inf->attach_flag)
|
|
|
|
|
{
|
|
|
|
|
kill (pid, 9);
|
|
|
|
|
waitpid (pid, &status, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error (_("Unable to find Mach task port for process-id %d: %s (0x%lx).\n"
|
|
|
|
|
" (please check gdb is setgid procmod)"),
|
|
|
|
|
pid, mach_error_string (kret), (unsigned long) kret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inferior_debug (2, _("inferior task: 0x%08x, pid: %d\n"), itask, 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);
|
|
|
|
|
|
|
|
|
|
kret = mach_port_insert_right (gdb_task, darwin_ex_port, darwin_ex_port,
|
|
|
|
|
MACH_MSG_TYPE_MAKE_SEND);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
|
|
|
|
kret = mach_port_move_member (gdb_task, darwin_ex_port, darwin_port_set);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
/* Create a port to be notified when the child task terminates. */
|
|
|
|
|
kret = mach_port_allocate (gdb_task, MACH_PORT_RIGHT_RECEIVE,
|
|
|
|
|
&darwin_not_port);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
kret = mach_port_insert_right (gdb_task, darwin_not_port, darwin_not_port,
|
|
|
|
|
MACH_MSG_TYPE_MAKE_SEND);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
kret = mach_port_move_member (gdb_task, darwin_not_port, darwin_port_set);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kret = mach_port_request_notification (gdb_task, itask,
|
|
|
|
|
MACH_NOTIFY_DEAD_NAME, 0,
|
|
|
|
|
darwin_not_port,
|
|
|
|
|
MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
|
|
|
|
&darwin_inf->prev_not_port);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
darwin_inf->task = itask;
|
|
|
|
|
darwin_inf->pid = pid;
|
|
|
|
|
|
|
|
|
|
kret = darwin_save_exception_ports (darwin_inf);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
/* Set exception port. */
|
|
|
|
|
if (enable_mach_exceptions)
|
|
|
|
|
mask = EXC_MASK_ALL;
|
|
|
|
|
else
|
|
|
|
|
mask = EXC_MASK_SOFTWARE;
|
|
|
|
|
kret = task_set_exception_ports
|
|
|
|
|
(itask, mask, darwin_ex_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
push_target (darwin_ops);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_init_thread_list (darwin_inferior *inf)
|
|
|
|
|
{
|
|
|
|
|
thread_t thread;
|
|
|
|
|
|
|
|
|
|
darwin_check_new_threads (inf);
|
|
|
|
|
|
|
|
|
|
gdb_assert (inf->threads && VEC_length (thread_t, inf->threads) > 0);
|
|
|
|
|
thread = VEC_index (thread_t, inf->threads, 0);
|
|
|
|
|
inferior_ptid = ptid_build (inf->pid, 0, thread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_ptrace_him (int pid)
|
|
|
|
|
{
|
|
|
|
|
task_t itask;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
mach_port_t prev_port;
|
|
|
|
|
int traps_expected;
|
|
|
|
|
|
|
|
|
|
darwin_attach_pid (pid);
|
|
|
|
|
|
|
|
|
|
/* Let's the child run. */
|
|
|
|
|
close (ptrace_fds[0]);
|
|
|
|
|
close (ptrace_fds[1]);
|
|
|
|
|
|
|
|
|
|
/* fork_inferior automatically add a thread - but it uses a wrong tid. */
|
|
|
|
|
delete_thread_silent (inferior_ptid);
|
|
|
|
|
darwin_init_thread_list (darwin_inf);
|
|
|
|
|
|
|
|
|
|
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_create_inferior (struct target_ops *ops, char *exec_file,
|
|
|
|
|
char *allargs, char **env, int from_tty)
|
|
|
|
|
{
|
|
|
|
|
/* Do the hard work. */
|
|
|
|
|
fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
|
|
|
|
|
darwin_pre_ptrace, NULL);
|
|
|
|
|
|
|
|
|
|
/* Return now in case of error. */
|
|
|
|
|
if (ptid_equal (inferior_ptid, null_ptid))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
pid_t pid;
|
|
|
|
|
pid_t pid2;
|
|
|
|
|
int wstatus;
|
|
|
|
|
int res;
|
|
|
|
|
struct inferior *inf;
|
|
|
|
|
|
|
|
|
|
gdb_assert (msg_state == NO_MESSAGE);
|
|
|
|
|
|
|
|
|
|
if (!args)
|
|
|
|
|
error_no_arg (_("process-id to attach"));
|
|
|
|
|
|
|
|
|
|
pid = atoi (args);
|
|
|
|
|
|
|
|
|
|
if (pid == getpid ()) /* Trying to masturbate? */
|
|
|
|
|
error (_("I refuse to debug myself!"));
|
|
|
|
|
|
|
|
|
|
if (from_tty)
|
|
|
|
|
printf_unfiltered (_("Attaching to pid %d\n"), pid);
|
|
|
|
|
|
|
|
|
|
res = PTRACE (PT_ATTACHEXC, pid, 0, 0);
|
|
|
|
|
if (res != 0)
|
|
|
|
|
error (_("Unable to attach to process-id %d: %s (%d)"),
|
|
|
|
|
pid, strerror (errno), errno);
|
|
|
|
|
|
|
|
|
|
inf = add_inferior (pid);
|
|
|
|
|
inf->attach_flag = 1;
|
|
|
|
|
|
|
|
|
|
darwin_attach_pid (pid);
|
|
|
|
|
|
|
|
|
|
pid2 = wait4 (pid, &wstatus, WUNTRACED, NULL);
|
|
|
|
|
gdb_assert (pid2 == pid);
|
|
|
|
|
inferior_debug (1, _("darwin_attach: wait4 pid=%d, status=0x%x\n"),
|
|
|
|
|
pid2, wstatus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
darwin_init_thread_list (darwin_inf);
|
|
|
|
|
|
|
|
|
|
darwin_check_osabi (darwin_inf, ptid_get_tid (inferior_ptid));
|
|
|
|
|
|
|
|
|
|
/* Looks strange, but the kernel doesn't stop the process...
|
|
|
|
|
(Bug in Leopard ?)
|
|
|
|
|
Do it manually. */
|
|
|
|
|
/* FIXME: doesn't look to work with multi-threads!! */
|
|
|
|
|
kill (pid, SIGSTOP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Take a program previously attached to and detaches it.
|
|
|
|
|
The program resumes execution and will no longer stop
|
|
|
|
|
on signals, etc. We'd better not have left any breakpoints
|
|
|
|
|
in the program or it'll die when it hits one. For this
|
|
|
|
|
to work, it may be necessary for the process to have been
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
if (from_tty)
|
|
|
|
|
{
|
|
|
|
|
char *exec_file = get_exec_file (0);
|
|
|
|
|
if (exec_file == 0)
|
|
|
|
|
exec_file = "";
|
|
|
|
|
printf_unfiltered (_("Detaching from program: %s, %d\n"), exec_file,
|
|
|
|
|
ptid_get_pid (inferior_ptid));
|
|
|
|
|
gdb_flush (gdb_stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
darwin_stop_inferior (darwin_inf);
|
|
|
|
|
|
|
|
|
|
kret = darwin_restore_exception_ports (darwin_inf);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
|
|
|
|
|
if (msg_state == GOT_MESSAGE)
|
|
|
|
|
{
|
|
|
|
|
exc_msg.ex_type = 0;
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_resume (ops, inferior_ptid, 0, 0);
|
2008-11-27 10:23:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kret = task_resume (darwin_inf->task);
|
|
|
|
|
gdb_assert (kret == KERN_SUCCESS);
|
|
|
|
|
|
|
|
|
|
res = PTRACE (PT_DETACH, darwin_inf->pid, 0, 0);
|
|
|
|
|
if (res != 0)
|
|
|
|
|
printf_unfiltered (_("Unable to detach from process-id %d: %s (%d)"),
|
|
|
|
|
darwin_inf->pid, strerror (errno), errno);
|
|
|
|
|
|
|
|
|
|
msg_state = NO_MESSAGE;
|
|
|
|
|
|
|
|
|
|
darwin_mourn_inferior (ops);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
darwin_files_info (struct target_ops *ops)
|
|
|
|
|
{
|
|
|
|
|
gdb_assert (darwin_inf != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
* linux-nat.c (linux_nat_wait): Adjust.
(linux_nat_pid_to_str): Adjust. Remove call to thread_db_init.
* linux-nat.h (thread_db_init): Delete declaration.
* linux-thread-db.c (target_beneath): Delete.
(thread_db_init): Delete.
(thread_db_detach): Use find_target_beneath.
(thread_db_wait): Adjust interface. Use find_target_beneath.
(thread_db_mourn_inferior): Use find_target_beneath.
(thread_db_can_async_p, thread_db_is_async_p, thread_db_async)
(thread_db_async_mask): Delete.
(thread_db_pid_to_str): Adjust interface. Use
find_target_beneath.
(thread_db_get_thread_local_address): Adjust interface. Use
find_target_beneath.
(init_thread_db_ops): Delete references to delete functions.
* target.c (update_current_target): Don't inherit or default
to_wait. Don't inherit to_pid_to_str and
to_get_thread_local_address.
(target_translate_tls_address): Look for a pushed target that
implements to_get_thread_local_address, and use it instead of
checking for target_get_thread_local_address_p.
(target_wait, target_pid_to_str): Reimplement as functions.
(dummy_pid_to_str): New.
(init_dummy_target): Register it.
(debug_to_wait): Delete.
* target.h (struct target_ops): Make to_wait, to_pid_to_str and
to_get_thread_local_address accept a pointer to struct target_ops.
(target_wait): Delete macro, and declare as function.
(target_pid_to_str): Likewise.
(target_get_thread_local_address)
(target_get_thread_local_address_p): Delete.
(noprocess): Add NORETURN and ATTR_NORETURN tags.
* inf-ptrace.c (inf_ptrace_wait): Adjust.
(inf_ptrace_pid_to_str): New.
(inf_ptrace_target): Use inf_ptrace_pid_to_str.
* aix-thread.c (aix_thread_wait, aix_thread_pid_to_str): Adjust.
* bsd-kvm.c (bsd_kvm_pid_to_str): Adjust.
* bsd-uthread.c (bsd_uthread_wait, bsd_uthread_pid_to_str):
Adjust.
* corelow.c (core_pid_to_str): Adjust.
* darwin-nat.c (darwin_wait, darwin_pid_to_str): Adjust.
* dec-thread.c (dec_thread_wait, dec_thread_pid_to_str): Adjust.
* gnu-nat.c (gnu_wait, gnu_pid_to_str): Adjust.
* go32-nat.c (go32_wait, go32_pid_to_str): Adjust.
* hpux-thread.c (hpux_thread_wait): Adjust.
* inf-ttrace.c (inf_ttrace_wait, inf_ttrace_pid_to_str): Adjust.
* monitor.c (monitor_wait, monitor_pid_to_str): Adjust.
* nto-procfs.c (procfs_wait, procfs_pid_to_str): Adjust.
* procfs.c (procfs_pid_to_str): Adjust.
* remote-m32r-sdi.c (m32r_wait, m32r_pid_to_str): Adjust.
* remote-mips.c (mips_wait): Adjust.
* remote-sim.c (gdbsim_wait, gdbsim_pid_to_str): Adjust.
* remote.c (remote_wait, remote_pid_to_str)
(remote_get_thread_local_address): Adjust.
* rs6000-nat.c (rs6000_wait): Adjust.
* sol-thread.c (procfs_pid_to_str): Adjust declaration.
(sol_thread_wait, solaris_pid_to_str): Adjust.
* spu-linux-nat.c (spu_child_wait): Adjust.
* windows-nat.c (windows_wait, windows_pid_to_str): Adjust.
2009-02-06 23:21:26 +01:00
|
|
|
|
darwin_pid_to_str (struct target_ops *ops, ptid_t ptid)
|
2008-11-27 10:23:01 +01:00
|
|
|
|
{
|
|
|
|
|
static char buf[128];
|
|
|
|
|
|
|
|
|
|
snprintf (buf, sizeof (buf),
|
|
|
|
|
_("process %d gdb-thread 0x%lx"),
|
|
|
|
|
(unsigned) ptid_get_pid (ptid),
|
|
|
|
|
(unsigned long) ptid_get_tid (ptid));
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
* corelow.c (get_core_registers): Adjust.
(core_file_thread_alive): Rename to...
(core_thread_alive): ... this.
(core_pid_to_str): Try gdbarch_core_pid_to_str first.
(init_core_ops): Adjust.
(coreops_suppress_target): Delete.
(_initialize_corelow): Unconditionally add core_ops.
* procfs.c: Include "inf-child.h".
(procfs_ops): Delete.
(init_procfs_ops): Delete. Reimplement as...
(procfs_target): ... this, inheriting from inf-child.
(procfs_attach, procfs_detach, procfs_fetch_registers): Adjust.
(procfs_prepare_to_store): Delete.
(procfs_store_registers, procfs_resume): Adjust.
(procfs_open): Delete.
(procfs_suppress_run): Delete.
(procfs_can_run): Delete.
(procfs_mourn_inferior): Adjust.
(procfs_init_inferior): Add target_ops parameter. Adjust.
(procfs_create_inferior): Don't pass procfs_init_inferior to
fork_inferior. Instead call it after fork_inferior returns.
(procfs_find_new_threads): Adjust.
(_initialize_procfs): Adjust to use procfs_target instead of
init_procfs_ops.
* sol-thread.c (orig_core_ops, sol_core_ops): Delete.
(lwp_to_thread): Use target_thread_alive.
(sol_thread_open): Delete.
(sol_thread_attach): Delete.
(sol_thread_detach, sol_thread_resume, sol_thread_wait)
(sol_thread_fetch_registers, sol_thread_store_registers): Adjust
to use find_target_beneath.
(sol_thread_prepare_to_store, sol_thread_xfer_memory): Delete.
(sol_thread_xfer_partial): Adjust to use find_target_beneath.
(sol_thread_files_info, sol_thread_kill_inferior): Delete.
(check_for_thread_db): New.
(sol_thread_notice_signals, sol_thread_create_inferior): Delete.
(sol_thread_new_objfile): Call check_for_thread_db.
(sol_thread_mourn_inferior): Adjust to use find_target_beneath.
(sol_thread_can_run): Delete.
(sol_thread_alive): Adjust to use find_target_beneath.
(sol_thread_stop): Delete.
(rw_common): Use target_write_memory or target_read_memory.
(ps_lgetregs, ps_lgetfpregs): Use target_fetch_registers.
(ps_lsetregs, ps_lsetfpregs): Use target_store_registers.
(solaris_pid_to_str): Remove check for libthread_db initialization
failing.
(sol_find_new_threads): Remove check for libthread_db
initialization failing, or for an invalid inferior_ptid. Adjust
to use find_target_beneath.
(sol_core_open, sol_core_close, sol_core_detach,
sol_core_files_info, sol_find_memory_regions,
sol_make_note_section, ignore): Delete.
(init_sol_thread_ops): Make it a thread_stratum target. Remove
unneeded callback settings.
(init_sol_core_ops): Delete.
(_initialize_sol_thread): No longer call init_sol_core_ops, set
procfs_suppress_run, or hack with core_ops.
* target.h (struct target_ops): Add a target_ops * parameter to
to_resume, to_fetch_registers, to_store_registers, to_thread_alive
and to_find_new_threads.
(target_fetch_registers, target_store_registers)
(target_thread_alive, target_find_new_threads): Redeclare as
function.
* target.c (update_current_target): Do not inherit or de_fault
to_resume, to_fetch_registers, to_store_registers,
to_thread_alive, to_find_new_threads.
(target_resume): Adjust.
(target_thread_alive, target_find_new_threads): New.
(debug_to_resume, debug_to_fetch_registers): Delete.
(target_fetch_registers): New.
(debug_to_store_registers): Delete.
(target_store_registers): New.
(debug_to_thread_alive, debug_to_find_new_threads): Delete.
(setup_target_debug): Adjust.
* gdbcore.h (core_ops): Delete declaration.
* inf-ptrace.c, linux-nat.c, remote.c, amd64-linux-nat.c,
inf-child.c, linux-thread-db.c, bsd-uthread.c, inf-ttrace.c,
i386-sol2-tdep.c, darwin-nat.c, gnu-nat.c, go32-nat.c,
hpux-thread.c, i386-linux-nat.c, i386fbsd-nat.c, monitor.c,
nto-procfs.c, remote-m32r-sdi.c, remote-mips.c, windows-nat.c,
alphabsd-nat.c, amd64bsd-nat.c, arm-linux-nat.c, armnbsd-nat.c,
bsd-kvm.c, hppa-hpux-nat.c, hppa-linux-nat.c, hppabsd-nat.c,
hppanbsd-nat.c, i386-darwin-nat.c, i386bsd-nat.c,
ia64-linux-nat.c, m32r-linux-nat.c, m68kbsd-nat.c,
m68klinux-nat.c, m88kbsd-nat.c, mips-linux-nat.c,
mips64obsd-nat.c, mipsnbsd-nat.c, ppc-linux-nat.c, ppcnbsd-nat.c,
ppcobsd-nat.c, remote-sim.c, rs6000-nat.c, s390-nat.c,
shnbsd-nat.c, sparc-nat.c, sparc-nat.h, spu-linux-nat.c,
vaxbsd-nat.c, xtensa-linux-nat.c: Adjust to target_ops changes.
* gdbarch.sh (core_pid_to_str): New gdbarch callback.
* gdbarch.h, gdbarch.c: Regenerate.
* sol2-tdep.c: Include "inferior.h".
(sol2_core_pid_to_str): New.
* sol2-tdep.h (sol2_core_pid_to_str): Declare.
* amd64-sol2-tdep.c (amd64_sol2_init_abi): Set it.
* sparc-sol2-tdep.c (sparc32_sol2_init_abi): Set it.
* sparc64-sol2-tdep.c (sparc64_sol2_init_abi): Set it.
* i386-sol2-tdep.c (i386_sol2_init_abi): Set it.
2009-02-23 01:03:50 +01:00
|
|
|
|
darwin_thread_alive (struct target_ops *ops, ptid_t ptid)
|
2008-11-27 10:23:01 +01:00
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If RDADDR is not NULL, read inferior task's LEN bytes from ADDR and
|
|
|
|
|
copy it to RDADDR in gdb's address space.
|
|
|
|
|
If WRADDR is not NULL, write gdb's LEN bytes from WRADDR and copy it
|
|
|
|
|
to ADDR in inferior task's address space.
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
kern_return_t err;
|
|
|
|
|
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_vm_size_t remaining_length;
|
|
|
|
|
mach_vm_address_t region_address;
|
|
|
|
|
mach_vm_size_t region_length;
|
|
|
|
|
|
|
|
|
|
inferior_debug (8, _("darwin_read_write_inferior(%s, len=%d)\n"),
|
|
|
|
|
core_addr_to_string (addr), length);
|
|
|
|
|
|
|
|
|
|
/* Get memory from inferior with page aligned addresses */
|
|
|
|
|
err = mach_vm_read (task, low_address, aligned_length,
|
|
|
|
|
&copied, ©_count);
|
|
|
|
|
if (err != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
warning (_("darwin_read_write_inferior: vm_read failed: %s"),
|
|
|
|
|
mach_error_string (err));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rdaddr != NULL)
|
|
|
|
|
memcpy (rdaddr, (char *)copied + offset, length);
|
|
|
|
|
|
|
|
|
|
if (wraddr == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
memcpy ((char *)copied + offset, wraddr, length);
|
|
|
|
|
|
|
|
|
|
/* Do writes atomically.
|
|
|
|
|
First check for holes and unwritable memory. */
|
|
|
|
|
for (region_address = low_address, remaining_length = aligned_length;
|
|
|
|
|
region_address < low_address + aligned_length;
|
|
|
|
|
region_address += region_length, remaining_length -= region_length)
|
|
|
|
|
{
|
|
|
|
|
vm_region_basic_info_data_64_t info;
|
|
|
|
|
mach_port_t object_name;
|
|
|
|
|
mach_vm_address_t old_address = region_address;
|
|
|
|
|
mach_msg_type_number_t count;
|
|
|
|
|
|
|
|
|
|
region_length = remaining_length;
|
|
|
|
|
count = VM_REGION_BASIC_INFO_COUNT_64;
|
|
|
|
|
err = mach_vm_region (task, ®ion_address, ®ion_length,
|
|
|
|
|
VM_REGION_BASIC_INFO_64,
|
|
|
|
|
(vm_region_info_t) &info, &count, &object_name);
|
|
|
|
|
|
|
|
|
|
if (err != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
warning (_("darwin_write_inferior: mach_vm_region failed: %s"),
|
|
|
|
|
mach_error_string (err));
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for holes in memory */
|
|
|
|
|
if (region_address > old_address)
|
|
|
|
|
{
|
|
|
|
|
warning (_("No memory at %s (vs %s+0x%x). Nothing written"),
|
|
|
|
|
core_addr_to_string (old_address),
|
|
|
|
|
core_addr_to_string (region_address),
|
|
|
|
|
(unsigned)region_length);
|
|
|
|
|
length = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(info.max_protection & VM_PROT_WRITE))
|
|
|
|
|
{
|
|
|
|
|
warning (_("Memory at address %s is unwritable. Nothing written"),
|
|
|
|
|
core_addr_to_string (old_address));
|
|
|
|
|
length = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(info.protection & VM_PROT_WRITE))
|
|
|
|
|
{
|
|
|
|
|
err = mach_vm_protect (task, old_address, region_length,
|
|
|
|
|
FALSE, info.protection | VM_PROT_WRITE);
|
|
|
|
|
if (err != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
warning
|
|
|
|
|
(_("darwin_read_write_inferior: mach_vm_protect failed: %s"),
|
|
|
|
|
mach_error_string (err));
|
|
|
|
|
length = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = mach_vm_write (task, low_address, copied, aligned_length);
|
|
|
|
|
|
|
|
|
|
if (err != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
warning (_("darwin_read_write_inferior: mach_vm_write failed: %s"),
|
|
|
|
|
mach_error_string (err));
|
|
|
|
|
length = 0;
|
|
|
|
|
}
|
|
|
|
|
out:
|
|
|
|
|
mach_vm_deallocate (mach_task_self (), copied, copy_count);
|
|
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
task_t task = darwin_inf->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
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
inferior_debug (8, _("darwin_xfer_partial(%s, %d, rbuf=%p, wbuf=%p)\n"),
|
|
|
|
|
core_addr_to_string (offset), (int)len, readbuf, writebuf);
|
|
|
|
|
|
|
|
|
|
if (object != TARGET_OBJECT_MEMORY)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return darwin_read_write_inferior (darwin_inf->task, offset,
|
|
|
|
|
readbuf, writebuf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_enable_mach_exceptions (char *args, int from_tty,
|
|
|
|
|
struct cmd_list_element *c)
|
|
|
|
|
{
|
|
|
|
|
if (darwin_inf && darwin_inf->task != TASK_NULL)
|
|
|
|
|
{
|
|
|
|
|
exception_mask_t mask;
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
|
|
if (enable_mach_exceptions)
|
|
|
|
|
mask = EXC_MASK_ALL;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
darwin_restore_exception_ports (darwin_inf);
|
|
|
|
|
mask = EXC_MASK_SOFTWARE;
|
|
|
|
|
}
|
|
|
|
|
kret = task_set_exception_ports (darwin_inf->task, mask, darwin_ex_port,
|
|
|
|
|
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_initialize_darwin_inferior ()
|
|
|
|
|
{
|
|
|
|
|
kern_return_t kret;
|
|
|
|
|
|
|
|
|
|
gdb_assert (darwin_inf == NULL);
|
|
|
|
|
|
|
|
|
|
gdb_task = mach_task_self ();
|
|
|
|
|
darwin_host_self = mach_host_self ();
|
|
|
|
|
|
|
|
|
|
/* Read page size. */
|
|
|
|
|
kret = host_page_size (darwin_host_self, &mach_page_size);
|
|
|
|
|
if (kret != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
mach_page_size = 0x1000;
|
|
|
|
|
MACH_CHECK_ERROR (kret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
darwin_inf = (struct darwin_inferior *)
|
|
|
|
|
xmalloc (sizeof (struct darwin_inferior));
|
|
|
|
|
|
|
|
|
|
memset (darwin_inf, 0, sizeof (*darwin_inf));
|
|
|
|
|
|
|
|
|
|
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_detach = darwin_detach;
|
|
|
|
|
darwin_ops->to_files_info = darwin_files_info;
|
|
|
|
|
darwin_ops->to_wait = darwin_wait;
|
|
|
|
|
darwin_ops->to_mourn_inferior = darwin_mourn_inferior;
|
|
|
|
|
darwin_ops->to_kill = darwin_kill_inferior;
|
|
|
|
|
darwin_ops->to_stop = darwin_stop;
|
|
|
|
|
darwin_ops->to_resume = darwin_resume;
|
|
|
|
|
darwin_ops->to_thread_alive = darwin_thread_alive;
|
|
|
|
|
darwin_ops->to_pid_to_str = darwin_pid_to_str;
|
|
|
|
|
darwin_ops->to_load = NULL;
|
|
|
|
|
darwin_ops->deprecated_xfer_memory = darwin_xfer_memory;
|
|
|
|
|
darwin_ops->to_xfer_partial = darwin_xfer_partial;
|
|
|
|
|
darwin_ops->to_has_thread_control = tc_schedlock /*| tc_switch */;
|
|
|
|
|
|
|
|
|
|
darwin_complete_target (darwin_ops);
|
|
|
|
|
|
|
|
|
|
add_target (darwin_ops);
|
|
|
|
|
|
|
|
|
|
inferior_debug (2, _("GDB task: 0x%lx, pid: %d\n"), mach_task_self (),
|
|
|
|
|
getpid ());
|
|
|
|
|
|
|
|
|
|
add_setshow_zinteger_cmd ("darwin", class_obscure,
|
|
|
|
|
&darwin_debug_flag, _("\
|
|
|
|
|
Set if printing inferior communication debugging statements."), _("\
|
|
|
|
|
Show if printing inferior communication debugging statements."), NULL,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
&setdebuglist, &showdebuglist);
|
|
|
|
|
|
|
|
|
|
add_setshow_boolean_cmd ("mach-exceptions", class_support,
|
|
|
|
|
&enable_mach_exceptions, _("\
|
|
|
|
|
Set if mach exceptions are caught."), _("\
|
|
|
|
|
Show if mach exceptions are caught."), _("\
|
|
|
|
|
When this mode is on, all low level exceptions are reported before being\n\
|
|
|
|
|
reported by the kernel."),
|
|
|
|
|
&set_enable_mach_exceptions, NULL,
|
|
|
|
|
&setlist, &showlist);
|
|
|
|
|
}
|