OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [m3-nat.c] - Diff between revs 105 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 105 Rev 1765
/* Interface GDB to Mach 3.0 operating systems.
/* Interface GDB to Mach 3.0 operating systems.
   (Most) Mach 3.0 related routines live in this file.
   (Most) Mach 3.0 related routines live in this file.
 
 
   Copyright (C) 1992, 1996, 1999-2000 Free Software Foundation, Inc.
   Copyright (C) 1992, 1996, 1999-2000 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   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
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
   Boston, MA 02111-1307, USA.  */
 
 
/*
/*
 * Author: Jukka Virtanen <jtv@hut.fi>
 * Author: Jukka Virtanen <jtv@hut.fi>
 *         Computing Centre
 *         Computing Centre
 *         Helsinki University of Technology
 *         Helsinki University of Technology
 *         Finland
 *         Finland
 *
 *
 * Thanks to my friends who helped with ideas and testing:
 * Thanks to my friends who helped with ideas and testing:
 *
 *
 *      Johannes Helander, Antti Louko, Tero Mononen,
 *      Johannes Helander, Antti Louko, Tero Mononen,
 *      jvh@cs.hut.fi      alo@hut.fi   tmo@cs.hut.fi
 *      jvh@cs.hut.fi      alo@hut.fi   tmo@cs.hut.fi
 *
 *
 *      Tero Kivinen       and          Eamonn McManus
 *      Tero Kivinen       and          Eamonn McManus
 *      kivinen@cs.hut.fi               emcmanus@gr.osf.org
 *      kivinen@cs.hut.fi               emcmanus@gr.osf.org
 *
 *
 */
 */
 
 
#include <stdio.h>
#include <stdio.h>
 
 
#include <mach.h>
#include <mach.h>
#include <servers/netname.h>
#include <servers/netname.h>
#include <servers/machid.h>
#include <servers/machid.h>
#include <mach/message.h>
#include <mach/message.h>
#include <mach/notify.h>
#include <mach/notify.h>
#include <mach_error.h>
#include <mach_error.h>
#include <mach/exception.h>
#include <mach/exception.h>
#include <mach/vm_attributes.h>
#include <mach/vm_attributes.h>
 
 
#include "defs.h"
#include "defs.h"
#include "inferior.h"
#include "inferior.h"
#include "symtab.h"
#include "symtab.h"
#include "value.h"
#include "value.h"
#include "language.h"
#include "language.h"
#include "target.h"
#include "target.h"
#include "gdb_wait.h"
#include "gdb_wait.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbcore.h"
 
 
#if 0
#if 0
#include <servers/machid_lib.h>
#include <servers/machid_lib.h>
#else
#else
#define MACH_TYPE_TASK                  1
#define MACH_TYPE_TASK                  1
#define MACH_TYPE_THREAD                2
#define MACH_TYPE_THREAD                2
#endif
#endif
 
 
/* Included only for signal names and NSIG
/* Included only for signal names and NSIG
 
 
 * note: There are many problems in signal handling with
 * note: There are many problems in signal handling with
 *       gdb in Mach 3.0 in general.
 *       gdb in Mach 3.0 in general.
 */
 */
#include <signal.h>
#include <signal.h>
#define SIG_UNKNOWN 0           /* Exception that has no matching unix signal */
#define SIG_UNKNOWN 0           /* Exception that has no matching unix signal */
 
 
#include <cthreads.h>
#include <cthreads.h>
 
 
/* This is what a cproc looks like.  This is here partly because
/* 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
   cthread_internals.h is not a header we can just #include, partly with
   an eye towards perhaps getting this to work with cross-debugging
   an eye towards perhaps getting this to work with cross-debugging
   someday.  Best solution is if CMU publishes a real interface to this
   someday.  Best solution is if CMU publishes a real interface to this
   stuff.  */
   stuff.  */
#define CPROC_NEXT_OFFSET 0
#define CPROC_NEXT_OFFSET 0
#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
#define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
#define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
#define CPROC_REPLY_SIZE (sizeof (mach_port_t))
#define CPROC_REPLY_SIZE (sizeof (mach_port_t))
#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
#define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
#define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
#define CPROC_WIRED_SIZE (sizeof (mach_port_t))
#define CPROC_WIRED_SIZE (sizeof (mach_port_t))
#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
 
 
/* Values for the state field in the cproc.  */
/* Values for the state field in the cproc.  */
#define CPROC_RUNNING   0
#define CPROC_RUNNING   0
#define CPROC_SWITCHING 1
#define CPROC_SWITCHING 1
#define CPROC_BLOCKED   2
#define CPROC_BLOCKED   2
#define CPROC_CONDWAIT  4
#define CPROC_CONDWAIT  4
 
 
/* For cproc and kernel thread mapping */
/* For cproc and kernel thread mapping */
typedef struct gdb_thread
typedef struct gdb_thread
  {
  {
    mach_port_t name;
    mach_port_t name;
    CORE_ADDR sp;
    CORE_ADDR sp;
    CORE_ADDR pc;
    CORE_ADDR pc;
    CORE_ADDR fp;
    CORE_ADDR fp;
    boolean_t in_emulator;
    boolean_t in_emulator;
    int slotid;
    int slotid;
 
 
    /* This is for the mthreads list.  It points to the cproc list.
    /* 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
       Perhaps the two lists should be merged (or perhaps it was a mistake
       to make them both use a struct gdb_thread).  */
       to make them both use a struct gdb_thread).  */
    struct gdb_thread *cproc;
    struct gdb_thread *cproc;
 
 
    /* These are for the cproc list, which is linked through the next field
    /* These are for the cproc list, which is linked through the next field
       of the struct gdb_thread.  */
       of the struct gdb_thread.  */
    char raw_cproc[CPROC_SIZE];
    char raw_cproc[CPROC_SIZE];
    /* The cthread which is pointed to by the incarnation field from the
    /* The cthread which is pointed to by the incarnation field from the
       cproc.  This points to the copy we've read into GDB.  */
       cproc.  This points to the copy we've read into GDB.  */
    cthread_t cthread;
    cthread_t cthread;
    /* Point back to the mthreads list.  */
    /* Point back to the mthreads list.  */
    int reverse_map;
    int reverse_map;
    struct gdb_thread *next;
    struct gdb_thread *next;
  }
  }
 *gdb_thread_t;
 *gdb_thread_t;
 
 
/*
/*
 * Actions for Mach exceptions.
 * Actions for Mach exceptions.
 *
 *
 * sigmap field maps the exception to corresponding Unix signal.
 * sigmap field maps the exception to corresponding Unix signal.
 *
 *
 * I do not know how to map the exception to unix signal
 * I do not know how to map the exception to unix signal
 * if SIG_UNKNOWN is specified.
 * if SIG_UNKNOWN is specified.
 */
 */
 
 
struct exception_list
struct exception_list
  {
  {
    char *name;
    char *name;
    boolean_t forward;
    boolean_t forward;
    boolean_t print;
    boolean_t print;
    int sigmap;
    int sigmap;
  }
  }
exception_map[] =
exception_map[] =
{
{
  {
  {
    "not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN
    "not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN
  }
  }
  ,
  ,
  {
  {
    "EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV
    "EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV
  }
  }
  ,
  ,
  {
  {
    "EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL
    "EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL
  }
  }
  ,
  ,
  {
  {
    "EXC_ARITHMETIC", FALSE, TRUE, SIGFPE
    "EXC_ARITHMETIC", FALSE, TRUE, SIGFPE
  }
  }
  ,
  ,
  {
  {
    "EXC_EMULATION", FALSE, TRUE, SIGEMT
    "EXC_EMULATION", FALSE, TRUE, SIGEMT
  }
  }
  ,                             /* ??? */
  ,                             /* ??? */
  {
  {
    "EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN
    "EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN
  }
  }
  ,
  ,
  {
  {
    "EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP
    "EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP
  }
  }
};
};
 
 
/* Mach exception table size */
/* Mach exception table size */
int max_exception = sizeof (exception_map) / sizeof (struct exception_list) - 1;
int max_exception = sizeof (exception_map) / sizeof (struct exception_list) - 1;
 
 
#define MAX_EXCEPTION max_exception
#define MAX_EXCEPTION max_exception
 
 
WAITTYPE wait_status;
WAITTYPE wait_status;
 
 
/* If you define this, intercepted bsd server calls will be
/* If you define this, intercepted bsd server calls will be
 * dumped while waiting the inferior to EXEC the correct
 * dumped while waiting the inferior to EXEC the correct
 * program
 * program
 */
 */
/* #define DUMP_SYSCALL         /* debugging interceptor */
/* #define DUMP_SYSCALL         /* debugging interceptor */
 
 
/* xx_debug() outputs messages if this is nonzero.
/* xx_debug() outputs messages if this is nonzero.
 * If > 1, DUMP_SYSCALL will dump message contents.
 * If > 1, DUMP_SYSCALL will dump message contents.
 */
 */
int debug_level = 0;
int debug_level = 0;
 
 
/* "Temporary" debug stuff */
/* "Temporary" debug stuff */
void
void
xx_debug (fmt, a, b, c)
xx_debug (fmt, a, b, c)
     char *fmt;
     char *fmt;
     int a, b, c;
     int a, b, c;
{
{
  if (debug_level)
  if (debug_level)
    warning (fmt, a, b, c);
    warning (fmt, a, b, c);
}
}
 
 
/* This is in libmach.a */
/* This is in libmach.a */
extern mach_port_t name_server_port;
extern mach_port_t name_server_port;
 
 
/* Set in catch_exception_raise */
/* Set in catch_exception_raise */
int stop_exception, stop_code, stop_subcode;
int stop_exception, stop_code, stop_subcode;
int stopped_in_exception;
int stopped_in_exception;
 
 
/* Thread that was the active thread when we stopped */
/* Thread that was the active thread when we stopped */
thread_t stop_thread = MACH_PORT_NULL;
thread_t stop_thread = MACH_PORT_NULL;
 
 
char *hostname = "";
char *hostname = "";
 
 
/* Set when task is attached or created */
/* Set when task is attached or created */
boolean_t emulator_present = FALSE;
boolean_t emulator_present = FALSE;
 
 
task_t inferior_task;
task_t inferior_task;
thread_t current_thread;
thread_t current_thread;
 
 
/* Exception ports for inferior task */
/* Exception ports for inferior task */
mach_port_t inferior_exception_port = MACH_PORT_NULL;
mach_port_t inferior_exception_port = MACH_PORT_NULL;
mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
 
 
/* task exceptions and notifications */
/* task exceptions and notifications */
mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
mach_port_t our_notify_port = MACH_PORT_NULL;
mach_port_t our_notify_port = MACH_PORT_NULL;
 
 
/* This is "inferior_wait_port_set" when not single stepping, and
/* This is "inferior_wait_port_set" when not single stepping, and
 *         "singlestepped_thread_port" when we are single stepping.
 *         "singlestepped_thread_port" when we are single stepping.
 *
 *
 * This is protected by a cleanup function: discard_single_step()
 * This is protected by a cleanup function: discard_single_step()
 */
 */
mach_port_t currently_waiting_for = MACH_PORT_NULL;
mach_port_t currently_waiting_for = MACH_PORT_NULL;
 
 
/* A port for external messages to gdb.
/* A port for external messages to gdb.
 * External in the meaning that they do not come
 * External in the meaning that they do not come
 * from the inferior_task, but rather from external
 * from the inferior_task, but rather from external
 * tasks.
 * tasks.
 *
 *
 * As a debugging feature:
 * As a debugging feature:
 * A debugger debugging another debugger can stop the
 * A debugger debugging another debugger can stop the
 * inferior debugger by the following command sequence
 * inferior debugger by the following command sequence
 * (without running external programs)
 * (without running external programs)
 *
 *
 *    (top-gdb) set stop_inferior_gdb ()
 *    (top-gdb) set stop_inferior_gdb ()
 *    (top-gdb) continue
 *    (top-gdb) continue
 */
 */
mach_port_t our_message_port = MACH_PORT_NULL;
mach_port_t our_message_port = MACH_PORT_NULL;
 
 
/* For single stepping */
/* For single stepping */
mach_port_t thread_exception_port = MACH_PORT_NULL;
mach_port_t thread_exception_port = MACH_PORT_NULL;
mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
 
 
/* For machid calls */
/* For machid calls */
mach_port_t mid_server = MACH_PORT_NULL;
mach_port_t mid_server = MACH_PORT_NULL;
mach_port_t mid_auth = MACH_PORT_NULL;
mach_port_t mid_auth = MACH_PORT_NULL;
 
 
/* If gdb thinks the inferior task is not suspended, it
/* If gdb thinks the inferior task is not suspended, it
 * must take suspend/abort the threads when it reads the state.
 * must take suspend/abort the threads when it reads the state.
 */
 */
int must_suspend_thread = 0;
int must_suspend_thread = 0;
 
 
/* When single stepping, we switch the port that mach_really_wait() listens to.
/* When single stepping, we switch the port that mach_really_wait() listens to.
 * This cleanup is a guard to prevent the port set from being left to
 * This cleanup is a guard to prevent the port set from being left to
 * the singlestepped_thread_port when error() is called.
 * the singlestepped_thread_port when error() is called.
 *  This is nonzero only when we are single stepping.
 *  This is nonzero only when we are single stepping.
 */
 */
#define NULL_CLEANUP (struct cleanup *)0
#define NULL_CLEANUP (struct cleanup *)0
struct cleanup *cleanup_step = NULL_CLEANUP;
struct cleanup *cleanup_step = NULL_CLEANUP;


 
 
static struct target_ops m3_ops;
static struct target_ops m3_ops;
 
 
static void m3_kill_inferior ();
static void m3_kill_inferior ();


#if 0
#if 0
#define MACH_TYPE_EXCEPTION_PORT        -1
#define MACH_TYPE_EXCEPTION_PORT        -1
#endif
#endif
 
 
/* Chain of ports to remember requested notifications. */
/* Chain of ports to remember requested notifications. */
 
 
struct port_chain
struct port_chain
  {
  {
    struct port_chain *next;
    struct port_chain *next;
    mach_port_t port;
    mach_port_t port;
    int type;
    int type;
    int mid;                    /* Now only valid with MACH_TYPE_THREAD and */
    int mid;                    /* Now only valid with MACH_TYPE_THREAD and */
    /*  MACH_TYPE_THREAD */
    /*  MACH_TYPE_THREAD */
  };
  };
typedef struct port_chain *port_chain_t;
typedef struct port_chain *port_chain_t;
 
 
/* Room for chain nodes comes from pchain_obstack */
/* Room for chain nodes comes from pchain_obstack */
struct obstack pchain_obstack;
struct obstack pchain_obstack;
struct obstack *port_chain_obstack = &pchain_obstack;
struct obstack *port_chain_obstack = &pchain_obstack;
 
 
/* For thread handling */
/* For thread handling */
struct obstack Cproc_obstack;
struct obstack Cproc_obstack;
struct obstack *cproc_obstack = &Cproc_obstack;
struct obstack *cproc_obstack = &Cproc_obstack;
 
 
/* the list of notified ports */
/* the list of notified ports */
port_chain_t notify_chain = (port_chain_t) NULL;
port_chain_t notify_chain = (port_chain_t) NULL;
 
 
port_chain_t
port_chain_t
port_chain_insert (list, name, type)
port_chain_insert (list, name, type)
     port_chain_t list;
     port_chain_t list;
     mach_port_t name;
     mach_port_t name;
     int type;
     int type;
{
{
  kern_return_t ret;
  kern_return_t ret;
  port_chain_t new;
  port_chain_t new;
  int mid;
  int mid;
 
 
  if (!MACH_PORT_VALID (name))
  if (!MACH_PORT_VALID (name))
    return list;
    return list;
 
 
  if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
  if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
    {
    {
      if (!MACH_PORT_VALID (mid_server))
      if (!MACH_PORT_VALID (mid_server))
        {
        {
          warning ("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);
                   name);
          mid = name;
          mid = name;
        }
        }
      else
      else
        {
        {
          ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
          ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
 
 
          if (ret != KERN_SUCCESS)
          if (ret != KERN_SUCCESS)
            {
            {
              warning ("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;
              mid = name;
            }
            }
        }
        }
    }
    }
  else
  else
    abort ();
    abort ();
 
 
  new = (port_chain_t) obstack_alloc (port_chain_obstack,
  new = (port_chain_t) obstack_alloc (port_chain_obstack,
                                      sizeof (struct port_chain));
                                      sizeof (struct port_chain));
  new->next = list;
  new->next = list;
  new->port = name;
  new->port = name;
  new->type = type;
  new->type = type;
  new->mid = mid;
  new->mid = mid;
 
 
  return new;
  return new;
}
}
 
 
port_chain_t
port_chain_t
port_chain_delete (list, elem)
port_chain_delete (list, elem)
     port_chain_t list;
     port_chain_t list;
     mach_port_t elem;
     mach_port_t elem;
{
{
  if (list)
  if (list)
    if (list->port == elem)
    if (list->port == elem)
      list = list->next;
      list = list->next;
    else
    else
      while (list->next)
      while (list->next)
        {
        {
          if (list->next->port == elem)
          if (list->next->port == elem)
            list->next = list->next->next;      /* GCd with obstack_free() */
            list->next = list->next->next;      /* GCd with obstack_free() */
          else
          else
            list = list->next;
            list = list->next;
        }
        }
  return list;
  return list;
}
}
 
 
void
void
port_chain_destroy (ostack)
port_chain_destroy (ostack)
     struct obstack *ostack;
     struct obstack *ostack;
{
{
  obstack_free (ostack, 0);
  obstack_free (ostack, 0);
  obstack_init (ostack);
  obstack_init (ostack);
}
}
 
 
port_chain_t
port_chain_t
port_chain_member (list, elem)
port_chain_member (list, elem)
     port_chain_t list;
     port_chain_t list;
     mach_port_t elem;
     mach_port_t elem;
{
{
  while (list)
  while (list)
    {
    {
      if (list->port == elem)
      if (list->port == elem)
        return list;
        return list;
      list = list->next;
      list = list->next;
    }
    }
  return (port_chain_t) NULL;
  return (port_chain_t) NULL;
}
}


int
int
map_port_name_to_mid (name, type)
map_port_name_to_mid (name, type)
     mach_port_t name;
     mach_port_t name;
     int type;
     int type;
{
{
  port_chain_t elem;
  port_chain_t elem;
 
 
  if (!MACH_PORT_VALID (name))
  if (!MACH_PORT_VALID (name))
    return -1;
    return -1;
 
 
  elem = port_chain_member (notify_chain, name);
  elem = port_chain_member (notify_chain, name);
 
 
  if (elem && (elem->type == type))
  if (elem && (elem->type == type))
    return elem->mid;
    return elem->mid;
 
 
  if (elem)
  if (elem)
    return -1;
    return -1;
 
 
  if (!MACH_PORT_VALID (mid_server))
  if (!MACH_PORT_VALID (mid_server))
    {
    {
      warning ("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);
               name);
      return -1;
      return -1;
    }
    }
  else
  else
    {
    {
      int mid;
      int mid;
      kern_return_t ret;
      kern_return_t ret;
 
 
      ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
      ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
 
 
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        {
        {
          warning ("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 -1;
        }
        }
      return mid;
      return mid;
    }
    }
}
}


/* Guard for currently_waiting_for and singlestepped_thread_port */
/* Guard for currently_waiting_for and singlestepped_thread_port */
static void
static void
discard_single_step (thread)
discard_single_step (thread)
     thread_t thread;
     thread_t thread;
{
{
  currently_waiting_for = inferior_wait_port_set;
  currently_waiting_for = inferior_wait_port_set;
 
 
  cleanup_step = NULL_CLEANUP;
  cleanup_step = NULL_CLEANUP;
  if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
  if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
    setup_single_step (thread, FALSE);
    setup_single_step (thread, FALSE);
}
}
 
 
setup_single_step (thread, start_step)
setup_single_step (thread, start_step)
     thread_t thread;
     thread_t thread;
     boolean_t start_step;
     boolean_t start_step;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (!MACH_PORT_VALID (thread))
  if (!MACH_PORT_VALID (thread))
    error ("Invalid thread supplied to setup_single_step");
    error ("Invalid thread supplied to setup_single_step");
  else
  else
    {
    {
      mach_port_t teport;
      mach_port_t teport;
 
 
      /* Get the current thread exception port */
      /* Get the current thread exception port */
      ret = thread_get_exception_port (thread, &teport);
      ret = thread_get_exception_port (thread, &teport);
      CHK ("Getting thread's exception port", ret);
      CHK ("Getting thread's exception port", ret);
 
 
      if (start_step)
      if (start_step)
        {
        {
          if (MACH_PORT_VALID (singlestepped_thread_port))
          if (MACH_PORT_VALID (singlestepped_thread_port))
            {
            {
              warning ("Singlestepped_thread_port (0x%x) is still valid?",
              warning ("Singlestepped_thread_port (0x%x) is still valid?",
                       singlestepped_thread_port);
                       singlestepped_thread_port);
              singlestepped_thread_port = MACH_PORT_NULL;
              singlestepped_thread_port = MACH_PORT_NULL;
            }
            }
 
 
          /* If we are already stepping this thread */
          /* If we are already stepping this thread */
          if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
          if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
            {
            {
              ret = mach_port_deallocate (mach_task_self (), teport);
              ret = mach_port_deallocate (mach_task_self (), teport);
              CHK ("Could not deallocate thread exception port", ret);
              CHK ("Could not deallocate thread exception port", ret);
            }
            }
          else
          else
            {
            {
              ret = thread_set_exception_port (thread, thread_exception_port);
              ret = thread_set_exception_port (thread, thread_exception_port);
              CHK ("Setting exception port for thread", ret);
              CHK ("Setting exception port for thread", ret);
#if 0
#if 0
              /* Insert thread exception port to wait port set */
              /* Insert thread exception port to wait port set */
              ret = mach_port_move_member (mach_task_self (),
              ret = mach_port_move_member (mach_task_self (),
                                           thread_exception_port,
                                           thread_exception_port,
                                           inferior_wait_port_set);
                                           inferior_wait_port_set);
              CHK ("Moving thread exception port to inferior_wait_port_set",
              CHK ("Moving thread exception port to inferior_wait_port_set",
                   ret);
                   ret);
#endif
#endif
              thread_saved_exception_port = teport;
              thread_saved_exception_port = teport;
            }
            }
 
 
          thread_trace (thread, TRUE);
          thread_trace (thread, TRUE);
 
 
          singlestepped_thread_port = thread_exception_port;
          singlestepped_thread_port = thread_exception_port;
          currently_waiting_for = singlestepped_thread_port;
          currently_waiting_for = singlestepped_thread_port;
          cleanup_step = make_cleanup (discard_single_step, thread);
          cleanup_step = make_cleanup (discard_single_step, thread);
        }
        }
      else
      else
        {
        {
          if (!MACH_PORT_VALID (teport))
          if (!MACH_PORT_VALID (teport))
            error ("Single stepped thread had an invalid exception port?");
            error ("Single stepped thread had an invalid exception port?");
 
 
          if (teport != thread_exception_port)
          if (teport != thread_exception_port)
            error ("Single stepped thread had an unknown exception port?");
            error ("Single stepped thread had an unknown exception port?");
 
 
          ret = mach_port_deallocate (mach_task_self (), teport);
          ret = mach_port_deallocate (mach_task_self (), teport);
          CHK ("Couldn't deallocate thread exception port", ret);
          CHK ("Couldn't deallocate thread exception port", ret);
#if 0
#if 0
          /* Remove thread exception port from wait port set */
          /* Remove thread exception port from wait port set */
          ret = mach_port_move_member (mach_task_self (),
          ret = mach_port_move_member (mach_task_self (),
                                       thread_exception_port,
                                       thread_exception_port,
                                       MACH_PORT_NULL);
                                       MACH_PORT_NULL);
          CHK ("Removing thread exception port from inferior_wait_port_set",
          CHK ("Removing thread exception port from inferior_wait_port_set",
               ret);
               ret);
#endif
#endif
          /* Restore thread's old exception port */
          /* Restore thread's old exception port */
          ret = thread_set_exception_port (thread,
          ret = thread_set_exception_port (thread,
                                           thread_saved_exception_port);
                                           thread_saved_exception_port);
          CHK ("Restoring stepped thread's exception port", ret);
          CHK ("Restoring stepped thread's exception port", ret);
 
 
          if (MACH_PORT_VALID (thread_saved_exception_port))
          if (MACH_PORT_VALID (thread_saved_exception_port))
            (void) mach_port_deallocate (mach_task_self (),
            (void) mach_port_deallocate (mach_task_self (),
                                         thread_saved_exception_port);
                                         thread_saved_exception_port);
 
 
          thread_trace (thread, FALSE);
          thread_trace (thread, FALSE);
 
 
          singlestepped_thread_port = MACH_PORT_NULL;
          singlestepped_thread_port = MACH_PORT_NULL;
          currently_waiting_for = inferior_wait_port_set;
          currently_waiting_for = inferior_wait_port_set;
          if (cleanup_step)
          if (cleanup_step)
            discard_cleanups (cleanup_step);
            discard_cleanups (cleanup_step);
        }
        }
    }
    }
}
}


static
static
request_notify (name, variant, type)
request_notify (name, variant, type)
     mach_port_t name;
     mach_port_t name;
     mach_msg_id_t variant;
     mach_msg_id_t variant;
     int type;
     int type;
{
{
  kern_return_t ret;
  kern_return_t ret;
  mach_port_t previous_port_dummy = MACH_PORT_NULL;
  mach_port_t previous_port_dummy = MACH_PORT_NULL;
 
 
  if (!MACH_PORT_VALID (name))
  if (!MACH_PORT_VALID (name))
    return;
    return;
 
 
  if (port_chain_member (notify_chain, name))
  if (port_chain_member (notify_chain, name))
    return;
    return;
 
 
  ret = mach_port_request_notification (mach_task_self (),
  ret = mach_port_request_notification (mach_task_self (),
                                        name,
                                        name,
                                        variant,
                                        variant,
                                        1,
                                        1,
                                        our_notify_port,
                                        our_notify_port,
                                        MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                        MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                        &previous_port_dummy);
                                        &previous_port_dummy);
  CHK ("Serious: request_notify failed", ret);
  CHK ("Serious: request_notify failed", ret);
 
 
  (void) mach_port_deallocate (mach_task_self (),
  (void) mach_port_deallocate (mach_task_self (),
                               previous_port_dummy);
                               previous_port_dummy);
 
 
  notify_chain = port_chain_insert (notify_chain, name, type);
  notify_chain = port_chain_insert (notify_chain, name, type);
}
}
 
 
reverse_msg_bits (msgp, type)
reverse_msg_bits (msgp, type)
     mach_msg_header_t *msgp;
     mach_msg_header_t *msgp;
     int type;
     int type;
{
{
  int rbits, lbits;
  int rbits, lbits;
  rbits = MACH_MSGH_BITS_REMOTE (msgp->msgh_bits);
  rbits = MACH_MSGH_BITS_REMOTE (msgp->msgh_bits);
  lbits = type;
  lbits = type;
  msgp->msgh_bits =
  msgp->msgh_bits =
    (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
    (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
    MACH_MSGH_BITS (lbits, rbits);
    MACH_MSGH_BITS (lbits, rbits);
}
}


/* On the third day He said:
/* On the third day He said:
 
 
   Let this be global
   Let this be global
   and then it was global.
   and then it was global.
 
 
   When creating the inferior fork, the
   When creating the inferior fork, the
   child code in inflow.c sets the name of the
   child code in inflow.c sets the name of the
   bootstrap_port in its address space to this
   bootstrap_port in its address space to this
   variable.
   variable.
 
 
   The name is transferred to our address space
   The name is transferred to our address space
   with mach3_read_inferior().
   with mach3_read_inferior().
 
 
   Thou shalt not do this with
   Thou shalt not do this with
   task_get_bootstrap_port() in this task, since
   task_get_bootstrap_port() in this task, since
   the name in the inferior task is different than
   the name in the inferior task is different than
   the one we get.
   the one we get.
 
 
   For blessed are the meek, as they shall inherit
   For blessed are the meek, as they shall inherit
   the address space.
   the address space.
 */
 */
mach_port_t original_server_port_name = MACH_PORT_NULL;
mach_port_t original_server_port_name = MACH_PORT_NULL;
 
 
 
 
/* Called from inferior after FORK but before EXEC */
/* Called from inferior after FORK but before EXEC */
static void
static void
m3_trace_me ()
m3_trace_me ()
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  /* Get the NAME of the bootstrap port in this task
  /* Get the NAME of the bootstrap port in this task
     so that GDB can read it */
     so that GDB can read it */
  ret = task_get_bootstrap_port (mach_task_self (),
  ret = task_get_bootstrap_port (mach_task_self (),
                                 &original_server_port_name);
                                 &original_server_port_name);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    abort ();
    abort ();
  ret = mach_port_deallocate (mach_task_self (),
  ret = mach_port_deallocate (mach_task_self (),
                              original_server_port_name);
                              original_server_port_name);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    abort ();
    abort ();
 
 
  /* Suspend this task to let the parent change my ports.
  /* Suspend this task to let the parent change my ports.
     Resumed by the debugger */
     Resumed by the debugger */
  ret = task_suspend (mach_task_self ());
  ret = task_suspend (mach_task_self ());
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    abort ();
    abort ();
}
}


/*
/*
 * Intercept system calls to Unix server.
 * Intercept system calls to Unix server.
 * After EXEC_COUNTER calls to exec(), return.
 * After EXEC_COUNTER calls to exec(), return.
 *
 *
 * Pre-assertion:  Child is suspended. (Not verified)
 * Pre-assertion:  Child is suspended. (Not verified)
 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
 */
 */
 
 
void
void
intercept_exec_calls (exec_counter)
intercept_exec_calls (exec_counter)
     int exec_counter;
     int exec_counter;
{
{
  int terminal_initted = 0;
  int terminal_initted = 0;
 
 
  struct syscall_msg_t
  struct syscall_msg_t
    {
    {
      mach_msg_header_t header;
      mach_msg_header_t header;
      mach_msg_type_t type;
      mach_msg_type_t type;
      char room[2000];          /* Enuff space */
      char room[2000];          /* Enuff space */
    };
    };
 
 
  struct syscall_msg_t syscall_in, syscall_out;
  struct syscall_msg_t syscall_in, syscall_out;
 
 
  mach_port_t fake_server;
  mach_port_t fake_server;
  mach_port_t original_server_send;
  mach_port_t original_server_send;
  mach_port_t original_exec_reply;
  mach_port_t original_exec_reply;
  mach_port_t exec_reply;
  mach_port_t exec_reply;
  mach_port_t exec_reply_send;
  mach_port_t exec_reply_send;
  mach_msg_type_name_t acquired;
  mach_msg_type_name_t acquired;
  mach_port_t emulator_server_port_name;
  mach_port_t emulator_server_port_name;
  struct task_basic_info info;
  struct task_basic_info info;
  mach_msg_type_number_t info_count;
  mach_msg_type_number_t info_count;
 
 
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (exec_counter <= 0)
  if (exec_counter <= 0)
    return;                     /* We are already set up in the correct program */
    return;                     /* We are already set up in the correct program */
 
 
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            &fake_server);
                            &fake_server);
  CHK ("create inferior_fake_server port failed", ret);
  CHK ("create inferior_fake_server port failed", ret);
 
 
  /* Wait for inferior_task to suspend itself */
  /* Wait for inferior_task to suspend itself */
  while (1)
  while (1)
    {
    {
      info_count = sizeof (info);
      info_count = sizeof (info);
      ret = task_info (inferior_task,
      ret = task_info (inferior_task,
                       TASK_BASIC_INFO,
                       TASK_BASIC_INFO,
                       (task_info_t) & info,
                       (task_info_t) & info,
                       &info_count);
                       &info_count);
      CHK ("Task info", ret);
      CHK ("Task info", ret);
 
 
      if (info.suspend_count)
      if (info.suspend_count)
        break;
        break;
 
 
      /* Note that the definition of the parameter was undefined
      /* Note that the definition of the parameter was undefined
       * at the time of this writing, so I just use an `ad hoc' value.
       * at the time of this writing, so I just use an `ad hoc' value.
       */
       */
      (void) swtch_pri (42);    /* Universal Priority Value */
      (void) swtch_pri (42);    /* Universal Priority Value */
    }
    }
 
 
  /* Read the inferior's bootstrap port name */
  /* Read the inferior's bootstrap port name */
  if (!mach3_read_inferior (&original_server_port_name,
  if (!mach3_read_inferior (&original_server_port_name,
                            &original_server_port_name,
                            &original_server_port_name,
                            sizeof (original_server_port_name)))
                            sizeof (original_server_port_name)))
    error ("Can't read inferior task bootstrap port name");
    error ("Can't read inferior task bootstrap port name");
 
 
  /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
  /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
  /*      Should get refs, and set them back when restoring */
  /*      Should get refs, and set them back when restoring */
  /* Steal the original bsd server send right from inferior */
  /* Steal the original bsd server send right from inferior */
  ret = mach_port_extract_right (inferior_task,
  ret = mach_port_extract_right (inferior_task,
                                 original_server_port_name,
                                 original_server_port_name,
                                 MACH_MSG_TYPE_MOVE_SEND,
                                 MACH_MSG_TYPE_MOVE_SEND,
                                 &original_server_send,
                                 &original_server_send,
                                 &acquired);
                                 &acquired);
  CHK ("mach_port_extract_right (bsd server send)", ret);
  CHK ("mach_port_extract_right (bsd server send)", ret);
 
 
  if (acquired != MACH_MSG_TYPE_PORT_SEND)
  if (acquired != MACH_MSG_TYPE_PORT_SEND)
    error ("Incorrect right extracted, send right to bsd server excpected");
    error ("Incorrect right extracted, send right to bsd server excpected");
 
 
  ret = mach_port_insert_right (inferior_task,
  ret = mach_port_insert_right (inferior_task,
                                original_server_port_name,
                                original_server_port_name,
                                fake_server,
                                fake_server,
                                MACH_MSG_TYPE_MAKE_SEND);
                                MACH_MSG_TYPE_MAKE_SEND);
  CHK ("mach_port_insert_right (fake server send)", ret);
  CHK ("mach_port_insert_right (fake server send)", ret);
 
 
  xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
  xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
            fake_server,
            fake_server,
            original_server_port_name, original_server_send);
            original_server_port_name, original_server_send);
 
 
  /* A receive right to the reply generated by unix server exec() request */
  /* A receive right to the reply generated by unix server exec() request */
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            &exec_reply);
                            &exec_reply);
  CHK ("create intercepted_reply_port port failed", ret);
  CHK ("create intercepted_reply_port port failed", ret);
 
 
  /* Pass this send right to Unix server so it replies to us after exec() */
  /* Pass this send right to Unix server so it replies to us after exec() */
  ret = mach_port_extract_right (mach_task_self (),
  ret = mach_port_extract_right (mach_task_self (),
                                 exec_reply,
                                 exec_reply,
                                 MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                 MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                 &exec_reply_send,
                                 &exec_reply_send,
                                 &acquired);
                                 &acquired);
  CHK ("mach_port_extract_right (exec_reply)", ret);
  CHK ("mach_port_extract_right (exec_reply)", ret);
 
 
  if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
  if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
    error ("Incorrect right extracted, send once excpected for exec reply");
    error ("Incorrect right extracted, send once excpected for exec reply");
 
 
  ret = mach_port_move_member (mach_task_self (),
  ret = mach_port_move_member (mach_task_self (),
                               fake_server,
                               fake_server,
                               inferior_wait_port_set);
                               inferior_wait_port_set);
  CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
  CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
 
 
  xx_debug ("syscall fake server set up, resuming inferior\n");
  xx_debug ("syscall fake server set up, resuming inferior\n");
 
 
  ret = task_resume (inferior_task);
  ret = task_resume (inferior_task);
  CHK ("task_resume (startup)", ret);
  CHK ("task_resume (startup)", ret);
 
 
  /* Read requests from the inferior.
  /* Read requests from the inferior.
     Pass directly through everything else except exec() calls.
     Pass directly through everything else except exec() calls.
   */
   */
  while (exec_counter > 0)
  while (exec_counter > 0)
    {
    {
      ret = mach_msg (&syscall_in.header,       /* header */
      ret = mach_msg (&syscall_in.header,       /* header */
                      MACH_RCV_MSG,     /* options */
                      MACH_RCV_MSG,     /* options */
                      0, /* send size */
                      0, /* send size */
                      sizeof (struct syscall_msg_t),    /* receive size */
                      sizeof (struct syscall_msg_t),    /* receive size */
                      inferior_wait_port_set,   /* receive_name */
                      inferior_wait_port_set,   /* receive_name */
                      MACH_MSG_TIMEOUT_NONE,
                      MACH_MSG_TIMEOUT_NONE,
                      MACH_PORT_NULL);
                      MACH_PORT_NULL);
      CHK ("mach_msg (intercepted sycall)", ret);
      CHK ("mach_msg (intercepted sycall)", ret);
 
 
#ifdef DUMP_SYSCALL
#ifdef DUMP_SYSCALL
      print_msg (&syscall_in.header);
      print_msg (&syscall_in.header);
#endif
#endif
 
 
      /* ASSERT : msgh_local_port == fake_server */
      /* ASSERT : msgh_local_port == fake_server */
 
 
      if (notify_server (&syscall_in.header, &syscall_out.header))
      if (notify_server (&syscall_in.header, &syscall_out.header))
        error ("received a notify while intercepting syscalls");
        error ("received a notify while intercepting syscalls");
 
 
      if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
      if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
        {
        {
          xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
          xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
          if (exec_counter == 1)
          if (exec_counter == 1)
            {
            {
              original_exec_reply = syscall_in.header.msgh_remote_port;
              original_exec_reply = syscall_in.header.msgh_remote_port;
              syscall_in.header.msgh_remote_port = exec_reply_send;
              syscall_in.header.msgh_remote_port = exec_reply_send;
            }
            }
 
 
          if (!terminal_initted)
          if (!terminal_initted)
            {
            {
              /* Now that the child has exec'd we know it has already set its
              /* Now that the child has exec'd we know it has already set its
                 process group.  On POSIX systems, tcsetpgrp will fail with
                 process group.  On POSIX systems, tcsetpgrp will fail with
                 EPERM if we try it before the child's setpgid.  */
                 EPERM if we try it before the child's setpgid.  */
 
 
              /* Set up the "saved terminal modes" of the inferior
              /* Set up the "saved terminal modes" of the inferior
                 based on what modes we are starting it with.  */
                 based on what modes we are starting it with.  */
              target_terminal_init ();
              target_terminal_init ();
 
 
              /* Install inferior's terminal modes.  */
              /* Install inferior's terminal modes.  */
              target_terminal_inferior ();
              target_terminal_inferior ();
 
 
              terminal_initted = 1;
              terminal_initted = 1;
            }
            }
 
 
          exec_counter--;
          exec_counter--;
        }
        }
 
 
      syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
      syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
      syscall_in.header.msgh_remote_port = original_server_send;
      syscall_in.header.msgh_remote_port = original_server_send;
 
 
      reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
      reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
 
 
      ret = mach_msg_send (&syscall_in.header);
      ret = mach_msg_send (&syscall_in.header);
      CHK ("Forwarded syscall", ret);
      CHK ("Forwarded syscall", ret);
    }
    }
 
 
  ret = mach_port_move_member (mach_task_self (),
  ret = mach_port_move_member (mach_task_self (),
                               fake_server,
                               fake_server,
                               MACH_PORT_NULL);
                               MACH_PORT_NULL);
  CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
  CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
 
 
  ret = mach_port_move_member (mach_task_self (),
  ret = mach_port_move_member (mach_task_self (),
                               exec_reply,
                               exec_reply,
                               inferior_wait_port_set);
                               inferior_wait_port_set);
  CHK ("Moving exec_reply to inferior_wait_port_set", ret);
  CHK ("Moving exec_reply to inferior_wait_port_set", ret);
 
 
  ret = mach_msg (&syscall_in.header,   /* header */
  ret = mach_msg (&syscall_in.header,   /* header */
                  MACH_RCV_MSG, /* options */
                  MACH_RCV_MSG, /* options */
                  0,             /* send size */
                  0,             /* send size */
                  sizeof (struct syscall_msg_t),        /* receive size */
                  sizeof (struct syscall_msg_t),        /* receive size */
                  inferior_wait_port_set,       /* receive_name */
                  inferior_wait_port_set,       /* receive_name */
                  MACH_MSG_TIMEOUT_NONE,
                  MACH_MSG_TIMEOUT_NONE,
                  MACH_PORT_NULL);
                  MACH_PORT_NULL);
  CHK ("mach_msg (exec reply)", ret);
  CHK ("mach_msg (exec reply)", ret);
 
 
  ret = task_suspend (inferior_task);
  ret = task_suspend (inferior_task);
  CHK ("Suspending inferior after last exec", ret);
  CHK ("Suspending inferior after last exec", ret);
 
 
  must_suspend_thread = 0;
  must_suspend_thread = 0;
 
 
  xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
  xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
 
 
#ifdef DUMP_SYSCALL
#ifdef DUMP_SYSCALL
  print_msg (&syscall_in.header);
  print_msg (&syscall_in.header);
#endif
#endif
 
 
  /* Message should appear as if it came from the unix server */
  /* Message should appear as if it came from the unix server */
  syscall_in.header.msgh_local_port = MACH_PORT_NULL;
  syscall_in.header.msgh_local_port = MACH_PORT_NULL;
 
 
  /*  and go to the inferior task original reply port */
  /*  and go to the inferior task original reply port */
  syscall_in.header.msgh_remote_port = original_exec_reply;
  syscall_in.header.msgh_remote_port = original_exec_reply;
 
 
  reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
  reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
 
 
  ret = mach_msg_send (&syscall_in.header);
  ret = mach_msg_send (&syscall_in.header);
  CHK ("Forwarding exec reply to inferior", ret);
  CHK ("Forwarding exec reply to inferior", ret);
 
 
  /* Garbage collect */
  /* Garbage collect */
  ret = mach_port_deallocate (inferior_task,
  ret = mach_port_deallocate (inferior_task,
                              original_server_port_name);
                              original_server_port_name);
  CHK ("deallocating fake server send right", ret);
  CHK ("deallocating fake server send right", ret);
 
 
  ret = mach_port_insert_right (inferior_task,
  ret = mach_port_insert_right (inferior_task,
                                original_server_port_name,
                                original_server_port_name,
                                original_server_send,
                                original_server_send,
                                MACH_MSG_TYPE_MOVE_SEND);
                                MACH_MSG_TYPE_MOVE_SEND);
  CHK ("Restoring the original bsd server send right", ret);
  CHK ("Restoring the original bsd server send right", ret);
 
 
  ret = mach_port_destroy (mach_task_self (),
  ret = mach_port_destroy (mach_task_self (),
                           fake_server);
                           fake_server);
  fake_server = MACH_PORT_DEAD;
  fake_server = MACH_PORT_DEAD;
  CHK ("mach_port_destroy (fake_server)", ret);
  CHK ("mach_port_destroy (fake_server)", ret);
 
 
  ret = mach_port_destroy (mach_task_self (),
  ret = mach_port_destroy (mach_task_self (),
                           exec_reply);
                           exec_reply);
  exec_reply = MACH_PORT_DEAD;
  exec_reply = MACH_PORT_DEAD;
  CHK ("mach_port_destroy (exec_reply)", ret);
  CHK ("mach_port_destroy (exec_reply)", ret);
 
 
  xx_debug ("Done with exec call interception\n");
  xx_debug ("Done with exec call interception\n");
}
}
 
 
void
void
consume_send_rights (thread_list, thread_count)
consume_send_rights (thread_list, thread_count)
     thread_array_t thread_list;
     thread_array_t thread_list;
     int thread_count;
     int thread_count;
{
{
  int index;
  int index;
 
 
  if (!thread_count)
  if (!thread_count)
    return;
    return;
 
 
  for (index = 0; index < thread_count; index++)
  for (index = 0; index < thread_count; index++)
    {
    {
      /* Since thread kill command kills threads, don't check ret */
      /* Since thread kill command kills threads, don't check ret */
      (void) mach_port_deallocate (mach_task_self (),
      (void) mach_port_deallocate (mach_task_self (),
                                   thread_list[index]);
                                   thread_list[index]);
    }
    }
}
}
 
 
/* suspend/abort/resume a thread. */
/* suspend/abort/resume a thread. */
setup_thread (thread, what)
setup_thread (thread, what)
     mach_port_t thread;
     mach_port_t thread;
     int what;
     int what;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (what)
  if (what)
    {
    {
      ret = thread_suspend (thread);
      ret = thread_suspend (thread);
      CHK ("setup_thread thread_suspend", ret);
      CHK ("setup_thread thread_suspend", ret);
 
 
      ret = thread_abort (thread);
      ret = thread_abort (thread);
      CHK ("setup_thread thread_abort", ret);
      CHK ("setup_thread thread_abort", ret);
    }
    }
  else
  else
    {
    {
      ret = thread_resume (thread);
      ret = thread_resume (thread);
      CHK ("setup_thread thread_resume", ret);
      CHK ("setup_thread thread_resume", ret);
    }
    }
}
}
 
 
int
int
map_slot_to_mid (slot, threads, thread_count)
map_slot_to_mid (slot, threads, thread_count)
     int slot;
     int slot;
     thread_array_t threads;
     thread_array_t threads;
     int thread_count;
     int thread_count;
{
{
  kern_return_t ret;
  kern_return_t ret;
  int deallocate = 0;
  int deallocate = 0;
  int index;
  int index;
  int mid;
  int mid;
 
 
  if (!threads)
  if (!threads)
    {
    {
      deallocate++;
      deallocate++;
      ret = task_threads (inferior_task, &threads, &thread_count);
      ret = task_threads (inferior_task, &threads, &thread_count);
      CHK ("Can not select a thread from a dead task", ret);
      CHK ("Can not select a thread from a dead task", ret);
    }
    }
 
 
  if (slot < 0 || slot >= thread_count)
  if (slot < 0 || slot >= thread_count)
    {
    {
      if (deallocate)
      if (deallocate)
        {
        {
          consume_send_rights (threads, thread_count);
          consume_send_rights (threads, thread_count);
          (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
          (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
                                (thread_count * sizeof (mach_port_t)));
                                (thread_count * sizeof (mach_port_t)));
        }
        }
      if (slot < 0)
      if (slot < 0)
        error ("invalid slot number");
        error ("invalid slot number");
      else
      else
        return -(slot + 1);
        return -(slot + 1);
    }
    }
 
 
  mid = map_port_name_to_mid (threads[slot], MACH_TYPE_THREAD);
  mid = map_port_name_to_mid (threads[slot], MACH_TYPE_THREAD);
 
 
  if (deallocate)
  if (deallocate)
    {
    {
      consume_send_rights (threads, thread_count);
      consume_send_rights (threads, thread_count);
      (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
      (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
                            (thread_count * sizeof (mach_port_t)));
                            (thread_count * sizeof (mach_port_t)));
    }
    }
 
 
  return mid;
  return mid;
}
}
 
 
static int
static int
parse_thread_id (arg, thread_count, slots)
parse_thread_id (arg, thread_count, slots)
     char *arg;
     char *arg;
     int thread_count;
     int thread_count;
     int slots;
     int slots;
{
{
  kern_return_t ret;
  kern_return_t ret;
  int mid;
  int mid;
  int slot;
  int slot;
  int index;
  int index;
 
 
  if (arg == 0)
  if (arg == 0)
    return 0;
    return 0;
 
 
  while (*arg && (*arg == ' ' || *arg == '\t'))
  while (*arg && (*arg == ' ' || *arg == '\t'))
    arg++;
    arg++;
 
 
  if (!*arg)
  if (!*arg)
    return 0;
    return 0;
 
 
  /* Currently parse MID and @SLOTNUMBER */
  /* Currently parse MID and @SLOTNUMBER */
  if (*arg != '@')
  if (*arg != '@')
    {
    {
      mid = atoi (arg);
      mid = atoi (arg);
      if (mid <= 0)
      if (mid <= 0)
        error ("valid thread mid expected");
        error ("valid thread mid expected");
      return mid;
      return mid;
    }
    }
 
 
  arg++;
  arg++;
  slot = atoi (arg);
  slot = atoi (arg);
 
 
  if (slot < 0)
  if (slot < 0)
    error ("invalid slot number");
    error ("invalid slot number");
 
 
  /* If you want slot numbers to remain slot numbers, set slots.
  /* If you want slot numbers to remain slot numbers, set slots.
 
 
   * Well, since 0 is reserved, return the ordinal number
   * Well, since 0 is reserved, return the ordinal number
   * of the thread rather than the slot number. Awk, this
   * of the thread rather than the slot number. Awk, this
   * counts as a kludge.
   * counts as a kludge.
   */
   */
  if (slots)
  if (slots)
    return -(slot + 1);
    return -(slot + 1);
 
 
  if (thread_count && slot >= thread_count)
  if (thread_count && slot >= thread_count)
    return -(slot + 1);
    return -(slot + 1);
 
 
  mid = map_slot_to_mid (slot);
  mid = map_slot_to_mid (slot);
 
 
  return mid;
  return mid;
}
}
 
 
/* THREAD_ID 0 is special; it selects the first kernel
/* THREAD_ID 0 is special; it selects the first kernel
 * thread from the list (i.e. SLOTNUMBER 0)
 * thread from the list (i.e. SLOTNUMBER 0)
 * This is used when starting the program with 'run' or when attaching.
 * This is used when starting the program with 'run' or when attaching.
 *
 *
 * If FLAG is 0 the context is not changed, and the registers, frame, etc
 * If FLAG is 0 the context is not changed, and the registers, frame, etc
 * will continue to describe the old thread.
 * will continue to describe the old thread.
 *
 *
 * If FLAG is nonzero, really select the thread.
 * If FLAG is nonzero, really select the thread.
 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
 *
 *
 */
 */
kern_return_t
kern_return_t
select_thread (task, thread_id, flag)
select_thread (task, thread_id, flag)
     mach_port_t task;
     mach_port_t task;
     int thread_id;
     int thread_id;
     int flag;
     int flag;
{
{
  thread_array_t thread_list;
  thread_array_t thread_list;
  int thread_count;
  int thread_count;
  kern_return_t ret;
  kern_return_t ret;
  int index;
  int index;
  thread_t new_thread = MACH_PORT_NULL;
  thread_t new_thread = MACH_PORT_NULL;
 
 
  if (thread_id < 0)
  if (thread_id < 0)
    error ("Can't select cprocs without kernel thread");
    error ("Can't select cprocs without kernel thread");
 
 
  ret = task_threads (task, &thread_list, &thread_count);
  ret = task_threads (task, &thread_list, &thread_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("Can not select a thread from a dead task");
      warning ("Can not select a thread from a dead task");
      m3_kill_inferior ();
      m3_kill_inferior ();
      return KERN_FAILURE;
      return KERN_FAILURE;
    }
    }
 
 
  if (thread_count == 0)
  if (thread_count == 0)
    {
    {
      /* The task can not do anything anymore, but it still
      /* The task can not do anything anymore, but it still
       * exists as a container for memory and ports.
       * exists as a container for memory and ports.
       */
       */
      registers_changed ();
      registers_changed ();
      warning ("Task %d has no threads",
      warning ("Task %d has no threads",
               map_port_name_to_mid (task, MACH_TYPE_TASK));
               map_port_name_to_mid (task, MACH_TYPE_TASK));
      current_thread = MACH_PORT_NULL;
      current_thread = MACH_PORT_NULL;
      (void) vm_deallocate (mach_task_self (),
      (void) vm_deallocate (mach_task_self (),
                            (vm_address_t) thread_list,
                            (vm_address_t) thread_list,
                            (thread_count * sizeof (mach_port_t)));
                            (thread_count * sizeof (mach_port_t)));
      return KERN_FAILURE;
      return KERN_FAILURE;
    }
    }
 
 
  if (!thread_id || flag == 2)
  if (!thread_id || flag == 2)
    {
    {
      /* First thread or a slotnumber */
      /* First thread or a slotnumber */
      if (!thread_id)
      if (!thread_id)
        new_thread = thread_list[0];
        new_thread = thread_list[0];
      else
      else
        {
        {
          if (thread_id < thread_count)
          if (thread_id < thread_count)
            new_thread = thread_list[thread_id];
            new_thread = thread_list[thread_id];
          else
          else
            {
            {
              (void) vm_deallocate (mach_task_self (),
              (void) vm_deallocate (mach_task_self (),
                                    (vm_address_t) thread_list,
                                    (vm_address_t) thread_list,
                                    (thread_count * sizeof (mach_port_t)));
                                    (thread_count * sizeof (mach_port_t)));
              error ("No such thread slot number : %d", thread_id);
              error ("No such thread slot number : %d", thread_id);
            }
            }
        }
        }
    }
    }
  else
  else
    {
    {
      for (index = 0; index < thread_count; index++)
      for (index = 0; index < thread_count; index++)
        if (thread_id == map_port_name_to_mid (thread_list[index],
        if (thread_id == map_port_name_to_mid (thread_list[index],
                                               MACH_TYPE_THREAD))
                                               MACH_TYPE_THREAD))
          {
          {
            new_thread = thread_list[index];
            new_thread = thread_list[index];
            index = -1;
            index = -1;
            break;
            break;
          }
          }
 
 
      if (index != -1)
      if (index != -1)
        error ("No thread with mid %d", thread_id);
        error ("No thread with mid %d", thread_id);
    }
    }
 
 
  /* Notify when the selected thread dies */
  /* Notify when the selected thread dies */
  request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
  request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
 
 
  ret = vm_deallocate (mach_task_self (),
  ret = vm_deallocate (mach_task_self (),
                       (vm_address_t) thread_list,
                       (vm_address_t) thread_list,
                       (thread_count * sizeof (mach_port_t)));
                       (thread_count * sizeof (mach_port_t)));
  CHK ("vm_deallocate", ret);
  CHK ("vm_deallocate", ret);
 
 
  if (!flag)
  if (!flag)
    current_thread = new_thread;
    current_thread = new_thread;
  else
  else
    {
    {
#if 0
#if 0
      if (MACH_PORT_VALID (current_thread))
      if (MACH_PORT_VALID (current_thread))
        {
        {
          /* Store the gdb's view of the thread we are deselecting
          /* Store the gdb's view of the thread we are deselecting
 
 
           * @@ I think gdb updates registers immediately when they are
           * @@ I think gdb updates registers immediately when they are
           * changed, so don't do this.
           * changed, so don't do this.
           */
           */
          ret = thread_abort (current_thread);
          ret = thread_abort (current_thread);
          CHK ("Could not abort system calls when saving state of old thread",
          CHK ("Could not abort system calls when saving state of old thread",
               ret);
               ret);
          target_prepare_to_store ();
          target_prepare_to_store ();
          target_store_registers (-1);
          target_store_registers (-1);
        }
        }
#endif
#endif
 
 
      registers_changed ();
      registers_changed ();
 
 
      current_thread = new_thread;
      current_thread = new_thread;
 
 
      ret = thread_abort (current_thread);
      ret = thread_abort (current_thread);
      CHK ("Could not abort system calls when selecting a thread", ret);
      CHK ("Could not abort system calls when selecting a thread", ret);
 
 
      stop_pc = read_pc ();
      stop_pc = read_pc ();
      flush_cached_frames ();
      flush_cached_frames ();
 
 
      select_frame (get_current_frame (), 0);
      select_frame (get_current_frame (), 0);
    }
    }
 
 
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
/*
/*
 * Switch to use thread named NEW_THREAD.
 * Switch to use thread named NEW_THREAD.
 * Return it's MID
 * Return it's MID
 */
 */
int
int
switch_to_thread (new_thread)
switch_to_thread (new_thread)
     thread_t new_thread;
     thread_t new_thread;
{
{
  thread_t saved_thread = current_thread;
  thread_t saved_thread = current_thread;
  int mid;
  int mid;
 
 
  mid = map_port_name_to_mid (new_thread,
  mid = map_port_name_to_mid (new_thread,
                              MACH_TYPE_THREAD);
                              MACH_TYPE_THREAD);
  if (mid == -1)
  if (mid == -1)
    warning ("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)
  else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
    {
    {
      if (current_thread)
      if (current_thread)
        current_thread = saved_thread;
        current_thread = saved_thread;
      error ("Could not select thread %d", mid);
      error ("Could not select thread %d", mid);
    }
    }
 
 
  return mid;
  return mid;
}
}
 
 
/* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
/* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
 * Note that the registers are not yet valid in the inferior task.
 * Note that the registers are not yet valid in the inferior task.
 */
 */
static int
static int
m3_trace_him (pid)
m3_trace_him (pid)
     int pid;
     int pid;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  push_target (&m3_ops);
  push_target (&m3_ops);
 
 
  inferior_task = task_by_pid (pid);
  inferior_task = task_by_pid (pid);
 
 
  if (!MACH_PORT_VALID (inferior_task))
  if (!MACH_PORT_VALID (inferior_task))
    error ("Can not map Unix pid %d to Mach task", pid);
    error ("Can not map Unix pid %d to Mach task", pid);
 
 
  /* Clean up previous notifications and create new ones */
  /* Clean up previous notifications and create new ones */
  setup_notify_port (1);
  setup_notify_port (1);
 
 
  /* When notification appears, the inferior task has died */
  /* When notification appears, the inferior task has died */
  request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
  request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
 
 
  emulator_present = have_emulator_p (inferior_task);
  emulator_present = have_emulator_p (inferior_task);
 
 
  /* By default, select the first thread,
  /* By default, select the first thread,
   * If task has no threads, gives a warning
   * If task has no threads, gives a warning
   * Does not fetch registers, since they are not yet valid.
   * Does not fetch registers, since they are not yet valid.
   */
   */
  select_thread (inferior_task, 0, 0);
  select_thread (inferior_task, 0, 0);
 
 
  inferior_exception_port = MACH_PORT_NULL;
  inferior_exception_port = MACH_PORT_NULL;
 
 
  setup_exception_port ();
  setup_exception_port ();
 
 
  xx_debug ("Now the debugged task is created\n");
  xx_debug ("Now the debugged task is created\n");
 
 
  /* One trap to exec the shell, one to exec the program being debugged.  */
  /* One trap to exec the shell, one to exec the program being debugged.  */
  intercept_exec_calls (2);
  intercept_exec_calls (2);
 
 
  return pid;
  return pid;
}
}
 
 
setup_exception_port ()
setup_exception_port ()
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            &inferior_exception_port);
                            &inferior_exception_port);
  CHK ("mach_port_allocate", ret);
  CHK ("mach_port_allocate", ret);
 
 
  /* add send right */
  /* add send right */
  ret = mach_port_insert_right (mach_task_self (),
  ret = mach_port_insert_right (mach_task_self (),
                                inferior_exception_port,
                                inferior_exception_port,
                                inferior_exception_port,
                                inferior_exception_port,
                                MACH_MSG_TYPE_MAKE_SEND);
                                MACH_MSG_TYPE_MAKE_SEND);
  CHK ("mach_port_insert_right", ret);
  CHK ("mach_port_insert_right", ret);
 
 
  ret = mach_port_move_member (mach_task_self (),
  ret = mach_port_move_member (mach_task_self (),
                               inferior_exception_port,
                               inferior_exception_port,
                               inferior_wait_port_set);
                               inferior_wait_port_set);
  CHK ("mach_port_move_member", ret);
  CHK ("mach_port_move_member", ret);
 
 
  ret = task_get_special_port (inferior_task,
  ret = task_get_special_port (inferior_task,
                               TASK_EXCEPTION_PORT,
                               TASK_EXCEPTION_PORT,
                               &inferior_old_exception_port);
                               &inferior_old_exception_port);
  CHK ("task_get_special_port(old exc)", ret);
  CHK ("task_get_special_port(old exc)", ret);
 
 
  ret = task_set_special_port (inferior_task,
  ret = task_set_special_port (inferior_task,
                               TASK_EXCEPTION_PORT,
                               TASK_EXCEPTION_PORT,
                               inferior_exception_port);
                               inferior_exception_port);
  CHK ("task_set_special_port", ret);
  CHK ("task_set_special_port", ret);
 
 
  ret = mach_port_deallocate (mach_task_self (),
  ret = mach_port_deallocate (mach_task_self (),
                              inferior_exception_port);
                              inferior_exception_port);
  CHK ("mack_port_deallocate", ret);
  CHK ("mack_port_deallocate", ret);
 
 
#if 0
#if 0
  /* When notify appears, the inferior_task's exception
  /* When notify appears, the inferior_task's exception
   * port has been destroyed.
   * port has been destroyed.
   *
   *
   * Not used, since the dead_name_notification already
   * Not used, since the dead_name_notification already
   * appears when task dies.
   * appears when task dies.
   *
   *
   */
   */
  request_notify (inferior_exception_port,
  request_notify (inferior_exception_port,
                  MACH_NOTIFY_NO_SENDERS,
                  MACH_NOTIFY_NO_SENDERS,
                  MACH_TYPE_EXCEPTION_PORT);
                  MACH_TYPE_EXCEPTION_PORT);
#endif
#endif
}
}
 
 
/* Nonzero if gdb is waiting for a message */
/* Nonzero if gdb is waiting for a message */
int mach_really_waiting;
int mach_really_waiting;
 
 
/* Wait for the inferior to stop for some reason.
/* Wait for the inferior to stop for some reason.
   - Loop on notifications until inferior_task dies.
   - Loop on notifications until inferior_task dies.
   - Loop on exceptions until stopped_in_exception comes true.
   - Loop on exceptions until stopped_in_exception comes true.
   (e.g. we receive a single step trace trap)
   (e.g. we receive a single step trace trap)
   - a message arrives to gdb's message port
   - a message arrives to gdb's message port
 
 
   There is no other way to exit this loop.
   There is no other way to exit this loop.
 
 
   Returns the inferior_pid for rest of gdb.
   Returns the inferior_pid for rest of gdb.
   Side effects: Set *OURSTATUS.  */
   Side effects: Set *OURSTATUS.  */
int
int
mach_really_wait (pid, ourstatus)
mach_really_wait (pid, ourstatus)
     int pid;
     int pid;
     struct target_waitstatus *ourstatus;
     struct target_waitstatus *ourstatus;
{
{
  kern_return_t ret;
  kern_return_t ret;
  int w;
  int w;
 
 
  struct msg
  struct msg
    {
    {
      mach_msg_header_t header;
      mach_msg_header_t header;
      mach_msg_type_t foo;
      mach_msg_type_t foo;
      int data[8000];
      int data[8000];
    }
    }
  in_msg, out_msg;
  in_msg, out_msg;
 
 
  /* Either notify (death), exception or message can stop the inferior */
  /* Either notify (death), exception or message can stop the inferior */
  stopped_in_exception = FALSE;
  stopped_in_exception = FALSE;
 
 
  while (1)
  while (1)
    {
    {
      QUIT;
      QUIT;
 
 
      stop_exception = stop_code = stop_subcode = -1;
      stop_exception = stop_code = stop_subcode = -1;
      stop_thread = MACH_PORT_NULL;
      stop_thread = MACH_PORT_NULL;
 
 
      mach_really_waiting = 1;
      mach_really_waiting = 1;
      ret = mach_msg (&in_msg.header,   /* header */
      ret = mach_msg (&in_msg.header,   /* header */
                      MACH_RCV_MSG,     /* options */
                      MACH_RCV_MSG,     /* options */
                      0, /* send size */
                      0, /* send size */
                      sizeof (struct msg),      /* receive size */
                      sizeof (struct msg),      /* receive size */
                      currently_waiting_for,    /* receive name */
                      currently_waiting_for,    /* receive name */
                      MACH_MSG_TIMEOUT_NONE,
                      MACH_MSG_TIMEOUT_NONE,
                      MACH_PORT_NULL);
                      MACH_PORT_NULL);
      mach_really_waiting = 0;
      mach_really_waiting = 0;
      CHK ("mach_msg (receive)", ret);
      CHK ("mach_msg (receive)", ret);
 
 
      /* Check if we received a notify of the childs' death */
      /* Check if we received a notify of the childs' death */
      if (notify_server (&in_msg.header, &out_msg.header))
      if (notify_server (&in_msg.header, &out_msg.header))
        {
        {
          /* If inferior_task is null then the inferior has
          /* If inferior_task is null then the inferior has
             gone away and we want to return to command level.
             gone away and we want to return to command level.
             Otherwise it was just an informative message and we
             Otherwise it was just an informative message and we
             need to look to see if there are any more. */
             need to look to see if there are any more. */
          if (inferior_task != MACH_PORT_NULL)
          if (inferior_task != MACH_PORT_NULL)
            continue;
            continue;
          else
          else
            {
            {
              /* Collect Unix exit status for gdb */
              /* Collect Unix exit status for gdb */
 
 
              wait3 (&w, WNOHANG, 0);
              wait3 (&w, WNOHANG, 0);
 
 
              /* This mess is here to check that the rest of
              /* This mess is here to check that the rest of
               * gdb knows that the inferior died. It also
               * gdb knows that the inferior died. It also
               * tries to hack around the fact that Mach 3.0 (mk69)
               * tries to hack around the fact that Mach 3.0 (mk69)
               * unix server (ux28) does not always know what
               * unix server (ux28) does not always know what
               * has happened to it's children when mach-magic
               * has happened to it's children when mach-magic
               * is applied on them.
               * is applied on them.
               */
               */
              if ((!WIFEXITED (w) && WIFSTOPPED (w)) ||
              if ((!WIFEXITED (w) && WIFSTOPPED (w)) ||
                  (WIFEXITED (w) && WEXITSTATUS (w) > 0377))
                  (WIFEXITED (w) && WEXITSTATUS (w) > 0377))
                {
                {
                  WSETEXIT (w, 0);
                  WSETEXIT (w, 0);
                  warning ("Using exit value 0 for terminated task");
                  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. */
                  /* Signals cause problems. Warn the user. */
                  if (sig != SIGKILL)   /* Bad luck if garbage matches this */
                  if (sig != SIGKILL)   /* Bad luck if garbage matches this */
                    warning ("The terminating signal stuff may be nonsense");
                    warning ("The terminating signal stuff may be nonsense");
                  else if (sig > NSIG)
                  else if (sig > NSIG)
                    {
                    {
                      WSETEXIT (w, 0);
                      WSETEXIT (w, 0);
                      warning ("Using exit value 0 for terminated task");
                      warning ("Using exit value 0 for terminated task");
                    }
                    }
                }
                }
              store_waitstatus (ourstatus, w);
              store_waitstatus (ourstatus, w);
              return inferior_pid;
              return inferior_pid;
            }
            }
        }
        }
 
 
      /* Hmm. Check for exception, as it was not a notification.
      /* Hmm. Check for exception, as it was not a notification.
         exc_server() does an upcall to catch_exception_raise()
         exc_server() does an upcall to catch_exception_raise()
         if this rpc is an exception. Further actions are decided
         if this rpc is an exception. Further actions are decided
         there.
         there.
       */
       */
      if (!exc_server (&in_msg.header, &out_msg.header))
      if (!exc_server (&in_msg.header, &out_msg.header))
        {
        {
 
 
          /* Not an exception, check for message.
          /* Not an exception, check for message.
 
 
           * Messages don't come from the inferior, or if they
           * Messages don't come from the inferior, or if they
           * do they better be asynchronous or it will hang.
           * do they better be asynchronous or it will hang.
           */
           */
          if (gdb_message_server (&in_msg.header))
          if (gdb_message_server (&in_msg.header))
            continue;
            continue;
 
 
          error ("Unrecognized message received in mach_really_wait");
          error ("Unrecognized message received in mach_really_wait");
        }
        }
 
 
      /* Send the reply of the exception rpc to the suspended task */
      /* Send the reply of the exception rpc to the suspended task */
      ret = mach_msg_send (&out_msg.header);
      ret = mach_msg_send (&out_msg.header);
      CHK ("mach_msg_send (exc reply)", ret);
      CHK ("mach_msg_send (exc reply)", ret);
 
 
      if (stopped_in_exception)
      if (stopped_in_exception)
        {
        {
          /* Get unix state. May be changed in mach3_exception_actions() */
          /* 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);
          store_waitstatus (ourstatus, w);
          return inferior_pid;
          return inferior_pid;
        }
        }
    }
    }
}
}
 
 
/* Called by macro DO_QUIT() in utils.c(quit).
/* Called by macro DO_QUIT() in utils.c(quit).
 * This is called just before calling error() to return to command level
 * This is called just before calling error() to return to command level
 */
 */
void
void
mach3_quit ()
mach3_quit ()
{
{
  int mid;
  int mid;
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (mach_really_waiting)
  if (mach_really_waiting)
    {
    {
      ret = task_suspend (inferior_task);
      ret = task_suspend (inferior_task);
 
 
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        {
        {
          warning ("Could not suspend task for interrupt: %s",
          warning ("Could not suspend task for interrupt: %s",
                   mach_error_string (ret));
                   mach_error_string (ret));
          mach_really_waiting = 0;
          mach_really_waiting = 0;
          return;
          return;
        }
        }
    }
    }
 
 
  must_suspend_thread = 0;
  must_suspend_thread = 0;
  mach_really_waiting = 0;
  mach_really_waiting = 0;
 
 
  mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
  mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
  if (mid == -1)
  if (mid == -1)
    {
    {
      warning ("Selecting first existing kernel thread");
      warning ("Selecting first existing kernel thread");
      mid = 0;
      mid = 0;
    }
    }
 
 
  current_thread = MACH_PORT_NULL;      /* Force setup */
  current_thread = MACH_PORT_NULL;      /* Force setup */
  select_thread (inferior_task, mid, 1);
  select_thread (inferior_task, mid, 1);
 
 
  return;
  return;
}
}
 
 
#if 0
#if 0
/* bogus bogus bogus.  It is NOT OK to quit out of target_wait.  */
/* bogus bogus bogus.  It is NOT OK to quit out of target_wait.  */
 
 
/* If ^C is typed when we are waiting for a message
/* If ^C is typed when we are waiting for a message
 * and your Unix server is able to notice that we
 * and your Unix server is able to notice that we
 * should quit now.
 * should quit now.
 *
 *
 * Called by REQUEST_QUIT() from utils.c(request_quit)
 * Called by REQUEST_QUIT() from utils.c(request_quit)
 */
 */
void
void
mach3_request_quit ()
mach3_request_quit ()
{
{
  if (mach_really_waiting)
  if (mach_really_waiting)
    immediate_quit = 1;
    immediate_quit = 1;
}
}
#endif
#endif
 
 
/*
/*
 * Gdb message server.
 * Gdb message server.
 * Currently implemented is the STOP message, that causes
 * Currently implemented is the STOP message, that causes
 * gdb to return to the command level like ^C had been typed from terminal.
 * gdb to return to the command level like ^C had been typed from terminal.
 */
 */
int
int
gdb_message_server (InP)
gdb_message_server (InP)
     mach_msg_header_t *InP;
     mach_msg_header_t *InP;
{
{
  kern_return_t ret;
  kern_return_t ret;
  int mid;
  int mid;
 
 
  if (InP->msgh_local_port == our_message_port)
  if (InP->msgh_local_port == our_message_port)
    {
    {
      /* A message coming to our_message_port. Check validity */
      /* A message coming to our_message_port. Check validity */
      switch (InP->msgh_id)
      switch (InP->msgh_id)
        {
        {
 
 
        case GDB_MESSAGE_ID_STOP:
        case GDB_MESSAGE_ID_STOP:
          ret = task_suspend (inferior_task);
          ret = task_suspend (inferior_task);
          if (ret != KERN_SUCCESS)
          if (ret != KERN_SUCCESS)
            warning ("Could not suspend task for stop message: %s",
            warning ("Could not suspend task for stop message: %s",
                     mach_error_string (ret));
                     mach_error_string (ret));
 
 
          /* QUIT in mach_really_wait() loop. */
          /* QUIT in mach_really_wait() loop. */
          request_quit (0);
          request_quit (0);
          break;
          break;
 
 
        default:
        default:
          warning ("Invalid message id %d received, ignored.",
          warning ("Invalid message id %d received, ignored.",
                   InP->msgh_id);
                   InP->msgh_id);
          break;
          break;
        }
        }
 
 
      return 1;
      return 1;
    }
    }
 
 
  /* Message not handled by this server */
  /* Message not handled by this server */
  return 0;
  return 0;
}
}
 
 
/* NOTE: This is not an RPC call. It is a simpleroutine.
/* NOTE: This is not an RPC call. It is a simpleroutine.
 
 
 * This is not called from this gdb code.
 * This is not called from this gdb code.
 *
 *
 * It may be called by another debugger to cause this
 * It may be called by another debugger to cause this
 * debugger to enter command level:
 * debugger to enter command level:
 *
 *
 *            (gdb) set stop_inferior_gdb ()
 *            (gdb) set stop_inferior_gdb ()
 *            (gdb) continue
 *            (gdb) continue
 *
 *
 * External program "stop-gdb" implements this also.
 * External program "stop-gdb" implements this also.
 */
 */
void
void
stop_inferior_gdb ()
stop_inferior_gdb ()
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  /* Code generated by mig, with minor cleanups :-)
  /* Code generated by mig, with minor cleanups :-)
 
 
   * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
   * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
   */
   */
 
 
  typedef struct
  typedef struct
    {
    {
      mach_msg_header_t Head;
      mach_msg_header_t Head;
    }
    }
  Request;
  Request;
 
 
  Request Mess;
  Request Mess;
 
 
  register Request *InP = &Mess;
  register Request *InP = &Mess;
 
 
  InP->Head.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
  InP->Head.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
 
 
  /* msgh_size passed as argument */
  /* msgh_size passed as argument */
  InP->Head.msgh_remote_port = our_message_port;
  InP->Head.msgh_remote_port = our_message_port;
  InP->Head.msgh_local_port = MACH_PORT_NULL;
  InP->Head.msgh_local_port = MACH_PORT_NULL;
  InP->Head.msgh_seqno = 0;
  InP->Head.msgh_seqno = 0;
  InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
  InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
 
 
  ret = mach_msg (&InP->Head,
  ret = mach_msg (&InP->Head,
                  MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
                  MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
                  sizeof (Request),
                  sizeof (Request),
                  0,
                  0,
                  MACH_PORT_NULL,
                  MACH_PORT_NULL,
                  MACH_MSG_TIMEOUT_NONE,
                  MACH_MSG_TIMEOUT_NONE,
                  MACH_PORT_NULL);
                  MACH_PORT_NULL);
}
}
 
 
#ifdef THREAD_ALLOWED_TO_BREAK
#ifdef THREAD_ALLOWED_TO_BREAK
/*
/*
 * Return 1 if the MID specifies the thread that caused the
 * Return 1 if the MID specifies the thread that caused the
 * last exception.
 * last exception.
 *  Since catch_exception_raise() selects the thread causing
 *  Since catch_exception_raise() selects the thread causing
 * the last exception to current_thread, we just check that
 * the last exception to current_thread, we just check that
 * it is selected and the last exception was a breakpoint.
 * it is selected and the last exception was a breakpoint.
 */
 */
int
int
mach_thread_for_breakpoint (mid)
mach_thread_for_breakpoint (mid)
     int mid;
     int mid;
{
{
  int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
  int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
 
 
  if (mid < 0)
  if (mid < 0)
    {
    {
      mid = map_slot_to_mid (-(mid + 1), 0, 0);
      mid = map_slot_to_mid (-(mid + 1), 0, 0);
      if (mid < 0)
      if (mid < 0)
        return 0;                /* Don't stop, no such slot */
        return 0;                /* Don't stop, no such slot */
    }
    }
 
 
  if (!mid || cmid == -1)
  if (!mid || cmid == -1)
    return 1;                   /* stop */
    return 1;                   /* stop */
 
 
  return cmid == mid && stop_exception == EXC_BREAKPOINT;
  return cmid == mid && stop_exception == EXC_BREAKPOINT;
}
}
#endif /* THREAD_ALLOWED_TO_BREAK */
#endif /* THREAD_ALLOWED_TO_BREAK */
 
 
#ifdef THREAD_PARSE_ID
#ifdef THREAD_PARSE_ID
/*
/*
 * Map a thread id string (MID or a @SLOTNUMBER)
 * Map a thread id string (MID or a @SLOTNUMBER)
 * to a thread-id.
 * to a thread-id.
 *
 *
 *   0  matches all threads.
 *   0  matches all threads.
 *   Otherwise the meaning is defined only in this file.
 *   Otherwise the meaning is defined only in this file.
 *   (mach_thread_for_breakpoint uses it)
 *   (mach_thread_for_breakpoint uses it)
 *
 *
 * @@ This allows non-existent MIDs to be specified.
 * @@ This allows non-existent MIDs to be specified.
 *    It now also allows non-existent slots to be
 *    It now also allows non-existent slots to be
 *    specified. (Slot numbers stored are negative,
 *    specified. (Slot numbers stored are negative,
 *    and the magnitude is one greater than the actual
 *    and the magnitude is one greater than the actual
 *    slot index. (Since 0 is reserved))
 *    slot index. (Since 0 is reserved))
 */
 */
int
int
mach_thread_parse_id (arg)
mach_thread_parse_id (arg)
     char *arg;
     char *arg;
{
{
  int mid;
  int mid;
  if (arg == 0)
  if (arg == 0)
    error ("thread id excpected");
    error ("thread id excpected");
  mid = parse_thread_id (arg, 0, 1);
  mid = parse_thread_id (arg, 0, 1);
 
 
  return mid;
  return mid;
}
}
#endif /* THREAD_PARSE_ID */
#endif /* THREAD_PARSE_ID */
 
 
#ifdef THREAD_OUTPUT_ID
#ifdef THREAD_OUTPUT_ID
char *
char *
mach_thread_output_id (mid)
mach_thread_output_id (mid)
     int mid;
     int mid;
{
{
  static char foobar[20];
  static char foobar[20];
 
 
  if (mid > 0)
  if (mid > 0)
    sprintf (foobar, "mid %d", mid);
    sprintf (foobar, "mid %d", mid);
  else if (mid < 0)
  else if (mid < 0)
    sprintf (foobar, "@%d", -(mid + 1));
    sprintf (foobar, "@%d", -(mid + 1));
  else
  else
    sprintf (foobar, "*any thread*");
    sprintf (foobar, "*any thread*");
 
 
  return foobar;
  return foobar;
}
}
#endif /* THREAD_OUTPUT_ID */
#endif /* THREAD_OUTPUT_ID */
 
 
/* Called with hook PREPARE_TO_PROCEED() from infrun.c.
/* Called with hook PREPARE_TO_PROCEED() from infrun.c.
 
 
 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
 *
 *
 *  if SELECT_IT is nonzero, reselect the thread that was active when
 *  if SELECT_IT is nonzero, reselect the thread that was active when
 *  we stopped at a breakpoint.
 *  we stopped at a breakpoint.
 *
 *
 */
 */
 
 
mach3_prepare_to_proceed (select_it)
mach3_prepare_to_proceed (select_it)
     int select_it;
     int select_it;
{
{
  if (stop_thread &&
  if (stop_thread &&
      stop_thread != current_thread &&
      stop_thread != current_thread &&
      stop_exception == EXC_BREAKPOINT)
      stop_exception == EXC_BREAKPOINT)
    {
    {
      int mid;
      int mid;
 
 
      if (!select_it)
      if (!select_it)
        return 1;
        return 1;
 
 
      mid = switch_to_thread (stop_thread);
      mid = switch_to_thread (stop_thread);
 
 
      return 1;
      return 1;
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
/* this stuff here is an upcall via libmach/excServer.c
/* this stuff here is an upcall via libmach/excServer.c
   and mach_really_wait which does the actual upcall.
   and mach_really_wait which does the actual upcall.
 
 
   The code will pass the exception to the inferior if:
   The code will pass the exception to the inferior if:
 
 
   - The task that signaled is not the inferior task
   - The task that signaled is not the inferior task
   (e.g. when debugging another debugger)
   (e.g. when debugging another debugger)
 
 
   - The user has explicitely requested to pass on the exceptions.
   - The user has explicitely requested to pass on the exceptions.
   (e.g to the default unix exception handler, which maps
   (e.g to the default unix exception handler, which maps
   exceptions to signals, or the user has her own exception handler)
   exceptions to signals, or the user has her own exception handler)
 
 
   - If the thread that signaled is being single-stepped and it
   - If the thread that signaled is being single-stepped and it
   has set it's own exception port and the exception is not
   has set it's own exception port and the exception is not
   EXC_BREAKPOINT. (Maybe this is not desirable?)
   EXC_BREAKPOINT. (Maybe this is not desirable?)
 */
 */
 
 
kern_return_t
kern_return_t
catch_exception_raise (port, thread, task, exception, code, subcode)
catch_exception_raise (port, thread, task, exception, code, subcode)
     mach_port_t port;
     mach_port_t port;
     thread_t thread;
     thread_t thread;
     task_t task;
     task_t task;
     int exception, code, subcode;
     int exception, code, subcode;
{
{
  kern_return_t ret;
  kern_return_t ret;
  boolean_t signal_thread;
  boolean_t signal_thread;
  int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
  int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
 
 
  if (!MACH_PORT_VALID (thread))
  if (!MACH_PORT_VALID (thread))
    {
    {
      /* If the exception was sent and thread dies before we
      /* If the exception was sent and thread dies before we
         receive it, THREAD will be MACH_PORT_DEAD
         receive it, THREAD will be MACH_PORT_DEAD
       */
       */
 
 
      current_thread = thread = MACH_PORT_NULL;
      current_thread = thread = MACH_PORT_NULL;
      error ("Received exception from nonexistent thread");
      error ("Received exception from nonexistent thread");
    }
    }
 
 
  /* Check if the task died in transit.
  /* Check if the task died in transit.
   * @@ Isn't the thread also invalid in such case?
   * @@ Isn't the thread also invalid in such case?
   */
   */
  if (!MACH_PORT_VALID (task))
  if (!MACH_PORT_VALID (task))
    {
    {
      current_thread = thread = MACH_PORT_NULL;
      current_thread = thread = MACH_PORT_NULL;
      error ("Received exception from nonexistent task");
      error ("Received exception from nonexistent task");
    }
    }
 
 
  if (exception < 0 || exception > MAX_EXCEPTION)
  if (exception < 0 || exception > MAX_EXCEPTION)
    internal_error ("catch_exception_raise: unknown exception code %d thread %d",
    internal_error ("catch_exception_raise: unknown exception code %d thread %d",
                    exception,
                    exception,
                    mid);
                    mid);
 
 
  if (!MACH_PORT_VALID (inferior_task))
  if (!MACH_PORT_VALID (inferior_task))
    error ("got an exception, but inferior_task is null or dead");
    error ("got an exception, but inferior_task is null or dead");
 
 
  stop_exception = exception;
  stop_exception = exception;
  stop_code = code;
  stop_code = code;
  stop_subcode = subcode;
  stop_subcode = subcode;
  stop_thread = thread;
  stop_thread = thread;
 
 
  signal_thread = exception != EXC_BREAKPOINT &&
  signal_thread = exception != EXC_BREAKPOINT &&
    port == singlestepped_thread_port &&
    port == singlestepped_thread_port &&
    MACH_PORT_VALID (thread_saved_exception_port);
    MACH_PORT_VALID (thread_saved_exception_port);
 
 
  /* If it was not our inferior or if we want to forward
  /* If it was not our inferior or if we want to forward
   * the exception to the inferior's handler, do it here
   * the exception to the inferior's handler, do it here
   *
   *
   * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
   * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
   */
   */
  if (task != inferior_task ||
  if (task != inferior_task ||
      signal_thread ||
      signal_thread ||
      exception_map[exception].forward)
      exception_map[exception].forward)
    {
    {
      mach_port_t eport = inferior_old_exception_port;
      mach_port_t eport = inferior_old_exception_port;
 
 
      if (signal_thread)
      if (signal_thread)
        {
        {
          /*
          /*
             GDB now forwards the exeption to thread's original handler,
             GDB now forwards the exeption to thread's original handler,
             since the user propably knows what he is doing.
             since the user propably knows what he is doing.
             Give a message, though.
             Give a message, though.
           */
           */
 
 
          mach3_exception_actions ((WAITTYPE *) NULL, TRUE, "Thread");
          mach3_exception_actions ((WAITTYPE *) NULL, TRUE, "Thread");
          eport = thread_saved_exception_port;
          eport = thread_saved_exception_port;
        }
        }
 
 
      /* Send the exception to the original handler */
      /* Send the exception to the original handler */
      ret = exception_raise (eport,
      ret = exception_raise (eport,
                             thread,
                             thread,
                             task,
                             task,
                             exception,
                             exception,
                             code,
                             code,
                             subcode);
                             subcode);
 
 
      (void) mach_port_deallocate (mach_task_self (), task);
      (void) mach_port_deallocate (mach_task_self (), task);
      (void) mach_port_deallocate (mach_task_self (), thread);
      (void) mach_port_deallocate (mach_task_self (), thread);
 
 
      /* If we come here, we don't want to trace any more, since we
      /* If we come here, we don't want to trace any more, since we
       * will never stop for tracing anyway.
       * will never stop for tracing anyway.
       */
       */
      discard_single_step (thread);
      discard_single_step (thread);
 
 
      /* Do not stop the inferior */
      /* Do not stop the inferior */
      return ret;
      return ret;
    }
    }
 
 
  /* Now gdb handles the exception */
  /* Now gdb handles the exception */
  stopped_in_exception = TRUE;
  stopped_in_exception = TRUE;
 
 
  ret = task_suspend (task);
  ret = task_suspend (task);
  CHK ("Error suspending inferior after exception", ret);
  CHK ("Error suspending inferior after exception", ret);
 
 
  must_suspend_thread = 0;
  must_suspend_thread = 0;
 
 
  if (current_thread != thread)
  if (current_thread != thread)
    {
    {
      if (MACH_PORT_VALID (singlestepped_thread_port))
      if (MACH_PORT_VALID (singlestepped_thread_port))
        /* Cleanup discards single stepping */
        /* Cleanup discards single stepping */
        error ("Exception from thread %d while singlestepping thread %d",
        error ("Exception from thread %d while singlestepping thread %d",
               mid,
               mid,
               map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
               map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
 
 
      /* Then select the thread that caused the exception */
      /* Then select the thread that caused the exception */
      if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
      if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
        error ("Could not select thread %d causing exception", mid);
        error ("Could not select thread %d causing exception", mid);
      else
      else
        warning ("Gdb selected thread %d", mid);
        warning ("Gdb selected thread %d", mid);
    }
    }
 
 
  /* If we receive an exception that is not breakpoint
  /* If we receive an exception that is not breakpoint
   * exception, we interrupt the single step and return to
   * exception, we interrupt the single step and return to
   * debugger. Trace condition is cleared.
   * debugger. Trace condition is cleared.
   */
   */
  if (MACH_PORT_VALID (singlestepped_thread_port))
  if (MACH_PORT_VALID (singlestepped_thread_port))
    {
    {
      if (stop_exception != EXC_BREAKPOINT)
      if (stop_exception != EXC_BREAKPOINT)
        warning ("Single step interrupted by exception");
        warning ("Single step interrupted by exception");
      else if (port == singlestepped_thread_port)
      else if (port == singlestepped_thread_port)
        {
        {
          /* Single step exception occurred, remove trace bit
          /* Single step exception occurred, remove trace bit
           * and return to gdb.
           * and return to gdb.
           */
           */
          if (!MACH_PORT_VALID (current_thread))
          if (!MACH_PORT_VALID (current_thread))
            error ("Single stepped thread is not valid");
            error ("Single stepped thread is not valid");
 
 
          /* Resume threads, but leave the task suspended */
          /* Resume threads, but leave the task suspended */
          resume_all_threads (0);
          resume_all_threads (0);
        }
        }
      else
      else
        warning ("Breakpoint while single stepping?");
        warning ("Breakpoint while single stepping?");
 
 
      discard_single_step (current_thread);
      discard_single_step (current_thread);
    }
    }
 
 
  (void) mach_port_deallocate (mach_task_self (), task);
  (void) mach_port_deallocate (mach_task_self (), task);
  (void) mach_port_deallocate (mach_task_self (), thread);
  (void) mach_port_deallocate (mach_task_self (), thread);
 
 
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}


int
int
port_valid (port, mask)
port_valid (port, mask)
     mach_port_t port;
     mach_port_t port;
     int mask;
     int mask;
{
{
  kern_return_t ret;
  kern_return_t ret;
  mach_port_type_t type;
  mach_port_type_t type;
 
 
  ret = mach_port_type (mach_task_self (),
  ret = mach_port_type (mach_task_self (),
                        port,
                        port,
                        &type);
                        &type);
  if (ret != KERN_SUCCESS || (type & mask) != mask)
  if (ret != KERN_SUCCESS || (type & mask) != mask)
    return 0;
    return 0;
  return 1;
  return 1;
}
}


/* @@ No vm read cache implemented yet */
/* @@ No vm read cache implemented yet */
boolean_t vm_read_cache_valid = FALSE;
boolean_t vm_read_cache_valid = FALSE;
 
 
/*
/*
 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
 * in gdb's address space.
 * in gdb's address space.
 *
 *
 * Return 0 on failure; number of bytes read otherwise.
 * Return 0 on failure; number of bytes read otherwise.
 */
 */
int
int
mach3_read_inferior (addr, myaddr, length)
mach3_read_inferior (addr, myaddr, length)
     CORE_ADDR addr;
     CORE_ADDR addr;
     char *myaddr;
     char *myaddr;
     int length;
     int length;
{
{
  kern_return_t ret;
  kern_return_t ret;
  vm_address_t low_address = (vm_address_t) trunc_page (addr);
  vm_address_t low_address = (vm_address_t) trunc_page (addr);
  vm_size_t aligned_length =
  vm_size_t aligned_length =
  (vm_size_t) round_page (addr + length) - low_address;
  (vm_size_t) round_page (addr + length) - low_address;
  pointer_t copied_memory;
  pointer_t copied_memory;
  int copy_count;
  int copy_count;
 
 
  /* Get memory from inferior with page aligned addresses */
  /* Get memory from inferior with page aligned addresses */
  ret = vm_read (inferior_task,
  ret = vm_read (inferior_task,
                 low_address,
                 low_address,
                 aligned_length,
                 aligned_length,
                 &copied_memory,
                 &copied_memory,
                 &copy_count);
                 &copy_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      /* the problem is that the inferior might be killed for whatever reason
      /* the problem is that the inferior might be killed for whatever reason
       * before we go to mach_really_wait. This is one place that ought to
       * before we go to mach_really_wait. This is one place that ought to
       * catch many of those errors.
       * catch many of those errors.
       * @@ A better fix would be to make all external events to GDB
       * @@ A better fix would be to make all external events to GDB
       * to arrive via a SINGLE port set. (Including user input!)
       * to arrive via a SINGLE port set. (Including user input!)
       */
       */
 
 
      if (!port_valid (inferior_task, MACH_PORT_TYPE_SEND))
      if (!port_valid (inferior_task, MACH_PORT_TYPE_SEND))
        {
        {
          m3_kill_inferior ();
          m3_kill_inferior ();
          error ("Inferior killed (task port invalid)");
          error ("Inferior killed (task port invalid)");
        }
        }
      else
      else
        {
        {
#ifdef OSF
#ifdef OSF
          extern int errno;
          extern int errno;
          /* valprint.c gives nicer format if this does not
          /* valprint.c gives nicer format if this does not
             screw it. Eamonn seems to like this, so I enable
             screw it. Eamonn seems to like this, so I enable
             it if OSF is defined...
             it if OSF is defined...
           */
           */
          warning ("[read inferior %x failed: %s]",
          warning ("[read inferior %x failed: %s]",
                   addr, mach_error_string (ret));
                   addr, mach_error_string (ret));
          errno = 0;
          errno = 0;
#endif
#endif
          return 0;
          return 0;
        }
        }
    }
    }
 
 
  memcpy (myaddr, (char *) addr - low_address + copied_memory, length);
  memcpy (myaddr, (char *) addr - low_address + copied_memory, length);
 
 
  ret = vm_deallocate (mach_task_self (),
  ret = vm_deallocate (mach_task_self (),
                       copied_memory,
                       copied_memory,
                       copy_count);
                       copy_count);
  CHK ("mach3_read_inferior vm_deallocate failed", ret);
  CHK ("mach3_read_inferior vm_deallocate failed", ret);
 
 
  return length;
  return length;
}
}
 
 
#ifdef __STDC__
#ifdef __STDC__
#define CHK_GOTO_OUT(str,ret) \
#define CHK_GOTO_OUT(str,ret) \
  do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
  do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
#else
#else
#define CHK_GOTO_OUT(str,ret) \
#define CHK_GOTO_OUT(str,ret) \
  do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
  do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
#endif
#endif
 
 
struct vm_region_list
struct vm_region_list
{
{
  struct vm_region_list *next;
  struct vm_region_list *next;
  vm_prot_t protection;
  vm_prot_t protection;
  vm_address_t start;
  vm_address_t start;
  vm_size_t length;
  vm_size_t length;
};
};
 
 
struct obstack region_obstack;
struct obstack region_obstack;
 
 
/*
/*
 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
 * in gdb's address space.
 * in gdb's address space.
 */
 */
int
int
mach3_write_inferior (addr, myaddr, length)
mach3_write_inferior (addr, myaddr, length)
     CORE_ADDR addr;
     CORE_ADDR addr;
     char *myaddr;
     char *myaddr;
     int length;
     int length;
{
{
  kern_return_t ret;
  kern_return_t ret;
  vm_address_t low_address = (vm_address_t) trunc_page (addr);
  vm_address_t low_address = (vm_address_t) trunc_page (addr);
  vm_size_t aligned_length =
  vm_size_t aligned_length =
  (vm_size_t) round_page (addr + length) - low_address;
  (vm_size_t) round_page (addr + length) - low_address;
  pointer_t copied_memory;
  pointer_t copied_memory;
  int copy_count;
  int copy_count;
  int deallocate = 0;
  int deallocate = 0;
 
 
  char *errstr = "Bug in mach3_write_inferior";
  char *errstr = "Bug in mach3_write_inferior";
 
 
  struct vm_region_list *region_element;
  struct vm_region_list *region_element;
  struct vm_region_list *region_head = (struct vm_region_list *) NULL;
  struct vm_region_list *region_head = (struct vm_region_list *) NULL;
 
 
  /* Get memory from inferior with page aligned addresses */
  /* Get memory from inferior with page aligned addresses */
  ret = vm_read (inferior_task,
  ret = vm_read (inferior_task,
                 low_address,
                 low_address,
                 aligned_length,
                 aligned_length,
                 &copied_memory,
                 &copied_memory,
                 &copy_count);
                 &copy_count);
  CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
  CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
 
 
  deallocate++;
  deallocate++;
 
 
  memcpy ((char *) addr - low_address + copied_memory, myaddr, length);
  memcpy ((char *) addr - low_address + copied_memory, myaddr, length);
 
 
  obstack_init (&region_obstack);
  obstack_init (&region_obstack);
 
 
  /* Do writes atomically.
  /* Do writes atomically.
   * First check for holes and unwritable memory.
   * First check for holes and unwritable memory.
   */
   */
  {
  {
    vm_size_t remaining_length = aligned_length;
    vm_size_t remaining_length = aligned_length;
    vm_address_t region_address = low_address;
    vm_address_t region_address = low_address;
 
 
    struct vm_region_list *scan;
    struct vm_region_list *scan;
 
 
    while (region_address < low_address + aligned_length)
    while (region_address < low_address + aligned_length)
      {
      {
        vm_prot_t protection;
        vm_prot_t protection;
        vm_prot_t max_protection;
        vm_prot_t max_protection;
        vm_inherit_t inheritance;
        vm_inherit_t inheritance;
        boolean_t shared;
        boolean_t shared;
        mach_port_t object_name;
        mach_port_t object_name;
        vm_offset_t offset;
        vm_offset_t offset;
        vm_size_t region_length = remaining_length;
        vm_size_t region_length = remaining_length;
        vm_address_t old_address = region_address;
        vm_address_t old_address = region_address;
 
 
        ret = vm_region (inferior_task,
        ret = vm_region (inferior_task,
                         &region_address,
                         &region_address,
                         &region_length,
                         &region_length,
                         &protection,
                         &protection,
                         &max_protection,
                         &max_protection,
                         &inheritance,
                         &inheritance,
                         &shared,
                         &shared,
                         &object_name,
                         &object_name,
                         &offset);
                         &offset);
        CHK_GOTO_OUT ("vm_region failed", ret);
        CHK_GOTO_OUT ("vm_region failed", ret);
 
 
        /* Check for holes in memory */
        /* Check for holes in memory */
        if (old_address != region_address)
        if (old_address != region_address)
          {
          {
            warning ("No memory at 0x%x. Nothing written",
            warning ("No memory at 0x%x. Nothing written",
                     old_address);
                     old_address);
            ret = KERN_SUCCESS;
            ret = KERN_SUCCESS;
            length = 0;
            length = 0;
            goto out;
            goto out;
          }
          }
 
 
        if (!(max_protection & VM_PROT_WRITE))
        if (!(max_protection & VM_PROT_WRITE))
          {
          {
            warning ("Memory at address 0x%x is unwritable. Nothing written",
            warning ("Memory at address 0x%x is unwritable. Nothing written",
                     old_address);
                     old_address);
            ret = KERN_SUCCESS;
            ret = KERN_SUCCESS;
            length = 0;
            length = 0;
            goto out;
            goto out;
          }
          }
 
 
        /* Chain the regions for later use */
        /* Chain the regions for later use */
        region_element =
        region_element =
          (struct vm_region_list *)
          (struct vm_region_list *)
          obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
          obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
 
 
        region_element->protection = protection;
        region_element->protection = protection;
        region_element->start = region_address;
        region_element->start = region_address;
        region_element->length = region_length;
        region_element->length = region_length;
 
 
        /* Chain the regions along with protections */
        /* Chain the regions along with protections */
        region_element->next = region_head;
        region_element->next = region_head;
        region_head = region_element;
        region_head = region_element;
 
 
        region_address += region_length;
        region_address += region_length;
        remaining_length = remaining_length - region_length;
        remaining_length = remaining_length - region_length;
      }
      }
 
 
    /* If things fail after this, we give up.
    /* If things fail after this, we give up.
     * Somebody is messing up inferior_task's mappings.
     * Somebody is messing up inferior_task's mappings.
     */
     */
 
 
    /* Enable writes to the chained vm regions */
    /* Enable writes to the chained vm regions */
    for (scan = region_head; scan; scan = scan->next)
    for (scan = region_head; scan; scan = scan->next)
      {
      {
        boolean_t protection_changed = FALSE;
        boolean_t protection_changed = FALSE;
 
 
        if (!(scan->protection & VM_PROT_WRITE))
        if (!(scan->protection & VM_PROT_WRITE))
          {
          {
            ret = vm_protect (inferior_task,
            ret = vm_protect (inferior_task,
                              scan->start,
                              scan->start,
                              scan->length,
                              scan->length,
                              FALSE,
                              FALSE,
                              scan->protection | VM_PROT_WRITE);
                              scan->protection | VM_PROT_WRITE);
            CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
            CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
          }
          }
      }
      }
 
 
    ret = vm_write (inferior_task,
    ret = vm_write (inferior_task,
                    low_address,
                    low_address,
                    copied_memory,
                    copied_memory,
                    aligned_length);
                    aligned_length);
    CHK_GOTO_OUT ("vm_write failed", ret);
    CHK_GOTO_OUT ("vm_write failed", ret);
 
 
    /* Set up the original region protections, if they were changed */
    /* Set up the original region protections, if they were changed */
    for (scan = region_head; scan; scan = scan->next)
    for (scan = region_head; scan; scan = scan->next)
      {
      {
        boolean_t protection_changed = FALSE;
        boolean_t protection_changed = FALSE;
 
 
        if (!(scan->protection & VM_PROT_WRITE))
        if (!(scan->protection & VM_PROT_WRITE))
          {
          {
            ret = vm_protect (inferior_task,
            ret = vm_protect (inferior_task,
                              scan->start,
                              scan->start,
                              scan->length,
                              scan->length,
                              FALSE,
                              FALSE,
                              scan->protection);
                              scan->protection);
            CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
            CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
          }
          }
      }
      }
  }
  }
 
 
out:
out:
  if (deallocate)
  if (deallocate)
    {
    {
      obstack_free (&region_obstack, 0);
      obstack_free (&region_obstack, 0);
 
 
      (void) vm_deallocate (mach_task_self (),
      (void) vm_deallocate (mach_task_self (),
                            copied_memory,
                            copied_memory,
                            copy_count);
                            copy_count);
    }
    }
 
 
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("%s %s", errstr, mach_error_string (ret));
      warning ("%s %s", errstr, mach_error_string (ret));
      return 0;
      return 0;
    }
    }
 
 
  return length;
  return length;
}
}
 
 
/* Return 0 on failure, number of bytes handled otherwise.  */
/* Return 0 on failure, number of bytes handled otherwise.  */
static int
static int
m3_xfer_memory (memaddr, myaddr, len, write, target)
m3_xfer_memory (memaddr, myaddr, len, write, target)
     CORE_ADDR memaddr;
     CORE_ADDR memaddr;
     char *myaddr;
     char *myaddr;
     int len;
     int len;
     int write;
     int write;
     struct target_ops *target; /* IGNORED */
     struct target_ops *target; /* IGNORED */
{
{
  int result;
  int result;
 
 
  if (write)
  if (write)
    result = mach3_write_inferior (memaddr, myaddr, len);
    result = mach3_write_inferior (memaddr, myaddr, len);
  else
  else
    result = mach3_read_inferior (memaddr, myaddr, len);
    result = mach3_read_inferior (memaddr, myaddr, len);
 
 
  return result;
  return result;
}
}


 
 
static char *
static char *
translate_state (state)
translate_state (state)
     int state;
     int state;
{
{
  switch (state)
  switch (state)
    {
    {
    case TH_STATE_RUNNING:
    case TH_STATE_RUNNING:
      return ("R");
      return ("R");
    case TH_STATE_STOPPED:
    case TH_STATE_STOPPED:
      return ("S");
      return ("S");
    case TH_STATE_WAITING:
    case TH_STATE_WAITING:
      return ("W");
      return ("W");
    case TH_STATE_UNINTERRUPTIBLE:
    case TH_STATE_UNINTERRUPTIBLE:
      return ("U");
      return ("U");
    case TH_STATE_HALTED:
    case TH_STATE_HALTED:
      return ("H");
      return ("H");
    default:
    default:
      return ("?");
      return ("?");
    }
    }
}
}
 
 
static char *
static char *
translate_cstate (state)
translate_cstate (state)
     int state;
     int state;
{
{
  switch (state)
  switch (state)
    {
    {
    case CPROC_RUNNING:
    case CPROC_RUNNING:
      return "R";
      return "R";
    case CPROC_SWITCHING:
    case CPROC_SWITCHING:
      return "S";
      return "S";
    case CPROC_BLOCKED:
    case CPROC_BLOCKED:
      return "B";
      return "B";
    case CPROC_CONDWAIT:
    case CPROC_CONDWAIT:
      return "C";
      return "C";
    case CPROC_CONDWAIT | CPROC_SWITCHING:
    case CPROC_CONDWAIT | CPROC_SWITCHING:
      return "CS";
      return "CS";
    default:
    default:
      return "?";
      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. */
mach_port_t                     /* no mach_port_name_t found in include files. */
map_inferior_port_name (inferior_name, type)
map_inferior_port_name (inferior_name, type)
     mach_port_t inferior_name;
     mach_port_t inferior_name;
     mach_msg_type_name_t type;
     mach_msg_type_name_t type;
{
{
  kern_return_t ret;
  kern_return_t ret;
  mach_msg_type_name_t acquired;
  mach_msg_type_name_t acquired;
  mach_port_t iport;
  mach_port_t iport;
 
 
  ret = mach_port_extract_right (inferior_task,
  ret = mach_port_extract_right (inferior_task,
                                 inferior_name,
                                 inferior_name,
                                 type,
                                 type,
                                 &iport,
                                 &iport,
                                 &acquired);
                                 &acquired);
  CHK ("mach_port_extract_right (map_inferior_port_name)", ret);
  CHK ("mach_port_extract_right (map_inferior_port_name)", ret);
 
 
  if (acquired != MACH_MSG_TYPE_PORT_SEND)
  if (acquired != MACH_MSG_TYPE_PORT_SEND)
    error ("Incorrect right extracted, (map_inferior_port_name)");
    error ("Incorrect right extracted, (map_inferior_port_name)");
 
 
  ret = mach_port_deallocate (mach_task_self (),
  ret = mach_port_deallocate (mach_task_self (),
                              iport);
                              iport);
  CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
  CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
 
 
  return iport;
  return iport;
}
}
 
 
/*
/*
 * Naming convention:
 * Naming convention:
 *  Always return user defined name if found.
 *  Always return user defined name if found.
 *  _K == A kernel thread with no matching CPROC
 *  _K == A kernel thread with no matching CPROC
 *  _C == A cproc with no current cthread
 *  _C == A cproc with no current cthread
 *  _t == A cthread with no user defined name
 *  _t == A cthread with no user defined name
 *
 *
 * The digits that follow the _names are the SLOT number of the
 * The digits that follow the _names are the SLOT number of the
 * kernel thread if there is such a thing, otherwise just a negation
 * kernel thread if there is such a thing, otherwise just a negation
 * of the sequential number of such cprocs.
 * of the sequential number of such cprocs.
 */
 */
 
 
static char buf[7];
static char buf[7];
 
 
static char *
static char *
get_thread_name (one_cproc, id)
get_thread_name (one_cproc, id)
     gdb_thread_t one_cproc;
     gdb_thread_t one_cproc;
     int id;
     int id;
{
{
  if (one_cproc)
  if (one_cproc)
    if (one_cproc->cthread == NULL)
    if (one_cproc->cthread == NULL)
      {
      {
        /* cproc not mapped to any cthread */
        /* cproc not mapped to any cthread */
        sprintf (buf, "_C%d", id);
        sprintf (buf, "_C%d", id);
      }
      }
    else if (!one_cproc->cthread->name)
    else if (!one_cproc->cthread->name)
      {
      {
        /* cproc and cthread, but no name */
        /* cproc and cthread, but no name */
        sprintf (buf, "_t%d", id);
        sprintf (buf, "_t%d", id);
      }
      }
    else
    else
      return (char *) (one_cproc->cthread->name);
      return (char *) (one_cproc->cthread->name);
  else
  else
    {
    {
      if (id < 0)
      if (id < 0)
        warning ("Inconsistency in thread name id %d", id);
        warning ("Inconsistency in thread name id %d", id);
 
 
      /* Kernel thread without cproc */
      /* Kernel thread without cproc */
      sprintf (buf, "_K%d", id);
      sprintf (buf, "_K%d", id);
    }
    }
 
 
  return buf;
  return buf;
}
}
 
 
int
int
fetch_thread_info (task, mthreads_out)
fetch_thread_info (task, mthreads_out)
     mach_port_t task;
     mach_port_t task;
     gdb_thread_t *mthreads_out;        /* out */
     gdb_thread_t *mthreads_out;        /* out */
{
{
  kern_return_t ret;
  kern_return_t ret;
  thread_array_t th_table;
  thread_array_t th_table;
  int th_count;
  int th_count;
  gdb_thread_t mthreads = NULL;
  gdb_thread_t mthreads = NULL;
  int index;
  int index;
 
 
  ret = task_threads (task, &th_table, &th_count);
  ret = task_threads (task, &th_table, &th_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("Error getting inferior's thread list:%s",
      warning ("Error getting inferior's thread list:%s",
               mach_error_string (ret));
               mach_error_string (ret));
      m3_kill_inferior ();
      m3_kill_inferior ();
      return -1;
      return -1;
    }
    }
 
 
  mthreads = (gdb_thread_t)
  mthreads = (gdb_thread_t)
    obstack_alloc
    obstack_alloc
    (cproc_obstack,
    (cproc_obstack,
     th_count * sizeof (struct gdb_thread));
     th_count * sizeof (struct gdb_thread));
 
 
  for (index = 0; index < th_count; index++)
  for (index = 0; index < th_count; index++)
    {
    {
      thread_t saved_thread = MACH_PORT_NULL;
      thread_t saved_thread = MACH_PORT_NULL;
      int mid;
      int mid;
 
 
      if (must_suspend_thread)
      if (must_suspend_thread)
        setup_thread (th_table[index], 1);
        setup_thread (th_table[index], 1);
 
 
      if (th_table[index] != current_thread)
      if (th_table[index] != current_thread)
        {
        {
          saved_thread = current_thread;
          saved_thread = current_thread;
 
 
          mid = switch_to_thread (th_table[index]);
          mid = switch_to_thread (th_table[index]);
        }
        }
 
 
      mthreads[index].name = th_table[index];
      mthreads[index].name = th_table[index];
      mthreads[index].cproc = NULL;     /* map_cprocs_to_kernel_threads() */
      mthreads[index].cproc = NULL;     /* map_cprocs_to_kernel_threads() */
      mthreads[index].in_emulator = FALSE;
      mthreads[index].in_emulator = FALSE;
      mthreads[index].slotid = index;
      mthreads[index].slotid = index;
 
 
      mthreads[index].sp = read_register (SP_REGNUM);
      mthreads[index].sp = read_register (SP_REGNUM);
      mthreads[index].fp = read_register (FP_REGNUM);
      mthreads[index].fp = read_register (FP_REGNUM);
      mthreads[index].pc = read_pc ();
      mthreads[index].pc = read_pc ();
 
 
      if (MACH_PORT_VALID (saved_thread))
      if (MACH_PORT_VALID (saved_thread))
        mid = switch_to_thread (saved_thread);
        mid = switch_to_thread (saved_thread);
 
 
      if (must_suspend_thread)
      if (must_suspend_thread)
        setup_thread (th_table[index], 0);
        setup_thread (th_table[index], 0);
    }
    }
 
 
  consume_send_rights (th_table, th_count);
  consume_send_rights (th_table, th_count);
  ret = vm_deallocate (mach_task_self (), (vm_address_t) th_table,
  ret = vm_deallocate (mach_task_self (), (vm_address_t) th_table,
                       (th_count * sizeof (mach_port_t)));
                       (th_count * sizeof (mach_port_t)));
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("Error trying to deallocate thread list : %s",
      warning ("Error trying to deallocate thread list : %s",
               mach_error_string (ret));
               mach_error_string (ret));
    }
    }
 
 
  *mthreads_out = mthreads;
  *mthreads_out = mthreads;
 
 
  return th_count;
  return th_count;
}
}
 
 
 
 
/*
/*
 * Current emulator always saves the USP on top of
 * Current emulator always saves the USP on top of
 * emulator stack below struct emul_stack_top stuff.
 * emulator stack below struct emul_stack_top stuff.
 */
 */
CORE_ADDR
CORE_ADDR
fetch_usp_from_emulator_stack (sp)
fetch_usp_from_emulator_stack (sp)
     CORE_ADDR sp;
     CORE_ADDR sp;
{
{
  CORE_ADDR stack_pointer;
  CORE_ADDR stack_pointer;
 
 
  sp = (sp & ~(EMULATOR_STACK_SIZE - 1)) +
  sp = (sp & ~(EMULATOR_STACK_SIZE - 1)) +
    EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
    EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
 
 
  if (mach3_read_inferior (sp,
  if (mach3_read_inferior (sp,
                           &stack_pointer,
                           &stack_pointer,
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
    {
    {
      warning ("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;
      return 0;
    }
    }
 
 
  return stack_pointer;
  return stack_pointer;
}
}
 
 
#ifdef MK67
#ifdef MK67
 
 
/* get_emulation_vector() interface was changed after mk67 */
/* get_emulation_vector() interface was changed after mk67 */
#define EMUL_VECTOR_COUNT 400   /* Value does not matter too much */
#define EMUL_VECTOR_COUNT 400   /* Value does not matter too much */
 
 
#endif /* MK67 */
#endif /* MK67 */
 
 
/* Check if the emulator exists at task's address space.
/* Check if the emulator exists at task's address space.
 */
 */
boolean_t
boolean_t
have_emulator_p (task)
have_emulator_p (task)
     task_t task;
     task_t task;
{
{
  kern_return_t ret;
  kern_return_t ret;
#ifndef EMUL_VECTOR_COUNT
#ifndef EMUL_VECTOR_COUNT
  vm_offset_t *emulation_vector;
  vm_offset_t *emulation_vector;
  int n;
  int n;
#else
#else
  vm_offset_t emulation_vector[EMUL_VECTOR_COUNT];
  vm_offset_t emulation_vector[EMUL_VECTOR_COUNT];
  int n = EMUL_VECTOR_COUNT;
  int n = EMUL_VECTOR_COUNT;
#endif
#endif
  int i;
  int i;
  int vector_start;
  int vector_start;
 
 
  ret = task_get_emulation_vector (task,
  ret = task_get_emulation_vector (task,
                                   &vector_start,
                                   &vector_start,
#ifndef EMUL_VECTOR_COUNT
#ifndef EMUL_VECTOR_COUNT
                                   &emulation_vector,
                                   &emulation_vector,
#else
#else
                                   emulation_vector,
                                   emulation_vector,
#endif
#endif
                                   &n);
                                   &n);
  CHK ("task_get_emulation_vector", ret);
  CHK ("task_get_emulation_vector", ret);
  xx_debug ("%d vectors from %d at 0x%08x\n",
  xx_debug ("%d vectors from %d at 0x%08x\n",
            n, vector_start, emulation_vector);
            n, vector_start, emulation_vector);
 
 
  for (i = 0; i < n; i++)
  for (i = 0; i < n; i++)
    {
    {
      vm_offset_t entry = emulation_vector[i];
      vm_offset_t entry = emulation_vector[i];
 
 
      if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
      if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
        return TRUE;
        return TRUE;
      else if (entry)
      else if (entry)
        {
        {
          static boolean_t informed = FALSE;
          static boolean_t informed = FALSE;
          if (!informed)
          if (!informed)
            {
            {
              warning ("Emulation vector address 0x08%x outside emulator space",
              warning ("Emulation vector address 0x08%x outside emulator space",
                       entry);
                       entry);
              informed = TRUE;
              informed = TRUE;
            }
            }
        }
        }
    }
    }
  return FALSE;
  return FALSE;
}
}
 
 
/* Map cprocs to kernel threads and vice versa.  */
/* Map cprocs to kernel threads and vice versa.  */
 
 
void
void
map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
     gdb_thread_t cprocs;
     gdb_thread_t cprocs;
     gdb_thread_t mthreads;
     gdb_thread_t mthreads;
     int thread_count;
     int thread_count;
{
{
  int index;
  int index;
  gdb_thread_t scan;
  gdb_thread_t scan;
  boolean_t all_mapped = TRUE;
  boolean_t all_mapped = TRUE;
  LONGEST stack_base;
  LONGEST stack_base;
  LONGEST stack_size;
  LONGEST stack_size;
 
 
  for (scan = cprocs; scan; scan = scan->next)
  for (scan = cprocs; scan; scan = scan->next)
    {
    {
      /* Default to: no kernel thread for this cproc */
      /* Default to: no kernel thread for this cproc */
      scan->reverse_map = -1;
      scan->reverse_map = -1;
 
 
      /* Check if the cproc is found by its stack */
      /* Check if the cproc is found by its stack */
      for (index = 0; index < thread_count; index++)
      for (index = 0; index < thread_count; index++)
        {
        {
          stack_base =
          stack_base =
            extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
            extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
                                    CPROC_BASE_SIZE);
                                    CPROC_BASE_SIZE);
          stack_size =
          stack_size =
            extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
            extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
                                    CPROC_SIZE_SIZE);
                                    CPROC_SIZE_SIZE);
          if ((mthreads + index)->sp > stack_base &&
          if ((mthreads + index)->sp > stack_base &&
              (mthreads + index)->sp <= stack_base + stack_size)
              (mthreads + index)->sp <= stack_base + stack_size)
            {
            {
              (mthreads + index)->cproc = scan;
              (mthreads + index)->cproc = scan;
              scan->reverse_map = index;
              scan->reverse_map = index;
              break;
              break;
            }
            }
        }
        }
      all_mapped &= (scan->reverse_map != -1);
      all_mapped &= (scan->reverse_map != -1);
    }
    }
 
 
  /* Check for threads that are currently in the emulator.
  /* Check for threads that are currently in the emulator.
   * If so, they have a different stack, and the still unmapped
   * If so, they have a different stack, and the still unmapped
   * cprocs may well get mapped to these threads.
   * cprocs may well get mapped to these threads.
   *
   *
   * If:
   * If:
   *  - cproc stack does not match any kernel thread stack pointer
   *  - cproc stack does not match any kernel thread stack pointer
   *  - there is at least one extra kernel thread
   *  - there is at least one extra kernel thread
   *    that has no cproc mapped above.
   *    that has no cproc mapped above.
   *  - some kernel thread stack pointer points to emulator space
   *  - some kernel thread stack pointer points to emulator space
   *  then we find the user stack pointer saved in the emulator
   *  then we find the user stack pointer saved in the emulator
   *  stack, and try to map that to the cprocs.
   *  stack, and try to map that to the cprocs.
   *
   *
   * Also set in_emulator for kernel threads.
   * Also set in_emulator for kernel threads.
   */
   */
 
 
  if (emulator_present)
  if (emulator_present)
    {
    {
      for (index = 0; index < thread_count; index++)
      for (index = 0; index < thread_count; index++)
        {
        {
          CORE_ADDR emul_sp;
          CORE_ADDR emul_sp;
          CORE_ADDR usp;
          CORE_ADDR usp;
 
 
          gdb_thread_t mthread = (mthreads + index);
          gdb_thread_t mthread = (mthreads + index);
          emul_sp = mthread->sp;
          emul_sp = mthread->sp;
 
 
          if (mthread->cproc == NULL &&
          if (mthread->cproc == NULL &&
              EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
              EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
            {
            {
              mthread->in_emulator = emulator_present;
              mthread->in_emulator = emulator_present;
 
 
              if (!all_mapped && cprocs)
              if (!all_mapped && cprocs)
                {
                {
                  usp = fetch_usp_from_emulator_stack (emul_sp);
                  usp = fetch_usp_from_emulator_stack (emul_sp);
 
 
                  /* @@ Could be more accurate */
                  /* @@ Could be more accurate */
                  if (!usp)
                  if (!usp)
                    error ("Zero stack pointer read from emulator?");
                    error ("Zero stack pointer read from emulator?");
 
 
                  /* Try to match this stack pointer to the cprocs that
                  /* Try to match this stack pointer to the cprocs that
                   * don't yet have a kernel thread.
                   * don't yet have a kernel thread.
                   */
                   */
                  for (scan = cprocs; scan; scan = scan->next)
                  for (scan = cprocs; scan; scan = scan->next)
                    {
                    {
 
 
                      /* Check is this unmapped CPROC stack contains
                      /* Check is this unmapped CPROC stack contains
                       * the user stack pointer saved in the
                       * the user stack pointer saved in the
                       * emulator.
                       * emulator.
                       */
                       */
                      if (scan->reverse_map == -1)
                      if (scan->reverse_map == -1)
                        {
                        {
                          stack_base =
                          stack_base =
                            extract_signed_integer
                            extract_signed_integer
                            (scan->raw_cproc + CPROC_BASE_OFFSET,
                            (scan->raw_cproc + CPROC_BASE_OFFSET,
                             CPROC_BASE_SIZE);
                             CPROC_BASE_SIZE);
                          stack_size =
                          stack_size =
                            extract_signed_integer
                            extract_signed_integer
                            (scan->raw_cproc + CPROC_SIZE_OFFSET,
                            (scan->raw_cproc + CPROC_SIZE_OFFSET,
                             CPROC_SIZE_SIZE);
                             CPROC_SIZE_SIZE);
                          if (usp > stack_base &&
                          if (usp > stack_base &&
                              usp <= stack_base + stack_size)
                              usp <= stack_base + stack_size)
                            {
                            {
                              mthread->cproc = scan;
                              mthread->cproc = scan;
                              scan->reverse_map = index;
                              scan->reverse_map = index;
                              break;
                              break;
                            }
                            }
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
}
}


/*
/*
 * Format of the thread_list command
 * Format of the thread_list command
 *
 *
 *                   slot mid sel   name  emul ks susp  cstate wired   address
 *                   slot mid sel   name  emul ks susp  cstate wired   address
 */
 */
#define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
#define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
 
 
#define TL_HEADER "\n@    MID  Name        KState CState   Where\n"
#define TL_HEADER "\n@    MID  Name        KState CState   Where\n"
 
 
void
void
print_tl_address (stream, pc)
print_tl_address (stream, pc)
     struct ui_file *stream;
     struct ui_file *stream;
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  if (!lookup_minimal_symbol_by_pc (pc))
  if (!lookup_minimal_symbol_by_pc (pc))
    fprintf_filtered (stream, local_hex_format (), pc);
    fprintf_filtered (stream, local_hex_format (), pc);
  else
  else
    {
    {
      extern int addressprint;
      extern int addressprint;
      extern int asm_demangle;
      extern int asm_demangle;
 
 
      int store = addressprint;
      int store = addressprint;
      addressprint = 0;
      addressprint = 0;
      print_address_symbolic (pc, stream, asm_demangle, "");
      print_address_symbolic (pc, stream, asm_demangle, "");
      addressprint = store;
      addressprint = store;
    }
    }
}
}


/* For thread names, but also for gdb_message_port external name */
/* For thread names, but also for gdb_message_port external name */
#define MAX_NAME_LEN 50
#define MAX_NAME_LEN 50
 
 
/* Returns the address of variable NAME or 0 if not found */
/* Returns the address of variable NAME or 0 if not found */
CORE_ADDR
CORE_ADDR
lookup_address_of_variable (name)
lookup_address_of_variable (name)
     char *name;
     char *name;
{
{
  struct symbol *sym;
  struct symbol *sym;
  CORE_ADDR symaddr = 0;
  CORE_ADDR symaddr = 0;
  struct minimal_symbol *msymbol;
  struct minimal_symbol *msymbol;
 
 
  sym = lookup_symbol (name,
  sym = lookup_symbol (name,
                       (struct block *) NULL,
                       (struct block *) NULL,
                       VAR_NAMESPACE,
                       VAR_NAMESPACE,
                       (int *) NULL,
                       (int *) NULL,
                       (struct symtab **) NULL);
                       (struct symtab **) NULL);
 
 
  if (sym)
  if (sym)
    symaddr = SYMBOL_VALUE (sym);
    symaddr = SYMBOL_VALUE (sym);
 
 
  if (!symaddr)
  if (!symaddr)
    {
    {
      msymbol = lookup_minimal_symbol (name, NULL, NULL);
      msymbol = lookup_minimal_symbol (name, NULL, NULL);
 
 
      if (msymbol && msymbol->type == mst_data)
      if (msymbol && msymbol->type == mst_data)
        symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
        symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
    }
    }
 
 
  return symaddr;
  return symaddr;
}
}
 
 
static gdb_thread_t
static gdb_thread_t
get_cprocs ()
get_cprocs ()
{
{
  gdb_thread_t cproc_head;
  gdb_thread_t cproc_head;
  gdb_thread_t cproc_copy;
  gdb_thread_t cproc_copy;
  CORE_ADDR their_cprocs;
  CORE_ADDR their_cprocs;
  char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
  char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
  char *name;
  char *name;
  cthread_t cthread;
  cthread_t cthread;
  CORE_ADDR symaddr;
  CORE_ADDR symaddr;
 
 
  symaddr = lookup_address_of_variable ("cproc_list");
  symaddr = lookup_address_of_variable ("cproc_list");
 
 
  if (!symaddr)
  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 */
         symbols, but don't give up yet */
 
 
      symaddr = lookup_address_of_variable ("cprocs");
      symaddr = lookup_address_of_variable ("cprocs");
 
 
      if (symaddr)
      if (symaddr)
        {
        {
          static int informed = 0;
          static int informed = 0;
          if (!informed)
          if (!informed)
            {
            {
              informed++;
              informed++;
              warning ("Your program is loaded with an old threads library.");
              warning ("Your program is loaded with an old threads library.");
              warning ("GDB does not know the old form of threads");
              warning ("GDB does not know the old form of threads");
              warning ("so things may not work.");
              warning ("so things may not work.");
            }
            }
        }
        }
    }
    }
 
 
  /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
  /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
  if (!symaddr)
  if (!symaddr)
    return NULL;
    return NULL;
 
 
  /* Get the address of the first cproc in the task */
  /* Get the address of the first cproc in the task */
  if (!mach3_read_inferior (symaddr,
  if (!mach3_read_inferior (symaddr,
                            buf,
                            buf,
                            TARGET_PTR_BIT / HOST_CHAR_BIT))
                            TARGET_PTR_BIT / HOST_CHAR_BIT))
    error ("Can't read cproc master list at address (0x%x).", symaddr);
    error ("Can't read cproc master list at address (0x%x).", symaddr);
  their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
  their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
 
 
  /* Scan the CPROCs in the task.
  /* Scan the CPROCs in the task.
     CPROCs are chained with LIST field, not NEXT field, which
     CPROCs are chained with LIST field, not NEXT field, which
     chains mutexes, condition variables and queues */
     chains mutexes, condition variables and queues */
 
 
  cproc_head = NULL;
  cproc_head = NULL;
 
 
  while (their_cprocs != (CORE_ADDR) 0)
  while (their_cprocs != (CORE_ADDR) 0)
    {
    {
      CORE_ADDR cproc_copy_incarnation;
      CORE_ADDR cproc_copy_incarnation;
      cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
      cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
                                                 sizeof (struct gdb_thread));
                                                 sizeof (struct gdb_thread));
 
 
      if (!mach3_read_inferior (their_cprocs,
      if (!mach3_read_inferior (their_cprocs,
                                &cproc_copy->raw_cproc[0],
                                &cproc_copy->raw_cproc[0],
                                CPROC_SIZE))
                                CPROC_SIZE))
        error ("Can't read next cproc at 0x%x.", their_cprocs);
        error ("Can't read next cproc at 0x%x.", their_cprocs);
 
 
      their_cprocs =
      their_cprocs =
        extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
        extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
                         CPROC_LIST_SIZE);
                         CPROC_LIST_SIZE);
      cproc_copy_incarnation =
      cproc_copy_incarnation =
        extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
        extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
                         CPROC_INCARNATION_SIZE);
                         CPROC_INCARNATION_SIZE);
 
 
      if (cproc_copy_incarnation == (CORE_ADDR) 0)
      if (cproc_copy_incarnation == (CORE_ADDR) 0)
        cproc_copy->cthread = NULL;
        cproc_copy->cthread = NULL;
      else
      else
        {
        {
          /* This CPROC has an attached CTHREAD. Get its name */
          /* This CPROC has an attached CTHREAD. Get its name */
          cthread = (cthread_t) obstack_alloc (cproc_obstack,
          cthread = (cthread_t) obstack_alloc (cproc_obstack,
                                               sizeof (struct cthread));
                                               sizeof (struct cthread));
 
 
          if (!mach3_read_inferior (cproc_copy_incarnation,
          if (!mach3_read_inferior (cproc_copy_incarnation,
                                    cthread,
                                    cthread,
                                    sizeof (struct cthread)))
                                    sizeof (struct cthread)))
              error ("Can't read next thread at 0x%x.",
              error ("Can't read next thread at 0x%x.",
                     cproc_copy_incarnation);
                     cproc_copy_incarnation);
 
 
          cproc_copy->cthread = cthread;
          cproc_copy->cthread = cthread;
 
 
          if (cthread->name)
          if (cthread->name)
            {
            {
              name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
              name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
 
 
              if (!mach3_read_inferior (cthread->name, name, MAX_NAME_LEN))
              if (!mach3_read_inferior (cthread->name, name, MAX_NAME_LEN))
                error ("Can't read next thread's name at 0x%x.", cthread->name);
                error ("Can't read next thread's name at 0x%x.", cthread->name);
 
 
              cthread->name = name;
              cthread->name = name;
            }
            }
        }
        }
 
 
      /* insert in front */
      /* insert in front */
      cproc_copy->next = cproc_head;
      cproc_copy->next = cproc_head;
      cproc_head = cproc_copy;
      cproc_head = cproc_copy;
    }
    }
  return cproc_head;
  return cproc_head;
}
}
 
 
#ifndef FETCH_CPROC_STATE
#ifndef FETCH_CPROC_STATE
/*
/*
 * Check if your machine does not grok the way this routine
 * Check if your machine does not grok the way this routine
 * fetches the FP,PC and SP of a cproc that is not
 * fetches the FP,PC and SP of a cproc that is not
 * currently attached to any kernel thread (e.g. its cproc.context
 * currently attached to any kernel thread (e.g. its cproc.context
 * field points to the place in stack where the context
 * field points to the place in stack where the context
 * is saved).
 * is saved).
 *
 *
 * If it doesn't, define your own routine.
 * If it doesn't, define your own routine.
 */
 */
#define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
#define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
 
 
int
int
mach3_cproc_state (mthread)
mach3_cproc_state (mthread)
     gdb_thread_t mthread;
     gdb_thread_t mthread;
{
{
  int context;
  int context;
 
 
  if (!mthread || !mthread->cproc)
  if (!mthread || !mthread->cproc)
    return -1;
    return -1;
 
 
  context = extract_signed_integer
  context = extract_signed_integer
    (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
    (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
     CPROC_CONTEXT_SIZE);
     CPROC_CONTEXT_SIZE);
  if (context == 0)
  if (context == 0)
    return -1;
    return -1;
 
 
  mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
  mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
 
 
  if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
  if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
                           &mthread->pc,
                           &mthread->pc,
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
    {
    {
      warning ("Can't read cproc pc from inferior");
      warning ("Can't read cproc pc from inferior");
      return -1;
      return -1;
    }
    }
 
 
  if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
  if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
                           &mthread->fp,
                           &mthread->fp,
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
                           sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
    {
    {
      warning ("Can't read cproc fp from inferior");
      warning ("Can't read cproc fp from inferior");
      return -1;
      return -1;
    }
    }
 
 
  return 0;
  return 0;
}
}
#endif /* FETCH_CPROC_STATE */
#endif /* FETCH_CPROC_STATE */


 
 
void
void
thread_list_command ()
thread_list_command ()
{
{
  thread_basic_info_data_t ths;
  thread_basic_info_data_t ths;
  int thread_count;
  int thread_count;
  gdb_thread_t cprocs;
  gdb_thread_t cprocs;
  gdb_thread_t scan;
  gdb_thread_t scan;
  int index;
  int index;
  char *name;
  char *name;
  char selected;
  char selected;
  char *wired;
  char *wired;
  int infoCnt;
  int infoCnt;
  kern_return_t ret;
  kern_return_t ret;
  mach_port_t mid_or_port;
  mach_port_t mid_or_port;
  gdb_thread_t their_threads;
  gdb_thread_t their_threads;
  gdb_thread_t kthread;
  gdb_thread_t kthread;
 
 
  int neworder = 1;
  int neworder = 1;
 
 
  char *fmt = "There are %d kernel threads in task %d.\n";
  char *fmt = "There are %d kernel threads in task %d.\n";
 
 
  int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
  int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  thread_count = fetch_thread_info (inferior_task,
  thread_count = fetch_thread_info (inferior_task,
                                    &their_threads);
                                    &their_threads);
  if (thread_count == -1)
  if (thread_count == -1)
    return;
    return;
 
 
  if (thread_count == 1)
  if (thread_count == 1)
    fmt = "There is %d kernel thread in task %d.\n";
    fmt = "There is %d kernel thread in task %d.\n";
 
 
  printf_filtered (fmt, thread_count, tmid);
  printf_filtered (fmt, thread_count, tmid);
 
 
  puts_filtered (TL_HEADER);
  puts_filtered (TL_HEADER);
 
 
  cprocs = get_cprocs ();
  cprocs = get_cprocs ();
 
 
  map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
  map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
 
 
  for (scan = cprocs; scan; scan = scan->next)
  for (scan = cprocs; scan; scan = scan->next)
    {
    {
      int mid;
      int mid;
      char buf[10];
      char buf[10];
      char slot[3];
      char slot[3];
      int cproc_state =
      int cproc_state =
      extract_signed_integer
      extract_signed_integer
      (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
      (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
 
 
      selected = ' ';
      selected = ' ';
 
 
      /* a wired cproc? */
      /* a wired cproc? */
      wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
      wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
                                CPROC_WIRED_SIZE)
                                CPROC_WIRED_SIZE)
               ? "wired" : "");
               ? "wired" : "");
 
 
      if (scan->reverse_map != -1)
      if (scan->reverse_map != -1)
        kthread = (their_threads + scan->reverse_map);
        kthread = (their_threads + scan->reverse_map);
      else
      else
        kthread = NULL;
        kthread = NULL;
 
 
      if (kthread)
      if (kthread)
        {
        {
          /* These cprocs have a kernel thread */
          /* These cprocs have a kernel thread */
 
 
          mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
          mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
 
 
          infoCnt = THREAD_BASIC_INFO_COUNT;
          infoCnt = THREAD_BASIC_INFO_COUNT;
 
 
          ret = thread_info (kthread->name,
          ret = thread_info (kthread->name,
                             THREAD_BASIC_INFO,
                             THREAD_BASIC_INFO,
                             (thread_info_t) & ths,
                             (thread_info_t) & ths,
                             &infoCnt);
                             &infoCnt);
 
 
          if (ret != KERN_SUCCESS)
          if (ret != KERN_SUCCESS)
            {
            {
              warning ("Unable to get basic info on thread %d : %s",
              warning ("Unable to get basic info on thread %d : %s",
                       mid,
                       mid,
                       mach_error_string (ret));
                       mach_error_string (ret));
              continue;
              continue;
            }
            }
 
 
          /* Who is the first to have more than 100 threads */
          /* Who is the first to have more than 100 threads */
          sprintf (slot, "%d", kthread->slotid % 100);
          sprintf (slot, "%d", kthread->slotid % 100);
 
 
          if (kthread->name == current_thread)
          if (kthread->name == current_thread)
            selected = '*';
            selected = '*';
 
 
          if (ths.suspend_count)
          if (ths.suspend_count)
            sprintf (buf, "%d", ths.suspend_count);
            sprintf (buf, "%d", ths.suspend_count);
          else
          else
            buf[0] = '\000';
            buf[0] = '\000';
 
 
#if 0
#if 0
          if (ths.flags & TH_FLAGS_SWAPPED)
          if (ths.flags & TH_FLAGS_SWAPPED)
            strcat (buf, "S");
            strcat (buf, "S");
#endif
#endif
 
 
          if (ths.flags & TH_FLAGS_IDLE)
          if (ths.flags & TH_FLAGS_IDLE)
            strcat (buf, "I");
            strcat (buf, "I");
 
 
          printf_filtered (TL_FORMAT,
          printf_filtered (TL_FORMAT,
                           slot,
                           slot,
                           mid,
                           mid,
                           selected,
                           selected,
                           get_thread_name (scan, kthread->slotid),
                           get_thread_name (scan, kthread->slotid),
                           kthread->in_emulator ? "E" : "",
                           kthread->in_emulator ? "E" : "",
                           translate_state (ths.run_state),
                           translate_state (ths.run_state),
                           buf,
                           buf,
                           translate_cstate (cproc_state),
                           translate_cstate (cproc_state),
                           wired);
                           wired);
          print_tl_address (gdb_stdout, kthread->pc);
          print_tl_address (gdb_stdout, kthread->pc);
        }
        }
      else
      else
        {
        {
          /* These cprocs don't have a kernel thread.
          /* These cprocs don't have a kernel thread.
           * find out the calling frame with
           * find out the calling frame with
           * FETCH_CPROC_STATE.
           * FETCH_CPROC_STATE.
           */
           */
 
 
          struct gdb_thread state;
          struct gdb_thread state;
 
 
#if 0
#if 0
          /* jtv -> emcmanus: why do you want this here? */
          /* jtv -> emcmanus: why do you want this here? */
          if (scan->incarnation == NULL)
          if (scan->incarnation == NULL)
            continue;           /* EMcM */
            continue;           /* EMcM */
#endif
#endif
 
 
          printf_filtered (TL_FORMAT,
          printf_filtered (TL_FORMAT,
                           "-",
                           "-",
                           -neworder,   /* Pseudo MID */
                           -neworder,   /* Pseudo MID */
                           selected,
                           selected,
                           get_thread_name (scan, -neworder),
                           get_thread_name (scan, -neworder),
                           "",
                           "",
                           "-", /* kernel state */
                           "-", /* kernel state */
                           "",
                           "",
                           translate_cstate (cproc_state),
                           translate_cstate (cproc_state),
                           "");
                           "");
          state.cproc = scan;
          state.cproc = scan;
 
 
          if (FETCH_CPROC_STATE (&state) == -1)
          if (FETCH_CPROC_STATE (&state) == -1)
            puts_filtered ("???");
            puts_filtered ("???");
          else
          else
            print_tl_address (gdb_stdout, state.pc);
            print_tl_address (gdb_stdout, state.pc);
 
 
          neworder++;
          neworder++;
        }
        }
      puts_filtered ("\n");
      puts_filtered ("\n");
    }
    }
 
 
  /* Scan for kernel threads without cprocs */
  /* Scan for kernel threads without cprocs */
  for (index = 0; index < thread_count; index++)
  for (index = 0; index < thread_count; index++)
    {
    {
      if (!their_threads[index].cproc)
      if (!their_threads[index].cproc)
        {
        {
          int mid;
          int mid;
 
 
          char buf[10];
          char buf[10];
          char slot[3];
          char slot[3];
 
 
          mach_port_t name = their_threads[index].name;
          mach_port_t name = their_threads[index].name;
 
 
          mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
          mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
 
 
          infoCnt = THREAD_BASIC_INFO_COUNT;
          infoCnt = THREAD_BASIC_INFO_COUNT;
 
 
          ret = thread_info (name,
          ret = thread_info (name,
                             THREAD_BASIC_INFO,
                             THREAD_BASIC_INFO,
                             (thread_info_t) & ths,
                             (thread_info_t) & ths,
                             &infoCnt);
                             &infoCnt);
 
 
          if (ret != KERN_SUCCESS)
          if (ret != KERN_SUCCESS)
            {
            {
              warning ("Unable to get basic info on thread %d : %s",
              warning ("Unable to get basic info on thread %d : %s",
                       mid,
                       mid,
                       mach_error_string (ret));
                       mach_error_string (ret));
              continue;
              continue;
            }
            }
 
 
          sprintf (slot, "%d", index % 100);
          sprintf (slot, "%d", index % 100);
 
 
          if (name == current_thread)
          if (name == current_thread)
            selected = '*';
            selected = '*';
          else
          else
            selected = ' ';
            selected = ' ';
 
 
          if (ths.suspend_count)
          if (ths.suspend_count)
            sprintf (buf, "%d", ths.suspend_count);
            sprintf (buf, "%d", ths.suspend_count);
          else
          else
            buf[0] = '\000';
            buf[0] = '\000';
 
 
#if 0
#if 0
          if (ths.flags & TH_FLAGS_SWAPPED)
          if (ths.flags & TH_FLAGS_SWAPPED)
            strcat (buf, "S");
            strcat (buf, "S");
#endif
#endif
 
 
          if (ths.flags & TH_FLAGS_IDLE)
          if (ths.flags & TH_FLAGS_IDLE)
            strcat (buf, "I");
            strcat (buf, "I");
 
 
          printf_filtered (TL_FORMAT,
          printf_filtered (TL_FORMAT,
                           slot,
                           slot,
                           mid,
                           mid,
                           selected,
                           selected,
                           get_thread_name (NULL, index),
                           get_thread_name (NULL, index),
                           their_threads[index].in_emulator ? "E" : "",
                           their_threads[index].in_emulator ? "E" : "",
                           translate_state (ths.run_state),
                           translate_state (ths.run_state),
                           buf,
                           buf,
                           "",  /* No cproc state */
                           "",  /* No cproc state */
                           ""); /* Can't be wired */
                           ""); /* Can't be wired */
          print_tl_address (gdb_stdout, their_threads[index].pc);
          print_tl_address (gdb_stdout, their_threads[index].pc);
          puts_filtered ("\n");
          puts_filtered ("\n");
        }
        }
    }
    }
 
 
  obstack_free (cproc_obstack, 0);
  obstack_free (cproc_obstack, 0);
  obstack_init (cproc_obstack);
  obstack_init (cproc_obstack);
}
}


void
void
thread_select_command (args, from_tty)
thread_select_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int mid;
  int mid;
  thread_array_t thread_list;
  thread_array_t thread_list;
  int thread_count;
  int thread_count;
  kern_return_t ret;
  kern_return_t ret;
  int is_slot = 0;
  int is_slot = 0;
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  if (!args)
  if (!args)
    error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
    error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
 
 
  while (*args == ' ' || *args == '\t')
  while (*args == ' ' || *args == '\t')
    args++;
    args++;
 
 
  if (*args == '@')
  if (*args == '@')
    {
    {
      is_slot++;
      is_slot++;
      args++;
      args++;
    }
    }
 
 
  mid = atoi (args);
  mid = atoi (args);
 
 
  if (mid == 0)
  if (mid == 0)
    if (!is_slot || *args != '0')       /* Rudimentary checks */
    if (!is_slot || *args != '0')       /* Rudimentary checks */
      error ("You must select threads by MID or @SLOTNUMBER");
      error ("You must select threads by MID or @SLOTNUMBER");
 
 
  if (select_thread (inferior_task, mid, is_slot ? 2 : 1) != KERN_SUCCESS)
  if (select_thread (inferior_task, mid, is_slot ? 2 : 1) != KERN_SUCCESS)
    return;
    return;
 
 
  if (from_tty)
  if (from_tty)
    printf_filtered ("Thread %d selected\n",
    printf_filtered ("Thread %d selected\n",
                     is_slot ? map_port_name_to_mid (current_thread,
                     is_slot ? map_port_name_to_mid (current_thread,
                                                   MACH_TYPE_THREAD) : mid);
                                                   MACH_TYPE_THREAD) : mid);
}
}


thread_trace (thread, set)
thread_trace (thread, set)
     mach_port_t thread;
     mach_port_t thread;
     boolean_t set;
     boolean_t set;
{
{
  int flavor = TRACE_FLAVOR;
  int flavor = TRACE_FLAVOR;
  unsigned int stateCnt = TRACE_FLAVOR_SIZE;
  unsigned int stateCnt = TRACE_FLAVOR_SIZE;
  kern_return_t ret;
  kern_return_t ret;
  thread_state_data_t state;
  thread_state_data_t state;
 
 
  if (!MACH_PORT_VALID (thread))
  if (!MACH_PORT_VALID (thread))
    {
    {
      warning ("thread_trace: invalid thread");
      warning ("thread_trace: invalid thread");
      return;
      return;
    }
    }
 
 
  if (must_suspend_thread)
  if (must_suspend_thread)
    setup_thread (thread, 1);
    setup_thread (thread, 1);
 
 
  ret = thread_get_state (thread, flavor, state, &stateCnt);
  ret = thread_get_state (thread, flavor, state, &stateCnt);
  CHK ("thread_trace: error reading thread state", ret);
  CHK ("thread_trace: error reading thread state", ret);
 
 
  if (set)
  if (set)
    {
    {
      TRACE_SET (thread, state);
      TRACE_SET (thread, state);
    }
    }
  else
  else
    {
    {
      if (!TRACE_CLEAR (thread, state))
      if (!TRACE_CLEAR (thread, state))
        {
        {
          if (must_suspend_thread)
          if (must_suspend_thread)
            setup_thread (thread, 0);
            setup_thread (thread, 0);
          return;
          return;
        }
        }
    }
    }
 
 
  ret = thread_set_state (thread, flavor, state, stateCnt);
  ret = thread_set_state (thread, flavor, state, stateCnt);
  CHK ("thread_trace: error writing thread state", ret);
  CHK ("thread_trace: error writing thread state", ret);
  if (must_suspend_thread)
  if (must_suspend_thread)
    setup_thread (thread, 0);
    setup_thread (thread, 0);
}
}
 
 
#ifdef  FLUSH_INFERIOR_CACHE
#ifdef  FLUSH_INFERIOR_CACHE
 
 
/* When over-writing code on some machines the I-Cache must be flushed
/* When over-writing code on some machines the I-Cache must be flushed
   explicitly, because it is not kept coherent by the lazy hardware.
   explicitly, because it is not kept coherent by the lazy hardware.
   This definitely includes breakpoints, for instance, or else we
   This definitely includes breakpoints, for instance, or else we
   end up looping in mysterious Bpt traps */
   end up looping in mysterious Bpt traps */
 
 
flush_inferior_icache (pc, amount)
flush_inferior_icache (pc, amount)
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
  vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
  kern_return_t ret;
  kern_return_t ret;
 
 
  ret = vm_machine_attribute (inferior_task,
  ret = vm_machine_attribute (inferior_task,
                              pc,
                              pc,
                              amount,
                              amount,
                              MATTR_CACHE,
                              MATTR_CACHE,
                              &flush);
                              &flush);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    warning ("Error flushing inferior's cache : %s",
    warning ("Error flushing inferior's cache : %s",
             mach_error_string (ret));
             mach_error_string (ret));
}
}
#endif /* FLUSH_INFERIOR_CACHE */
#endif /* FLUSH_INFERIOR_CACHE */


 
 
static
static
suspend_all_threads (from_tty)
suspend_all_threads (from_tty)
     int from_tty;
     int from_tty;
{
{
  kern_return_t ret;
  kern_return_t ret;
  thread_array_t thread_list;
  thread_array_t thread_list;
  int thread_count, index;
  int thread_count, index;
  int infoCnt;
  int infoCnt;
  thread_basic_info_data_t th_info;
  thread_basic_info_data_t th_info;
 
 
 
 
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("Could not suspend inferior threads.");
      warning ("Could not suspend inferior threads.");
      m3_kill_inferior ();
      m3_kill_inferior ();
      return_to_top_level (RETURN_ERROR);
      return_to_top_level (RETURN_ERROR);
    }
    }
 
 
  for (index = 0; index < thread_count; index++)
  for (index = 0; index < thread_count; index++)
    {
    {
      int mid;
      int mid;
 
 
      mid = map_port_name_to_mid (thread_list[index],
      mid = map_port_name_to_mid (thread_list[index],
                                  MACH_TYPE_THREAD);
                                  MACH_TYPE_THREAD);
 
 
      ret = thread_suspend (thread_list[index]);
      ret = thread_suspend (thread_list[index]);
 
 
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        warning ("Error trying to suspend thread %d : %s",
        warning ("Error trying to suspend thread %d : %s",
                 mid, mach_error_string (ret));
                 mid, mach_error_string (ret));
 
 
      if (from_tty)
      if (from_tty)
        {
        {
          infoCnt = THREAD_BASIC_INFO_COUNT;
          infoCnt = THREAD_BASIC_INFO_COUNT;
          ret = thread_info (thread_list[index],
          ret = thread_info (thread_list[index],
                             THREAD_BASIC_INFO,
                             THREAD_BASIC_INFO,
                             (thread_info_t) & th_info,
                             (thread_info_t) & th_info,
                             &infoCnt);
                             &infoCnt);
          CHK ("suspend can't get thread info", ret);
          CHK ("suspend can't get thread info", ret);
 
 
          warning ("Thread %d suspend count is %d",
          warning ("Thread %d suspend count is %d",
                   mid, th_info.suspend_count);
                   mid, th_info.suspend_count);
        }
        }
    }
    }
 
 
  consume_send_rights (thread_list, thread_count);
  consume_send_rights (thread_list, thread_count);
  ret = vm_deallocate (mach_task_self (),
  ret = vm_deallocate (mach_task_self (),
                       (vm_address_t) thread_list,
                       (vm_address_t) thread_list,
                       (thread_count * sizeof (int)));
                       (thread_count * sizeof (int)));
  CHK ("Error trying to deallocate thread list", ret);
  CHK ("Error trying to deallocate thread list", ret);
}
}
 
 
void
void
thread_suspend_command (args, from_tty)
thread_suspend_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  kern_return_t ret;
  kern_return_t ret;
  int mid;
  int mid;
  mach_port_t saved_thread;
  mach_port_t saved_thread;
  int infoCnt;
  int infoCnt;
  thread_basic_info_data_t th_info;
  thread_basic_info_data_t th_info;
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  if (!strcasecmp (args, "all"))
  if (!strcasecmp (args, "all"))
    {
    {
      suspend_all_threads (from_tty);
      suspend_all_threads (from_tty);
      return;
      return;
    }
    }
 
 
  saved_thread = current_thread;
  saved_thread = current_thread;
 
 
  mid = parse_thread_id (args, 0, 0);
  mid = parse_thread_id (args, 0, 0);
 
 
  if (mid < 0)
  if (mid < 0)
    error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
    error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
 
 
  if (mid == 0)
  if (mid == 0)
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
  else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
  else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
    {
    {
      if (current_thread)
      if (current_thread)
        current_thread = saved_thread;
        current_thread = saved_thread;
      error ("Could not select thread %d", mid);
      error ("Could not select thread %d", mid);
    }
    }
 
 
  ret = thread_suspend (current_thread);
  ret = thread_suspend (current_thread);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    warning ("thread_suspend failed : %s",
    warning ("thread_suspend failed : %s",
             mach_error_string (ret));
             mach_error_string (ret));
 
 
  infoCnt = THREAD_BASIC_INFO_COUNT;
  infoCnt = THREAD_BASIC_INFO_COUNT;
  ret = thread_info (current_thread,
  ret = thread_info (current_thread,
                     THREAD_BASIC_INFO,
                     THREAD_BASIC_INFO,
                     (thread_info_t) & th_info,
                     (thread_info_t) & th_info,
                     &infoCnt);
                     &infoCnt);
  CHK ("suspend can't get thread info", ret);
  CHK ("suspend can't get thread info", ret);
 
 
  warning ("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;
  current_thread = saved_thread;
}
}
 
 
resume_all_threads (from_tty)
resume_all_threads (from_tty)
     int from_tty;
     int from_tty;
{
{
  kern_return_t ret;
  kern_return_t ret;
  thread_array_t thread_list;
  thread_array_t thread_list;
  int thread_count, index;
  int thread_count, index;
  int mid;
  int mid;
  int infoCnt;
  int infoCnt;
  thread_basic_info_data_t th_info;
  thread_basic_info_data_t th_info;
 
 
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      m3_kill_inferior ();
      m3_kill_inferior ();
      error ("task_threads", mach_error_string (ret));
      error ("task_threads", mach_error_string (ret));
    }
    }
 
 
  for (index = 0; index < thread_count; index++)
  for (index = 0; index < thread_count; index++)
    {
    {
      infoCnt = THREAD_BASIC_INFO_COUNT;
      infoCnt = THREAD_BASIC_INFO_COUNT;
      ret = thread_info (thread_list[index],
      ret = thread_info (thread_list[index],
                         THREAD_BASIC_INFO,
                         THREAD_BASIC_INFO,
                         (thread_info_t) & th_info,
                         (thread_info_t) & th_info,
                         &infoCnt);
                         &infoCnt);
      CHK ("resume_all can't get thread info", ret);
      CHK ("resume_all can't get thread info", ret);
 
 
      mid = map_port_name_to_mid (thread_list[index],
      mid = map_port_name_to_mid (thread_list[index],
                                  MACH_TYPE_THREAD);
                                  MACH_TYPE_THREAD);
 
 
      if (!th_info.suspend_count)
      if (!th_info.suspend_count)
        {
        {
          if (mid != -1 && from_tty)
          if (mid != -1 && from_tty)
            warning ("Thread %d is not suspended", mid);
            warning ("Thread %d is not suspended", mid);
          continue;
          continue;
        }
        }
 
 
      ret = thread_resume (thread_list[index]);
      ret = thread_resume (thread_list[index]);
 
 
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        warning ("Error trying to resume thread %d : %s",
        warning ("Error trying to resume thread %d : %s",
                 mid, mach_error_string (ret));
                 mid, mach_error_string (ret));
      else if (mid != -1 && from_tty)
      else if (mid != -1 && from_tty)
        warning ("Thread %d suspend count is %d",
        warning ("Thread %d suspend count is %d",
                 mid, --th_info.suspend_count);
                 mid, --th_info.suspend_count);
    }
    }
 
 
  consume_send_rights (thread_list, thread_count);
  consume_send_rights (thread_list, thread_count);
  ret = vm_deallocate (mach_task_self (),
  ret = vm_deallocate (mach_task_self (),
                       (vm_address_t) thread_list,
                       (vm_address_t) thread_list,
                       (thread_count * sizeof (int)));
                       (thread_count * sizeof (int)));
  CHK ("Error trying to deallocate thread list", ret);
  CHK ("Error trying to deallocate thread list", ret);
}
}
 
 
void
void
thread_resume_command (args, from_tty)
thread_resume_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int mid;
  int mid;
  mach_port_t saved_thread;
  mach_port_t saved_thread;
  kern_return_t ret;
  kern_return_t ret;
  thread_basic_info_data_t th_info;
  thread_basic_info_data_t th_info;
  int infoCnt = THREAD_BASIC_INFO_COUNT;
  int infoCnt = THREAD_BASIC_INFO_COUNT;
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  if (!strcasecmp (args, "all"))
  if (!strcasecmp (args, "all"))
    {
    {
      resume_all_threads (from_tty);
      resume_all_threads (from_tty);
      return;
      return;
    }
    }
 
 
  saved_thread = current_thread;
  saved_thread = current_thread;
 
 
  mid = parse_thread_id (args, 0, 0);
  mid = parse_thread_id (args, 0, 0);
 
 
  if (mid < 0)
  if (mid < 0)
    error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
    error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
 
 
  if (mid == 0)
  if (mid == 0)
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
  else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
  else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
    {
    {
      if (current_thread)
      if (current_thread)
        current_thread = saved_thread;
        current_thread = saved_thread;
      return_to_top_level (RETURN_ERROR);
      return_to_top_level (RETURN_ERROR);
    }
    }
 
 
  ret = thread_info (current_thread,
  ret = thread_info (current_thread,
                     THREAD_BASIC_INFO,
                     THREAD_BASIC_INFO,
                     (thread_info_t) & th_info,
                     (thread_info_t) & th_info,
                     &infoCnt);
                     &infoCnt);
  CHK ("resume can't get thread info", ret);
  CHK ("resume can't get thread info", ret);
 
 
  if (!th_info.suspend_count)
  if (!th_info.suspend_count)
    {
    {
      warning ("Thread %d is not suspended", mid);
      warning ("Thread %d is not suspended", mid);
      goto out;
      goto out;
    }
    }
 
 
  ret = thread_resume (current_thread);
  ret = thread_resume (current_thread);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    warning ("thread_resume failed : %s",
    warning ("thread_resume failed : %s",
             mach_error_string (ret));
             mach_error_string (ret));
  else
  else
    {
    {
      th_info.suspend_count--;
      th_info.suspend_count--;
      warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
      warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
    }
    }
 
 
out:
out:
  current_thread = saved_thread;
  current_thread = saved_thread;
}
}
 
 
void
void
thread_kill_command (args, from_tty)
thread_kill_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int mid;
  int mid;
  kern_return_t ret;
  kern_return_t ret;
  int thread_count;
  int thread_count;
  thread_array_t thread_table;
  thread_array_t thread_table;
  int index;
  int index;
  mach_port_t thread_to_kill = MACH_PORT_NULL;
  mach_port_t thread_to_kill = MACH_PORT_NULL;
 
 
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  if (!args)
  if (!args)
    error_no_arg ("thread mid to kill from the inferior task");
    error_no_arg ("thread mid to kill from the inferior task");
 
 
  mid = parse_thread_id (args, 0, 0);
  mid = parse_thread_id (args, 0, 0);
 
 
  if (mid < 0)
  if (mid < 0)
    error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
    error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
 
 
  if (mid)
  if (mid)
    {
    {
      ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
      ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
      CHK ("thread_kill_command: machid_mach_port map failed", ret);
      CHK ("thread_kill_command: machid_mach_port map failed", ret);
    }
    }
  else
  else
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
    mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
 
 
  /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
  /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
  ret = task_threads (inferior_task, &thread_table, &thread_count);
  ret = task_threads (inferior_task, &thread_table, &thread_count);
  CHK ("Error getting inferior's thread list", ret);
  CHK ("Error getting inferior's thread list", ret);
 
 
  if (thread_to_kill == current_thread)
  if (thread_to_kill == current_thread)
    {
    {
      ret = thread_terminate (thread_to_kill);
      ret = thread_terminate (thread_to_kill);
      CHK ("Thread could not be terminated", ret);
      CHK ("Thread could not be terminated", ret);
 
 
      if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
      if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
        warning ("Last thread was killed, use \"kill\" command to kill task");
        warning ("Last thread was killed, use \"kill\" command to kill task");
    }
    }
  else
  else
    for (index = 0; index < thread_count; index++)
    for (index = 0; index < thread_count; index++)
      if (thread_table[index] == thread_to_kill)
      if (thread_table[index] == thread_to_kill)
        {
        {
          ret = thread_terminate (thread_to_kill);
          ret = thread_terminate (thread_to_kill);
          CHK ("Thread could not be terminated", ret);
          CHK ("Thread could not be terminated", ret);
        }
        }
 
 
  if (thread_count > 1)
  if (thread_count > 1)
    consume_send_rights (thread_table, thread_count);
    consume_send_rights (thread_table, thread_count);
 
 
  ret = vm_deallocate (mach_task_self (), (vm_address_t) thread_table,
  ret = vm_deallocate (mach_task_self (), (vm_address_t) thread_table,
                       (thread_count * sizeof (mach_port_t)));
                       (thread_count * sizeof (mach_port_t)));
  CHK ("Error trying to deallocate thread list", ret);
  CHK ("Error trying to deallocate thread list", ret);
 
 
  warning ("Thread %d killed", mid);
  warning ("Thread %d killed", mid);
}
}


 
 
/* Task specific commands; add more if you like */
/* Task specific commands; add more if you like */
 
 
void
void
task_resume_command (args, from_tty)
task_resume_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  kern_return_t ret;
  kern_return_t ret;
  task_basic_info_data_t ta_info;
  task_basic_info_data_t ta_info;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
  int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  /* Would be trivial to change, but is it desirable? */
  /* Would be trivial to change, but is it desirable? */
  if (args)
  if (args)
    error ("Currently gdb can resume only it's inferior task");
    error ("Currently gdb can resume only it's inferior task");
 
 
  ret = task_info (inferior_task,
  ret = task_info (inferior_task,
                   TASK_BASIC_INFO,
                   TASK_BASIC_INFO,
                   (task_info_t) & ta_info,
                   (task_info_t) & ta_info,
                   &infoCnt);
                   &infoCnt);
  CHK ("task_resume_command: task_info failed", ret);
  CHK ("task_resume_command: task_info failed", ret);
 
 
  if (ta_info.suspend_count == 0)
  if (ta_info.suspend_count == 0)
    error ("Inferior task %d is not suspended", mid);
    error ("Inferior task %d is not suspended", mid);
  else if (ta_info.suspend_count == 1 &&
  else if (ta_info.suspend_count == 1 &&
           from_tty &&
           from_tty &&
        !query ("Suspend count is now 1. Do you know what you are doing? "))
        !query ("Suspend count is now 1. Do you know what you are doing? "))
    error ("Task not resumed");
    error ("Task not resumed");
 
 
  ret = task_resume (inferior_task);
  ret = task_resume (inferior_task);
  CHK ("task_resume_command: task_resume", ret);
  CHK ("task_resume_command: task_resume", ret);
 
 
  if (ta_info.suspend_count == 1)
  if (ta_info.suspend_count == 1)
    {
    {
      warning ("Inferior task %d is no longer suspended", mid);
      warning ("Inferior task %d is no longer suspended", mid);
      must_suspend_thread = 1;
      must_suspend_thread = 1;
      /* @@ This is not complete: Registers change all the time when not
      /* @@ This is not complete: Registers change all the time when not
         suspended! */
         suspended! */
      registers_changed ();
      registers_changed ();
    }
    }
  else
  else
    warning ("Inferior task %d suspend count is now %d",
    warning ("Inferior task %d suspend count is now %d",
             mid, ta_info.suspend_count - 1);
             mid, ta_info.suspend_count - 1);
}
}
 
 
 
 
void
void
task_suspend_command (args, from_tty)
task_suspend_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  kern_return_t ret;
  kern_return_t ret;
  task_basic_info_data_t ta_info;
  task_basic_info_data_t ta_info;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
  int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  /* Would be trivial to change, but is it desirable? */
  /* Would be trivial to change, but is it desirable? */
  if (args)
  if (args)
    error ("Currently gdb can suspend only it's inferior task");
    error ("Currently gdb can suspend only it's inferior task");
 
 
  ret = task_suspend (inferior_task);
  ret = task_suspend (inferior_task);
  CHK ("task_suspend_command: task_suspend", ret);
  CHK ("task_suspend_command: task_suspend", ret);
 
 
  must_suspend_thread = 0;
  must_suspend_thread = 0;
 
 
  ret = task_info (inferior_task,
  ret = task_info (inferior_task,
                   TASK_BASIC_INFO,
                   TASK_BASIC_INFO,
                   (task_info_t) & ta_info,
                   (task_info_t) & ta_info,
                   &infoCnt);
                   &infoCnt);
  CHK ("task_suspend_command: task_info failed", ret);
  CHK ("task_suspend_command: task_info failed", ret);
 
 
  warning ("Inferior task %d suspend count is now %d",
  warning ("Inferior task %d suspend count is now %d",
           mid, ta_info.suspend_count);
           mid, ta_info.suspend_count);
}
}
 
 
static char *
static char *
get_size (bytes)
get_size (bytes)
     int bytes;
     int bytes;
{
{
  static char size[30];
  static char size[30];
  int zz = bytes / 1024;
  int zz = bytes / 1024;
 
 
  if (zz / 1024)
  if (zz / 1024)
    sprintf (size, "%-2.1f M", ((float) bytes) / (1024.0 * 1024.0));
    sprintf (size, "%-2.1f M", ((float) bytes) / (1024.0 * 1024.0));
  else
  else
    sprintf (size, "%d K", zz);
    sprintf (size, "%d K", zz);
 
 
  return size;
  return size;
}
}
 
 
/* Does this require the target task to be suspended?? I don't think so. */
/* Does this require the target task to be suspended?? I don't think so. */
void
void
task_info_command (args, from_tty)
task_info_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int mid = -5;
  int mid = -5;
  mach_port_t task;
  mach_port_t task;
  kern_return_t ret;
  kern_return_t ret;
  task_basic_info_data_t ta_info;
  task_basic_info_data_t ta_info;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int infoCnt = TASK_BASIC_INFO_COUNT;
  int page_size = round_page (1);
  int page_size = round_page (1);
  int thread_count = 0;
  int thread_count = 0;
 
 
  if (MACH_PORT_VALID (inferior_task))
  if (MACH_PORT_VALID (inferior_task))
    mid = map_port_name_to_mid (inferior_task,
    mid = map_port_name_to_mid (inferior_task,
                                MACH_TYPE_TASK);
                                MACH_TYPE_TASK);
 
 
  task = inferior_task;
  task = inferior_task;
 
 
  if (args)
  if (args)
    {
    {
      int tmid = atoi (args);
      int tmid = atoi (args);
 
 
      if (tmid <= 0)
      if (tmid <= 0)
        error ("Invalid mid %d for task info", tmid);
        error ("Invalid mid %d for task info", tmid);
 
 
      if (tmid != mid)
      if (tmid != mid)
        {
        {
          mid = tmid;
          mid = tmid;
          ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
          ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
          CHK ("task_info_command: machid_mach_port map failed", ret);
          CHK ("task_info_command: machid_mach_port map failed", ret);
        }
        }
    }
    }
 
 
  if (mid < 0)
  if (mid < 0)
    error ("You have to give the task MID as an argument");
    error ("You have to give the task MID as an argument");
 
 
  ret = task_info (task,
  ret = task_info (task,
                   TASK_BASIC_INFO,
                   TASK_BASIC_INFO,
                   (task_info_t) & ta_info,
                   (task_info_t) & ta_info,
                   &infoCnt);
                   &infoCnt);
  CHK ("task_info_command: task_info failed", ret);
  CHK ("task_info_command: task_info failed", ret);
 
 
  printf_filtered ("\nTask info for task %d:\n\n", mid);
  printf_filtered ("\nTask info for task %d:\n\n", mid);
  printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
  printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
  printf_filtered (" Base priority : %d\n", ta_info.base_priority);
  printf_filtered (" Base priority : %d\n", ta_info.base_priority);
  printf_filtered (" Virtual size  : %s\n", get_size (ta_info.virtual_size));
  printf_filtered (" Virtual size  : %s\n", get_size (ta_info.virtual_size));
  printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
  printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
 
 
  {
  {
    thread_array_t thread_list;
    thread_array_t thread_list;
 
 
    ret = task_threads (task, &thread_list, &thread_count);
    ret = task_threads (task, &thread_list, &thread_count);
    CHK ("task_info_command: task_threads", ret);
    CHK ("task_info_command: task_threads", ret);
 
 
    printf_filtered (" Thread count  : %d\n", thread_count);
    printf_filtered (" Thread count  : %d\n", thread_count);
 
 
    consume_send_rights (thread_list, thread_count);
    consume_send_rights (thread_list, thread_count);
    ret = vm_deallocate (mach_task_self (),
    ret = vm_deallocate (mach_task_self (),
                         (vm_address_t) thread_list,
                         (vm_address_t) thread_list,
                         (thread_count * sizeof (int)));
                         (thread_count * sizeof (int)));
    CHK ("Error trying to deallocate thread list", ret);
    CHK ("Error trying to deallocate thread list", ret);
  }
  }
  if (have_emulator_p (task))
  if (have_emulator_p (task))
    printf_filtered (" Emulator at   : 0x%x..0x%x\n",
    printf_filtered (" Emulator at   : 0x%x..0x%x\n",
                     EMULATOR_BASE, EMULATOR_END);
                     EMULATOR_BASE, EMULATOR_END);
  else
  else
    printf_filtered (" No emulator.\n");
    printf_filtered (" No emulator.\n");
 
 
  if (thread_count && task == inferior_task)
  if (thread_count && task == inferior_task)
    printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
    printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
}
}


/* You may either FORWARD the exception to the inferior, or KEEP
/* You may either FORWARD the exception to the inferior, or KEEP
 * it and return to GDB command level.
 * it and return to GDB command level.
 *
 *
 * exception mid [ forward | keep ]
 * exception mid [ forward | keep ]
 */
 */
 
 
static void
static void
exception_command (args, from_tty)
exception_command (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  char *scan = args;
  char *scan = args;
  int exception;
  int exception;
  int len;
  int len;
 
 
  if (!args)
  if (!args)
    error_no_arg ("exception number action");
    error_no_arg ("exception number action");
 
 
  while (*scan == ' ' || *scan == '\t')
  while (*scan == ' ' || *scan == '\t')
    scan++;
    scan++;
 
 
  if ('0' <= *scan && *scan <= '9')
  if ('0' <= *scan && *scan <= '9')
    while ('0' <= *scan && *scan <= '9')
    while ('0' <= *scan && *scan <= '9')
      scan++;
      scan++;
  else
  else
    error ("exception number action");
    error ("exception number action");
 
 
  exception = atoi (args);
  exception = atoi (args);
  if (exception <= 0 || exception > MAX_EXCEPTION)
  if (exception <= 0 || exception > MAX_EXCEPTION)
    error ("Allowed exception numbers are in range 1..%d",
    error ("Allowed exception numbers are in range 1..%d",
           MAX_EXCEPTION);
           MAX_EXCEPTION);
 
 
  if (*scan != ' ' && *scan != '\t')
  if (*scan != ' ' && *scan != '\t')
    error ("exception number must be followed by a space");
    error ("exception number must be followed by a space");
  else
  else
    while (*scan == ' ' || *scan == '\t')
    while (*scan == ' ' || *scan == '\t')
      scan++;
      scan++;
 
 
  args = scan;
  args = scan;
  len = 0;
  len = 0;
  while (*scan)
  while (*scan)
    {
    {
      len++;
      len++;
      scan++;
      scan++;
    }
    }
 
 
  if (!len)
  if (!len)
    error ("exception number action");
    error ("exception number action");
 
 
  if (!strncasecmp (args, "forward", len))
  if (!strncasecmp (args, "forward", len))
    exception_map[exception].forward = TRUE;
    exception_map[exception].forward = TRUE;
  else if (!strncasecmp (args, "keep", len))
  else if (!strncasecmp (args, "keep", len))
    exception_map[exception].forward = FALSE;
    exception_map[exception].forward = FALSE;
  else
  else
    error ("exception action is either \"keep\" or \"forward\"");
    error ("exception action is either \"keep\" or \"forward\"");
}
}
 
 
static void
static void
print_exception_info (exception)
print_exception_info (exception)
     int exception;
     int exception;
{
{
  boolean_t forward = exception_map[exception].forward;
  boolean_t forward = exception_map[exception].forward;
 
 
  printf_filtered ("%s\t(%d): ", exception_map[exception].name,
  printf_filtered ("%s\t(%d): ", exception_map[exception].name,
                   exception);
                   exception);
  if (!forward)
  if (!forward)
    if (exception_map[exception].sigmap != SIG_UNKNOWN)
    if (exception_map[exception].sigmap != SIG_UNKNOWN)
      printf_filtered ("keep and handle as signal %d\n",
      printf_filtered ("keep and handle as signal %d\n",
                       exception_map[exception].sigmap);
                       exception_map[exception].sigmap);
    else
    else
      printf_filtered ("keep and handle as unknown signal %d\n",
      printf_filtered ("keep and handle as unknown signal %d\n",
                       exception_map[exception].sigmap);
                       exception_map[exception].sigmap);
  else
  else
    printf_filtered ("forward exception to inferior\n");
    printf_filtered ("forward exception to inferior\n");
}
}
 
 
void
void
exception_info (args, from_tty)
exception_info (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int exception;
  int exception;
 
 
  if (!args)
  if (!args)
    for (exception = 1; exception <= MAX_EXCEPTION; exception++)
    for (exception = 1; exception <= MAX_EXCEPTION; exception++)
      print_exception_info (exception);
      print_exception_info (exception);
  else
  else
    {
    {
      exception = atoi (args);
      exception = atoi (args);
 
 
      if (exception <= 0 || exception > MAX_EXCEPTION)
      if (exception <= 0 || exception > MAX_EXCEPTION)
        error ("Invalid exception number, values from 1 to %d allowed",
        error ("Invalid exception number, values from 1 to %d allowed",
               MAX_EXCEPTION);
               MAX_EXCEPTION);
      print_exception_info (exception);
      print_exception_info (exception);
    }
    }
}
}


/* Check for actions for mach exceptions.
/* Check for actions for mach exceptions.
 */
 */
mach3_exception_actions (w, force_print_only, who)
mach3_exception_actions (w, force_print_only, who)
     WAITTYPE *w;
     WAITTYPE *w;
     boolean_t force_print_only;
     boolean_t force_print_only;
     char *who;
     char *who;
{
{
  boolean_t force_print = FALSE;
  boolean_t force_print = FALSE;
 
 
 
 
  if (force_print_only ||
  if (force_print_only ||
      exception_map[stop_exception].sigmap == SIG_UNKNOWN)
      exception_map[stop_exception].sigmap == SIG_UNKNOWN)
    force_print = TRUE;
    force_print = TRUE;
  else
  else
    WSETSTOP (*w, exception_map[stop_exception].sigmap);
    WSETSTOP (*w, exception_map[stop_exception].sigmap);
 
 
  if (exception_map[stop_exception].print || force_print)
  if (exception_map[stop_exception].print || force_print)
    {
    {
      target_terminal_ours ();
      target_terminal_ours ();
 
 
      printf_filtered ("\n%s received %s exception : ",
      printf_filtered ("\n%s received %s exception : ",
                       who,
                       who,
                       exception_map[stop_exception].name);
                       exception_map[stop_exception].name);
 
 
      wrap_here ("   ");
      wrap_here ("   ");
 
 
      switch (stop_exception)
      switch (stop_exception)
        {
        {
        case EXC_BAD_ACCESS:
        case EXC_BAD_ACCESS:
          printf_filtered ("referencing address 0x%x : %s\n",
          printf_filtered ("referencing address 0x%x : %s\n",
                           stop_subcode,
                           stop_subcode,
                           mach_error_string (stop_code));
                           mach_error_string (stop_code));
          break;
          break;
        case EXC_BAD_INSTRUCTION:
        case EXC_BAD_INSTRUCTION:
          printf_filtered
          printf_filtered
            ("illegal or undefined instruction. code %d subcode %d\n",
            ("illegal or undefined instruction. code %d subcode %d\n",
             stop_code, stop_subcode);
             stop_code, stop_subcode);
          break;
          break;
        case EXC_ARITHMETIC:
        case EXC_ARITHMETIC:
          printf_filtered ("code %d\n", stop_code);
          printf_filtered ("code %d\n", stop_code);
          break;
          break;
        case EXC_EMULATION:
        case EXC_EMULATION:
          printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
          printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
          break;
          break;
        case EXC_SOFTWARE:
        case EXC_SOFTWARE:
          printf_filtered ("%s specific, code 0x%x\n",
          printf_filtered ("%s specific, code 0x%x\n",
                           stop_code < 0xffff ? "hardware" : "os emulation",
                           stop_code < 0xffff ? "hardware" : "os emulation",
                           stop_code);
                           stop_code);
          break;
          break;
        case EXC_BREAKPOINT:
        case EXC_BREAKPOINT:
          printf_filtered ("type %d (machine dependent)\n",
          printf_filtered ("type %d (machine dependent)\n",
                           stop_code);
                           stop_code);
          break;
          break;
        default:
        default:
          internal_error ("Unknown exception");
          internal_error ("Unknown exception");
        }
        }
    }
    }
}
}


setup_notify_port (create_new)
setup_notify_port (create_new)
     int create_new;
     int create_new;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (MACH_PORT_VALID (our_notify_port))
  if (MACH_PORT_VALID (our_notify_port))
    {
    {
      ret = mach_port_destroy (mach_task_self (), our_notify_port);
      ret = mach_port_destroy (mach_task_self (), our_notify_port);
      CHK ("Could not destroy our_notify_port", ret);
      CHK ("Could not destroy our_notify_port", ret);
    }
    }
 
 
  our_notify_port = MACH_PORT_NULL;
  our_notify_port = MACH_PORT_NULL;
  notify_chain = (port_chain_t) NULL;
  notify_chain = (port_chain_t) NULL;
  port_chain_destroy (port_chain_obstack);
  port_chain_destroy (port_chain_obstack);
 
 
  if (create_new)
  if (create_new)
    {
    {
      ret = mach_port_allocate (mach_task_self (),
      ret = mach_port_allocate (mach_task_self (),
                                MACH_PORT_RIGHT_RECEIVE,
                                MACH_PORT_RIGHT_RECEIVE,
                                &our_notify_port);
                                &our_notify_port);
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        internal_error ("Creating notify port %s", mach_error_string (ret));
        internal_error ("Creating notify port %s", mach_error_string (ret));
 
 
      ret = mach_port_move_member (mach_task_self (),
      ret = mach_port_move_member (mach_task_self (),
                                   our_notify_port,
                                   our_notify_port,
                                   inferior_wait_port_set);
                                   inferior_wait_port_set);
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        internal_error ("initial move member %s", mach_error_string (ret));
        internal_error ("initial move member %s", mach_error_string (ret));
    }
    }
}
}
 
 
/*
/*
 * Register our message port to the net name server
 * Register our message port to the net name server
 *
 *
 * Currently used only by the external stop-gdb program
 * Currently used only by the external stop-gdb program
 * since ^C does not work if you would like to enter
 * since ^C does not work if you would like to enter
 * gdb command level while debugging your program.
 * gdb command level while debugging your program.
 *
 *
 * NOTE: If the message port is sometimes used for other
 * NOTE: If the message port is sometimes used for other
 * purposes also, the NAME must not be a guessable one.
 * purposes also, the NAME must not be a guessable one.
 * Then, there should be a way to change it.
 * Then, there should be a way to change it.
 */
 */
 
 
char registered_name[MAX_NAME_LEN];
char registered_name[MAX_NAME_LEN];
 
 
void
void
message_port_info (args, from_tty)
message_port_info (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  if (registered_name[0])
  if (registered_name[0])
    printf_filtered ("gdb's message port name: '%s'\n",
    printf_filtered ("gdb's message port name: '%s'\n",
                     registered_name);
                     registered_name);
  else
  else
    printf_filtered ("gdb's message port is not currently registered\n");
    printf_filtered ("gdb's message port is not currently registered\n");
}
}
 
 
void
void
gdb_register_port (name, port)
gdb_register_port (name, port)
     char *name;
     char *name;
     mach_port_t port;
     mach_port_t port;
{
{
  kern_return_t ret;
  kern_return_t ret;
  static int already_signed = 0;
  static int already_signed = 0;
  int len;
  int len;
 
 
  if (!MACH_PORT_VALID (port) || !name || !*name)
  if (!MACH_PORT_VALID (port) || !name || !*name)
    {
    {
      warning ("Invalid registration request");
      warning ("Invalid registration request");
      return;
      return;
    }
    }
 
 
  if (!already_signed)
  if (!already_signed)
    {
    {
      ret = mach_port_insert_right (mach_task_self (),
      ret = mach_port_insert_right (mach_task_self (),
                                    our_message_port,
                                    our_message_port,
                                    our_message_port,
                                    our_message_port,
                                    MACH_MSG_TYPE_MAKE_SEND);
                                    MACH_MSG_TYPE_MAKE_SEND);
      CHK ("Failed to create a signature to our_message_port", ret);
      CHK ("Failed to create a signature to our_message_port", ret);
      already_signed = 1;
      already_signed = 1;
    }
    }
  else if (already_signed > 1)
  else if (already_signed > 1)
    {
    {
      ret = netname_check_out (name_server_port,
      ret = netname_check_out (name_server_port,
                               registered_name,
                               registered_name,
                               our_message_port);
                               our_message_port);
      CHK ("Failed to check out gdb's message port", ret);
      CHK ("Failed to check out gdb's message port", ret);
      registered_name[0] = '\000';
      registered_name[0] = '\000';
      already_signed = 1;
      already_signed = 1;
    }
    }
 
 
  ret = netname_check_in (name_server_port,     /* Name server port */
  ret = netname_check_in (name_server_port,     /* Name server port */
                          name, /* Name of service */
                          name, /* Name of service */
                          our_message_port,     /* Signature */
                          our_message_port,     /* Signature */
                          port);        /* Creates a new send right */
                          port);        /* Creates a new send right */
  CHK ("Failed to check in the port", ret);
  CHK ("Failed to check in the port", ret);
 
 
  len = 0;
  len = 0;
  while (len < MAX_NAME_LEN && *(name + len))
  while (len < MAX_NAME_LEN && *(name + len))
    {
    {
      registered_name[len] = *(name + len);
      registered_name[len] = *(name + len);
      len++;
      len++;
    }
    }
  registered_name[len] = '\000';
  registered_name[len] = '\000';
  already_signed = 2;
  already_signed = 2;
}
}
 
 
struct cmd_list_element *cmd_thread_list;
struct cmd_list_element *cmd_thread_list;
struct cmd_list_element *cmd_task_list;
struct cmd_list_element *cmd_task_list;
 
 
/*ARGSUSED */
/*ARGSUSED */
static void
static void
thread_command (arg, from_tty)
thread_command (arg, from_tty)
     char *arg;
     char *arg;
     int from_tty;
     int from_tty;
{
{
  printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n");
  printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n");
  help_list (cmd_thread_list, "thread ", -1, gdb_stdout);
  help_list (cmd_thread_list, "thread ", -1, gdb_stdout);
}
}
 
 
/*ARGSUSED */
/*ARGSUSED */
static void
static void
task_command (arg, from_tty)
task_command (arg, from_tty)
     char *arg;
     char *arg;
     int from_tty;
     int from_tty;
{
{
  printf_unfiltered ("\"task\" must be followed by the name of a task command.\n");
  printf_unfiltered ("\"task\" must be followed by the name of a task command.\n");
  help_list (cmd_task_list, "task ", -1, gdb_stdout);
  help_list (cmd_task_list, "task ", -1, gdb_stdout);
}
}
 
 
add_mach_specific_commands ()
add_mach_specific_commands ()
{
{
  /* Thread handling commands */
  /* Thread handling commands */
 
 
  /* FIXME: Move our thread support into the generic thread.c stuff so we
  /* FIXME: Move our thread support into the generic thread.c stuff so we
     can share that code.  */
     can share that code.  */
  add_prefix_cmd ("mthread", class_stack, thread_command,
  add_prefix_cmd ("mthread", class_stack, thread_command,
          "Generic command for handling Mach threads in the debugged task.",
          "Generic command for handling Mach threads in the debugged task.",
                  &cmd_thread_list, "thread ", 0, &cmdlist);
                  &cmd_thread_list, "thread ", 0, &cmdlist);
 
 
  add_com_alias ("th", "mthread", class_stack, 1);
  add_com_alias ("th", "mthread", class_stack, 1);
 
 
  add_cmd ("select", class_stack, thread_select_command,
  add_cmd ("select", class_stack, thread_select_command,
           "Select and print MID of the selected thread",
           "Select and print MID of the selected thread",
           &cmd_thread_list);
           &cmd_thread_list);
  add_cmd ("list", class_stack, thread_list_command,
  add_cmd ("list", class_stack, thread_list_command,
           "List info of task's threads. Selected thread is marked with '*'",
           "List info of task's threads. Selected thread is marked with '*'",
           &cmd_thread_list);
           &cmd_thread_list);
  add_cmd ("suspend", class_run, thread_suspend_command,
  add_cmd ("suspend", class_run, thread_suspend_command,
           "Suspend one or all of the threads in the selected task.",
           "Suspend one or all of the threads in the selected task.",
           &cmd_thread_list);
           &cmd_thread_list);
  add_cmd ("resume", class_run, thread_resume_command,
  add_cmd ("resume", class_run, thread_resume_command,
           "Resume one or all of the threads in the selected task.",
           "Resume one or all of the threads in the selected task.",
           &cmd_thread_list);
           &cmd_thread_list);
  add_cmd ("kill", class_run, thread_kill_command,
  add_cmd ("kill", class_run, thread_kill_command,
           "Kill the specified thread MID from inferior task.",
           "Kill the specified thread MID from inferior task.",
           &cmd_thread_list);
           &cmd_thread_list);
#if 0
#if 0
  /* The rest of this support (condition_thread) was not merged.  It probably
  /* 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
     should not be merged in this form, but instead added to the generic GDB
     thread support.  */
     thread support.  */
  add_cmd ("break", class_breakpoint, condition_thread,
  add_cmd ("break", class_breakpoint, condition_thread,
           "Breakpoint N will only be effective for thread MID or @SLOT\n\
           "Breakpoint N will only be effective for thread MID or @SLOT\n\
            If MID/@SLOT is omitted allow all threads to break at breakpoint",
            If MID/@SLOT is omitted allow all threads to break at breakpoint",
           &cmd_thread_list);
           &cmd_thread_list);
#endif
#endif
  /* Thread command shorthands (for backward compatibility) */
  /* Thread command shorthands (for backward compatibility) */
  add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
  add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
  add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
  add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
 
 
  /* task handling commands */
  /* task handling commands */
 
 
  add_prefix_cmd ("task", class_stack, task_command,
  add_prefix_cmd ("task", class_stack, task_command,
                  "Generic command for handling debugged task.",
                  "Generic command for handling debugged task.",
                  &cmd_task_list, "task ", 0, &cmdlist);
                  &cmd_task_list, "task ", 0, &cmdlist);
 
 
  add_com_alias ("ta", "task", class_stack, 1);
  add_com_alias ("ta", "task", class_stack, 1);
 
 
  add_cmd ("suspend", class_run, task_suspend_command,
  add_cmd ("suspend", class_run, task_suspend_command,
           "Suspend the inferior task.",
           "Suspend the inferior task.",
           &cmd_task_list);
           &cmd_task_list);
  add_cmd ("resume", class_run, task_resume_command,
  add_cmd ("resume", class_run, task_resume_command,
           "Resume the inferior task.",
           "Resume the inferior task.",
           &cmd_task_list);
           &cmd_task_list);
  add_cmd ("info", no_class, task_info_command,
  add_cmd ("info", no_class, task_info_command,
           "Print information about the specified task.",
           "Print information about the specified task.",
           &cmd_task_list);
           &cmd_task_list);
 
 
  /* Print my message port name */
  /* Print my message port name */
 
 
  add_info ("message-port", message_port_info,
  add_info ("message-port", message_port_info,
            "Returns the name of gdb's message port in the netnameserver");
            "Returns the name of gdb's message port in the netnameserver");
 
 
  /* Exception commands */
  /* Exception commands */
 
 
  add_info ("exceptions", exception_info,
  add_info ("exceptions", exception_info,
            "What debugger does when program gets various exceptions.\n\
            "What debugger does when program gets various exceptions.\n\
Specify an exception number as argument to print info on that\n\
Specify an exception number as argument to print info on that\n\
exception only.");
exception only.");
 
 
  add_com ("exception", class_run, exception_command,
  add_com ("exception", class_run, exception_command,
           "Specify how to handle an exception.\n\
           "Specify how to handle an exception.\n\
Args are exception number followed by \"forward\" or \"keep\".\n\
Args are exception number followed by \"forward\" or \"keep\".\n\
`Forward' means forward the exception to the program's normal exception\n\
`Forward' means forward the exception to the program's normal exception\n\
handler.\n\
handler.\n\
`Keep' means reenter debugger if this exception happens, and GDB maps\n\
`Keep' means reenter debugger if this exception happens, and GDB maps\n\
the exception to some signal (see info exception)\n\
the exception to some signal (see info exception)\n\
Normally \"keep\" is used to return to GDB on exception.");
Normally \"keep\" is used to return to GDB on exception.");
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_dead_name (notify, name)
do_mach_notify_dead_name (notify, name)
     mach_port_t notify;
     mach_port_t notify;
     mach_port_t name;
     mach_port_t name;
{
{
  kern_return_t kr = KERN_SUCCESS;
  kern_return_t kr = KERN_SUCCESS;
 
 
  /* Find the thing that notified */
  /* Find the thing that notified */
  port_chain_t element = port_chain_member (notify_chain, name);
  port_chain_t element = port_chain_member (notify_chain, name);
 
 
  /* Take name of from unreceived dead name notification list */
  /* Take name of from unreceived dead name notification list */
  notify_chain = port_chain_delete (notify_chain, name);
  notify_chain = port_chain_delete (notify_chain, name);
 
 
  if (!element)
  if (!element)
    error ("Received a dead name notify from unchained port (0x%x)", name);
    error ("Received a dead name notify from unchained port (0x%x)", name);
 
 
  switch (element->type)
  switch (element->type)
    {
    {
 
 
    case MACH_TYPE_THREAD:
    case MACH_TYPE_THREAD:
      target_terminal_ours_for_output ();
      target_terminal_ours_for_output ();
      if (name == current_thread)
      if (name == current_thread)
        {
        {
          printf_filtered ("\nCurrent thread %d died", element->mid);
          printf_filtered ("\nCurrent thread %d died", element->mid);
          current_thread = MACH_PORT_NULL;
          current_thread = MACH_PORT_NULL;
        }
        }
      else
      else
        printf_filtered ("\nThread %d died", element->mid);
        printf_filtered ("\nThread %d died", element->mid);
 
 
      break;
      break;
 
 
    case MACH_TYPE_TASK:
    case MACH_TYPE_TASK:
      target_terminal_ours_for_output ();
      target_terminal_ours_for_output ();
      if (name != inferior_task)
      if (name != inferior_task)
        printf_filtered ("Task %d died, but it was not the selected task",
        printf_filtered ("Task %d died, but it was not the selected task",
                         element->mid);
                         element->mid);
      else
      else
        {
        {
          printf_filtered ("Current task %d died", element->mid);
          printf_filtered ("Current task %d died", element->mid);
 
 
          mach_port_destroy (mach_task_self (), name);
          mach_port_destroy (mach_task_self (), name);
          inferior_task = MACH_PORT_NULL;
          inferior_task = MACH_PORT_NULL;
 
 
          if (notify_chain)
          if (notify_chain)
            warning ("There were still unreceived dead_name_notifications???");
            warning ("There were still unreceived dead_name_notifications???");
 
 
          /* Destroy the old notifications */
          /* Destroy the old notifications */
          setup_notify_port (0);
          setup_notify_port (0);
 
 
        }
        }
      break;
      break;
 
 
    default:
    default:
      error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
      error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
             name, element->type, element->mid);
             name, element->type, element->mid);
      break;
      break;
    }
    }
 
 
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_msg_accepted (notify, name)
do_mach_notify_msg_accepted (notify, name)
     mach_port_t notify;
     mach_port_t notify;
     mach_port_t name;
     mach_port_t name;
{
{
  warning ("do_mach_notify_msg_accepted : notify %x, name %x",
  warning ("do_mach_notify_msg_accepted : notify %x, name %x",
           notify, name);
           notify, name);
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_no_senders (notify, mscount)
do_mach_notify_no_senders (notify, mscount)
     mach_port_t notify;
     mach_port_t notify;
     mach_port_mscount_t mscount;
     mach_port_mscount_t mscount;
{
{
  warning ("do_mach_notify_no_senders : notify %x, mscount %x",
  warning ("do_mach_notify_no_senders : notify %x, mscount %x",
           notify, mscount);
           notify, mscount);
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_port_deleted (notify, name)
do_mach_notify_port_deleted (notify, name)
     mach_port_t notify;
     mach_port_t notify;
     mach_port_t name;
     mach_port_t name;
{
{
  warning ("do_mach_notify_port_deleted : notify %x, name %x",
  warning ("do_mach_notify_port_deleted : notify %x, name %x",
           notify, name);
           notify, name);
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_port_destroyed (notify, rights)
do_mach_notify_port_destroyed (notify, rights)
     mach_port_t notify;
     mach_port_t notify;
     mach_port_t rights;
     mach_port_t rights;
{
{
  warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
  warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
           notify, rights);
           notify, rights);
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
kern_return_t
kern_return_t
do_mach_notify_send_once (notify)
do_mach_notify_send_once (notify)
     mach_port_t notify;
     mach_port_t notify;
{
{
#ifdef DUMP_SYSCALL
#ifdef DUMP_SYSCALL
  /* MANY of these are generated. */
  /* MANY of these are generated. */
  warning ("do_mach_notify_send_once : notify %x",
  warning ("do_mach_notify_send_once : notify %x",
           notify);
           notify);
#endif
#endif
  return KERN_SUCCESS;
  return KERN_SUCCESS;
}
}
 
 
/* Kills the inferior. It's gone when you call this */
/* Kills the inferior. It's gone when you call this */
static void
static void
kill_inferior_fast ()
kill_inferior_fast ()
{
{
  WAITTYPE w;
  WAITTYPE w;
 
 
  if (inferior_pid == 0 || inferior_pid == 1)
  if (inferior_pid == 0 || inferior_pid == 1)
    return;
    return;
 
 
  /* kill() it, since the Unix server does not otherwise notice when
  /* kill() it, since the Unix server does not otherwise notice when
   * killed with task_terminate().
   * killed with task_terminate().
   */
   */
  if (inferior_pid > 0)
  if (inferior_pid > 0)
    kill (inferior_pid, SIGKILL);
    kill (inferior_pid, SIGKILL);
 
 
  /* It's propably terminate already */
  /* It's propably terminate already */
  (void) task_terminate (inferior_task);
  (void) task_terminate (inferior_task);
 
 
  inferior_task = MACH_PORT_NULL;
  inferior_task = MACH_PORT_NULL;
  current_thread = MACH_PORT_NULL;
  current_thread = MACH_PORT_NULL;
 
 
  wait3 (&w, WNOHANG, 0);
  wait3 (&w, WNOHANG, 0);
 
 
  setup_notify_port (0);
  setup_notify_port (0);
}
}
 
 
static void
static void
m3_kill_inferior ()
m3_kill_inferior ()
{
{
  kill_inferior_fast ();
  kill_inferior_fast ();
  target_mourn_inferior ();
  target_mourn_inferior ();
}
}
 
 
/* Clean up after the inferior dies.  */
/* Clean up after the inferior dies.  */
 
 
static void
static void
m3_mourn_inferior ()
m3_mourn_inferior ()
{
{
  unpush_target (&m3_ops);
  unpush_target (&m3_ops);
  generic_mourn_inferior ();
  generic_mourn_inferior ();
}
}


 
 
/* Fork an inferior process, and start debugging it.  */
/* Fork an inferior process, and start debugging it.  */
 
 
static void
static void
m3_create_inferior (exec_file, allargs, env)
m3_create_inferior (exec_file, allargs, env)
     char *exec_file;
     char *exec_file;
     char *allargs;
     char *allargs;
     char **env;
     char **env;
{
{
  fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL, NULL);
  fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL, NULL);
  /* We are at the first instruction we care about.  */
  /* We are at the first instruction we care about.  */
  /* Pedal to the metal... */
  /* Pedal to the metal... */
  proceed ((CORE_ADDR) -1, 0, 0);
  proceed ((CORE_ADDR) -1, 0, 0);
}
}
 
 
/* Mark our target-struct as eligible for stray "run" and "attach"
/* Mark our target-struct as eligible for stray "run" and "attach"
   commands.  */
   commands.  */
static int
static int
m3_can_run ()
m3_can_run ()
{
{
  return 1;
  return 1;
}
}


/* Mach 3.0 does not need ptrace for anything
/* Mach 3.0 does not need ptrace for anything
 * Make sure nobody uses it on mach.
 * Make sure nobody uses it on mach.
 */
 */
ptrace (a, b, c, d)
ptrace (a, b, c, d)
     int a, b, c, d;
     int a, b, c, d;
{
{
  error ("Lose, Lose! Somebody called ptrace\n");
  error ("Lose, Lose! Somebody called ptrace\n");
}
}
 
 
/* Resume execution of the inferior process.
/* Resume execution of the inferior process.
   If STEP is nonzero, single-step it.
   If STEP is nonzero, single-step it.
   If SIGNAL is nonzero, give it that signal.  */
   If SIGNAL is nonzero, give it that signal.  */
 
 
void
void
m3_resume (pid, step, signal)
m3_resume (pid, step, signal)
     int pid;
     int pid;
     int step;
     int step;
     enum target_signal signal;
     enum target_signal signal;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (step)
  if (step)
    {
    {
      thread_basic_info_data_t th_info;
      thread_basic_info_data_t th_info;
      unsigned int infoCnt = THREAD_BASIC_INFO_COUNT;
      unsigned int infoCnt = THREAD_BASIC_INFO_COUNT;
 
 
      /* There is no point in single stepping when current_thread
      /* There is no point in single stepping when current_thread
       * is dead.
       * is dead.
       */
       */
      if (!MACH_PORT_VALID (current_thread))
      if (!MACH_PORT_VALID (current_thread))
        error ("No thread selected; can not single step");
        error ("No thread selected; can not single step");
 
 
      /* If current_thread is suspended, tracing it would never return.
      /* If current_thread is suspended, tracing it would never return.
       */
       */
      ret = thread_info (current_thread,
      ret = thread_info (current_thread,
                         THREAD_BASIC_INFO,
                         THREAD_BASIC_INFO,
                         (thread_info_t) & th_info,
                         (thread_info_t) & th_info,
                         &infoCnt);
                         &infoCnt);
      CHK ("child_resume: can't get thread info", ret);
      CHK ("child_resume: can't get thread info", ret);
 
 
      if (th_info.suspend_count)
      if (th_info.suspend_count)
        error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
        error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
    }
    }
 
 
  vm_read_cache_valid = FALSE;
  vm_read_cache_valid = FALSE;
 
 
  if (signal && inferior_pid > 0)        /* Do not signal, if attached by MID */
  if (signal && inferior_pid > 0)        /* Do not signal, if attached by MID */
    kill (inferior_pid, target_signal_to_host (signal));
    kill (inferior_pid, target_signal_to_host (signal));
 
 
  if (step)
  if (step)
    {
    {
      suspend_all_threads (0);
      suspend_all_threads (0);
 
 
      setup_single_step (current_thread, TRUE);
      setup_single_step (current_thread, TRUE);
 
 
      ret = thread_resume (current_thread);
      ret = thread_resume (current_thread);
      CHK ("thread_resume", ret);
      CHK ("thread_resume", ret);
    }
    }
 
 
  ret = task_resume (inferior_task);
  ret = task_resume (inferior_task);
  if (ret == KERN_FAILURE)
  if (ret == KERN_FAILURE)
    warning ("Task was not suspended");
    warning ("Task was not suspended");
  else
  else
    CHK ("Resuming task", ret);
    CHK ("Resuming task", ret);
 
 
  /* HACK HACK This is needed by the multiserver system HACK HACK */
  /* HACK HACK This is needed by the multiserver system HACK HACK */
  while ((ret = task_resume (inferior_task)) == KERN_SUCCESS)
  while ((ret = task_resume (inferior_task)) == KERN_SUCCESS)
    /* make sure it really runs */ ;
    /* make sure it really runs */ ;
  /* HACK HACK This is needed by the multiserver system HACK HACK */
  /* HACK HACK This is needed by the multiserver system HACK HACK */
}
}


#ifdef ATTACH_DETACH
#ifdef ATTACH_DETACH
 
 
/* Start debugging the process with the given task */
/* Start debugging the process with the given task */
void
void
task_attach (tid)
task_attach (tid)
     task_t tid;
     task_t tid;
{
{
  kern_return_t ret;
  kern_return_t ret;
  inferior_task = tid;
  inferior_task = tid;
 
 
  ret = task_suspend (inferior_task);
  ret = task_suspend (inferior_task);
  CHK ("task_attach: task_suspend", ret);
  CHK ("task_attach: task_suspend", ret);
 
 
  must_suspend_thread = 0;
  must_suspend_thread = 0;
 
 
  setup_notify_port (1);
  setup_notify_port (1);
 
 
  request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
  request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
 
 
  setup_exception_port ();
  setup_exception_port ();
 
 
  emulator_present = have_emulator_p (inferior_task);
  emulator_present = have_emulator_p (inferior_task);
 
 
  attach_flag = 1;
  attach_flag = 1;
}
}
 
 
/* Well, we can call error also here and leave the
/* Well, we can call error also here and leave the
 * target stack inconsistent. Sigh.
 * target stack inconsistent. Sigh.
 * Fix this sometime (the only way to fail here is that
 * Fix this sometime (the only way to fail here is that
 * the task has no threads at all, which is rare, but
 * the task has no threads at all, which is rare, but
 * possible; or if the target task has died, which is also
 * possible; or if the target task has died, which is also
 * possible, but unlikely, since it has been suspended.
 * possible, but unlikely, since it has been suspended.
 * (Someone must have killed it))
 * (Someone must have killed it))
 */
 */
void
void
attach_to_thread ()
attach_to_thread ()
{
{
  if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
  if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
    error ("Could not select any threads to attach to");
    error ("Could not select any threads to attach to");
}
}
 
 
mid_attach (mid)
mid_attach (mid)
     int mid;
     int mid;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task);
  ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task);
  CHK ("mid_attach: machid_mach_port", ret);
  CHK ("mid_attach: machid_mach_port", ret);
 
 
  task_attach (inferior_task);
  task_attach (inferior_task);
 
 
  return mid;
  return mid;
}
}
 
 
/*
/*
 * Start debugging the process whose unix process-id is PID.
 * Start debugging the process whose unix process-id is PID.
 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
 *
 *
 * Prevent (possible unwanted) dangerous operations by enabled users
 * Prevent (possible unwanted) dangerous operations by enabled users
 * like "atta 0" or "atta foo" (equal to the previous :-) and
 * like "atta 0" or "atta foo" (equal to the previous :-) and
 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
 */
 */
static int
static int
m3_do_attach (pid)
m3_do_attach (pid)
     int pid;
     int pid;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  if (pid == 0)
  if (pid == 0)
    error ("MID=0, Debugging the master unix server does not compute");
    error ("MID=0, Debugging the master unix server does not compute");
 
 
  /* Foo. This assumes gdb has a unix pid */
  /* Foo. This assumes gdb has a unix pid */
  if (pid == getpid ())
  if (pid == getpid ())
    error ("I will debug myself only by mid. (Gdb would suspend itself!)");
    error ("I will debug myself only by mid. (Gdb would suspend itself!)");
 
 
  if (pid < 0)
  if (pid < 0)
    {
    {
      mid_attach (-(pid));
      mid_attach (-(pid));
 
 
      /* inferior_pid will be NEGATIVE! */
      /* inferior_pid will be NEGATIVE! */
      inferior_pid = pid;
      inferior_pid = pid;
 
 
      return inferior_pid;
      return inferior_pid;
    }
    }
 
 
  inferior_task = task_by_pid (pid);
  inferior_task = task_by_pid (pid);
  if (!MACH_PORT_VALID (inferior_task))
  if (!MACH_PORT_VALID (inferior_task))
    error ("Cannot map Unix pid %d to Mach task port", pid);
    error ("Cannot map Unix pid %d to Mach task port", pid);
 
 
  task_attach (inferior_task);
  task_attach (inferior_task);
 
 
  inferior_pid = pid;
  inferior_pid = pid;
 
 
  return inferior_pid;
  return inferior_pid;
}
}
 
 
/* Attach to process PID, then initialize for debugging it
/* Attach to process PID, then initialize for debugging it
   and wait for the trace-trap that results from attaching.  */
   and wait for the trace-trap that results from attaching.  */
 
 
static void
static void
m3_attach (args, from_tty)
m3_attach (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  char *exec_file;
  char *exec_file;
  int pid;
  int pid;
 
 
  if (!args)
  if (!args)
    error_no_arg ("process-id to attach");
    error_no_arg ("process-id to attach");
 
 
  pid = atoi (args);
  pid = atoi (args);
 
 
  if (pid == getpid ())         /* Trying to masturbate? */
  if (pid == getpid ())         /* Trying to masturbate? */
    error ("I refuse to debug myself!");
    error ("I refuse to debug myself!");
 
 
  if (from_tty)
  if (from_tty)
    {
    {
      exec_file = (char *) get_exec_file (0);
      exec_file = (char *) get_exec_file (0);
 
 
      if (exec_file)
      if (exec_file)
        printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
        printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
      else
      else
        printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
        printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
 
 
      gdb_flush (gdb_stdout);
      gdb_flush (gdb_stdout);
    }
    }
 
 
  m3_do_attach (pid);
  m3_do_attach (pid);
  inferior_pid = pid;
  inferior_pid = pid;
  push_target (&m3_ops);
  push_target (&m3_ops);
}
}


void
void
deallocate_inferior_ports ()
deallocate_inferior_ports ()
{
{
  kern_return_t ret;
  kern_return_t ret;
  thread_array_t thread_list;
  thread_array_t thread_list;
  int thread_count, index;
  int thread_count, index;
 
 
  if (!MACH_PORT_VALID (inferior_task))
  if (!MACH_PORT_VALID (inferior_task))
    return;
    return;
 
 
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  ret = task_threads (inferior_task, &thread_list, &thread_count);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      warning ("deallocate_inferior_ports: task_threads",
      warning ("deallocate_inferior_ports: task_threads",
               mach_error_string (ret));
               mach_error_string (ret));
      return;
      return;
    }
    }
 
 
  /* Get rid of send rights to task threads */
  /* Get rid of send rights to task threads */
  for (index = 0; index < thread_count; index++)
  for (index = 0; index < thread_count; index++)
    {
    {
      int rights;
      int rights;
      ret = mach_port_get_refs (mach_task_self (),
      ret = mach_port_get_refs (mach_task_self (),
                                thread_list[index],
                                thread_list[index],
                                MACH_PORT_RIGHT_SEND,
                                MACH_PORT_RIGHT_SEND,
                                &rights);
                                &rights);
      CHK ("deallocate_inferior_ports: get refs", ret);
      CHK ("deallocate_inferior_ports: get refs", ret);
 
 
      if (rights > 0)
      if (rights > 0)
        {
        {
          ret = mach_port_mod_refs (mach_task_self (),
          ret = mach_port_mod_refs (mach_task_self (),
                                    thread_list[index],
                                    thread_list[index],
                                    MACH_PORT_RIGHT_SEND,
                                    MACH_PORT_RIGHT_SEND,
                                    -rights);
                                    -rights);
          CHK ("deallocate_inferior_ports: mod refs", ret);
          CHK ("deallocate_inferior_ports: mod refs", ret);
        }
        }
    }
    }
 
 
  ret = mach_port_mod_refs (mach_task_self (),
  ret = mach_port_mod_refs (mach_task_self (),
                            inferior_exception_port,
                            inferior_exception_port,
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            -1);
                            -1);
  CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret);
  CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret);
 
 
  ret = mach_port_deallocate (mach_task_self (),
  ret = mach_port_deallocate (mach_task_self (),
                              inferior_task);
                              inferior_task);
  CHK ("deallocate_task_port: deallocating inferior_task", ret);
  CHK ("deallocate_task_port: deallocating inferior_task", ret);
 
 
  current_thread = MACH_PORT_NULL;
  current_thread = MACH_PORT_NULL;
  inferior_task = MACH_PORT_NULL;
  inferior_task = MACH_PORT_NULL;
}
}
 
 
/* Stop debugging the process whose number is PID
/* Stop debugging the process whose number is PID
   and continue it with signal number SIGNAL.
   and continue it with signal number SIGNAL.
   SIGNAL = 0 means just continue it.  */
   SIGNAL = 0 means just continue it.  */
 
 
static void
static void
m3_do_detach (signal)
m3_do_detach (signal)
     int signal;
     int signal;
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  MACH_ERROR_NO_INFERIOR;
  MACH_ERROR_NO_INFERIOR;
 
 
  if (current_thread != MACH_PORT_NULL)
  if (current_thread != MACH_PORT_NULL)
    {
    {
      /* Store the gdb's view of the thread we are deselecting
      /* Store the gdb's view of the thread we are deselecting
       * before we detach.
       * before we detach.
       * @@ I am really not sure if this is ever needeed.
       * @@ I am really not sure if this is ever needeed.
       */
       */
      target_prepare_to_store ();
      target_prepare_to_store ();
      target_store_registers (-1);
      target_store_registers (-1);
    }
    }
 
 
  ret = task_set_special_port (inferior_task,
  ret = task_set_special_port (inferior_task,
                               TASK_EXCEPTION_PORT,
                               TASK_EXCEPTION_PORT,
                               inferior_old_exception_port);
                               inferior_old_exception_port);
  CHK ("task_set_special_port", ret);
  CHK ("task_set_special_port", ret);
 
 
  /* Discard all requested notifications */
  /* Discard all requested notifications */
  setup_notify_port (0);
  setup_notify_port (0);
 
 
  if (remove_breakpoints ())
  if (remove_breakpoints ())
    warning ("Could not remove breakpoints when detaching");
    warning ("Could not remove breakpoints when detaching");
 
 
  if (signal && inferior_pid > 0)
  if (signal && inferior_pid > 0)
    kill (inferior_pid, signal);
    kill (inferior_pid, signal);
 
 
  /* the task might be dead by now */
  /* the task might be dead by now */
  (void) task_resume (inferior_task);
  (void) task_resume (inferior_task);
 
 
  deallocate_inferior_ports ();
  deallocate_inferior_ports ();
 
 
  attach_flag = 0;
  attach_flag = 0;
}
}
 
 
/* Take a program previously attached to and detaches it.
/* Take a program previously attached to and detaches it.
   The program resumes execution and will no longer stop
   The program resumes execution and will no longer stop
   on signals, etc.  We'd better not have left any breakpoints
   on signals, etc.  We'd better not have left any breakpoints
   in the program or it'll die when it hits one.  For this
   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
   to work, it may be necessary for the process to have been
   previously attached.  It *might* work if the program was
   previously attached.  It *might* work if the program was
   started via fork.  */
   started via fork.  */
 
 
static void
static void
m3_detach (args, from_tty)
m3_detach (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int siggnal = 0;
  int siggnal = 0;
 
 
  if (from_tty)
  if (from_tty)
    {
    {
      char *exec_file = get_exec_file (0);
      char *exec_file = get_exec_file (0);
      if (exec_file == 0)
      if (exec_file == 0)
        exec_file = "";
        exec_file = "";
      printf_unfiltered ("Detaching from program: %s %s\n",
      printf_unfiltered ("Detaching from program: %s %s\n",
                         exec_file, target_pid_to_str (inferior_pid));
                         exec_file, target_pid_to_str (inferior_pid));
      gdb_flush (gdb_stdout);
      gdb_flush (gdb_stdout);
    }
    }
  if (args)
  if (args)
    siggnal = atoi (args);
    siggnal = atoi (args);
 
 
  m3_do_detach (siggnal);
  m3_do_detach (siggnal);
  inferior_pid = 0;
  inferior_pid = 0;
  unpush_target (&m3_ops);      /* Pop out of handling an inferior */
  unpush_target (&m3_ops);      /* Pop out of handling an inferior */
}
}
#endif /* ATTACH_DETACH */
#endif /* ATTACH_DETACH */
 
 
/* Get ready to modify the registers array.  On machines which store
/* Get ready to modify the registers array.  On machines which store
   individual registers, this doesn't need to do anything.  On machines
   individual registers, this doesn't need to do anything.  On machines
   which store all the registers in one fell swoop, this makes sure
   which store all the registers in one fell swoop, this makes sure
   that registers contains all the registers from the program being
   that registers contains all the registers from the program being
   debugged.  */
   debugged.  */
 
 
static void
static void
m3_prepare_to_store ()
m3_prepare_to_store ()
{
{
#ifdef CHILD_PREPARE_TO_STORE
#ifdef CHILD_PREPARE_TO_STORE
  CHILD_PREPARE_TO_STORE ();
  CHILD_PREPARE_TO_STORE ();
#endif
#endif
}
}
 
 
/* Print status information about what we're accessing.  */
/* Print status information about what we're accessing.  */
 
 
static void
static void
m3_files_info (ignore)
m3_files_info (ignore)
     struct target_ops *ignore;
     struct target_ops *ignore;
{
{
  /* FIXME: should print MID and all that crap.  */
  /* FIXME: should print MID and all that crap.  */
  printf_unfiltered ("\tUsing the running image of %s %s.\n",
  printf_unfiltered ("\tUsing the running image of %s %s.\n",
      attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
      attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
}
}
 
 
static void
static void
m3_open (arg, from_tty)
m3_open (arg, from_tty)
     char *arg;
     char *arg;
     int from_tty;
     int from_tty;
{
{
  error ("Use the \"run\" command to start a Unix child process.");
  error ("Use the \"run\" command to start a Unix child process.");
}
}
 
 
#ifdef DUMP_SYSCALL
#ifdef DUMP_SYSCALL
#ifdef __STDC__
#ifdef __STDC__
#define STR(x) #x
#define STR(x) #x
#else
#else
#define STR(x) "x"
#define STR(x) "x"
#endif
#endif
 
 
char *bsd1_names[] =
char *bsd1_names[] =
{
{
  "execve",
  "execve",
  "fork",
  "fork",
  "take_signal",
  "take_signal",
  "sigreturn",
  "sigreturn",
  "getrusage",
  "getrusage",
  "chdir",
  "chdir",
  "chroot",
  "chroot",
  "open",
  "open",
  "creat",
  "creat",
  "mknod",
  "mknod",
  "link",
  "link",
  "symlink",
  "symlink",
  "unlink",
  "unlink",
  "access",
  "access",
  "stat",
  "stat",
  "readlink",
  "readlink",
  "chmod",
  "chmod",
  "chown",
  "chown",
  "utimes",
  "utimes",
  "truncate",
  "truncate",
  "rename",
  "rename",
  "mkdir",
  "mkdir",
  "rmdir",
  "rmdir",
  "xutimes",
  "xutimes",
  "mount",
  "mount",
  "umount",
  "umount",
  "acct",
  "acct",
  "setquota",
  "setquota",
  "write_short",
  "write_short",
  "write_long",
  "write_long",
  "send_short",
  "send_short",
  "send_long",
  "send_long",
  "sendto_short",
  "sendto_short",
  "sendto_long",
  "sendto_long",
  "select",
  "select",
  "task_by_pid",
  "task_by_pid",
  "recvfrom_short",
  "recvfrom_short",
  "recvfrom_long",
  "recvfrom_long",
  "setgroups",
  "setgroups",
  "setrlimit",
  "setrlimit",
  "sigvec",
  "sigvec",
  "sigstack",
  "sigstack",
  "settimeofday",
  "settimeofday",
  "adjtime",
  "adjtime",
  "setitimer",
  "setitimer",
  "sethostname",
  "sethostname",
  "bind",
  "bind",
  "accept",
  "accept",
  "connect",
  "connect",
  "setsockopt",
  "setsockopt",
  "getsockopt",
  "getsockopt",
  "getsockname",
  "getsockname",
  "getpeername",
  "getpeername",
  "init_process",
  "init_process",
  "table_set",
  "table_set",
  "table_get",
  "table_get",
  "pioctl",
  "pioctl",
  "emulator_error",
  "emulator_error",
  "readwrite",
  "readwrite",
  "share_wakeup",
  "share_wakeup",
  0,
  0,
  "maprw_request_it",
  "maprw_request_it",
  "maprw_release_it",
  "maprw_release_it",
  "maprw_remap",
  "maprw_remap",
  "pid_by_task",
  "pid_by_task",
};
};
 
 
int bsd1_nnames = sizeof (bsd1_names) / sizeof (bsd1_names[0]);
int bsd1_nnames = sizeof (bsd1_names) / sizeof (bsd1_names[0]);
 
 
char *
char *
name_str (name, buf)
name_str (name, buf)
 
 
     int name;
     int name;
     char *buf;
     char *buf;
 
 
{
{
  switch (name)
  switch (name)
    {
    {
    case MACH_MSG_TYPE_BOOLEAN:
    case MACH_MSG_TYPE_BOOLEAN:
      return "boolean";
      return "boolean";
    case MACH_MSG_TYPE_INTEGER_16:
    case MACH_MSG_TYPE_INTEGER_16:
      return "short";
      return "short";
    case MACH_MSG_TYPE_INTEGER_32:
    case MACH_MSG_TYPE_INTEGER_32:
      return "long";
      return "long";
    case MACH_MSG_TYPE_CHAR:
    case MACH_MSG_TYPE_CHAR:
      return "char";
      return "char";
    case MACH_MSG_TYPE_BYTE:
    case MACH_MSG_TYPE_BYTE:
      return "byte";
      return "byte";
    case MACH_MSG_TYPE_REAL:
    case MACH_MSG_TYPE_REAL:
      return "real";
      return "real";
    case MACH_MSG_TYPE_STRING:
    case MACH_MSG_TYPE_STRING:
      return "string";
      return "string";
    default:
    default:
      sprintf (buf, "%d", name);
      sprintf (buf, "%d", name);
      return buf;
      return buf;
    }
    }
}
}
 
 
char *
char *
id_str (id, buf)
id_str (id, buf)
 
 
     int id;
     int id;
     char *buf;
     char *buf;
 
 
{
{
  char *p;
  char *p;
  if (id >= 101000 && id < 101000 + bsd1_nnames)
  if (id >= 101000 && id < 101000 + bsd1_nnames)
    {
    {
      if (p = bsd1_names[id - 101000])
      if (p = bsd1_names[id - 101000])
        return p;
        return p;
    }
    }
  if (id == 102000)
  if (id == 102000)
    return "psignal_retry";
    return "psignal_retry";
  if (id == 100000)
  if (id == 100000)
    return "syscall";
    return "syscall";
  sprintf (buf, "%d", id);
  sprintf (buf, "%d", id);
  return buf;
  return buf;
}
}
 
 
print_msg (mp)
print_msg (mp)
     mach_msg_header_t *mp;
     mach_msg_header_t *mp;
{
{
  char *fmt_x = "%20s : 0x%08x\n";
  char *fmt_x = "%20s : 0x%08x\n";
  char *fmt_d = "%20s : %10d\n";
  char *fmt_d = "%20s : %10d\n";
  char *fmt_s = "%20s : %s\n";
  char *fmt_s = "%20s : %s\n";
  char buf[100];
  char buf[100];
 
 
  puts_filtered ("\n");
  puts_filtered ("\n");
#define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
#define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
  pr (fmt_x, (*mp), msgh_bits);
  pr (fmt_x, (*mp), msgh_bits);
  pr (fmt_d, (*mp), msgh_size);
  pr (fmt_d, (*mp), msgh_size);
  pr (fmt_x, (*mp), msgh_remote_port);
  pr (fmt_x, (*mp), msgh_remote_port);
  pr (fmt_x, (*mp), msgh_local_port);
  pr (fmt_x, (*mp), msgh_local_port);
  pr (fmt_d, (*mp), msgh_kind);
  pr (fmt_d, (*mp), msgh_kind);
  printf_filtered (fmt_s, STR (msgh_id), id_str (mp->msgh_id, buf));
  printf_filtered (fmt_s, STR (msgh_id), id_str (mp->msgh_id, buf));
 
 
  if (debug_level > 1)
  if (debug_level > 1)
    {
    {
      char *p, *ep, *dp;
      char *p, *ep, *dp;
      int plen;
      int plen;
      p = (char *) mp;
      p = (char *) mp;
      ep = p + mp->msgh_size;
      ep = p + mp->msgh_size;
      p += sizeof (*mp);
      p += sizeof (*mp);
      for (; p < ep; p += plen)
      for (; p < ep; p += plen)
        {
        {
          mach_msg_type_t *tp;
          mach_msg_type_t *tp;
          mach_msg_type_long_t *tlp;
          mach_msg_type_long_t *tlp;
          int name, size, number;
          int name, size, number;
          tp = (mach_msg_type_t *) p;
          tp = (mach_msg_type_t *) p;
          if (tp->msgt_longform)
          if (tp->msgt_longform)
            {
            {
              tlp = (mach_msg_type_long_t *) tp;
              tlp = (mach_msg_type_long_t *) tp;
              name = tlp->msgtl_name;
              name = tlp->msgtl_name;
              size = tlp->msgtl_size;
              size = tlp->msgtl_size;
              number = tlp->msgtl_number;
              number = tlp->msgtl_number;
              plen = sizeof (*tlp);
              plen = sizeof (*tlp);
            }
            }
          else
          else
            {
            {
              name = tp->msgt_name;
              name = tp->msgt_name;
              size = tp->msgt_size;
              size = tp->msgt_size;
              number = tp->msgt_number;
              number = tp->msgt_number;
              plen = sizeof (*tp);
              plen = sizeof (*tp);
            }
            }
          printf_filtered ("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
          printf_filtered ("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
                        name_str (name, buf), size, number, tp->msgt_inline,
                        name_str (name, buf), size, number, tp->msgt_inline,
                           tp->msgt_longform, tp->msgt_deallocate);
                           tp->msgt_longform, tp->msgt_deallocate);
          dp = p + plen;
          dp = p + plen;
          if (tp->msgt_inline)
          if (tp->msgt_inline)
            {
            {
              int l;
              int l;
              l = size * number / 8;
              l = size * number / 8;
              l = (l + sizeof (long) - 1) & ~((sizeof (long)) - 1);
              l = (l + sizeof (long) - 1) & ~((sizeof (long)) - 1);
              plen += l;
              plen += l;
              print_data (dp, size, number);
              print_data (dp, size, number);
            }
            }
          else
          else
            {
            {
              plen += sizeof (int *);
              plen += sizeof (int *);
            }
            }
          printf_filtered ("plen=%d\n", plen);
          printf_filtered ("plen=%d\n", plen);
        }
        }
    }
    }
}
}
 
 
print_data (p, size, number)
print_data (p, size, number)
 
 
     char *p;
     char *p;
 
 
{
{
  int *ip;
  int *ip;
  short *sp;
  short *sp;
  int i;
  int i;
 
 
  switch (size)
  switch (size)
    {
    {
    case 8:
    case 8:
      for (i = 0; i < number; i++)
      for (i = 0; i < number; i++)
        {
        {
          printf_filtered (" %02x", p[i]);
          printf_filtered (" %02x", p[i]);
        }
        }
      break;
      break;
    case 16:
    case 16:
      sp = (short *) p;
      sp = (short *) p;
      for (i = 0; i < number; i++)
      for (i = 0; i < number; i++)
        {
        {
          printf_filtered (" %04x", sp[i]);
          printf_filtered (" %04x", sp[i]);
        }
        }
      break;
      break;
    case 32:
    case 32:
      ip = (int *) p;
      ip = (int *) p;
      for (i = 0; i < number; i++)
      for (i = 0; i < number; i++)
        {
        {
          printf_filtered (" %08x", ip[i]);
          printf_filtered (" %08x", ip[i]);
        }
        }
      break;
      break;
    }
    }
  puts_filtered ("\n");
  puts_filtered ("\n");
}
}
#endif /* DUMP_SYSCALL */
#endif /* DUMP_SYSCALL */
 
 
static void
static void
m3_stop ()
m3_stop ()
{
{
  error ("to_stop target function not implemented");
  error ("to_stop target function not implemented");
}
}
 
 
static char *
static char *
m3_pid_to_exec_file (pid)
m3_pid_to_exec_file (pid)
     int pid;
     int pid;
{
{
  error ("to_pid_to_exec_file target function not implemented");
  error ("to_pid_to_exec_file target function not implemented");
  return NULL;                  /* To keep all compilers happy. */
  return NULL;                  /* To keep all compilers happy. */
}
}
 
 
static void
static void
init_m3_ops ()
init_m3_ops ()
{
{
  m3_ops.to_shortname = "mach";
  m3_ops.to_shortname = "mach";
  m3_ops.to_longname = "Mach child process";
  m3_ops.to_longname = "Mach child process";
  m3_ops.to_doc = "Mach child process (started by the \"run\" command).";
  m3_ops.to_doc = "Mach child process (started by the \"run\" command).";
  m3_ops.to_open = m3_open;
  m3_ops.to_open = m3_open;
  m3_ops.to_attach = m3_attach;
  m3_ops.to_attach = m3_attach;
  m3_ops.to_detach = m3_detach;
  m3_ops.to_detach = m3_detach;
  m3_ops.to_resume = m3_resume;
  m3_ops.to_resume = m3_resume;
  m3_ops.to_wait = mach_really__wait;
  m3_ops.to_wait = mach_really__wait;
  m3_ops.to_fetch_registers = fetch_inferior_registers;
  m3_ops.to_fetch_registers = fetch_inferior_registers;
  m3_ops.to_store_registers = store_inferior_registers;
  m3_ops.to_store_registers = store_inferior_registers;
  m3_ops.to_prepare_to_store = m3_prepare_to_store;
  m3_ops.to_prepare_to_store = m3_prepare_to_store;
  m3_ops.to_xfer_memory = m3_xfer_memory;
  m3_ops.to_xfer_memory = m3_xfer_memory;
  m3_ops.to_files_info = m3_files_info;
  m3_ops.to_files_info = m3_files_info;
  m3_ops.to_insert_breakpoint = memory_insert_breakpoint;
  m3_ops.to_insert_breakpoint = memory_insert_breakpoint;
  m3_ops.to_remove_breakpoint = memory_remove_breakpoint;
  m3_ops.to_remove_breakpoint = memory_remove_breakpoint;
  m3_ops.to_terminal_init = terminal_init_inferior;
  m3_ops.to_terminal_init = terminal_init_inferior;
  m3_ops.to_terminal_inferior = terminal_inferior;
  m3_ops.to_terminal_inferior = terminal_inferior;
  m3_ops.to_terminal_ours_for_output = terminal_ours_for_output;
  m3_ops.to_terminal_ours_for_output = terminal_ours_for_output;
  m3_ops.to_terminal_ours = terminal_ours;
  m3_ops.to_terminal_ours = terminal_ours;
  m3_ops.to_terminal_info = child_terminal_info;
  m3_ops.to_terminal_info = child_terminal_info;
  m3_ops.to_kill = m3_kill_inferior;
  m3_ops.to_kill = m3_kill_inferior;
  m3_ops.to_create_inferior = m3_create_inferior;
  m3_ops.to_create_inferior = m3_create_inferior;
  m3_ops.to_mourn_inferior = m3_mourn_inferior;
  m3_ops.to_mourn_inferior = m3_mourn_inferior;
  m3_ops.to_can_run = m3_can_run;
  m3_ops.to_can_run = m3_can_run;
  m3_ops.to_stop = m3_stop;
  m3_ops.to_stop = m3_stop;
  m3_ops.to_pid_to_exec_file = m3_pid_to_exec_file;
  m3_ops.to_pid_to_exec_file = m3_pid_to_exec_file;
  m3_ops.to_stratum = process_stratum;
  m3_ops.to_stratum = process_stratum;
  m3_ops.to_has_all_memory = 1;
  m3_ops.to_has_all_memory = 1;
  m3_ops.to_has_memory = 1;
  m3_ops.to_has_memory = 1;
  m3_ops.to_has_stack = 1;
  m3_ops.to_has_stack = 1;
  m3_ops.to_has_registers = 1;
  m3_ops.to_has_registers = 1;
  m3_ops.to_has_execution = 1;
  m3_ops.to_has_execution = 1;
  m3_ops.to_magic = OPS_MAGIC;
  m3_ops.to_magic = OPS_MAGIC;
}
}
 
 
void
void
_initialize_m3_nat ()
_initialize_m3_nat ()
{
{
  kern_return_t ret;
  kern_return_t ret;
 
 
  init_m3_ops ();
  init_m3_ops ();
  add_target (&m3_ops);
  add_target (&m3_ops);
 
 
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_PORT_SET,
                            MACH_PORT_RIGHT_PORT_SET,
                            &inferior_wait_port_set);
                            &inferior_wait_port_set);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    internal_error ("initial port set %s", mach_error_string (ret));
    internal_error ("initial port set %s", mach_error_string (ret));
 
 
  /* mach_really_wait now waits for this */
  /* mach_really_wait now waits for this */
  currently_waiting_for = inferior_wait_port_set;
  currently_waiting_for = inferior_wait_port_set;
 
 
  ret = netname_look_up (name_server_port, hostname, "MachID", &mid_server);
  ret = netname_look_up (name_server_port, hostname, "MachID", &mid_server);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    {
    {
      mid_server = MACH_PORT_NULL;
      mid_server = MACH_PORT_NULL;
 
 
      warning ("initialize machid: netname_lookup_up(MachID) : %s",
      warning ("initialize machid: netname_lookup_up(MachID) : %s",
               mach_error_string (ret));
               mach_error_string (ret));
      warning ("Some (most?) features disabled...");
      warning ("Some (most?) features disabled...");
    }
    }
 
 
  mid_auth = mach_privileged_host_port ();
  mid_auth = mach_privileged_host_port ();
  if (mid_auth == MACH_PORT_NULL)
  if (mid_auth == MACH_PORT_NULL)
    mid_auth = mach_task_self ();
    mid_auth = mach_task_self ();
 
 
  obstack_init (port_chain_obstack);
  obstack_init (port_chain_obstack);
 
 
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            &thread_exception_port);
                            &thread_exception_port);
  CHK ("Creating thread_exception_port for single stepping", ret);
  CHK ("Creating thread_exception_port for single stepping", ret);
 
 
  ret = mach_port_insert_right (mach_task_self (),
  ret = mach_port_insert_right (mach_task_self (),
                                thread_exception_port,
                                thread_exception_port,
                                thread_exception_port,
                                thread_exception_port,
                                MACH_MSG_TYPE_MAKE_SEND);
                                MACH_MSG_TYPE_MAKE_SEND);
  CHK ("Inserting send right to thread_exception_port", ret);
  CHK ("Inserting send right to thread_exception_port", ret);
 
 
  /* Allocate message port */
  /* Allocate message port */
  ret = mach_port_allocate (mach_task_self (),
  ret = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE,
                            MACH_PORT_RIGHT_RECEIVE,
                            &our_message_port);
                            &our_message_port);
  if (ret != KERN_SUCCESS)
  if (ret != KERN_SUCCESS)
    warning ("Creating message port %s", mach_error_string (ret));
    warning ("Creating message port %s", mach_error_string (ret));
  else
  else
    {
    {
      char buf[MAX_NAME_LEN];
      char buf[MAX_NAME_LEN];
      ret = mach_port_move_member (mach_task_self (),
      ret = mach_port_move_member (mach_task_self (),
                                   our_message_port,
                                   our_message_port,
                                   inferior_wait_port_set);
                                   inferior_wait_port_set);
      if (ret != KERN_SUCCESS)
      if (ret != KERN_SUCCESS)
        warning ("message move member %s", mach_error_string (ret));
        warning ("message move member %s", mach_error_string (ret));
 
 
 
 
      /* @@@@ No way to change message port name currently */
      /* @@@@ No way to change message port name currently */
      /* Foo. This assumes gdb has a unix pid */
      /* Foo. This assumes gdb has a unix pid */
      sprintf (buf, "gdb-%d", getpid ());
      sprintf (buf, "gdb-%d", getpid ());
      gdb_register_port (buf, our_message_port);
      gdb_register_port (buf, our_message_port);
    }
    }
 
 
  /* Heap for thread commands */
  /* Heap for thread commands */
  obstack_init (cproc_obstack);
  obstack_init (cproc_obstack);
 
 
  add_mach_specific_commands ();
  add_mach_specific_commands ();
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.