/* Interface GDB to Mach 3.0 operating systems.
(Most) Mach 3.0 related routines live in this file.
- Copyright (C) 1992 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1996 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
#include "target.h"
#include "wait.h"
#include "gdbcmd.h"
-#include "gdb-threads.h"
+#include "gdbcore.h"
+#if 0
#include <servers/machid_lib.h>
+#else
+#define MACH_TYPE_TASK 1
+#define MACH_TYPE_THREAD 2
+#endif
/* Included only for signal names and NSIG
*
#include <signal.h>
#define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
-#define private static
+#include <cthreads.h>
+
+/* This is what a cproc looks like. This is here partly because
+ cthread_internals.h is not a header we can just #include, partly with
+ an eye towards perhaps getting this to work with cross-debugging
+ someday. Best solution is if CMU publishes a real interface to this
+ stuff. */
+#define CPROC_NEXT_OFFSET 0
+#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
+#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
+#define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
+#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
+#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
+#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
+#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
+#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
+#define CPROC_REPLY_SIZE (sizeof (mach_port_t))
+#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
+#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
+#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
+#define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
+#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
+#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
+#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
+#define CPROC_WIRED_SIZE (sizeof (mach_port_t))
+#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
+#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
+#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
+#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
+#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
+#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
+#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
+#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
+#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
+
+/* Values for the state field in the cproc. */
+#define CPROC_RUNNING 0
+#define CPROC_SWITCHING 1
+#define CPROC_BLOCKED 2
+#define CPROC_CONDWAIT 4
+
+/* For cproc and kernel thread mapping */
+typedef struct gdb_thread {
+ mach_port_t name;
+ CORE_ADDR sp;
+ CORE_ADDR pc;
+ CORE_ADDR fp;
+ boolean_t in_emulator;
+ int slotid;
+
+ /* This is for the mthreads list. It points to the cproc list.
+ Perhaps the two lists should be merged (or perhaps it was a mistake
+ to make them both use a struct gdb_thread). */
+ struct gdb_thread *cproc;
+
+ /* These are for the cproc list, which is linked through the next field
+ of the struct gdb_thread. */
+ char raw_cproc[CPROC_SIZE];
+ /* The cthread which is pointed to by the incarnation field from the
+ cproc. This points to the copy we've read into GDB. */
+ cthread_t cthread;
+ /* Point back to the mthreads list. */
+ int reverse_map;
+ struct gdb_thread *next;
+} *gdb_thread_t;
/*
* Actions for Mach exceptions.
int a,b,c;
{
if (debug_level)
- message (fmt, a, b, c);
+ warning (fmt, a, b, c);
}
/* This is in libmach.a */
#define NULL_CLEANUP (struct cleanup *)0
struct cleanup *cleanup_step = NULL_CLEANUP;
+\f
+extern struct target_ops m3_ops;
+static void m3_kill_inferior ();
\f
#if 0
#define MACH_TYPE_EXCEPTION_PORT -1
{
if (! MACH_PORT_VALID (mid_server))
{
- message ("Machid server port invalid, can not map port 0x%x to MID",
+ warning ("Machid server port invalid, can not map port 0x%x to MID",
name);
mid = name;
}
if (ret != KERN_SUCCESS)
{
- message ("Can not map name (0x%x) to MID with machid", name);
+ warning ("Can not map name (0x%x) to MID with machid", name);
mid = name;
}
}
}
else
- mid = 3735928559; /* 0x? :-) */
+ abort ();
new = (port_chain_t) obstack_alloc (port_chain_obstack,
sizeof (struct port_chain));
if (! MACH_PORT_VALID (mid_server))
{
- message ("Machid server port invalid, can not map port 0x%x to mid",
+ warning ("Machid server port invalid, can not map port 0x%x to mid",
name);
return -1;
}
if (ret != KERN_SUCCESS)
{
- message ("Can not map name (0x%x) to mid with machid", name);
+ warning ("Can not map name (0x%x) to mid with machid", name);
return -1;
}
return mid;
}
\f
/* Guard for currently_waiting_for and singlestepped_thread_port */
-private void
+static void
discard_single_step (thread)
thread_t thread;
{
{
if (MACH_PORT_VALID (singlestepped_thread_port))
{
- message ("Singlestepped_thread_port (0x%x) is still valid?",
+ warning ("Singlestepped_thread_port (0x%x) is still valid?",
singlestepped_thread_port);
singlestepped_thread_port = MACH_PORT_NULL;
}
}
}
\f
-private
+static
request_notify (name, variant, type)
mach_port_t name;
mach_msg_id_t variant;
/* Called from inferior after FORK but before EXEC */
-prepare_inferior_task ()
+static void
+m3_trace_me ()
{
kern_return_t ret;
intercept_exec_calls (exec_counter)
int exec_counter;
{
+ int terminal_initted = 0;
+
struct syscall_msg_t {
mach_msg_header_t header;
mach_msg_type_t type;
original_exec_reply = syscall_in.header.msgh_remote_port;
syscall_in.header.msgh_remote_port = exec_reply_send;
}
+
+ if (!terminal_initted)
+ {
+ /* Now that the child has exec'd we know it has already set its
+ process group. On POSIX systems, tcsetpgrp will fail with
+ EPERM if we try it before the child's setpgid. */
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ terminal_initted = 1;
+ }
+
exec_counter--;
}
return mid;
}
-private int
+static int
parse_thread_id (arg, thread_count, slots)
char *arg;
int thread_count;
ret = task_threads (task, &thread_list, &thread_count);
if (ret != KERN_SUCCESS)
{
- message ("Can not select a thread from a dead task");
- kill_inferior ();
+ warning ("Can not select a thread from a dead task");
+ m3_kill_inferior ();
return KERN_FAILURE;
}
* exists as a container for memory and ports.
*/
registers_changed ();
- message ("Task %d has no threads",
+ warning ("Task %d has no threads",
map_port_name_to_mid (task, MACH_TYPE_TASK));
current_thread = MACH_PORT_NULL;
(void) vm_deallocate(mach_task_self(),
CHK ("Could not abort system calls when selecting a thread", ret);
stop_pc = read_pc();
- set_current_frame (create_new_frame (read_register (FP_REGNUM),
- stop_pc));
+ flush_cached_frames ();
select_frame (get_current_frame (), 0);
-
- stop_frame_address = FRAME_FP (get_current_frame ());
}
return KERN_SUCCESS;
mid = map_port_name_to_mid (new_thread,
MACH_TYPE_THREAD);
if (mid == -1)
- message ("Can't map thread name 0x%x to mid", new_thread);
+ warning ("Can't map thread name 0x%x to mid", new_thread);
else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
{
if (current_thread)
/* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
* Note that the registers are not yet valid in the inferior task.
*/
-void
-mach_create_inferior_hook (pid)
+static int
+m3_trace_him (pid)
int pid;
{
kern_return_t ret;
+ push_target (&m3_ops);
+
inferior_task = task_by_pid (pid);
if (! MACH_PORT_VALID (inferior_task))
setup_exception_port ();
xx_debug ("Now the debugged task is created\n");
+
+ /* One trap to exec the shell, one to exec the program being debugged. */
+ intercept_exec_calls (2);
+
+ return pid;
}
setup_exception_port ()
There is no other way to exit this loop.
Returns the inferior_pid for rest of gdb.
- Side effects: Set unix exit value to *w.
- */
+ Side effects: Set *OURSTATUS. */
int
-mach_really_wait (w)
- WAITTYPE *w;
+mach_really_wait (pid, ourstatus)
+ int pid;
+ struct target_waitstatus *ourstatus;
{
- int pid;
kern_return_t ret;
+ int w;
struct msg {
mach_msg_header_t header;
{
/* Collect Unix exit status for gdb */
- wait3(w, WNOHANG, 0);
+ wait3(&w, WNOHANG, 0);
/* This mess is here to check that the rest of
* gdb knows that the inferior died. It also
* has happened to it's children when mach-magic
* is applied on them.
*/
- if ((!WIFEXITED(*w) && WIFSTOPPED(*w)) ||
- (WIFEXITED(*w) && WEXITSTATUS(*w) > 0377))
+ if ((!WIFEXITED(w) && WIFSTOPPED(w)) ||
+ (WIFEXITED(w) && WEXITSTATUS(w) > 0377))
{
- WSETEXIT(*w, 0);
- message ("Using exit value 0 for terminated task");
+ WSETEXIT(w, 0);
+ warning ("Using exit value 0 for terminated task");
}
- else if (!WIFEXITED(*w))
+ else if (!WIFEXITED(w))
{
- int sig = WTERMSIG(*w);
+ int sig = WTERMSIG(w);
/* Signals cause problems. Warn the user. */
if (sig != SIGKILL) /* Bad luck if garbage matches this */
- message ("The terminating signal stuff may be nonsense");
+ warning ("The terminating signal stuff may be nonsense");
else if (sig > NSIG)
{
- WSETEXIT(*w, 0);
- message ("Using exit value 0 for terminated task");
+ WSETEXIT(w, 0);
+ warning ("Using exit value 0 for terminated task");
}
}
+ store_waitstatus (ourstatus, w);
return inferior_pid;
}
}
if (stopped_in_exception)
{
/* Get unix state. May be changed in mach3_exception_actions() */
- wait3(w, WNOHANG, 0);
+ wait3(&w, WNOHANG, 0);
- mach3_exception_actions (w, FALSE, "Task");
+ mach3_exception_actions (&w, FALSE, "Task");
+ store_waitstatus (ourstatus, w);
return inferior_pid;
}
}
if (ret != KERN_SUCCESS)
{
- message ("Could not suspend task for interrupt: %s",
+ warning ("Could not suspend task for interrupt: %s",
mach_error_string (ret));
mach_really_waiting = 0;
return;
mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
if (mid == -1)
{
- message ("Selecting first existing kernel thread");
+ warning ("Selecting first existing kernel thread");
mid = 0;
}
return;
}
+#if 0
+/* bogus bogus bogus. It is NOT OK to quit out of target_wait. */
+
/* If ^C is typed when we are waiting for a message
* and your Unix server is able to notice that we
* should quit now.
if (mach_really_waiting)
immediate_quit = 1;
}
+#endif
/*
* Gdb message server.
case GDB_MESSAGE_ID_STOP:
ret = task_suspend (inferior_task);
if (ret != KERN_SUCCESS)
- message ("Could not suspend task for stop message: %s",
+ warning ("Could not suspend task for stop message: %s",
mach_error_string (ret));
/* QUIT in mach_really_wait() loop. */
break;
default:
- message ("Invalid message id %d received, ignored.",
+ warning ("Invalid message id %d received, ignored.",
InP->msgh_id);
break;
}
if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
error ("Could not select thread %d causing exception", mid);
else
- message ("Gdb selected thread %d", mid);
+ warning ("Gdb selected thread %d", mid);
}
/* If we receive an exception that is not breakpoint
if (MACH_PORT_VALID (singlestepped_thread_port))
{
if (stop_exception != EXC_BREAKPOINT)
- message ("Single step interrupted by exception");
+ warning ("Single step interrupted by exception");
else if (port == singlestepped_thread_port)
{
/* Single step exception occurred, remove trace bit
resume_all_threads (0);
}
else
- message ("Breakpoint while single stepping?");
+ warning ("Breakpoint while single stepping?");
discard_single_step (current_thread);
}
if (! port_valid (inferior_task, MACH_PORT_TYPE_SEND))
{
- kill_inferior ();
+ m3_kill_inferior ();
error ("Inferior killed (task port invalid)");
}
else
screw it. Eamonn seems to like this, so I enable
it if OSF is defined...
*/
- message ("[read inferior %x failed: %s]",
+ warning ("[read inferior %x failed: %s]",
addr, mach_error_string (ret));
errno = 0;
#endif
}
}
- bcopy ((char *)addr - low_address + copied_memory, myaddr, length);
+ memcpy (myaddr, (char *)addr - low_address + copied_memory, length);
ret = vm_deallocate (mach_task_self (),
copied_memory,
deallocate++;
- bcopy (myaddr, (char *)addr - low_address + copied_memory, length);
+ memcpy ((char *)addr - low_address + copied_memory, myaddr, length);
obstack_init (®ion_obstack);
/* Check for holes in memory */
if (old_address != region_address)
{
- message ("No memory at 0x%x. Nothing written",
+ warning ("No memory at 0x%x. Nothing written",
old_address);
ret = KERN_SUCCESS;
length = 0;
if (!(max_protection & VM_PROT_WRITE))
{
- message ("Memory at address 0x%x is unwritable. Nothing written",
+ warning ("Memory at address 0x%x is unwritable. Nothing written",
old_address);
ret = KERN_SUCCESS;
length = 0;
if (ret != KERN_SUCCESS)
{
- message ("%s %s", errstr, mach_error_string (ret));
+ warning ("%s %s", errstr, mach_error_string (ret));
return 0;
}
return length;
}
-/*
- * Return 0 on failure, number of bytes handled otherwise.
- */
-int
-child_xfer_memory (memaddr, myaddr, len, write, target)
+/* Return 0 on failure, number of bytes handled otherwise. */
+static int
+m3_xfer_memory (memaddr, myaddr, len, write, target)
CORE_ADDR memaddr;
char *myaddr;
int len;
}
\f
-private char *
+static char *
translate_state(state)
int state;
{
}
}
-private char *
-translate_cstate(state)
-int state;
+static char *
+translate_cstate (state)
+ int state;
{
- switch (state) {
- case CPROC_RUNNING: return "R";
- case CPROC_SWITCHING: return "S";
- case CPROC_BLOCKED: return "B";
- case CPROC_CONDWAIT: return "C";
- case CPROC_CONDWAIT|CPROC_SWITCHING:
- return "CS";
- default: return "?";
- }
+ switch (state)
+ {
+ case CPROC_RUNNING: return "R";
+ case CPROC_SWITCHING: return "S";
+ case CPROC_BLOCKED: return "B";
+ case CPROC_CONDWAIT: return "C";
+ case CPROC_CONDWAIT|CPROC_SWITCHING: return "CS";
+ default: return "?";
+ }
}
-/* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND
- */
+/* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */
mach_port_t /* no mach_port_name_t found in include files. */
map_inferior_port_name (inferior_name, type)
* of the sequential number of such cprocs.
*/
-private char buf[7];
+static char buf[7];
-private char *
+static char *
get_thread_name (one_cproc, id)
- cproc_t one_cproc;
+ gdb_thread_t one_cproc;
int id;
{
if (one_cproc)
- if (one_cproc->incarnation == NULL)
+ if (one_cproc->cthread == NULL)
{
/* cproc not mapped to any cthread */
sprintf(buf, "_C%d", id);
}
- else if (! one_cproc->incarnation->name)
+ else if (! one_cproc->cthread->name)
{
/* cproc and cthread, but no name */
sprintf(buf, "_t%d", id);
}
else
- return (one_cproc->incarnation->name);
+ return (char *)(one_cproc->cthread->name);
else
{
if (id < 0)
- message ("Inconsistency in thread name id %d", id);
+ warning ("Inconsistency in thread name id %d", id);
/* Kernel thread without cproc */
sprintf(buf, "_K%d", id);
ret = task_threads (task, &th_table, &th_count);
if (ret != KERN_SUCCESS)
{
- message ("Error getting inferior's thread list:%s",
+ warning ("Error getting inferior's thread list:%s",
mach_error_string(ret));
- kill_inferior ();
+ m3_kill_inferior ();
return -1;
}
(th_count * sizeof(mach_port_t)));
if (ret != KERN_SUCCESS)
{
- message ("Error trying to deallocate thread list : %s",
+ warning ("Error trying to deallocate thread list : %s",
mach_error_string (ret));
}
&stack_pointer,
sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
{
- message ("Can't read user sp from emulator stack address 0x%x", sp);
+ warning ("Can't read user sp from emulator stack address 0x%x", sp);
return 0;
}
static boolean_t informed = FALSE;
if (!informed)
{
- message("Emulation vector address 0x08%x outside emulator space",
+ warning("Emulation vector address 0x08%x outside emulator space",
entry);
informed = TRUE;
}
return FALSE;
}
-/*
- * Map cprocs to kernel threads and vice versa.
- *
- * For reverse mapping the code mis-uses one struct cproc field,
- * see "os-mach3.h" and code here.
- *
- */
+/* Map cprocs to kernel threads and vice versa. */
void
map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
- cproc_t cprocs;
- gdb_thread_t mthreads;
+ gdb_thread_t cprocs;
+ gdb_thread_t mthreads;
int thread_count;
{
int index;
- cproc_t scan;
- boolean_t all_mapped = TRUE;
+ gdb_thread_t scan;
+ boolean_t all_mapped = TRUE;
+ LONGEST stack_base;
+ LONGEST stack_size;
- for (scan = cprocs; scan; scan = scan->list)
+ for (scan = cprocs; scan; scan = scan->next)
{
/* Default to: no kernel thread for this cproc */
- CPROC_REVERSE_MAP (scan) = -1;
+ scan->reverse_map = -1;
/* Check if the cproc is found by its stack */
for (index = 0; index < thread_count; index++)
{
- if ((mthreads + index)->sp > scan->stack_base &&
- (mthreads + index)->sp <= scan->stack_base + scan->stack_size)
+ stack_base =
+ extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
+ CPROC_BASE_SIZE);
+ stack_size =
+ extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
+ CPROC_SIZE_SIZE);
+ if ((mthreads + index)->sp > stack_base &&
+ (mthreads + index)->sp <= stack_base + stack_size)
{
(mthreads + index)->cproc = scan;
- CPROC_REVERSE_MAP (scan) = index;
+ scan->reverse_map = index;
break;
}
}
- all_mapped &= (CPROC_REVERSE_MAP(scan) != -1);
+ all_mapped &= (scan->reverse_map != -1);
}
/* Check for threads that are currently in the emulator.
gdb_thread_t mthread = (mthreads+index);
emul_sp = mthread->sp;
- if (! mthread->cproc &&
+ if (mthread->cproc == NULL &&
EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
{
mthread->in_emulator = emulator_present;
/* Try to match this stack pointer to the cprocs that
* don't yet have a kernel thread.
*/
- for (scan = cprocs; scan; scan = scan->list)
+ for (scan = cprocs; scan; scan = scan->next)
{
/* Check is this unmapped CPROC stack contains
* the user stack pointer saved in the
* emulator.
*/
- if (CPROC_REVERSE_MAP (scan) == -1 &&
- usp > scan->stack_base &&
- usp <= scan->stack_base + scan->stack_size)
+ if (scan->reverse_map == -1)
{
- mthread->cproc = scan;
- CPROC_REVERSE_MAP (scan) = index;
- break;
+ stack_base =
+ extract_signed_integer
+ (scan->raw_cproc + CPROC_BASE_OFFSET,
+ CPROC_BASE_SIZE);
+ stack_size =
+ extract_signed_integer
+ (scan->raw_cproc + CPROC_SIZE_OFFSET,
+ CPROC_SIZE_SIZE);
+ if (usp > stack_base &&
+ usp <= stack_base + stack_size)
+ {
+ mthread->cproc = scan;
+ scan->reverse_map = index;
+ break;
+ }
}
}
}
void
print_tl_address (stream, pc)
- FILE *stream;
+ GDB_FILE *stream;
CORE_ADDR pc;
{
if (! lookup_minimal_symbol_by_pc (pc))
if (! symaddr)
{
- msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
if (msymbol && msymbol->type == mst_data)
- symaddr = msymbol->address;
+ symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
}
return symaddr;
}
-private cproc_t
+static gdb_thread_t
get_cprocs()
{
- cproc_t their_cprocs, cproc_head, cproc_copy;
+ gdb_thread_t cproc_head;
+ gdb_thread_t cproc_copy;
+ CORE_ADDR their_cprocs;
+ char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
char *name;
cthread_t cthread;
CORE_ADDR symaddr;
symaddr = lookup_address_of_variable ("cproc_list");
if (! symaddr)
- { /* cproc_list is not in a file compiled with debugging
+ {
+ /* cproc_list is not in a file compiled with debugging
symbols, but don't give up yet */
-
+
symaddr = lookup_address_of_variable ("cprocs");
if (symaddr)
{
static int informed = 0;
- if (!informed) {
- informed++;
- message ("Your program is loaded with an old threads library.");
- message ("GDB does not know the old form of threads");
- message ("so things may not work.");
- }
+ if (!informed)
+ {
+ informed++;
+ warning ("Your program is loaded with an old threads library.");
+ warning ("GDB does not know the old form of threads");
+ warning ("so things may not work.");
+ }
}
}
/* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
if (! symaddr)
- return NO_CPROC;
+ return NULL;
/* Get the address of the first cproc in the task */
- if (!mach3_read_inferior(symaddr,
- &their_cprocs,
- sizeof(cproc_t)))
- error("Can't read cproc master list at address (0x%x).", symaddr);
+ if (!mach3_read_inferior (symaddr,
+ buf,
+ TARGET_PTR_BIT / HOST_CHAR_BIT))
+ error ("Can't read cproc master list at address (0x%x).", symaddr);
+ their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
/* Scan the CPROCs in the task.
CPROCs are chained with LIST field, not NEXT field, which
chains mutexes, condition variables and queues */
-
- cproc_head = NO_CPROC;
- while (their_cprocs != NO_CPROC)
+ cproc_head = NULL;
+
+ while (their_cprocs != (CORE_ADDR)0)
{
- cproc_copy = (cproc_t) obstack_alloc(cproc_obstack,
- sizeof(struct cproc));
-
- if (!mach3_read_inferior(their_cprocs,
- cproc_copy,
- sizeof(struct cproc)))
+ CORE_ADDR cproc_copy_incarnation;
+ cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
+ sizeof (struct gdb_thread));
+
+ if (!mach3_read_inferior (their_cprocs,
+ &cproc_copy->raw_cproc[0],
+ CPROC_SIZE))
error("Can't read next cproc at 0x%x.", their_cprocs);
-
- their_cprocs = cproc_copy->list;
-
- if (cproc_copy->incarnation != NULL)
+
+ their_cprocs =
+ extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
+ CPROC_LIST_SIZE);
+ cproc_copy_incarnation =
+ extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
+ CPROC_INCARNATION_SIZE);
+
+ if (cproc_copy_incarnation == (CORE_ADDR)0)
+ cproc_copy->cthread = NULL;
+ else
{
/* This CPROC has an attached CTHREAD. Get its name */
cthread = (cthread_t)obstack_alloc (cproc_obstack,
sizeof(struct cthread));
-
- if (!mach3_read_inferior(cproc_copy->incarnation,
+
+ if (!mach3_read_inferior (cproc_copy_incarnation,
cthread,
sizeof(struct cthread)))
error("Can't read next thread at 0x%x.",
- cproc_copy->incarnation);
-
- cproc_copy->incarnation = cthread;
-
+ cproc_copy_incarnation);
+
+ cproc_copy->cthread = cthread;
+
if (cthread->name)
{
name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
cthread->name = name;
}
}
-
+
/* insert in front */
- cproc_copy->list = cproc_head;
- cproc_head = cproc_copy;
+ cproc_copy->next = cproc_head;
+ cproc_head = cproc_copy;
}
- return(cproc_head);
+ return cproc_head;
}
#ifndef FETCH_CPROC_STATE
{
int context;
- if (! mthread || !mthread->cproc || !mthread->cproc->context)
+ if (! mthread || !mthread->cproc)
return -1;
- context = mthread->cproc->context;
+ context = extract_signed_integer
+ (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
+ CPROC_CONTEXT_SIZE);
+ if (context == 0)
+ return -1;
mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
&mthread->pc,
sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
{
- message ("Can't read cproc pc from inferior");
+ warning ("Can't read cproc pc from inferior");
return -1;
}
&mthread->fp,
sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
{
- message ("Can't read cproc fp from inferior");
+ warning ("Can't read cproc fp from inferior");
return -1;
}
{
thread_basic_info_data_t ths;
int thread_count;
- cproc_t cprocs;
- cproc_t scan;
+ gdb_thread_t cprocs;
+ gdb_thread_t scan;
int index;
char *name;
char selected;
map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
- for (scan = cprocs; scan; scan = scan->list)
+ for (scan = cprocs; scan; scan = scan->next)
{
int mid;
char buf[10];
char slot[3];
+ int cproc_state =
+ extract_signed_integer
+ (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
selected = ' ';
/* a wired cproc? */
- wired = scan->wired ? "wired" : "";
-
- if (CPROC_REVERSE_MAP(scan) != -1)
- kthread = (their_threads + CPROC_REVERSE_MAP(scan));
+ wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
+ CPROC_WIRED_SIZE)
+ ? "wired" : "");
+
+ if (scan->reverse_map != -1)
+ kthread = (their_threads + scan->reverse_map);
else
kthread = NULL;
if (ret != KERN_SUCCESS)
{
- message ("Unable to get basic info on thread %d : %s",
+ warning ("Unable to get basic info on thread %d : %s",
mid,
mach_error_string (ret));
continue;
kthread->in_emulator ? "E" : "",
translate_state (ths.run_state),
buf,
- translate_cstate (scan->state),
+ translate_cstate (cproc_state),
wired);
- print_tl_address (stdout, kthread->pc);
+ print_tl_address (gdb_stdout, kthread->pc);
}
else
{
"",
"-", /* kernel state */
"",
- translate_cstate (scan->state),
+ translate_cstate (cproc_state),
"");
state.cproc = scan;
if (FETCH_CPROC_STATE (&state) == -1)
puts_filtered ("???");
else
- print_tl_address (stdout, state.pc);
+ print_tl_address (gdb_stdout, state.pc);
neworder++;
}
if (ret != KERN_SUCCESS)
{
- message ("Unable to get basic info on thread %d : %s",
+ warning ("Unable to get basic info on thread %d : %s",
mid,
mach_error_string (ret));
continue;
buf,
"", /* No cproc state */
""); /* Can't be wired */
- print_tl_address (stdout, their_threads[index].pc);
+ print_tl_address (gdb_stdout, their_threads[index].pc);
puts_filtered ("\n");
}
}
if (! MACH_PORT_VALID (thread))
{
- message ("thread_trace: invalid thread");
+ warning ("thread_trace: invalid thread");
return;
}
MATTR_CACHE,
&flush);
if (ret != KERN_SUCCESS)
- message ("Error flushing inferior's cache : %s",
+ warning ("Error flushing inferior's cache : %s",
mach_error_string (ret));
}
#endif FLUSH_INFERIOR_CACHE
\f
-private
+static
suspend_all_threads (from_tty)
int from_tty;
{
ret = task_threads (inferior_task, &thread_list, &thread_count);
if (ret != KERN_SUCCESS)
{
- message ("Could not suspend inferior threads.");
- kill_inferior ();
- return_to_top_level ();
+ warning ("Could not suspend inferior threads.");
+ m3_kill_inferior ();
+ return_to_top_level (RETURN_ERROR);
}
for (index = 0; index < thread_count; index++)
ret = thread_suspend(thread_list[ index ]);
if (ret != KERN_SUCCESS)
- message ("Error trying to suspend thread %d : %s",
+ warning ("Error trying to suspend thread %d : %s",
mid, mach_error_string (ret));
if (from_tty)
&infoCnt);
CHK ("suspend can't get thread info", ret);
- message ("Thread %d suspend count is %d",
+ warning ("Thread %d suspend count is %d",
mid, th_info.suspend_count);
}
}
ret = thread_suspend (current_thread);
if (ret != KERN_SUCCESS)
- message ("thread_suspend failed : %s",
+ warning ("thread_suspend failed : %s",
mach_error_string (ret));
infoCnt = THREAD_BASIC_INFO_COUNT;
&infoCnt);
CHK ("suspend can't get thread info", ret);
- message ("Thread %d suspend count is %d", mid, th_info.suspend_count);
+ warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
current_thread = saved_thread;
}
ret = task_threads (inferior_task, &thread_list, &thread_count);
if (ret != KERN_SUCCESS)
{
- kill_inferior ();
+ m3_kill_inferior ();
error("task_threads", mach_error_string( ret));
}
if (! th_info.suspend_count)
{
if (mid != -1 && from_tty)
- message ("Thread %d is not suspended", mid);
+ warning ("Thread %d is not suspended", mid);
continue;
}
ret = thread_resume (thread_list[ index ]);
if (ret != KERN_SUCCESS)
- message ("Error trying to resume thread %d : %s",
+ warning ("Error trying to resume thread %d : %s",
mid, mach_error_string (ret));
else if (mid != -1 && from_tty)
- message ("Thread %d suspend count is %d",
+ warning ("Thread %d suspend count is %d",
mid, --th_info.suspend_count);
}
{
if (current_thread)
current_thread = saved_thread;
- return_to_top_level ();
+ return_to_top_level (RETURN_ERROR);
}
ret = thread_info (current_thread,
if (! th_info.suspend_count)
{
- message ("Thread %d is not suspended", mid);
+ warning ("Thread %d is not suspended", mid);
goto out;
}
ret = thread_resume (current_thread);
if (ret != KERN_SUCCESS)
- message ("thread_resume failed : %s",
+ warning ("thread_resume failed : %s",
mach_error_string (ret));
else
{
th_info.suspend_count--;
- message ("Thread %d suspend count is %d", mid, th_info.suspend_count);
+ warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
}
out:
CHK ("Thread could not be terminated", ret);
if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
- message ("Last thread was killed, use \"kill\" command to kill task");
+ warning ("Last thread was killed, use \"kill\" command to kill task");
}
else
for (index = 0; index < thread_count; index++)
(thread_count * sizeof(mach_port_t)));
CHK ("Error trying to deallocate thread list", ret);
- message ("Thread %d killed", mid);
+ warning ("Thread %d killed", mid);
}
\f
if (ta_info.suspend_count == 1)
{
- message ("Inferior task %d is no longer suspended", mid);
+ warning ("Inferior task %d is no longer suspended", mid);
must_suspend_thread = 1;
/* @@ This is not complete: Registers change all the time when not
suspended! */
registers_changed ();
}
else
- message ("Inferior task %d suspend count is now %d",
+ warning ("Inferior task %d suspend count is now %d",
mid, ta_info.suspend_count-1);
}
&infoCnt);
CHK ("task_suspend_command: task_info failed", ret);
- message ("Inferior task %d suspend count is now %d",
+ warning ("Inferior task %d suspend count is now %d",
mid, ta_info.suspend_count);
}
-private char *
+static char *
get_size (bytes)
int bytes;
{
* exception mid [ forward | keep ]
*/
-private void
+static void
exception_command (args, from_tty)
char *args;
int from_tty;
error ("exception action is either \"keep\" or \"forward\"");
}
-private void
+static void
print_exception_info (exception)
int exception;
{
if (exception_map[stop_exception].print || force_print)
{
- int giveback = grab_terminal ();
+ target_terminal_ours ();
printf_filtered ("\n%s received %s exception : ",
who,
default:
fatal ("Unknown exception");
}
-
- if (giveback)
- terminal_inferior ();
}
}
\f
if (! MACH_PORT_VALID (port) || !name || !*name)
{
- message ("Invalid registration request");
+ warning ("Invalid registration request");
return;
}
struct cmd_list_element *cmd_task_list;
/*ARGSUSED*/
-private void
+static void
thread_command (arg, from_tty)
char *arg;
int from_tty;
{
- printf ("\"thread\" must be followed by the name of a thread command.\n");
- help_list (cmd_thread_list, "thread ", -1, stdout);
+ printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n");
+ help_list (cmd_thread_list, "thread ", -1, gdb_stdout);
}
/*ARGSUSED*/
-private void
+static void
task_command (arg, from_tty)
char *arg;
int from_tty;
{
- printf ("\"task\" must be followed by the name of a task command.\n");
- help_list (cmd_task_list, "task ", -1, stdout);
+ printf_unfiltered ("\"task\" must be followed by the name of a task command.\n");
+ help_list (cmd_task_list, "task ", -1, gdb_stdout);
}
add_mach_specific_commands ()
{
- extern void condition_thread ();
-
/* Thread handling commands */
- add_prefix_cmd ("thread", class_stack, thread_command,
- "Generic command for handling threads in the debugged task.",
+ /* FIXME: Move our thread support into the generic thread.c stuff so we
+ can share that code. */
+ add_prefix_cmd ("mthread", class_stack, thread_command,
+ "Generic command for handling Mach threads in the debugged task.",
&cmd_thread_list, "thread ", 0, &cmdlist);
- add_com_alias ("th", "thread", class_stack, 1);
+ add_com_alias ("th", "mthread", class_stack, 1);
add_cmd ("select", class_stack, thread_select_command,
"Select and print MID of the selected thread",
add_cmd ("kill", class_run, thread_kill_command,
"Kill the specified thread MID from inferior task.",
&cmd_thread_list);
+#if 0
+ /* The rest of this support (condition_thread) was not merged. It probably
+ should not be merged in this form, but instead added to the generic GDB
+ thread support. */
add_cmd ("break", class_breakpoint, condition_thread,
"Breakpoint N will only be effective for thread MID or @SLOT\n\
If MID/@SLOT is omitted allow all threads to break at breakpoint",
&cmd_thread_list);
+#endif
/* Thread command shorthands (for backward compatibility) */
- add_alias_cmd ("ts", "thread select", 0, 0, &cmdlist);
- add_alias_cmd ("tl", "thread list", 0, 0, &cmdlist);
+ add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
+ add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
/* task handling commands */
Normally \"keep\" is used to return to GDB on exception.");
}
-void
-_initialize_mach_os ()
-{
- kern_return_t ret;
-
- ret = mach_port_allocate(mach_task_self(),
- MACH_PORT_RIGHT_PORT_SET,
- &inferior_wait_port_set);
- if (ret != KERN_SUCCESS)
- fatal("initial port set %s",mach_error_string(ret));
-
- /* mach_really_wait now waits for this */
- currently_waiting_for = inferior_wait_port_set;
-
- ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server);
- if (ret != KERN_SUCCESS)
- {
- mid_server = MACH_PORT_NULL;
-
- message ("initialize machid: netname_lookup_up(MachID) : %s",
- mach_error_string(ret));
- message ("Some (most?) features disabled...");
- }
-
- mid_auth = mach_privileged_host_port();
- if (mid_auth == MACH_PORT_NULL)
- mid_auth = mach_task_self();
-
- obstack_init (port_chain_obstack);
-
- ret = mach_port_allocate (mach_task_self (),
- MACH_PORT_RIGHT_RECEIVE,
- &thread_exception_port);
- CHK ("Creating thread_exception_port for single stepping", ret);
-
- ret = mach_port_insert_right (mach_task_self (),
- thread_exception_port,
- thread_exception_port,
- MACH_MSG_TYPE_MAKE_SEND);
- CHK ("Inserting send right to thread_exception_port", ret);
-
- /* Allocate message port */
- ret = mach_port_allocate (mach_task_self (),
- MACH_PORT_RIGHT_RECEIVE,
- &our_message_port);
- if (ret != KERN_SUCCESS)
- message ("Creating message port %s", mach_error_string (ret));
- else
- {
- char buf[ MAX_NAME_LEN ];
- ret = mach_port_move_member(mach_task_self (),
- our_message_port,
- inferior_wait_port_set);
- if (ret != KERN_SUCCESS)
- message ("message move member %s", mach_error_string (ret));
-
-
- /* @@@@ No way to change message port name currently */
- /* Foo. This assumes gdb has a unix pid */
- sprintf (buf, "gdb-%d", getpid ());
- gdb_register_port (buf, our_message_port);
- }
-
- /* Heap for thread commands */
- obstack_init (cproc_obstack);
-
- add_mach_specific_commands ();
-}
-
kern_return_t
do_mach_notify_dead_name (notify, name)
mach_port_t notify;
switch (element->type) {
case MACH_TYPE_THREAD:
+ target_terminal_ours_for_output ();
if (name == current_thread)
{
- message ("\nCurrent thread %d died", element->mid);
+ printf_filtered ("\nCurrent thread %d died", element->mid);
current_thread = MACH_PORT_NULL;
}
else
- message ("\nThread %d died", element->mid);
+ printf_filtered ("\nThread %d died", element->mid);
break;
case MACH_TYPE_TASK:
+ target_terminal_ours_for_output ();
if (name != inferior_task)
- message ("Task %d died, but it was not the selected task",
+ printf_filtered ("Task %d died, but it was not the selected task",
element->mid);
else
{
- message ("Current task %d died", element->mid);
+ printf_filtered ("Current task %d died", element->mid);
mach_port_destroy (mach_task_self(), name);
inferior_task = MACH_PORT_NULL;
if (notify_chain)
- message("There were still unreceived dead_name_notifications???");
+ warning ("There were still unreceived dead_name_notifications???");
/* Destroy the old notifications */
setup_notify_port (0);
mach_port_t notify;
mach_port_t name;
{
- message ("do_mach_notify_msg_accepted : notify %x, name %x",
+ warning ("do_mach_notify_msg_accepted : notify %x, name %x",
notify, name);
return KERN_SUCCESS;
}
mach_port_t notify;
mach_port_mscount_t mscount;
{
- message ("do_mach_notify_no_senders : notify %x, mscount %x",
+ warning ("do_mach_notify_no_senders : notify %x, mscount %x",
notify, mscount);
return KERN_SUCCESS;
}
mach_port_t notify;
mach_port_t name;
{
- message ("do_mach_notify_port_deleted : notify %x, name %x",
+ warning ("do_mach_notify_port_deleted : notify %x, name %x",
notify, name);
return KERN_SUCCESS;
}
mach_port_t notify;
mach_port_t rights;
{
- message ("do_mach_notify_port_destroyed : notify %x, rights %x",
+ warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
notify, rights);
return KERN_SUCCESS;
}
{
#ifdef DUMP_SYSCALL
/* MANY of these are generated. */
- message ("do_mach_notify_send_once : notify %x",
+ warning ("do_mach_notify_send_once : notify %x",
notify);
#endif
return KERN_SUCCESS;
}
/* Kills the inferior. It's gone when you call this */
-void
+static void
kill_inferior_fast ()
{
WAITTYPE w;
setup_notify_port (0);
}
-void
-kill_inferior ()
+static void
+m3_kill_inferior ()
{
kill_inferior_fast ();
target_mourn_inferior ();
}
+/* Clean up after the inferior dies. */
+
+static void
+m3_mourn_inferior ()
+{
+ unpush_target (&m3_ops);
+ generic_mourn_inferior ();
+}
+
+\f
+/* Fork an inferior process, and start debugging it. */
+
+static void
+m3_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, 0, 0);
+}
+
+/* Mark our target-struct as eligible for stray "run" and "attach"
+ commands. */
+static int
+m3_can_run ()
+{
+ return 1;
+}
\f
/* Mach 3.0 does not need ptrace for anything
* Make sure nobody uses it on mach.
If SIGNAL is nonzero, give it that signal. */
void
-child_resume (step, signal)
+m3_resume (pid, step, signal)
+ int pid;
int step;
- int signal;
+ enum target_signal signal;
{
kern_return_t ret;
vm_read_cache_valid = FALSE;
if (signal && inferior_pid > 0) /* Do not signal, if attached by MID */
- kill (inferior_pid, signal);
+ kill (inferior_pid, target_signal_to_host (signal));
if (step)
{
ret = task_resume (inferior_task);
if (ret == KERN_FAILURE)
- message ("Task was not suspended");
+ warning ("Task was not suspended");
else
CHK ("Resuming task", ret);
* like "atta 0" or "atta foo" (equal to the previous :-) and
* "atta pidself". Anyway, the latter is allowed by specifying a MID.
*/
-attach (pid)
+static int
+m3_do_attach (pid)
int pid;
{
kern_return_t ret;
return inferior_pid;
}
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+
+static void
+m3_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+ int pid;
+
+ 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)
+ {
+ exec_file = (char *) get_exec_file (0);
+
+ if (exec_file)
+ printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
+ else
+ printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ m3_do_attach (pid);
+ inferior_pid = pid;
+ push_target (&m3_ops);
+}
+\f
void
deallocate_inferior_ports ()
{
ret = task_threads (inferior_task, &thread_list, &thread_count);
if (ret != KERN_SUCCESS)
{
- message ("deallocate_inferior_ports: task_threads",
+ warning ("deallocate_inferior_ports: task_threads",
mach_error_string(ret));
return;
}
and continue it with signal number SIGNAL.
SIGNAL = 0 means just continue it. */
-void
-detach (signal)
+static void
+m3_do_detach (signal)
int signal;
{
kern_return_t ret;
setup_notify_port (0);
if (remove_breakpoints ())
- message ("Could not remove breakpoints when detaching");
+ warning ("Could not remove breakpoints when detaching");
if (signal && inferior_pid > 0)
kill (inferior_pid, signal);
attach_flag = 0;
}
+
+/* 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
+m3_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ int siggnal = 0;
+
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_unfiltered ("Detaching from program: %s %s\n",
+ exec_file, target_pid_to_str (inferior_pid));
+ gdb_flush (gdb_stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ m3_do_detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&m3_ops); /* Pop out of handling an inferior */
+}
#endif /* ATTACH_DETACH */
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+m3_prepare_to_store ()
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+m3_files_info (ignore)
+ struct target_ops *ignore;
+{
+ /* FIXME: should print MID and all that crap. */
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
+ attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
+}
+
+static void
+m3_open (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
#ifdef DUMP_SYSCALL
#ifdef __STDC__
#define STR(x) #x
puts_filtered("\n");
}
#endif DUMP_SYSCALL
+
+static void
+m3_stop ()
+{
+ error ("to_stop target function not implemented");
+}
+
+struct target_ops m3_ops = {
+ "mach", /* to_shortname */
+ "Mach child process", /* to_longname */
+ "Mach child process (started by the \"run\" command).", /* to_doc */
+ m3_open, /* to_open */
+ 0, /* to_close */
+ m3_attach, /* to_attach */
+ m3_detach, /* to_detach */
+ m3_resume, /* to_resume */
+ mach_really_wait, /* to_wait */
+ fetch_inferior_registers, /* to_fetch_registers */
+ store_inferior_registers, /* to_store_registers */
+ m3_prepare_to_store, /* to_prepare_to_store */
+ m3_xfer_memory, /* to_xfer_memory */
+ m3_files_info, /* to_files_info */
+ memory_insert_breakpoint, /* to_insert_breakpoint */
+ memory_remove_breakpoint, /* to_remove_breakpoint */
+ terminal_init_inferior, /* to_terminal_init */
+ terminal_inferior, /* to_terminal_inferior */
+ terminal_ours_for_output, /* to_terminal_ours_for_output */
+ terminal_ours, /* to_terminal_ours */
+ child_terminal_info, /* to_terminal_info */
+ m3_kill_inferior, /* to_kill */
+ 0, /* to_load */
+ 0, /* to_lookup_symbol */
+
+ m3_create_inferior, /* to_create_inferior */
+ m3_mourn_inferior, /* to_mourn_inferior */
+ m3_can_run, /* to_can_run */
+ 0, /* to_notice_signals */
+ 0, /* to_thread_alive */
+ m3_stop, /* to_stop */
+ process_stratum, /* to_stratum */
+ 0, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ 0, /* sections */
+ 0, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+
+void
+_initialize_m3_nat ()
+{
+ kern_return_t ret;
+
+ add_target (&m3_ops);
+
+ ret = mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_PORT_SET,
+ &inferior_wait_port_set);
+ if (ret != KERN_SUCCESS)
+ fatal("initial port set %s",mach_error_string(ret));
+
+ /* mach_really_wait now waits for this */
+ currently_waiting_for = inferior_wait_port_set;
+
+ ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server);
+ if (ret != KERN_SUCCESS)
+ {
+ mid_server = MACH_PORT_NULL;
+
+ warning ("initialize machid: netname_lookup_up(MachID) : %s",
+ mach_error_string(ret));
+ warning ("Some (most?) features disabled...");
+ }
+
+ mid_auth = mach_privileged_host_port();
+ if (mid_auth == MACH_PORT_NULL)
+ mid_auth = mach_task_self();
+
+ obstack_init (port_chain_obstack);
+
+ ret = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE,
+ &thread_exception_port);
+ CHK ("Creating thread_exception_port for single stepping", ret);
+
+ ret = mach_port_insert_right (mach_task_self (),
+ thread_exception_port,
+ thread_exception_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ CHK ("Inserting send right to thread_exception_port", ret);
+
+ /* Allocate message port */
+ ret = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE,
+ &our_message_port);
+ if (ret != KERN_SUCCESS)
+ warning ("Creating message port %s", mach_error_string (ret));
+ else
+ {
+ char buf[ MAX_NAME_LEN ];
+ ret = mach_port_move_member(mach_task_self (),
+ our_message_port,
+ inferior_wait_port_set);
+ if (ret != KERN_SUCCESS)
+ warning ("message move member %s", mach_error_string (ret));
+
+
+ /* @@@@ No way to change message port name currently */
+ /* Foo. This assumes gdb has a unix pid */
+ sprintf (buf, "gdb-%d", getpid ());
+ gdb_register_port (buf, our_message_port);
+ }
+
+ /* Heap for thread commands */
+ obstack_init (cproc_obstack);
+
+ add_mach_specific_commands ();
+}