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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [gnu-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 the GNU Hurd.
/* Interface GDB to the GNU Hurd.
   Copyright (C) 1992, 95, 96, 97, 1999, 2000 Free Software Foundation, Inc.
   Copyright (C) 1992, 95, 96, 97, 1999, 2000 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   Written by Miles Bader <miles@gnu.ai.mit.edu>
   Written by Miles Bader <miles@gnu.ai.mit.edu>
 
 
   Some code and ideas from m3-nat.c by Jukka Virtanen <jtv@hut.fi>
   Some code and ideas from m3-nat.c by Jukka Virtanen <jtv@hut.fi>
 
 
   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.
 */
 */
 
 
#include <assert.h>
#include <assert.h>
#include <errno.h>
#include <errno.h>
#include <limits.h>
#include <limits.h>
#include <setjmp.h>
#include <setjmp.h>
#include <signal.h>
#include <signal.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/ptrace.h>
 
 
#include <mach.h>
#include <mach.h>
#include <mach_error.h>
#include <mach_error.h>
#include <mach/exception.h>
#include <mach/exception.h>
#include <mach/message.h>
#include <mach/message.h>
#include <mach/notify.h>
#include <mach/notify.h>
#include <mach/vm_attributes.h>
#include <mach/vm_attributes.h>
 
 
#include <hurd.h>
#include <hurd.h>
#include <hurd/interrupt.h>
#include <hurd/interrupt.h>
#include <hurd/msg.h>
#include <hurd/msg.h>
#include <hurd/msg_request.h>
#include <hurd/msg_request.h>
#include <hurd/process.h>
#include <hurd/process.h>
#include <hurd/process_request.h>
#include <hurd/process_request.h>
#include <hurd/signal.h>
#include <hurd/signal.h>
#include <hurd/sigpreempt.h>
#include <hurd/sigpreempt.h>
 
 
#include <portinfo.h>
#include <portinfo.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"
#include "gdbthread.h"
#include "gdbthread.h"
 
 
#include "gnu-nat.h"
#include "gnu-nat.h"
 
 
#include "exc_request_S.h"
#include "exc_request_S.h"
#include "notify_S.h"
#include "notify_S.h"
#include "process_reply_S.h"
#include "process_reply_S.h"
#include "msg_reply_S.h"
#include "msg_reply_S.h"
#include "exc_request_U.h"
#include "exc_request_U.h"
#include "msg_U.h"
#include "msg_U.h"
 
 
static process_t proc_server = MACH_PORT_NULL;
static process_t proc_server = MACH_PORT_NULL;
 
 
/* If we've sent a proc_wait_request to the proc server, the pid of the
/* If we've sent a proc_wait_request to the proc server, the pid of the
   process we asked about.  We can only ever have one outstanding.  */
   process we asked about.  We can only ever have one outstanding.  */
int proc_wait_pid = 0;
int proc_wait_pid = 0;
 
 
/* The number of wait requests we've sent, and expect replies from.  */
/* The number of wait requests we've sent, and expect replies from.  */
int proc_waits_pending = 0;
int proc_waits_pending = 0;
 
 
int gnu_debug_flag = 0;
int gnu_debug_flag = 0;
 
 
/* Forward decls */
/* Forward decls */
 
 
extern struct target_ops gnu_ops;
extern struct target_ops gnu_ops;
 
 
struct inf *make_inf ();
struct inf *make_inf ();
void inf_clear_wait (struct inf *inf);
void inf_clear_wait (struct inf *inf);
void inf_cleanup (struct inf *inf);
void inf_cleanup (struct inf *inf);
void inf_startup (struct inf *inf, int pid);
void inf_startup (struct inf *inf, int pid);
int inf_update_suspends (struct inf *inf);
int inf_update_suspends (struct inf *inf);
void inf_set_pid (struct inf *inf, pid_t pid);
void inf_set_pid (struct inf *inf, pid_t pid);
void inf_validate_procs (struct inf *inf);
void inf_validate_procs (struct inf *inf);
void inf_steal_exc_ports (struct inf *inf);
void inf_steal_exc_ports (struct inf *inf);
void inf_restore_exc_ports (struct inf *inf);
void inf_restore_exc_ports (struct inf *inf);
struct proc *inf_tid_to_proc (struct inf *inf, int tid);
struct proc *inf_tid_to_proc (struct inf *inf, int tid);
inline void inf_set_threads_resume_sc (struct inf *inf,
inline void inf_set_threads_resume_sc (struct inf *inf,
                                       struct proc *run_thread,
                                       struct proc *run_thread,
                                       int run_others);
                                       int run_others);
inline int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
inline int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
inline void inf_suspend (struct inf *inf);
inline void inf_suspend (struct inf *inf);
inline void inf_resume (struct inf *inf);
inline void inf_resume (struct inf *inf);
void inf_set_step_thread (struct inf *inf, struct proc *proc);
void inf_set_step_thread (struct inf *inf, struct proc *proc);
void inf_detach (struct inf *inf);
void inf_detach (struct inf *inf);
void inf_attach (struct inf *inf, int pid);
void inf_attach (struct inf *inf, int pid);
void inf_signal (struct inf *inf, enum target_signal sig);
void inf_signal (struct inf *inf, enum target_signal sig);
void inf_continue (struct inf *inf);
void inf_continue (struct inf *inf);
 
 
#define inf_debug(_inf, msg, args...) \
#define inf_debug(_inf, msg, args...) \
  do { struct inf *__inf = (_inf); \
  do { struct inf *__inf = (_inf); \
       debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
       debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
 
 
void proc_abort (struct proc *proc, int force);
void proc_abort (struct proc *proc, int force);
struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
struct proc *_proc_free (struct proc *proc);
struct proc *_proc_free (struct proc *proc);
int proc_update_sc (struct proc *proc);
int proc_update_sc (struct proc *proc);
error_t proc_get_exception_port (struct proc *proc, mach_port_t * port);
error_t proc_get_exception_port (struct proc *proc, mach_port_t * port);
error_t proc_set_exception_port (struct proc *proc, mach_port_t port);
error_t proc_set_exception_port (struct proc *proc, mach_port_t port);
static mach_port_t _proc_get_exc_port (struct proc *proc);
static mach_port_t _proc_get_exc_port (struct proc *proc);
void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
void proc_restore_exc_port (struct proc *proc);
void proc_restore_exc_port (struct proc *proc);
int proc_trace (struct proc *proc, int set);
int proc_trace (struct proc *proc, int set);
 
 
/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
   to INF's msg port and task port respectively.  If it has no msg port,
   to INF's msg port and task port respectively.  If it has no msg port,
   EIEIO is returned.  INF must refer to a running process!  */
   EIEIO is returned.  INF must refer to a running process!  */
#define INF_MSGPORT_RPC(inf, rpc_expr) \
#define INF_MSGPORT_RPC(inf, rpc_expr) \
  HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \
  HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \
                    (refport = inf->task->port, 0), 0, \
                    (refport = inf->task->port, 0), 0, \
                    msgport ? (rpc_expr) : EIEIO)
                    msgport ? (rpc_expr) : EIEIO)
 
 
/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure
/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure
   there's someone around to deal with the RPC (and resuspend things
   there's someone around to deal with the RPC (and resuspend things
   afterwards).  This effects INF's threads' resume_sc count.  */
   afterwards).  This effects INF's threads' resume_sc count.  */
#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \
#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \
  (inf_set_threads_resume_sc_for_signal_thread (inf) \
  (inf_set_threads_resume_sc_for_signal_thread (inf) \
   ? ({ error_t __e; \
   ? ({ error_t __e; \
        inf_resume (inf); \
        inf_resume (inf); \
        __e = INF_MSGPORT_RPC (inf, rpc_expr); \
        __e = INF_MSGPORT_RPC (inf, rpc_expr); \
        inf_suspend (inf); \
        inf_suspend (inf); \
        __e; }) \
        __e; }) \
   : EIEIO)
   : EIEIO)
 
 


/* The state passed by an exception message.  */
/* The state passed by an exception message.  */
struct exc_state
struct exc_state
  {
  {
    int exception;              /* The exception code */
    int exception;              /* The exception code */
    int code, subcode;
    int code, subcode;
    mach_port_t handler;        /* The real exception port to handle this. */
    mach_port_t handler;        /* The real exception port to handle this. */
    mach_port_t reply;          /* The reply port from the exception call. */
    mach_port_t reply;          /* The reply port from the exception call. */
  };
  };
 
 
/* The results of the last wait an inf did. */
/* The results of the last wait an inf did. */
struct inf_wait
struct inf_wait
  {
  {
    struct target_waitstatus status;    /* The status returned to gdb.  */
    struct target_waitstatus status;    /* The status returned to gdb.  */
    struct exc_state exc;       /* The exception that caused us to return. */
    struct exc_state exc;       /* The exception that caused us to return. */
    struct proc *thread;        /* The thread in question.  */
    struct proc *thread;        /* The thread in question.  */
    int suppress;               /* Something trivial happened.  */
    int suppress;               /* Something trivial happened.  */
  };
  };
 
 
/* The state of an inferior.  */
/* The state of an inferior.  */
struct inf
struct inf
  {
  {
    /* Fields describing the current inferior.  */
    /* Fields describing the current inferior.  */
 
 
    struct proc *task;          /* The mach task.   */
    struct proc *task;          /* The mach task.   */
    struct proc *threads;       /* A linked list of all threads in TASK.  */
    struct proc *threads;       /* A linked list of all threads in TASK.  */
 
 
    /* True if THREADS needn't be validated by querying the task.  We assume that
    /* True if THREADS needn't be validated by querying the task.  We assume that
       we and the task in question are the only ones frobbing the thread list,
       we and the task in question are the only ones frobbing the thread list,
       so as long as we don't let any code run, we don't have to worry about
       so as long as we don't let any code run, we don't have to worry about
       THREADS changing.  */
       THREADS changing.  */
    int threads_up_to_date;
    int threads_up_to_date;
 
 
    pid_t pid;                  /* The real system PID. */
    pid_t pid;                  /* The real system PID. */
 
 
    struct inf_wait wait;       /* What to return from target_wait.  */
    struct inf_wait wait;       /* What to return from target_wait.  */
 
 
    /* One thread proc in INF may be in `single-stepping mode'.  This is it.  */
    /* One thread proc in INF may be in `single-stepping mode'.  This is it.  */
    struct proc *step_thread;
    struct proc *step_thread;
 
 
    /* The thread we think is the signal thread.  */
    /* The thread we think is the signal thread.  */
    struct proc *signal_thread;
    struct proc *signal_thread;
 
 
    mach_port_t event_port;     /* Where we receive various msgs.  */
    mach_port_t event_port;     /* Where we receive various msgs.  */
 
 
    /* True if we think at least one thread in the inferior could currently be
    /* True if we think at least one thread in the inferior could currently be
       running.  */
       running.  */
    unsigned int running:1;
    unsigned int running:1;
 
 
    /* True if the process has stopped (in the proc server sense).  Note that
    /* True if the process has stopped (in the proc server sense).  Note that
       since a proc server `stop' leaves the signal thread running, the inf can
       since a proc server `stop' leaves the signal thread running, the inf can
       be RUNNING && STOPPED...  */
       be RUNNING && STOPPED...  */
    unsigned int stopped:1;
    unsigned int stopped:1;
 
 
    /* True if the inferior has no message port.  */
    /* True if the inferior has no message port.  */
    unsigned int nomsg:1;
    unsigned int nomsg:1;
 
 
    /* True if the inferior is traced.  */
    /* True if the inferior is traced.  */
    unsigned int traced:1;
    unsigned int traced:1;
 
 
    /* True if we shouldn't try waiting for the inferior, usually because we
    /* True if we shouldn't try waiting for the inferior, usually because we
       can't for some reason.  */
       can't for some reason.  */
    unsigned int no_wait:1;
    unsigned int no_wait:1;
 
 
    /* When starting a new inferior, we don't try to validate threads until all
    /* When starting a new inferior, we don't try to validate threads until all
       the proper execs have been done.  This is a count of how many execs we
       the proper execs have been done.  This is a count of how many execs we
       expect to happen.  */
       expect to happen.  */
    unsigned pending_execs;
    unsigned pending_execs;
 
 
    /* Fields describing global state */
    /* Fields describing global state */
 
 
    /* The task suspend count used when gdb has control.  This is normally 1 to
    /* The task suspend count used when gdb has control.  This is normally 1 to
       make things easier for us, but sometimes (like when attaching to vital
       make things easier for us, but sometimes (like when attaching to vital
       system servers) it may be desirable to let the task continue to run
       system servers) it may be desirable to let the task continue to run
       (pausing individual threads as necessary).  */
       (pausing individual threads as necessary).  */
    int pause_sc;
    int pause_sc;
 
 
    /* The task suspend count left when detaching from a task.  */
    /* The task suspend count left when detaching from a task.  */
    int detach_sc;
    int detach_sc;
 
 
    /* The initial values used for the run_sc and pause_sc of newly discovered
    /* The initial values used for the run_sc and pause_sc of newly discovered
       threads -- see the definition of those fields in struct proc.  */
       threads -- see the definition of those fields in struct proc.  */
    int default_thread_run_sc;
    int default_thread_run_sc;
    int default_thread_pause_sc;
    int default_thread_pause_sc;
    int default_thread_detach_sc;
    int default_thread_detach_sc;
 
 
    /* True if the process should be traced when started/attached.  Newly
    /* True if the process should be traced when started/attached.  Newly
       started processes *must* be traced at first to exec them properly, but
       started processes *must* be traced at first to exec them properly, but
       if this is false, tracing is turned off as soon it has done so.  */
       if this is false, tracing is turned off as soon it has done so.  */
    int want_signals;
    int want_signals;
 
 
    /* True if exceptions from the inferior process should be trapped.  This
    /* True if exceptions from the inferior process should be trapped.  This
       must be on to use breakpoints.  */
       must be on to use breakpoints.  */
    int want_exceptions;
    int want_exceptions;
  };
  };
 
 
 
 
int
int
__proc_pid (struct proc *proc)
__proc_pid (struct proc *proc)
{
{
  return proc->inf->pid;
  return proc->inf->pid;
}
}
 
 


/* Update PROC's real suspend count to match it's desired one.  Returns true
/* Update PROC's real suspend count to match it's desired one.  Returns true
   if we think PROC is now in a runnable state.  */
   if we think PROC is now in a runnable state.  */
int
int
proc_update_sc (struct proc *proc)
proc_update_sc (struct proc *proc)
{
{
  int running;
  int running;
  int err = 0;
  int err = 0;
  int delta = proc->sc - proc->cur_sc;
  int delta = proc->sc - proc->cur_sc;
 
 
  if (delta)
  if (delta)
    proc_debug (proc, "sc: %d --> %d", proc->cur_sc, proc->sc);
    proc_debug (proc, "sc: %d --> %d", proc->cur_sc, proc->sc);
 
 
  if (proc->sc == 0 && proc->state_changed)
  if (proc->sc == 0 && proc->state_changed)
    /* Since PROC may start running, we must write back any state changes. */
    /* Since PROC may start running, we must write back any state changes. */
    {
    {
      assert (proc_is_thread (proc));
      assert (proc_is_thread (proc));
      proc_debug (proc, "storing back changed thread state");
      proc_debug (proc, "storing back changed thread state");
      err = thread_set_state (proc->port, THREAD_STATE_FLAVOR,
      err = thread_set_state (proc->port, THREAD_STATE_FLAVOR,
                         (thread_state_t) &proc->state, THREAD_STATE_SIZE);
                         (thread_state_t) &proc->state, THREAD_STATE_SIZE);
      if (!err)
      if (!err)
        proc->state_changed = 0;
        proc->state_changed = 0;
    }
    }
 
 
  if (delta > 0)
  if (delta > 0)
    {
    {
      while (delta-- > 0 && !err)
      while (delta-- > 0 && !err)
        {
        {
          if (proc_is_task (proc))
          if (proc_is_task (proc))
            err = task_suspend (proc->port);
            err = task_suspend (proc->port);
          else
          else
            err = thread_suspend (proc->port);
            err = thread_suspend (proc->port);
        }
        }
    }
    }
  else
  else
    {
    {
      while (delta++ < 0 && !err)
      while (delta++ < 0 && !err)
        {
        {
          if (proc_is_task (proc))
          if (proc_is_task (proc))
            err = task_resume (proc->port);
            err = task_resume (proc->port);
          else
          else
            err = thread_resume (proc->port);
            err = thread_resume (proc->port);
        }
        }
    }
    }
  if (!err)
  if (!err)
    proc->cur_sc = proc->sc;
    proc->cur_sc = proc->sc;
 
 
  /* If we got an error, then the task/thread has disappeared.  */
  /* If we got an error, then the task/thread has disappeared.  */
  running = !err && proc->sc == 0;
  running = !err && proc->sc == 0;
 
 
  proc_debug (proc, "is %s", err ? "dead" : running ? "running" : "suspended");
  proc_debug (proc, "is %s", err ? "dead" : running ? "running" : "suspended");
  if (err)
  if (err)
    proc_debug (proc, "err = %s", strerror (err));
    proc_debug (proc, "err = %s", strerror (err));
 
 
  if (running)
  if (running)
    {
    {
      proc->aborted = 0;
      proc->aborted = 0;
      proc->state_valid = proc->state_changed = 0;
      proc->state_valid = proc->state_changed = 0;
      proc->fetched_regs = 0;
      proc->fetched_regs = 0;
    }
    }
 
 
  return running;
  return running;
}
}
 
 


/* Thread_abort is called on PROC if needed.  PROC must be a thread proc.
/* Thread_abort is called on PROC if needed.  PROC must be a thread proc.
   If PROC is deemed `precious', then nothing is done unless FORCE is true.
   If PROC is deemed `precious', then nothing is done unless FORCE is true.
   In particular, a thread is precious if it's running (in which case forcing
   In particular, a thread is precious if it's running (in which case forcing
   it includes suspending it first), or if it has an exception pending.  */
   it includes suspending it first), or if it has an exception pending.  */
void
void
proc_abort (struct proc *proc, int force)
proc_abort (struct proc *proc, int force)
{
{
  assert (proc_is_thread (proc));
  assert (proc_is_thread (proc));
 
 
  if (!proc->aborted)
  if (!proc->aborted)
    {
    {
      struct inf *inf = proc->inf;
      struct inf *inf = proc->inf;
      int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0);
      int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0);
 
 
      if (running && force)
      if (running && force)
        {
        {
          proc->sc = 1;
          proc->sc = 1;
          inf_update_suspends (proc->inf);
          inf_update_suspends (proc->inf);
          running = 0;
          running = 0;
          warning ("Stopped %s.", proc_string (proc));
          warning ("Stopped %s.", proc_string (proc));
        }
        }
      else if (proc == inf->wait.thread && inf->wait.exc.reply && !force)
      else if (proc == inf->wait.thread && inf->wait.exc.reply && !force)
        /* An exception is pending on PROC, which don't mess with.  */
        /* An exception is pending on PROC, which don't mess with.  */
        running = 1;
        running = 1;
 
 
      if (!running)
      if (!running)
        /* We only abort the thread if it's not actually running.  */
        /* We only abort the thread if it's not actually running.  */
        {
        {
          thread_abort (proc->port);
          thread_abort (proc->port);
          proc_debug (proc, "aborted");
          proc_debug (proc, "aborted");
          proc->aborted = 1;
          proc->aborted = 1;
        }
        }
      else
      else
        proc_debug (proc, "not aborting");
        proc_debug (proc, "not aborting");
    }
    }
}
}
 
 
/* Make sure that the state field in PROC is up to date, and return a pointer
/* Make sure that the state field in PROC is up to date, and return a pointer
   to it, or 0 if something is wrong.  If WILL_MODIFY is true, makes sure
   to it, or 0 if something is wrong.  If WILL_MODIFY is true, makes sure
   that the thread is stopped and aborted first, and sets the state_changed
   that the thread is stopped and aborted first, and sets the state_changed
   field in PROC to true.  */
   field in PROC to true.  */
thread_state_t
thread_state_t
proc_get_state (struct proc *proc, int will_modify)
proc_get_state (struct proc *proc, int will_modify)
{
{
  int was_aborted = proc->aborted;
  int was_aborted = proc->aborted;
 
 
  proc_debug (proc, "updating state info%s",
  proc_debug (proc, "updating state info%s",
              will_modify ? " (with intention to modify)" : "");
              will_modify ? " (with intention to modify)" : "");
 
 
  proc_abort (proc, will_modify);
  proc_abort (proc, will_modify);
 
 
  if (!was_aborted && proc->aborted)
  if (!was_aborted && proc->aborted)
    /* PROC's state may have changed since we last fetched it.  */
    /* PROC's state may have changed since we last fetched it.  */
    proc->state_valid = 0;
    proc->state_valid = 0;
 
 
  if (!proc->state_valid)
  if (!proc->state_valid)
    {
    {
      mach_msg_type_number_t state_size = THREAD_STATE_SIZE;
      mach_msg_type_number_t state_size = THREAD_STATE_SIZE;
      error_t err =
      error_t err =
      thread_get_state (proc->port, THREAD_STATE_FLAVOR,
      thread_get_state (proc->port, THREAD_STATE_FLAVOR,
                        (thread_state_t) &proc->state, &state_size);
                        (thread_state_t) &proc->state, &state_size);
      proc_debug (proc, "getting thread state");
      proc_debug (proc, "getting thread state");
      proc->state_valid = !err;
      proc->state_valid = !err;
    }
    }
 
 
  if (proc->state_valid)
  if (proc->state_valid)
    {
    {
      if (will_modify)
      if (will_modify)
        proc->state_changed = 1;
        proc->state_changed = 1;
      return (thread_state_t) &proc->state;
      return (thread_state_t) &proc->state;
    }
    }
  else
  else
    return 0;
    return 0;
}
}
 
 


/* Set PORT to PROC's exception port.  */
/* Set PORT to PROC's exception port.  */
error_t
error_t
proc_get_exception_port (struct proc * proc, mach_port_t * port)
proc_get_exception_port (struct proc * proc, mach_port_t * port)
{
{
  if (proc_is_task (proc))
  if (proc_is_task (proc))
    return task_get_exception_port (proc->port, port);
    return task_get_exception_port (proc->port, port);
  else
  else
    return thread_get_exception_port (proc->port, port);
    return thread_get_exception_port (proc->port, port);
}
}
 
 
/* Set PROC's exception port to PORT.  */
/* Set PROC's exception port to PORT.  */
error_t
error_t
proc_set_exception_port (struct proc * proc, mach_port_t port)
proc_set_exception_port (struct proc * proc, mach_port_t port)
{
{
  proc_debug (proc, "setting exception port: %d", port);
  proc_debug (proc, "setting exception port: %d", port);
  if (proc_is_task (proc))
  if (proc_is_task (proc))
    return task_set_exception_port (proc->port, port);
    return task_set_exception_port (proc->port, port);
  else
  else
    return thread_set_exception_port (proc->port, port);
    return thread_set_exception_port (proc->port, port);
}
}
 
 
/* Get PROC's exception port, cleaning up a bit if proc has died.  */
/* Get PROC's exception port, cleaning up a bit if proc has died.  */
static mach_port_t
static mach_port_t
_proc_get_exc_port (struct proc *proc)
_proc_get_exc_port (struct proc *proc)
{
{
  mach_port_t exc_port;
  mach_port_t exc_port;
  error_t err = proc_get_exception_port (proc, &exc_port);
  error_t err = proc_get_exception_port (proc, &exc_port);
 
 
  if (err)
  if (err)
    /* PROC must be dead.  */
    /* PROC must be dead.  */
    {
    {
      if (proc->exc_port)
      if (proc->exc_port)
        mach_port_deallocate (mach_task_self (), proc->exc_port);
        mach_port_deallocate (mach_task_self (), proc->exc_port);
      proc->exc_port = MACH_PORT_NULL;
      proc->exc_port = MACH_PORT_NULL;
      if (proc->saved_exc_port)
      if (proc->saved_exc_port)
        mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
        mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
      proc->saved_exc_port = MACH_PORT_NULL;
      proc->saved_exc_port = MACH_PORT_NULL;
    }
    }
 
 
  return exc_port;
  return exc_port;
}
}
 
 
/* Replace PROC's exception port with EXC_PORT, unless it's already been
/* Replace PROC's exception port with EXC_PORT, unless it's already been
   done.  Stash away any existing exception port so we can restore it later. */
   done.  Stash away any existing exception port so we can restore it later. */
void
void
proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
{
{
  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
 
 
  if (cur_exc_port)
  if (cur_exc_port)
    {
    {
      error_t err = 0;
      error_t err = 0;
 
 
      proc_debug (proc, "inserting exception port: %d", exc_port);
      proc_debug (proc, "inserting exception port: %d", exc_port);
 
 
      if (cur_exc_port != exc_port)
      if (cur_exc_port != exc_port)
        /* Put in our exception port.  */
        /* Put in our exception port.  */
        err = proc_set_exception_port (proc, exc_port);
        err = proc_set_exception_port (proc, exc_port);
 
 
      if (err || cur_exc_port == proc->exc_port)
      if (err || cur_exc_port == proc->exc_port)
        /* We previously set the exception port, and it's still set.  So we
        /* We previously set the exception port, and it's still set.  So we
           just keep the old saved port which is what the proc set.  */
           just keep the old saved port which is what the proc set.  */
        {
        {
          if (cur_exc_port)
          if (cur_exc_port)
            mach_port_deallocate (mach_task_self (), cur_exc_port);
            mach_port_deallocate (mach_task_self (), cur_exc_port);
        }
        }
      else
      else
        /* Keep a copy of PROC's old exception port so it can be restored. */
        /* Keep a copy of PROC's old exception port so it can be restored. */
        {
        {
          if (proc->saved_exc_port)
          if (proc->saved_exc_port)
            mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
            mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
          proc->saved_exc_port = cur_exc_port;
          proc->saved_exc_port = cur_exc_port;
        }
        }
 
 
      proc_debug (proc, "saved exception port: %d", proc->saved_exc_port);
      proc_debug (proc, "saved exception port: %d", proc->saved_exc_port);
 
 
      if (!err)
      if (!err)
        proc->exc_port = exc_port;
        proc->exc_port = exc_port;
      else
      else
        warning ("Error setting exception port for %s: %s",
        warning ("Error setting exception port for %s: %s",
                 proc_string (proc), strerror (err));
                 proc_string (proc), strerror (err));
    }
    }
}
}
 
 
/* If we previously replaced PROC's exception port, put back what we
/* If we previously replaced PROC's exception port, put back what we
   found there at the time, unless *our* exception port has since been
   found there at the time, unless *our* exception port has since been
   overwritten, in which case who knows what's going on.  */
   overwritten, in which case who knows what's going on.  */
void
void
proc_restore_exc_port (struct proc *proc)
proc_restore_exc_port (struct proc *proc)
{
{
  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
 
 
  if (cur_exc_port)
  if (cur_exc_port)
    {
    {
      error_t err = 0;
      error_t err = 0;
 
 
      proc_debug (proc, "restoring real exception port");
      proc_debug (proc, "restoring real exception port");
 
 
      if (proc->exc_port == cur_exc_port)
      if (proc->exc_port == cur_exc_port)
        /* Our's is still there.  */
        /* Our's is still there.  */
        err = proc_set_exception_port (proc, proc->saved_exc_port);
        err = proc_set_exception_port (proc, proc->saved_exc_port);
 
 
      if (proc->saved_exc_port)
      if (proc->saved_exc_port)
        mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
        mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
      proc->saved_exc_port = MACH_PORT_NULL;
      proc->saved_exc_port = MACH_PORT_NULL;
 
 
      if (!err)
      if (!err)
        proc->exc_port = MACH_PORT_NULL;
        proc->exc_port = MACH_PORT_NULL;
      else
      else
        warning ("Error setting exception port for %s: %s",
        warning ("Error setting exception port for %s: %s",
                 proc_string (proc), strerror (err));
                 proc_string (proc), strerror (err));
    }
    }
}
}
 
 


/* Turns hardware tracing in PROC on or off when SET is true or false,
/* Turns hardware tracing in PROC on or off when SET is true or false,
   respectively.  Returns true on success.  */
   respectively.  Returns true on success.  */
int
int
proc_trace (struct proc *proc, int set)
proc_trace (struct proc *proc, int set)
{
{
  thread_state_t state = proc_get_state (proc, 1);
  thread_state_t state = proc_get_state (proc, 1);
 
 
  if (!state)
  if (!state)
    return 0;                    /* the thread must be dead.  */
    return 0;                    /* the thread must be dead.  */
 
 
  proc_debug (proc, "tracing %s", set ? "on" : "off");
  proc_debug (proc, "tracing %s", set ? "on" : "off");
 
 
  if (set)
  if (set)
    {
    {
      /* XXX We don't get the exception unless the thread has its own
      /* XXX We don't get the exception unless the thread has its own
         exception port???? */
         exception port???? */
      if (proc->exc_port == MACH_PORT_NULL)
      if (proc->exc_port == MACH_PORT_NULL)
        proc_steal_exc_port (proc, proc->inf->event_port);
        proc_steal_exc_port (proc, proc->inf->event_port);
      THREAD_STATE_SET_TRACED (state);
      THREAD_STATE_SET_TRACED (state);
    }
    }
  else
  else
    THREAD_STATE_CLEAR_TRACED (state);
    THREAD_STATE_CLEAR_TRACED (state);
 
 
  return 1;
  return 1;
}
}
 
 


/* A variable from which to assign new TIDs.  */
/* A variable from which to assign new TIDs.  */
static int next_thread_id = 1;
static int next_thread_id = 1;
 
 
/* Returns a new proc structure with the given fields.  Also adds a
/* Returns a new proc structure with the given fields.  Also adds a
   notification for PORT becoming dead to be sent to INF's notify port.  */
   notification for PORT becoming dead to be sent to INF's notify port.  */
struct proc *
struct proc *
make_proc (struct inf *inf, mach_port_t port, int tid)
make_proc (struct inf *inf, mach_port_t port, int tid)
{
{
  error_t err;
  error_t err;
  mach_port_t prev_port = MACH_PORT_NULL;
  mach_port_t prev_port = MACH_PORT_NULL;
  struct proc *proc = malloc (sizeof (struct proc));
  struct proc *proc = malloc (sizeof (struct proc));
 
 
  proc->port = port;
  proc->port = port;
  proc->tid = tid;
  proc->tid = tid;
  proc->inf = inf;
  proc->inf = inf;
  proc->next = 0;
  proc->next = 0;
  proc->saved_exc_port = MACH_PORT_NULL;
  proc->saved_exc_port = MACH_PORT_NULL;
  proc->exc_port = MACH_PORT_NULL;
  proc->exc_port = MACH_PORT_NULL;
 
 
  proc->sc = 0;
  proc->sc = 0;
  proc->cur_sc = 0;
  proc->cur_sc = 0;
 
 
  /* Note that these are all the values for threads; the task simply uses the
  /* Note that these are all the values for threads; the task simply uses the
     corresponding field in INF directly.  */
     corresponding field in INF directly.  */
  proc->run_sc = inf->default_thread_run_sc;
  proc->run_sc = inf->default_thread_run_sc;
  proc->pause_sc = inf->default_thread_pause_sc;
  proc->pause_sc = inf->default_thread_pause_sc;
  proc->detach_sc = inf->default_thread_detach_sc;
  proc->detach_sc = inf->default_thread_detach_sc;
  proc->resume_sc = proc->run_sc;
  proc->resume_sc = proc->run_sc;
 
 
  proc->aborted = 0;
  proc->aborted = 0;
  proc->dead = 0;
  proc->dead = 0;
  proc->state_valid = 0;
  proc->state_valid = 0;
  proc->state_changed = 0;
  proc->state_changed = 0;
 
 
  proc_debug (proc, "is new");
  proc_debug (proc, "is new");
 
 
  /* Get notified when things die.  */
  /* Get notified when things die.  */
  err =
  err =
    mach_port_request_notification (mach_task_self (), port,
    mach_port_request_notification (mach_task_self (), port,
                                    MACH_NOTIFY_DEAD_NAME, 1,
                                    MACH_NOTIFY_DEAD_NAME, 1,
                                    inf->event_port,
                                    inf->event_port,
                                    MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                    MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                    &prev_port);
                                    &prev_port);
  if (err)
  if (err)
    warning ("Couldn't request notification for port %d: %s",
    warning ("Couldn't request notification for port %d: %s",
             port, strerror (err));
             port, strerror (err));
  else
  else
    {
    {
      proc_debug (proc, "notifications to: %d", inf->event_port);
      proc_debug (proc, "notifications to: %d", inf->event_port);
      if (prev_port != MACH_PORT_NULL)
      if (prev_port != MACH_PORT_NULL)
        mach_port_deallocate (mach_task_self (), prev_port);
        mach_port_deallocate (mach_task_self (), prev_port);
    }
    }
 
 
  if (inf->want_exceptions)
  if (inf->want_exceptions)
    {
    {
      if (proc_is_task (proc))
      if (proc_is_task (proc))
        /* Make the task exception port point to us.  */
        /* Make the task exception port point to us.  */
        proc_steal_exc_port (proc, inf->event_port);
        proc_steal_exc_port (proc, inf->event_port);
      else
      else
        /* Just clear thread exception ports -- they default to the
        /* Just clear thread exception ports -- they default to the
           task one.  */
           task one.  */
        proc_steal_exc_port (proc, MACH_PORT_NULL);
        proc_steal_exc_port (proc, MACH_PORT_NULL);
    }
    }
 
 
  return proc;
  return proc;
}
}
 
 
/* Frees PROC and any resources it uses, and returns the value of PROC's
/* Frees PROC and any resources it uses, and returns the value of PROC's
   next field.  */
   next field.  */
struct proc *
struct proc *
_proc_free (struct proc *proc)
_proc_free (struct proc *proc)
{
{
  struct inf *inf = proc->inf;
  struct inf *inf = proc->inf;
  struct proc *next = proc->next;
  struct proc *next = proc->next;
 
 
  proc_debug (proc, "freeing...");
  proc_debug (proc, "freeing...");
 
 
  if (proc == inf->step_thread)
  if (proc == inf->step_thread)
    /* Turn off single stepping.  */
    /* Turn off single stepping.  */
    inf_set_step_thread (inf, 0);
    inf_set_step_thread (inf, 0);
  if (proc == inf->wait.thread)
  if (proc == inf->wait.thread)
    inf_clear_wait (inf);
    inf_clear_wait (inf);
  if (proc == inf->signal_thread)
  if (proc == inf->signal_thread)
    inf->signal_thread = 0;
    inf->signal_thread = 0;
 
 
  if (proc->port != MACH_PORT_NULL)
  if (proc->port != MACH_PORT_NULL)
    {
    {
      if (proc->exc_port != MACH_PORT_NULL)
      if (proc->exc_port != MACH_PORT_NULL)
        /* Restore the original exception port.  */
        /* Restore the original exception port.  */
        proc_restore_exc_port (proc);
        proc_restore_exc_port (proc);
      if (proc->cur_sc != 0)
      if (proc->cur_sc != 0)
        /* Resume the thread/task.  */
        /* Resume the thread/task.  */
        {
        {
          proc->sc = 0;
          proc->sc = 0;
          proc_update_sc (proc);
          proc_update_sc (proc);
        }
        }
      mach_port_deallocate (mach_task_self (), proc->port);
      mach_port_deallocate (mach_task_self (), proc->port);
    }
    }
 
 
  free (proc);
  free (proc);
  return next;
  return next;
}
}
 
 


struct inf *
struct inf *
make_inf ()
make_inf ()
{
{
  struct inf *inf = malloc (sizeof (struct inf));
  struct inf *inf = malloc (sizeof (struct inf));
 
 
  if (!inf)
  if (!inf)
    return 0;
    return 0;
 
 
  inf->task = 0;
  inf->task = 0;
  inf->threads = 0;
  inf->threads = 0;
  inf->threads_up_to_date = 0;
  inf->threads_up_to_date = 0;
  inf->pid = 0;
  inf->pid = 0;
  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
  inf->wait.thread = 0;
  inf->wait.thread = 0;
  inf->wait.exc.handler = MACH_PORT_NULL;
  inf->wait.exc.handler = MACH_PORT_NULL;
  inf->wait.exc.reply = MACH_PORT_NULL;
  inf->wait.exc.reply = MACH_PORT_NULL;
  inf->step_thread = 0;
  inf->step_thread = 0;
  inf->signal_thread = 0;
  inf->signal_thread = 0;
  inf->event_port = MACH_PORT_NULL;
  inf->event_port = MACH_PORT_NULL;
  inf->running = 0;
  inf->running = 0;
  inf->stopped = 0;
  inf->stopped = 0;
  inf->nomsg = 1;
  inf->nomsg = 1;
  inf->traced = 0;
  inf->traced = 0;
  inf->no_wait = 0;
  inf->no_wait = 0;
  inf->pending_execs = 0;
  inf->pending_execs = 0;
  inf->pause_sc = 1;
  inf->pause_sc = 1;
  inf->detach_sc = 0;
  inf->detach_sc = 0;
  inf->default_thread_run_sc = 0;
  inf->default_thread_run_sc = 0;
  inf->default_thread_pause_sc = 0;
  inf->default_thread_pause_sc = 0;
  inf->default_thread_detach_sc = 0;
  inf->default_thread_detach_sc = 0;
  inf->want_signals = 1;        /* By default */
  inf->want_signals = 1;        /* By default */
  inf->want_exceptions = 1;     /* By default */
  inf->want_exceptions = 1;     /* By default */
 
 
  return inf;
  return inf;
}
}
 
 
/* Clear INF's target wait status.  */
/* Clear INF's target wait status.  */
void
void
inf_clear_wait (struct inf *inf)
inf_clear_wait (struct inf *inf)
{
{
  inf_debug (inf, "clearing wait");
  inf_debug (inf, "clearing wait");
  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
  inf->wait.thread = 0;
  inf->wait.thread = 0;
  inf->wait.suppress = 0;
  inf->wait.suppress = 0;
  if (inf->wait.exc.handler != MACH_PORT_NULL)
  if (inf->wait.exc.handler != MACH_PORT_NULL)
    {
    {
      mach_port_deallocate (mach_task_self (), inf->wait.exc.handler);
      mach_port_deallocate (mach_task_self (), inf->wait.exc.handler);
      inf->wait.exc.handler = MACH_PORT_NULL;
      inf->wait.exc.handler = MACH_PORT_NULL;
    }
    }
  if (inf->wait.exc.reply != MACH_PORT_NULL)
  if (inf->wait.exc.reply != MACH_PORT_NULL)
    {
    {
      mach_port_deallocate (mach_task_self (), inf->wait.exc.reply);
      mach_port_deallocate (mach_task_self (), inf->wait.exc.reply);
      inf->wait.exc.reply = MACH_PORT_NULL;
      inf->wait.exc.reply = MACH_PORT_NULL;
    }
    }
}
}
 
 


void
void
inf_cleanup (struct inf *inf)
inf_cleanup (struct inf *inf)
{
{
  inf_debug (inf, "cleanup");
  inf_debug (inf, "cleanup");
 
 
  inf_clear_wait (inf);
  inf_clear_wait (inf);
 
 
  inf_set_pid (inf, -1);
  inf_set_pid (inf, -1);
  inf->pid = 0;
  inf->pid = 0;
  inf->running = 0;
  inf->running = 0;
  inf->stopped = 0;
  inf->stopped = 0;
  inf->nomsg = 1;
  inf->nomsg = 1;
  inf->traced = 0;
  inf->traced = 0;
  inf->no_wait = 0;
  inf->no_wait = 0;
  inf->pending_execs = 0;
  inf->pending_execs = 0;
 
 
  if (inf->event_port)
  if (inf->event_port)
    {
    {
      mach_port_destroy (mach_task_self (), inf->event_port);
      mach_port_destroy (mach_task_self (), inf->event_port);
      inf->event_port = MACH_PORT_NULL;
      inf->event_port = MACH_PORT_NULL;
    }
    }
}
}
 
 
void
void
inf_startup (struct inf *inf, int pid)
inf_startup (struct inf *inf, int pid)
{
{
  error_t err;
  error_t err;
 
 
  inf_debug (inf, "startup: pid = %d", pid);
  inf_debug (inf, "startup: pid = %d", pid);
 
 
  inf_cleanup (inf);
  inf_cleanup (inf);
 
 
  /* Make the port on which we receive all events.  */
  /* Make the port on which we receive all events.  */
  err = mach_port_allocate (mach_task_self (),
  err = mach_port_allocate (mach_task_self (),
                            MACH_PORT_RIGHT_RECEIVE, &inf->event_port);
                            MACH_PORT_RIGHT_RECEIVE, &inf->event_port);
  if (err)
  if (err)
    error ("Error allocating event port: %s", strerror (err));
    error ("Error allocating event port: %s", strerror (err));
 
 
  /* Make a send right for it, so we can easily copy it for other people.  */
  /* Make a send right for it, so we can easily copy it for other people.  */
  mach_port_insert_right (mach_task_self (), inf->event_port,
  mach_port_insert_right (mach_task_self (), inf->event_port,
                          inf->event_port, MACH_MSG_TYPE_MAKE_SEND);
                          inf->event_port, MACH_MSG_TYPE_MAKE_SEND);
  inf_set_pid (inf, pid);
  inf_set_pid (inf, pid);
}
}
 
 


/* Close current process, if any, and attach INF to process PORT.  */
/* Close current process, if any, and attach INF to process PORT.  */
void
void
inf_set_pid (struct inf *inf, pid_t pid)
inf_set_pid (struct inf *inf, pid_t pid)
{
{
  task_t task_port;
  task_t task_port;
  struct proc *task = inf->task;
  struct proc *task = inf->task;
 
 
  inf_debug (inf, "setting pid: %d", pid);
  inf_debug (inf, "setting pid: %d", pid);
 
 
  if (pid < 0)
  if (pid < 0)
    task_port = MACH_PORT_NULL;
    task_port = MACH_PORT_NULL;
  else
  else
    {
    {
      error_t err = proc_pid2task (proc_server, pid, &task_port);
      error_t err = proc_pid2task (proc_server, pid, &task_port);
      if (err)
      if (err)
        error ("Error getting task for pid %d: %s", pid, strerror (err));
        error ("Error getting task for pid %d: %s", pid, strerror (err));
    }
    }
 
 
  inf_debug (inf, "setting task: %d", task_port);
  inf_debug (inf, "setting task: %d", task_port);
 
 
  if (inf->pause_sc)
  if (inf->pause_sc)
    task_suspend (task_port);
    task_suspend (task_port);
 
 
  if (task && task->port != task_port)
  if (task && task->port != task_port)
    {
    {
      inf->task = 0;
      inf->task = 0;
      inf_validate_procs (inf); /* Trash all the threads. */
      inf_validate_procs (inf); /* Trash all the threads. */
      _proc_free (task);        /* And the task. */
      _proc_free (task);        /* And the task. */
    }
    }
 
 
  if (task_port != MACH_PORT_NULL)
  if (task_port != MACH_PORT_NULL)
    {
    {
      inf->task = make_proc (inf, task_port, PROC_TID_TASK);
      inf->task = make_proc (inf, task_port, PROC_TID_TASK);
      inf->threads_up_to_date = 0;
      inf->threads_up_to_date = 0;
    }
    }
 
 
  if (inf->task)
  if (inf->task)
    {
    {
      inf->pid = pid;
      inf->pid = pid;
      if (inf->pause_sc)
      if (inf->pause_sc)
        /* Reflect task_suspend above.  */
        /* Reflect task_suspend above.  */
        inf->task->sc = inf->task->cur_sc = 1;
        inf->task->sc = inf->task->cur_sc = 1;
    }
    }
  else
  else
    inf->pid = -1;
    inf->pid = -1;
}
}
 
 


/* Validates INF's stopped, nomsg and traced field from the actual
/* Validates INF's stopped, nomsg and traced field from the actual
   proc server state.  Note that the traced field is only updated from
   proc server state.  Note that the traced field is only updated from
   the proc server state if we do not have a message port.  If we do
   the proc server state if we do not have a message port.  If we do
   have a message port we'd better look at the tracemask itself.  */
   have a message port we'd better look at the tracemask itself.  */
static void
static void
inf_validate_procinfo (struct inf *inf)
inf_validate_procinfo (struct inf *inf)
{
{
  char *noise;
  char *noise;
  mach_msg_type_number_t noise_len = 0;
  mach_msg_type_number_t noise_len = 0;
  struct procinfo *pi;
  struct procinfo *pi;
  mach_msg_type_number_t pi_len = 0;
  mach_msg_type_number_t pi_len = 0;
  int info_flags = 0;
  int info_flags = 0;
  error_t err =
  error_t err =
  proc_getprocinfo (proc_server, inf->pid, &info_flags,
  proc_getprocinfo (proc_server, inf->pid, &info_flags,
                    (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
                    (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
 
 
  if (!err)
  if (!err)
    {
    {
      inf->stopped = !!(pi->state & PI_STOPPED);
      inf->stopped = !!(pi->state & PI_STOPPED);
      inf->nomsg = !!(pi->state & PI_NOMSG);
      inf->nomsg = !!(pi->state & PI_NOMSG);
      if (inf->nomsg)
      if (inf->nomsg)
        inf->traced = !!(pi->state & PI_TRACED);
        inf->traced = !!(pi->state & PI_TRACED);
      vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
      vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
      if (noise_len > 0)
      if (noise_len > 0)
        vm_deallocate (mach_task_self (), (vm_address_t) noise, noise_len);
        vm_deallocate (mach_task_self (), (vm_address_t) noise, noise_len);
    }
    }
}
}
 
 
/* Validates INF's task suspend count.  If it's higher than we expect,
/* Validates INF's task suspend count.  If it's higher than we expect,
   verify with the user before `stealing' the extra count.  */
   verify with the user before `stealing' the extra count.  */
static void
static void
inf_validate_task_sc (struct inf *inf)
inf_validate_task_sc (struct inf *inf)
{
{
  char *noise;
  char *noise;
  mach_msg_type_number_t noise_len = 0;
  mach_msg_type_number_t noise_len = 0;
  struct procinfo *pi;
  struct procinfo *pi;
  mach_msg_type_number_t pi_len = 0;
  mach_msg_type_number_t pi_len = 0;
  int info_flags = PI_FETCH_TASKINFO;
  int info_flags = PI_FETCH_TASKINFO;
  int suspend_count = -1;
  int suspend_count = -1;
  error_t err;
  error_t err;
 
 
 retry:
 retry:
  err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
  err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
                          (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
                          (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
  if (err)
  if (err)
    {
    {
      inf->task->dead = 1; /* oh well */
      inf->task->dead = 1; /* oh well */
      return;
      return;
    }
    }
 
 
  if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1)
  if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1)
    {
    {
      /* The proc server might have suspended the task while stopping
      /* The proc server might have suspended the task while stopping
         it.  This happens when the task is handling a traced signal.
         it.  This happens when the task is handling a traced signal.
         Refetch the suspend count.  The proc server should be
         Refetch the suspend count.  The proc server should be
         finished stopping the task by now.  */
         finished stopping the task by now.  */
      suspend_count = pi->taskinfo.suspend_count;
      suspend_count = pi->taskinfo.suspend_count;
      goto retry;
      goto retry;
    }
    }
 
 
  suspend_count = pi->taskinfo.suspend_count;
  suspend_count = pi->taskinfo.suspend_count;
 
 
  vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
  vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
  if (noise_len > 0)
  if (noise_len > 0)
    vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
    vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
 
 
  if (inf->task->cur_sc < suspend_count)
  if (inf->task->cur_sc < suspend_count)
    {
    {
      int abort;
      int abort;
 
 
      target_terminal_ours ();  /* Allow I/O.  */
      target_terminal_ours ();  /* Allow I/O.  */
      abort = !query ("Pid %d has an additional task suspend count of %d;"
      abort = !query ("Pid %d has an additional task suspend count of %d;"
                      " clear it? ", inf->pid,
                      " clear it? ", inf->pid,
                      suspend_count - inf->task->cur_sc);
                      suspend_count - inf->task->cur_sc);
      target_terminal_inferior ();      /* Give it back to the child.  */
      target_terminal_inferior ();      /* Give it back to the child.  */
 
 
      if (abort)
      if (abort)
        error ("Additional task suspend count left untouched.");
        error ("Additional task suspend count left untouched.");
 
 
      inf->task->cur_sc = suspend_count;
      inf->task->cur_sc = suspend_count;
    }
    }
}
}
 
 
/* Turns tracing for INF on or off, depending on ON, unless it already
/* Turns tracing for INF on or off, depending on ON, unless it already
   is.  If INF is running, the resume_sc count of INF's threads will
   is.  If INF is running, the resume_sc count of INF's threads will
   be modified, and the signal thread will briefly be run to change
   be modified, and the signal thread will briefly be run to change
   the trace state.  */
   the trace state.  */
void
void
inf_set_traced (struct inf *inf, int on)
inf_set_traced (struct inf *inf, int on)
{
{
  if (on == inf->traced)
  if (on == inf->traced)
    return;
    return;
 
 
  if (inf->task && !inf->task->dead)
  if (inf->task && !inf->task->dead)
    /* Make it take effect immediately.  */
    /* Make it take effect immediately.  */
    {
    {
      sigset_t mask = on ? ~(sigset_t) 0 : 0;
      sigset_t mask = on ? ~(sigset_t) 0 : 0;
      error_t err =
      error_t err =
        INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
        INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
                                                       INIT_TRACEMASK, mask));
                                                       INIT_TRACEMASK, mask));
      if (err == EIEIO)
      if (err == EIEIO)
        {
        {
          if (on)
          if (on)
            warning ("Can't modify tracing state for pid %d: %s",
            warning ("Can't modify tracing state for pid %d: %s",
                     inf->pid, "No signal thread");
                     inf->pid, "No signal thread");
          inf->traced = on;
          inf->traced = on;
        }
        }
      else if (err)
      else if (err)
        warning ("Can't modify tracing state for pid %d: %s",
        warning ("Can't modify tracing state for pid %d: %s",
                 inf->pid, strerror (err));
                 inf->pid, strerror (err));
      else
      else
        inf->traced = on;
        inf->traced = on;
    }
    }
  else
  else
    inf->traced = on;
    inf->traced = on;
}
}
 
 


/* Makes all the real suspend count deltas of all the procs in INF
/* Makes all the real suspend count deltas of all the procs in INF
   match the desired values.  Careful to always do thread/task suspend
   match the desired values.  Careful to always do thread/task suspend
   counts in the safe order.  Returns true if at least one thread is
   counts in the safe order.  Returns true if at least one thread is
   thought to be running. */
   thought to be running. */
int
int
inf_update_suspends (struct inf *inf)
inf_update_suspends (struct inf *inf)
{
{
  struct proc *task = inf->task;
  struct proc *task = inf->task;
  /* We don't have to update INF->threads even though we're iterating over it
  /* We don't have to update INF->threads even though we're iterating over it
     because we'll change a thread only if it already has an existing proc
     because we'll change a thread only if it already has an existing proc
     entry.  */
     entry.  */
 
 
  inf_debug (inf, "updating suspend counts");
  inf_debug (inf, "updating suspend counts");
 
 
  if (task)
  if (task)
    {
    {
      struct proc *thread;
      struct proc *thread;
      int task_running = (task->sc == 0), thread_running = 0;
      int task_running = (task->sc == 0), thread_running = 0;
 
 
      if (task->sc > task->cur_sc)
      if (task->sc > task->cur_sc)
        /* The task is becoming _more_ suspended; do before any threads.  */
        /* The task is becoming _more_ suspended; do before any threads.  */
        task_running = proc_update_sc (task);
        task_running = proc_update_sc (task);
 
 
      if (inf->pending_execs)
      if (inf->pending_execs)
        /* When we're waiting for an exec, things may be happening behind our
        /* When we're waiting for an exec, things may be happening behind our
           back, so be conservative.  */
           back, so be conservative.  */
        thread_running = 1;
        thread_running = 1;
 
 
      /* Do all the thread suspend counts.  */
      /* Do all the thread suspend counts.  */
      for (thread = inf->threads; thread; thread = thread->next)
      for (thread = inf->threads; thread; thread = thread->next)
        thread_running |= proc_update_sc (thread);
        thread_running |= proc_update_sc (thread);
 
 
      if (task->sc != task->cur_sc)
      if (task->sc != task->cur_sc)
        /* We didn't do the task first, because we wanted to wait for the
        /* We didn't do the task first, because we wanted to wait for the
           threads; do it now.  */
           threads; do it now.  */
        task_running = proc_update_sc (task);
        task_running = proc_update_sc (task);
 
 
      inf_debug (inf, "%srunning...",
      inf_debug (inf, "%srunning...",
                 (thread_running && task_running) ? "" : "not ");
                 (thread_running && task_running) ? "" : "not ");
 
 
      inf->running = thread_running && task_running;
      inf->running = thread_running && task_running;
 
 
      /* Once any thread has executed some code, we can't depend on the
      /* Once any thread has executed some code, we can't depend on the
         threads list any more.  */
         threads list any more.  */
      if (inf->running)
      if (inf->running)
        inf->threads_up_to_date = 0;
        inf->threads_up_to_date = 0;
 
 
      return inf->running;
      return inf->running;
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 


/* Converts a GDB pid to a struct proc.  */
/* Converts a GDB pid to a struct proc.  */
struct proc *
struct proc *
inf_tid_to_thread (struct inf *inf, int tid)
inf_tid_to_thread (struct inf *inf, int tid)
{
{
  struct proc *thread = inf->threads;
  struct proc *thread = inf->threads;
 
 
  while (thread)
  while (thread)
    if (thread->tid == tid)
    if (thread->tid == tid)
      return thread;
      return thread;
    else
    else
      thread = thread->next;
      thread = thread->next;
  return 0;
  return 0;
}
}
 
 
/* Converts a thread port to a struct proc.  */
/* Converts a thread port to a struct proc.  */
struct proc *
struct proc *
inf_port_to_thread (struct inf *inf, mach_port_t port)
inf_port_to_thread (struct inf *inf, mach_port_t port)
{
{
  struct proc *thread = inf->threads;
  struct proc *thread = inf->threads;
  while (thread)
  while (thread)
    if (thread->port == port)
    if (thread->port == port)
      return thread;
      return thread;
    else
    else
      thread = thread->next;
      thread = thread->next;
  return 0;
  return 0;
}
}
 
 


/* Make INF's list of threads be consistent with reality of TASK.  */
/* Make INF's list of threads be consistent with reality of TASK.  */
void
void
inf_validate_procs (struct inf *inf)
inf_validate_procs (struct inf *inf)
{
{
  thread_array_t threads;
  thread_array_t threads;
  mach_msg_type_number_t num_threads, i;
  mach_msg_type_number_t num_threads, i;
  struct proc *task = inf->task;
  struct proc *task = inf->task;
 
 
  /* If no threads are currently running, this function will guarantee that
  /* If no threads are currently running, this function will guarantee that
     things are up to date.  The exception is if there are zero threads --
     things are up to date.  The exception is if there are zero threads --
     then it is almost certainly in an odd state, and probably some outside
     then it is almost certainly in an odd state, and probably some outside
     agent will create threads.  */
     agent will create threads.  */
  inf->threads_up_to_date = inf->threads ? !inf->running : 0;
  inf->threads_up_to_date = inf->threads ? !inf->running : 0;
 
 
  if (task)
  if (task)
    {
    {
      error_t err = task_threads (task->port, &threads, &num_threads);
      error_t err = task_threads (task->port, &threads, &num_threads);
      inf_debug (inf, "fetching threads");
      inf_debug (inf, "fetching threads");
      if (err)
      if (err)
        /* TASK must be dead.  */
        /* TASK must be dead.  */
        {
        {
          task->dead = 1;
          task->dead = 1;
          task = 0;
          task = 0;
        }
        }
    }
    }
 
 
  if (!task)
  if (!task)
    {
    {
      num_threads = 0;
      num_threads = 0;
      inf_debug (inf, "no task");
      inf_debug (inf, "no task");
    }
    }
 
 
  {
  {
    /* Make things normally linear.  */
    /* Make things normally linear.  */
    mach_msg_type_number_t search_start = 0;
    mach_msg_type_number_t search_start = 0;
    /* Which thread in PROCS corresponds to each task thread, & the task.  */
    /* Which thread in PROCS corresponds to each task thread, & the task.  */
    struct proc *matched[num_threads + 1];
    struct proc *matched[num_threads + 1];
    /* The last thread in INF->threads, so we can add to the end.  */
    /* The last thread in INF->threads, so we can add to the end.  */
    struct proc *last = 0;
    struct proc *last = 0;
    /* The current thread we're considering. */
    /* The current thread we're considering. */
    struct proc *thread = inf->threads;
    struct proc *thread = inf->threads;
 
 
    bzero (matched, sizeof (matched));
    bzero (matched, sizeof (matched));
 
 
    while (thread)
    while (thread)
      {
      {
        mach_msg_type_number_t left;
        mach_msg_type_number_t left;
 
 
        for (i = search_start, left = num_threads; left; i++, left--)
        for (i = search_start, left = num_threads; left; i++, left--)
          {
          {
            if (i >= num_threads)
            if (i >= num_threads)
              i -= num_threads; /* I wrapped around.  */
              i -= num_threads; /* I wrapped around.  */
            if (thread->port == threads[i])
            if (thread->port == threads[i])
              /* We already know about this thread.  */
              /* We already know about this thread.  */
              {
              {
                matched[i] = thread;
                matched[i] = thread;
                last = thread;
                last = thread;
                thread = thread->next;
                thread = thread->next;
                search_start++;
                search_start++;
                break;
                break;
              }
              }
          }
          }
 
 
        if (!left)
        if (!left)
          {
          {
            proc_debug (thread, "died!");
            proc_debug (thread, "died!");
            thread->port = MACH_PORT_NULL;
            thread->port = MACH_PORT_NULL;
            thread = _proc_free (thread);       /* THREAD is dead.  */
            thread = _proc_free (thread);       /* THREAD is dead.  */
            (last ? last->next : inf->threads) = thread;
            (last ? last->next : inf->threads) = thread;
          }
          }
      }
      }
 
 
    for (i = 0; i < num_threads; i++)
    for (i = 0; i < num_threads; i++)
      {
      {
        if (matched[i])
        if (matched[i])
          /* Throw away the duplicate send right.  */
          /* Throw away the duplicate send right.  */
          mach_port_deallocate (mach_task_self (), threads[i]);
          mach_port_deallocate (mach_task_self (), threads[i]);
        else
        else
          /* THREADS[I] is a thread we don't know about yet!  */
          /* THREADS[I] is a thread we don't know about yet!  */
          {
          {
            thread = make_proc (inf, threads[i], next_thread_id++);
            thread = make_proc (inf, threads[i], next_thread_id++);
            (last ? last->next : inf->threads) = thread;
            (last ? last->next : inf->threads) = thread;
            last = thread;
            last = thread;
            proc_debug (thread, "new thread: %d", threads[i]);
            proc_debug (thread, "new thread: %d", threads[i]);
            add_thread (thread->tid);   /* Tell GDB's generic thread code.  */
            add_thread (thread->tid);   /* Tell GDB's generic thread code.  */
          }
          }
      }
      }
 
 
    vm_deallocate (mach_task_self (),
    vm_deallocate (mach_task_self (),
                   (vm_address_t) threads, (num_threads * sizeof (thread_t)));
                   (vm_address_t) threads, (num_threads * sizeof (thread_t)));
  }
  }
}
}
 
 


/* Makes sure that INF's thread list is synced with the actual process.  */
/* Makes sure that INF's thread list is synced with the actual process.  */
inline int
inline int
inf_update_procs (struct inf *inf)
inf_update_procs (struct inf *inf)
{
{
  if (!inf->task)
  if (!inf->task)
    return 0;
    return 0;
  if (!inf->threads_up_to_date)
  if (!inf->threads_up_to_date)
    inf_validate_procs (inf);
    inf_validate_procs (inf);
  return !!inf->task;
  return !!inf->task;
}
}
 
 
/* Sets the resume_sc of each thread in inf.  That of RUN_THREAD is set to 0,
/* Sets the resume_sc of each thread in inf.  That of RUN_THREAD is set to 0,
   and others are set to their run_sc if RUN_OTHERS is true, and otherwise
   and others are set to their run_sc if RUN_OTHERS is true, and otherwise
   their pause_sc.  */
   their pause_sc.  */
inline void
inline void
inf_set_threads_resume_sc (struct inf *inf,
inf_set_threads_resume_sc (struct inf *inf,
                           struct proc *run_thread, int run_others)
                           struct proc *run_thread, int run_others)
{
{
  struct proc *thread;
  struct proc *thread;
  inf_update_procs (inf);
  inf_update_procs (inf);
  for (thread = inf->threads; thread; thread = thread->next)
  for (thread = inf->threads; thread; thread = thread->next)
    if (thread == run_thread)
    if (thread == run_thread)
      thread->resume_sc = 0;
      thread->resume_sc = 0;
    else if (run_others)
    else if (run_others)
      thread->resume_sc = thread->run_sc;
      thread->resume_sc = thread->run_sc;
    else
    else
      thread->resume_sc = thread->pause_sc;
      thread->resume_sc = thread->pause_sc;
}
}
 
 


/* Cause INF to continue execution immediately; individual threads may still
/* Cause INF to continue execution immediately; individual threads may still
   be suspended (but their suspend counts will be updated).  */
   be suspended (but their suspend counts will be updated).  */
inline void
inline void
inf_resume (struct inf *inf)
inf_resume (struct inf *inf)
{
{
  struct proc *thread;
  struct proc *thread;
 
 
  inf_update_procs (inf);
  inf_update_procs (inf);
 
 
  for (thread = inf->threads; thread; thread = thread->next)
  for (thread = inf->threads; thread; thread = thread->next)
    thread->sc = thread->resume_sc;
    thread->sc = thread->resume_sc;
 
 
  if (inf->task)
  if (inf->task)
    {
    {
      if (!inf->pending_execs)
      if (!inf->pending_execs)
        /* Try to make sure our task count is correct -- in the case where
        /* Try to make sure our task count is correct -- in the case where
           we're waiting for an exec though, things are too volatile, so just
           we're waiting for an exec though, things are too volatile, so just
           assume things will be reasonable (which they usually will be).  */
           assume things will be reasonable (which they usually will be).  */
        inf_validate_task_sc (inf);
        inf_validate_task_sc (inf);
      inf->task->sc = 0;
      inf->task->sc = 0;
    }
    }
 
 
  inf_update_suspends (inf);
  inf_update_suspends (inf);
}
}
 
 
/* Cause INF to stop execution immediately; individual threads may still
/* Cause INF to stop execution immediately; individual threads may still
   be running.  */
   be running.  */
inline void
inline void
inf_suspend (struct inf *inf)
inf_suspend (struct inf *inf)
{
{
  struct proc *thread;
  struct proc *thread;
 
 
  inf_update_procs (inf);
  inf_update_procs (inf);
 
 
  for (thread = inf->threads; thread; thread = thread->next)
  for (thread = inf->threads; thread; thread = thread->next)
    thread->sc = thread->pause_sc;
    thread->sc = thread->pause_sc;
 
 
  if (inf->task)
  if (inf->task)
    inf->task->sc = inf->pause_sc;
    inf->task->sc = inf->pause_sc;
 
 
  inf_update_suspends (inf);
  inf_update_suspends (inf);
}
}
 
 


/* INF has one thread PROC that is in single-stepping mode.  This
/* INF has one thread PROC that is in single-stepping mode.  This
   function changes it to be PROC, changing any old step_thread to be
   function changes it to be PROC, changing any old step_thread to be
   a normal one.  A PROC of 0 clears any existing value.  */
   a normal one.  A PROC of 0 clears any existing value.  */
void
void
inf_set_step_thread (struct inf *inf, struct proc *thread)
inf_set_step_thread (struct inf *inf, struct proc *thread)
{
{
  assert (!thread || proc_is_thread (thread));
  assert (!thread || proc_is_thread (thread));
 
 
  if (thread)
  if (thread)
    inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid);
    inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid);
  else
  else
    inf_debug (inf, "clearing step thread");
    inf_debug (inf, "clearing step thread");
 
 
  if (inf->step_thread != thread)
  if (inf->step_thread != thread)
    {
    {
      if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL)
      if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL)
        if (!proc_trace (inf->step_thread, 0))
        if (!proc_trace (inf->step_thread, 0))
          return;
          return;
      if (thread && proc_trace (thread, 1))
      if (thread && proc_trace (thread, 1))
        inf->step_thread = thread;
        inf->step_thread = thread;
      else
      else
        inf->step_thread = 0;
        inf->step_thread = 0;
    }
    }
}
}
 
 


/* Set up the thread resume_sc's so that only the signal thread is running
/* Set up the thread resume_sc's so that only the signal thread is running
   (plus whatever other thread are set to always run).  Returns true if we
   (plus whatever other thread are set to always run).  Returns true if we
   did so, or false if we can't find a signal thread.  */
   did so, or false if we can't find a signal thread.  */
inline int
inline int
inf_set_threads_resume_sc_for_signal_thread (struct inf *inf)
inf_set_threads_resume_sc_for_signal_thread (struct inf *inf)
{
{
  if (inf->signal_thread)
  if (inf->signal_thread)
    {
    {
      inf_set_threads_resume_sc (inf, inf->signal_thread, 0);
      inf_set_threads_resume_sc (inf, inf->signal_thread, 0);
      return 1;
      return 1;
    }
    }
  else
  else
    return 0;
    return 0;
}
}
 
 
static void
static void
inf_update_signal_thread (struct inf *inf)
inf_update_signal_thread (struct inf *inf)
{
{
  /* XXX for now we assume that if there's a msgport, the 2nd thread is
  /* XXX for now we assume that if there's a msgport, the 2nd thread is
     the signal thread.  */
     the signal thread.  */
  inf->signal_thread = inf->threads ? inf->threads->next : 0;
  inf->signal_thread = inf->threads ? inf->threads->next : 0;
}
}
 
 


/* Detachs from INF's inferior task, letting it run once again...  */
/* Detachs from INF's inferior task, letting it run once again...  */
void
void
inf_detach (struct inf *inf)
inf_detach (struct inf *inf)
{
{
  struct proc *task = inf->task;
  struct proc *task = inf->task;
 
 
  inf_debug (inf, "detaching...");
  inf_debug (inf, "detaching...");
 
 
  inf_clear_wait (inf);
  inf_clear_wait (inf);
  inf_set_step_thread (inf, 0);
  inf_set_step_thread (inf, 0);
 
 
  if (task)
  if (task)
    {
    {
      struct proc *thread;
      struct proc *thread;
 
 
      inf_validate_procinfo (inf);
      inf_validate_procinfo (inf);
 
 
      inf_set_traced (inf, 0);
      inf_set_traced (inf, 0);
      if (inf->stopped)
      if (inf->stopped)
        {
        {
          if (inf->nomsg)
          if (inf->nomsg)
            inf_continue (inf);
            inf_continue (inf);
          else
          else
            inf_signal (inf, TARGET_SIGNAL_0);
            inf_signal (inf, TARGET_SIGNAL_0);
        }
        }
 
 
      proc_restore_exc_port (task);
      proc_restore_exc_port (task);
      task->sc = inf->detach_sc;
      task->sc = inf->detach_sc;
 
 
      for (thread = inf->threads; thread; thread = thread->next)
      for (thread = inf->threads; thread; thread = thread->next)
        {
        {
          proc_restore_exc_port (thread);
          proc_restore_exc_port (thread);
          thread->sc = thread->detach_sc;
          thread->sc = thread->detach_sc;
        }
        }
 
 
      inf_update_suspends (inf);
      inf_update_suspends (inf);
    }
    }
 
 
  inf_cleanup (inf);
  inf_cleanup (inf);
}
}
 
 
/* Attaches INF to the process with process id PID, returning it in a
/* Attaches INF to the process with process id PID, returning it in a
   suspended state suitable for debugging.  */
   suspended state suitable for debugging.  */
void
void
inf_attach (struct inf *inf, int pid)
inf_attach (struct inf *inf, int pid)
{
{
  inf_debug (inf, "attaching: %d", pid);
  inf_debug (inf, "attaching: %d", pid);
 
 
  if (inf->pid)
  if (inf->pid)
    inf_detach (inf);
    inf_detach (inf);
 
 
  inf_startup (inf, pid);
  inf_startup (inf, pid);
}
}
 
 


/* Makes sure that we've got our exception ports entrenched in the process. */
/* Makes sure that we've got our exception ports entrenched in the process. */
void
void
inf_steal_exc_ports (struct inf *inf)
inf_steal_exc_ports (struct inf *inf)
{
{
  struct proc *thread;
  struct proc *thread;
 
 
  inf_debug (inf, "stealing exception ports");
  inf_debug (inf, "stealing exception ports");
 
 
  inf_set_step_thread (inf, 0);  /* The step thread is special. */
  inf_set_step_thread (inf, 0);  /* The step thread is special. */
 
 
  proc_steal_exc_port (inf->task, inf->event_port);
  proc_steal_exc_port (inf->task, inf->event_port);
  for (thread = inf->threads; thread; thread = thread->next)
  for (thread = inf->threads; thread; thread = thread->next)
    proc_steal_exc_port (thread, MACH_PORT_NULL);
    proc_steal_exc_port (thread, MACH_PORT_NULL);
}
}
 
 
/* Makes sure the process has its own exception ports.  */
/* Makes sure the process has its own exception ports.  */
void
void
inf_restore_exc_ports (struct inf *inf)
inf_restore_exc_ports (struct inf *inf)
{
{
  struct proc *thread;
  struct proc *thread;
 
 
  inf_debug (inf, "restoring exception ports");
  inf_debug (inf, "restoring exception ports");
 
 
  inf_set_step_thread (inf, 0);  /* The step thread is special. */
  inf_set_step_thread (inf, 0);  /* The step thread is special. */
 
 
  proc_restore_exc_port (inf->task);
  proc_restore_exc_port (inf->task);
  for (thread = inf->threads; thread; thread = thread->next)
  for (thread = inf->threads; thread; thread = thread->next)
    proc_restore_exc_port (thread);
    proc_restore_exc_port (thread);
}
}
 
 


/* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
/* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
   signal 0, will continue it.  INF is assumed to be in a paused state, and
   signal 0, will continue it.  INF is assumed to be in a paused state, and
   the resume_sc's of INF's threads may be affected.  */
   the resume_sc's of INF's threads may be affected.  */
void
void
inf_signal (struct inf *inf, enum target_signal sig)
inf_signal (struct inf *inf, enum target_signal sig)
{
{
  error_t err = 0;
  error_t err = 0;
  int host_sig = target_signal_to_host (sig);
  int host_sig = target_signal_to_host (sig);
 
 
#define NAME target_signal_to_name (sig)
#define NAME target_signal_to_name (sig)
 
 
  if (host_sig >= _NSIG)
  if (host_sig >= _NSIG)
    /* A mach exception.  Exceptions are encoded in the signal space by
    /* A mach exception.  Exceptions are encoded in the signal space by
       putting them after _NSIG; this assumes they're positive (and not
       putting them after _NSIG; this assumes they're positive (and not
       extremely large)!  */
       extremely large)!  */
    {
    {
      struct inf_wait *w = &inf->wait;
      struct inf_wait *w = &inf->wait;
      if (w->status.kind == TARGET_WAITKIND_STOPPED
      if (w->status.kind == TARGET_WAITKIND_STOPPED
          && w->status.value.sig == sig
          && w->status.value.sig == sig
          && w->thread && !w->thread->aborted)
          && w->thread && !w->thread->aborted)
        /* We're passing through the last exception we received.  This is
        /* We're passing through the last exception we received.  This is
           kind of bogus, because exceptions are per-thread whereas gdb
           kind of bogus, because exceptions are per-thread whereas gdb
           treats signals as per-process.  We just forward the exception to
           treats signals as per-process.  We just forward the exception to
           the correct handler, even it's not for the same thread as TID --
           the correct handler, even it's not for the same thread as TID --
           i.e., we pretend it's global.  */
           i.e., we pretend it's global.  */
        {
        {
          struct exc_state *e = &w->exc;
          struct exc_state *e = &w->exc;
          inf_debug (inf, "passing through exception:"
          inf_debug (inf, "passing through exception:"
                     " task = %d, thread = %d, exc = %d"
                     " task = %d, thread = %d, exc = %d"
                     ", code = %d, subcode = %d",
                     ", code = %d, subcode = %d",
                     w->thread->port, inf->task->port,
                     w->thread->port, inf->task->port,
                     e->exception, e->code, e->subcode);
                     e->exception, e->code, e->subcode);
          err =
          err =
            exception_raise_request (e->handler,
            exception_raise_request (e->handler,
                                     e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE,
                                     e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE,
                                     w->thread->port, inf->task->port,
                                     w->thread->port, inf->task->port,
                                     e->exception, e->code, e->subcode);
                                     e->exception, e->code, e->subcode);
        }
        }
      else
      else
        error ("Can't forward spontaneous exception (%s).", NAME);
        error ("Can't forward spontaneous exception (%s).", NAME);
    }
    }
  else
  else
    /* A Unix signal.  */
    /* A Unix signal.  */
  if (inf->stopped)
  if (inf->stopped)
    /* The process is stopped and expecting a signal.  Just send off a
    /* The process is stopped and expecting a signal.  Just send off a
       request and let it get handled when we resume everything.  */
       request and let it get handled when we resume everything.  */
    {
    {
      inf_debug (inf, "sending %s to stopped process", NAME);
      inf_debug (inf, "sending %s to stopped process", NAME);
      err =
      err =
        INF_MSGPORT_RPC (inf,
        INF_MSGPORT_RPC (inf,
                         msg_sig_post_untraced_request (msgport,
                         msg_sig_post_untraced_request (msgport,
                                                        inf->event_port,
                                                        inf->event_port,
                                               MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                               MACH_MSG_TYPE_MAKE_SEND_ONCE,
                                                        host_sig, 0,
                                                        host_sig, 0,
                                                        refport));
                                                        refport));
      if (!err)
      if (!err)
        /* Posting an untraced signal automatically continues it.
        /* Posting an untraced signal automatically continues it.
           We clear this here rather than when we get the reply
           We clear this here rather than when we get the reply
           because we'd rather assume it's not stopped when it
           because we'd rather assume it's not stopped when it
           actually is, than the reverse.  */
           actually is, than the reverse.  */
        inf->stopped = 0;
        inf->stopped = 0;
    }
    }
  else
  else
    /* It's not expecting it.  We have to let just the signal thread
    /* It's not expecting it.  We have to let just the signal thread
       run, and wait for it to get into a reasonable state before we
       run, and wait for it to get into a reasonable state before we
       can continue the rest of the process.  When we finally resume the
       can continue the rest of the process.  When we finally resume the
       process the signal we request will be the very first thing that
       process the signal we request will be the very first thing that
       happens. */
       happens. */
    {
    {
      inf_debug (inf, "sending %s to unstopped process"
      inf_debug (inf, "sending %s to unstopped process"
                 " (so resuming signal thread)", NAME);
                 " (so resuming signal thread)", NAME);
      err =
      err =
        INF_RESUME_MSGPORT_RPC (inf,
        INF_RESUME_MSGPORT_RPC (inf,
                                msg_sig_post_untraced (msgport, host_sig,
                                msg_sig_post_untraced (msgport, host_sig,
                                                       0, refport));
                                                       0, refport));
    }
    }
 
 
  if (err == EIEIO)
  if (err == EIEIO)
    /* Can't do too much... */
    /* Can't do too much... */
    warning ("Can't deliver signal %s: No signal thread.", NAME);
    warning ("Can't deliver signal %s: No signal thread.", NAME);
  else if (err)
  else if (err)
    warning ("Delivering signal %s: %s", NAME, strerror (err));
    warning ("Delivering signal %s: %s", NAME, strerror (err));
 
 
#undef NAME
#undef NAME
}
}
 
 


/* Continue INF without delivering a signal.  This is meant to be used
/* Continue INF without delivering a signal.  This is meant to be used
   when INF does not have a message port.  */
   when INF does not have a message port.  */
void
void
inf_continue (struct inf *inf)
inf_continue (struct inf *inf)
{
{
  process_t proc;
  process_t proc;
  error_t err = proc_pid2proc (proc_server, inf->pid, &proc);
  error_t err = proc_pid2proc (proc_server, inf->pid, &proc);
 
 
  if (!err)
  if (!err)
    {
    {
      inf_debug (inf, "continuing process");
      inf_debug (inf, "continuing process");
 
 
      err = proc_mark_cont (proc);
      err = proc_mark_cont (proc);
      if (!err)
      if (!err)
        {
        {
          struct proc *thread;
          struct proc *thread;
 
 
          for (thread = inf->threads; thread; thread = thread->next)
          for (thread = inf->threads; thread; thread = thread->next)
            thread_resume (thread->port);
            thread_resume (thread->port);
 
 
          inf->stopped = 0;
          inf->stopped = 0;
        }
        }
    }
    }
 
 
  if (err)
  if (err)
    warning ("Can't continue process: %s", strerror (err));
    warning ("Can't continue process: %s", strerror (err));
}
}
 
 


/* The inferior used for all gdb target ops.  */
/* The inferior used for all gdb target ops.  */
struct inf *current_inferior = 0;
struct inf *current_inferior = 0;
 
 
/* The inferior being waited for by gnu_wait.  Since GDB is decidely not
/* The inferior being waited for by gnu_wait.  Since GDB is decidely not
   multi-threaded, we don't bother to lock this.  */
   multi-threaded, we don't bother to lock this.  */
struct inf *waiting_inf;
struct inf *waiting_inf;
 
 
/* Wait for something to happen in the inferior, returning what in STATUS. */
/* Wait for something to happen in the inferior, returning what in STATUS. */
static int
static int
gnu_wait (int tid, struct target_waitstatus *status)
gnu_wait (int tid, struct target_waitstatus *status)
{
{
  struct msg
  struct msg
    {
    {
      mach_msg_header_t hdr;
      mach_msg_header_t hdr;
      mach_msg_type_t type;
      mach_msg_type_t type;
      int data[8000];
      int data[8000];
    } msg;
    } msg;
  error_t err;
  error_t err;
  struct proc *thread;
  struct proc *thread;
  struct inf *inf = current_inferior;
  struct inf *inf = current_inferior;
 
 
  extern int exc_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int exc_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *);
  extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *);
 
 
  assert (inf->task);
  assert (inf->task);
 
 
  if (!inf->threads && !inf->pending_execs)
  if (!inf->threads && !inf->pending_execs)
    /* No threads!  Assume that maybe some outside agency is frobbing our
    /* No threads!  Assume that maybe some outside agency is frobbing our
       task, and really look for new threads.  If we can't find any, just tell
       task, and really look for new threads.  If we can't find any, just tell
       the user to try again later.  */
       the user to try again later.  */
    {
    {
      inf_validate_procs (inf);
      inf_validate_procs (inf);
      if (!inf->threads && !inf->task->dead)
      if (!inf->threads && !inf->task->dead)
        error ("There are no threads; try again later.");
        error ("There are no threads; try again later.");
    }
    }
 
 
  waiting_inf = inf;
  waiting_inf = inf;
 
 
  inf_debug (inf, "waiting for: %d", tid);
  inf_debug (inf, "waiting for: %d", tid);
 
 
rewait:
rewait:
  if (proc_wait_pid != inf->pid && !inf->no_wait)
  if (proc_wait_pid != inf->pid && !inf->no_wait)
    /* Always get information on events from the proc server.  */
    /* Always get information on events from the proc server.  */
    {
    {
      inf_debug (inf, "requesting wait on pid %d", inf->pid);
      inf_debug (inf, "requesting wait on pid %d", inf->pid);
 
 
      if (proc_wait_pid)
      if (proc_wait_pid)
        /* The proc server is single-threaded, and only allows a single
        /* The proc server is single-threaded, and only allows a single
           outstanding wait request, so we have to cancel the previous one. */
           outstanding wait request, so we have to cancel the previous one. */
        {
        {
          inf_debug (inf, "cancelling previous wait on pid %d", proc_wait_pid);
          inf_debug (inf, "cancelling previous wait on pid %d", proc_wait_pid);
          interrupt_operation (proc_server, 0);
          interrupt_operation (proc_server, 0);
        }
        }
 
 
      err =
      err =
        proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
        proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
      if (err)
      if (err)
        warning ("wait request failed: %s", strerror (err));
        warning ("wait request failed: %s", strerror (err));
      else
      else
        {
        {
          inf_debug (inf, "waits pending: %d", proc_waits_pending);
          inf_debug (inf, "waits pending: %d", proc_waits_pending);
          proc_wait_pid = inf->pid;
          proc_wait_pid = inf->pid;
          /* Even if proc_waits_pending was > 0 before, we still won't
          /* Even if proc_waits_pending was > 0 before, we still won't
             get any other replies, because it was either from a
             get any other replies, because it was either from a
             different INF, or a different process attached to INF --
             different INF, or a different process attached to INF --
             and the event port, which is the wait reply port, changes
             and the event port, which is the wait reply port, changes
             when you switch processes. */
             when you switch processes. */
          proc_waits_pending = 1;
          proc_waits_pending = 1;
        }
        }
    }
    }
 
 
  inf_clear_wait (inf);
  inf_clear_wait (inf);
 
 
  /* What can happen? (1) Dead name notification; (2) Exceptions arrive;
  /* What can happen? (1) Dead name notification; (2) Exceptions arrive;
     (3) wait reply from the proc server.  */
     (3) wait reply from the proc server.  */
 
 
  inf_debug (inf, "waiting for an event...");
  inf_debug (inf, "waiting for an event...");
  err = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
  err = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
                  0, sizeof (struct msg), inf->event_port,
                  0, sizeof (struct msg), inf->event_port,
                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
 
 
  /* Re-suspend the task.  */
  /* Re-suspend the task.  */
  inf_suspend (inf);
  inf_suspend (inf);
 
 
  if (!inf->task && inf->pending_execs)
  if (!inf->task && inf->pending_execs)
    /* When doing an exec, it's possible that the old task wasn't reused
    /* When doing an exec, it's possible that the old task wasn't reused
       (e.g., setuid execs).  So if the task seems to have disappeared,
       (e.g., setuid execs).  So if the task seems to have disappeared,
       attempt to refetch it, as the pid should still be the same.  */
       attempt to refetch it, as the pid should still be the same.  */
    inf_set_pid (inf, inf->pid);
    inf_set_pid (inf, inf->pid);
 
 
  if (err == EMACH_RCV_INTERRUPTED)
  if (err == EMACH_RCV_INTERRUPTED)
    inf_debug (inf, "interrupted");
    inf_debug (inf, "interrupted");
  else if (err)
  else if (err)
    error ("Couldn't wait for an event: %s", strerror (err));
    error ("Couldn't wait for an event: %s", strerror (err));
  else
  else
    {
    {
      struct
      struct
        {
        {
          mach_msg_header_t hdr;
          mach_msg_header_t hdr;
          mach_msg_type_t err_type;
          mach_msg_type_t err_type;
          kern_return_t err;
          kern_return_t err;
          char noise[200];
          char noise[200];
        }
        }
      reply;
      reply;
 
 
      inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id);
      inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id);
 
 
      /* Handle what we got.  */
      /* Handle what we got.  */
      if (!notify_server (&msg.hdr, &reply.hdr)
      if (!notify_server (&msg.hdr, &reply.hdr)
          && !exc_server (&msg.hdr, &reply.hdr)
          && !exc_server (&msg.hdr, &reply.hdr)
          && !process_reply_server (&msg.hdr, &reply.hdr)
          && !process_reply_server (&msg.hdr, &reply.hdr)
          && !msg_reply_server (&msg.hdr, &reply.hdr))
          && !msg_reply_server (&msg.hdr, &reply.hdr))
        /* Whatever it is, it's something strange.  */
        /* Whatever it is, it's something strange.  */
        error ("Got a strange event, msg id = %d.", msg.hdr.msgh_id);
        error ("Got a strange event, msg id = %d.", msg.hdr.msgh_id);
 
 
      if (reply.err)
      if (reply.err)
        error ("Handling event, msgid = %d: %s",
        error ("Handling event, msgid = %d: %s",
               msg.hdr.msgh_id, strerror (reply.err));
               msg.hdr.msgh_id, strerror (reply.err));
    }
    }
 
 
  if (inf->pending_execs)
  if (inf->pending_execs)
    /* We're waiting for the inferior to finish execing.  */
    /* We're waiting for the inferior to finish execing.  */
    {
    {
      struct inf_wait *w = &inf->wait;
      struct inf_wait *w = &inf->wait;
      enum target_waitkind kind = w->status.kind;
      enum target_waitkind kind = w->status.kind;
 
 
      if (kind == TARGET_WAITKIND_SPURIOUS)
      if (kind == TARGET_WAITKIND_SPURIOUS)
        /* Since gdb is actually counting the number of times the inferior
        /* Since gdb is actually counting the number of times the inferior
           stops, expecting one stop per exec, we only return major events
           stops, expecting one stop per exec, we only return major events
           while execing.  */
           while execing.  */
        {
        {
          w->suppress = 1;
          w->suppress = 1;
          inf_debug (inf, "pending_execs = %d, ignoring minor event",
          inf_debug (inf, "pending_execs = %d, ignoring minor event",
                     inf->pending_execs);
                     inf->pending_execs);
        }
        }
      else if (kind == TARGET_WAITKIND_STOPPED
      else if (kind == TARGET_WAITKIND_STOPPED
               && w->status.value.sig == TARGET_SIGNAL_TRAP)
               && w->status.value.sig == TARGET_SIGNAL_TRAP)
        /* Ah hah!  A SIGTRAP from the inferior while starting up probably
        /* Ah hah!  A SIGTRAP from the inferior while starting up probably
           means we've succesfully completed an exec!  */
           means we've succesfully completed an exec!  */
        {
        {
          if (--inf->pending_execs == 0)
          if (--inf->pending_execs == 0)
            /* We're done!  */
            /* We're done!  */
            {
            {
#if 0                           /* do we need this? */
#if 0                           /* do we need this? */
              prune_threads (1);        /* Get rid of the old shell threads */
              prune_threads (1);        /* Get rid of the old shell threads */
              renumber_threads (0);      /* Give our threads reasonable names. */
              renumber_threads (0);      /* Give our threads reasonable names. */
#endif
#endif
            }
            }
          inf_debug (inf, "pending exec completed, pending_execs => %d",
          inf_debug (inf, "pending exec completed, pending_execs => %d",
                     inf->pending_execs);
                     inf->pending_execs);
        }
        }
      else if (kind == TARGET_WAITKIND_STOPPED)
      else if (kind == TARGET_WAITKIND_STOPPED)
        /* It's possible that this signal is because of a crashed process
        /* It's possible that this signal is because of a crashed process
           being handled by the hurd crash server; in this case, the process
           being handled by the hurd crash server; in this case, the process
           will have an extra task suspend, which we need to know about.
           will have an extra task suspend, which we need to know about.
           Since the code in inf_resume that normally checks for this is
           Since the code in inf_resume that normally checks for this is
           disabled while INF->pending_execs, we do the check here instead.  */
           disabled while INF->pending_execs, we do the check here instead.  */
        inf_validate_task_sc (inf);
        inf_validate_task_sc (inf);
    }
    }
 
 
  if (inf->wait.suppress)
  if (inf->wait.suppress)
    /* Some totally spurious event happened that we don't consider
    /* Some totally spurious event happened that we don't consider
       worth returning to gdb.  Just keep waiting.  */
       worth returning to gdb.  Just keep waiting.  */
    {
    {
      inf_debug (inf, "suppressing return, rewaiting...");
      inf_debug (inf, "suppressing return, rewaiting...");
      inf_resume (inf);
      inf_resume (inf);
      goto rewait;
      goto rewait;
    }
    }
 
 
  /* Pass back out our results.  */
  /* Pass back out our results.  */
  bcopy (&inf->wait.status, status, sizeof (*status));
  bcopy (&inf->wait.status, status, sizeof (*status));
 
 
  thread = inf->wait.thread;
  thread = inf->wait.thread;
  if (thread)
  if (thread)
    tid = thread->tid;
    tid = thread->tid;
  else
  else
    thread = inf_tid_to_thread (inf, tid);
    thread = inf_tid_to_thread (inf, tid);
 
 
  if (!thread || thread->port == MACH_PORT_NULL)
  if (!thread || thread->port == MACH_PORT_NULL)
    {
    {
      /* TID is dead; try and find a new thread.  */
      /* TID is dead; try and find a new thread.  */
      if (inf_update_procs (inf) && inf->threads)
      if (inf_update_procs (inf) && inf->threads)
        tid = inf->threads->tid; /* The first available thread.  */
        tid = inf->threads->tid; /* The first available thread.  */
      else
      else
        tid = inferior_pid;     /* let wait_for_inferior handle exit case */
        tid = inferior_pid;     /* let wait_for_inferior handle exit case */
    }
    }
 
 
  if (thread && tid >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS
  if (thread && tid >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS
      && inf->pause_sc == 0 && thread->pause_sc == 0)
      && inf->pause_sc == 0 && thread->pause_sc == 0)
    /* If something actually happened to THREAD, make sure we
    /* If something actually happened to THREAD, make sure we
       suspend it.  */
       suspend it.  */
    {
    {
      thread->sc = 1;
      thread->sc = 1;
      inf_update_suspends (inf);
      inf_update_suspends (inf);
    }
    }
 
 
  inf_debug (inf, "returning tid = %d, status = %s (%d)", tid,
  inf_debug (inf, "returning tid = %d, status = %s (%d)", tid,
             status->kind == TARGET_WAITKIND_EXITED ? "EXITED"
             status->kind == TARGET_WAITKIND_EXITED ? "EXITED"
             : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED"
             : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED"
             : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED"
             : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED"
             : status->kind == TARGET_WAITKIND_LOADED ? "LOADED"
             : status->kind == TARGET_WAITKIND_LOADED ? "LOADED"
             : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS"
             : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS"
             : "?",
             : "?",
             status->value.integer);
             status->value.integer);
 
 
  return tid;
  return tid;
}
}
 
 


/* The rpc handler called by exc_server.  */
/* The rpc handler called by exc_server.  */
error_t
error_t
S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
                           thread_t thread_port, task_t task_port,
                           thread_t thread_port, task_t task_port,
                           int exception, int code, int subcode)
                           int exception, int code, int subcode)
{
{
  struct inf *inf = waiting_inf;
  struct inf *inf = waiting_inf;
  struct proc *thread = inf_port_to_thread (inf, thread_port);
  struct proc *thread = inf_port_to_thread (inf, thread_port);
 
 
  inf_debug (waiting_inf,
  inf_debug (waiting_inf,
             "thread = %d, task = %d, exc = %d, code = %d, subcode = %d",
             "thread = %d, task = %d, exc = %d, code = %d, subcode = %d",
             thread_port, task_port, exception, code, subcode);
             thread_port, task_port, exception, code, subcode);
 
 
  if (!thread)
  if (!thread)
    /* We don't know about thread?  */
    /* We don't know about thread?  */
    {
    {
      inf_update_procs (inf);
      inf_update_procs (inf);
      thread = inf_port_to_thread (inf, thread_port);
      thread = inf_port_to_thread (inf, thread_port);
      if (!thread)
      if (!thread)
        /* Give up, the generating thread is gone.  */
        /* Give up, the generating thread is gone.  */
        return 0;
        return 0;
    }
    }
 
 
  mach_port_deallocate (mach_task_self (), thread_port);
  mach_port_deallocate (mach_task_self (), thread_port);
  mach_port_deallocate (mach_task_self (), task_port);
  mach_port_deallocate (mach_task_self (), task_port);
 
 
  if (!thread->aborted)
  if (!thread->aborted)
    /* THREAD hasn't been aborted since this exception happened (abortion
    /* THREAD hasn't been aborted since this exception happened (abortion
       clears any exception state), so it must be real.  */
       clears any exception state), so it must be real.  */
    {
    {
      /* Store away the details; this will destroy any previous info.  */
      /* Store away the details; this will destroy any previous info.  */
      inf->wait.thread = thread;
      inf->wait.thread = thread;
 
 
      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
 
 
      if (exception == EXC_BREAKPOINT)
      if (exception == EXC_BREAKPOINT)
        /* GDB likes to get SIGTRAP for breakpoints.  */
        /* GDB likes to get SIGTRAP for breakpoints.  */
        {
        {
          inf->wait.status.value.sig = TARGET_SIGNAL_TRAP;
          inf->wait.status.value.sig = TARGET_SIGNAL_TRAP;
          mach_port_deallocate (mach_task_self (), reply_port);
          mach_port_deallocate (mach_task_self (), reply_port);
        }
        }
      else
      else
        /* Record the exception so that we can forward it later.  */
        /* Record the exception so that we can forward it later.  */
        {
        {
          if (thread->exc_port == port)
          if (thread->exc_port == port)
            {
            {
              inf_debug (waiting_inf, "Handler is thread exeption port <%d>",
              inf_debug (waiting_inf, "Handler is thread exeption port <%d>",
                         thread->saved_exc_port);
                         thread->saved_exc_port);
              inf->wait.exc.handler = thread->saved_exc_port;
              inf->wait.exc.handler = thread->saved_exc_port;
            }
            }
          else
          else
            {
            {
              inf_debug (waiting_inf, "Handler is task exeption port <%d>",
              inf_debug (waiting_inf, "Handler is task exeption port <%d>",
                         inf->task->saved_exc_port);
                         inf->task->saved_exc_port);
              inf->wait.exc.handler = inf->task->saved_exc_port;
              inf->wait.exc.handler = inf->task->saved_exc_port;
              assert (inf->task->exc_port == port);
              assert (inf->task->exc_port == port);
            }
            }
          if (inf->wait.exc.handler != MACH_PORT_NULL)
          if (inf->wait.exc.handler != MACH_PORT_NULL)
            /* Add a reference to the exception handler. */
            /* Add a reference to the exception handler. */
            mach_port_mod_refs (mach_task_self (),
            mach_port_mod_refs (mach_task_self (),
                                inf->wait.exc.handler, MACH_PORT_RIGHT_SEND,
                                inf->wait.exc.handler, MACH_PORT_RIGHT_SEND,
                                1);
                                1);
 
 
          inf->wait.exc.exception = exception;
          inf->wait.exc.exception = exception;
          inf->wait.exc.code = code;
          inf->wait.exc.code = code;
          inf->wait.exc.subcode = subcode;
          inf->wait.exc.subcode = subcode;
          inf->wait.exc.reply = reply_port;
          inf->wait.exc.reply = reply_port;
 
 
          /* Exceptions are encoded in the signal space by putting them after
          /* Exceptions are encoded in the signal space by putting them after
             _NSIG; this assumes they're positive (and not extremely large)! */
             _NSIG; this assumes they're positive (and not extremely large)! */
          inf->wait.status.value.sig =
          inf->wait.status.value.sig =
            target_signal_from_host (_NSIG + exception);
            target_signal_from_host (_NSIG + exception);
        }
        }
    }
    }
  else
  else
    /* A supppressed exception, which ignore.  */
    /* A supppressed exception, which ignore.  */
    {
    {
      inf->wait.suppress = 1;
      inf->wait.suppress = 1;
      mach_port_deallocate (mach_task_self (), reply_port);
      mach_port_deallocate (mach_task_self (), reply_port);
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 


/* Fill in INF's wait field after a task has died without giving us more
/* Fill in INF's wait field after a task has died without giving us more
   detailed information.  */
   detailed information.  */
void
void
inf_task_died_status (struct inf *inf)
inf_task_died_status (struct inf *inf)
{
{
  warning ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid);
  warning ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid);
  inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED;
  inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED;
  inf->wait.status.value.sig = TARGET_SIGNAL_KILL;
  inf->wait.status.value.sig = TARGET_SIGNAL_KILL;
}
}
 
 
/* Notify server routines.  The only real one is dead name notification.  */
/* Notify server routines.  The only real one is dead name notification.  */
error_t
error_t
do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port)
do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port)
{
{
  struct inf *inf = waiting_inf;
  struct inf *inf = waiting_inf;
 
 
  inf_debug (waiting_inf, "port = %d", dead_port);
  inf_debug (waiting_inf, "port = %d", dead_port);
 
 
  if (inf->task && inf->task->port == dead_port)
  if (inf->task && inf->task->port == dead_port)
    {
    {
      proc_debug (inf->task, "is dead");
      proc_debug (inf->task, "is dead");
      inf->task->port = MACH_PORT_NULL;
      inf->task->port = MACH_PORT_NULL;
      if (proc_wait_pid == inf->pid)
      if (proc_wait_pid == inf->pid)
        /* We have a wait outstanding on the process, which will return more
        /* We have a wait outstanding on the process, which will return more
           detailed information, so delay until we get that.  */
           detailed information, so delay until we get that.  */
        inf->wait.suppress = 1;
        inf->wait.suppress = 1;
      else
      else
        /* We never waited for the process (maybe it wasn't a child), so just
        /* We never waited for the process (maybe it wasn't a child), so just
           pretend it got a SIGKILL.  */
           pretend it got a SIGKILL.  */
        inf_task_died_status (inf);
        inf_task_died_status (inf);
    }
    }
  else
  else
    {
    {
      struct proc *thread = inf_port_to_thread (inf, dead_port);
      struct proc *thread = inf_port_to_thread (inf, dead_port);
      if (thread)
      if (thread)
        {
        {
          proc_debug (thread, "is dead");
          proc_debug (thread, "is dead");
          thread->port = MACH_PORT_NULL;
          thread->port = MACH_PORT_NULL;
        }
        }
 
 
      if (inf->task->dead)
      if (inf->task->dead)
        /* Since the task is dead, its threads are dying with it.  */
        /* Since the task is dead, its threads are dying with it.  */
        inf->wait.suppress = 1;
        inf->wait.suppress = 1;
    }
    }
 
 
  mach_port_deallocate (mach_task_self (), dead_port);
  mach_port_deallocate (mach_task_self (), dead_port);
  inf->threads_up_to_date = 0;   /* Just in case */
  inf->threads_up_to_date = 0;   /* Just in case */
 
 
  return 0;
  return 0;
}
}
 
 


static error_t
static error_t
ill_rpc (char *fun)
ill_rpc (char *fun)
{
{
  warning ("illegal rpc: %s", fun);
  warning ("illegal rpc: %s", fun);
  return 0;
  return 0;
}
}
 
 
error_t
error_t
do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count)
do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 
error_t
error_t
do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 
error_t
error_t
do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name)
do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 
error_t
error_t
do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name)
do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 
error_t
error_t
do_mach_notify_send_once (mach_port_t notify)
do_mach_notify_send_once (mach_port_t notify)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 


/* Process_reply server routines.  We only use process_wait_reply.  */
/* Process_reply server routines.  We only use process_wait_reply.  */
 
 
error_t
error_t
S_proc_wait_reply (mach_port_t reply, error_t err,
S_proc_wait_reply (mach_port_t reply, error_t err,
                   int status, int sigcode, rusage_t rusage, pid_t pid)
                   int status, int sigcode, rusage_t rusage, pid_t pid)
{
{
  struct inf *inf = waiting_inf;
  struct inf *inf = waiting_inf;
 
 
  inf_debug (inf, "err = %s, pid = %d, status = 0x%x, sigcode = %d",
  inf_debug (inf, "err = %s, pid = %d, status = 0x%x, sigcode = %d",
             err ? strerror (err) : "0", pid, status, sigcode);
             err ? strerror (err) : "0", pid, status, sigcode);
 
 
  if (err && proc_wait_pid && (!inf->task || !inf->task->port))
  if (err && proc_wait_pid && (!inf->task || !inf->task->port))
    /* Ack.  The task has died, but the task-died notification code didn't
    /* Ack.  The task has died, but the task-died notification code didn't
       tell anyone because it thought a more detailed reply from the
       tell anyone because it thought a more detailed reply from the
       procserver was forthcoming.  However, we now learn that won't
       procserver was forthcoming.  However, we now learn that won't
       happen...  So we have to act like the task just died, and this time,
       happen...  So we have to act like the task just died, and this time,
       tell the world.  */
       tell the world.  */
    inf_task_died_status (inf);
    inf_task_died_status (inf);
 
 
  if (--proc_waits_pending == 0)
  if (--proc_waits_pending == 0)
    /* PROC_WAIT_PID represents the most recent wait.  We will always get
    /* PROC_WAIT_PID represents the most recent wait.  We will always get
       replies in order because the proc server is single threaded.  */
       replies in order because the proc server is single threaded.  */
    proc_wait_pid = 0;
    proc_wait_pid = 0;
 
 
  inf_debug (inf, "waits pending now: %d", proc_waits_pending);
  inf_debug (inf, "waits pending now: %d", proc_waits_pending);
 
 
  if (err)
  if (err)
    {
    {
      if (err != EINTR)
      if (err != EINTR)
        {
        {
          warning ("Can't wait for pid %d: %s", inf->pid, strerror (err));
          warning ("Can't wait for pid %d: %s", inf->pid, strerror (err));
          inf->no_wait = 1;
          inf->no_wait = 1;
 
 
          /* Since we can't see the inferior's signals, don't trap them.  */
          /* Since we can't see the inferior's signals, don't trap them.  */
          inf_set_traced (inf, 0);
          inf_set_traced (inf, 0);
        }
        }
    }
    }
  else if (pid == inf->pid)
  else if (pid == inf->pid)
    {
    {
      store_waitstatus (&inf->wait.status, status);
      store_waitstatus (&inf->wait.status, status);
      if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED)
      if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED)
        /* The process has sent us a signal, and stopped itself in a sane
        /* The process has sent us a signal, and stopped itself in a sane
           state pending our actions.  */
           state pending our actions.  */
        {
        {
          inf_debug (inf, "process has stopped itself");
          inf_debug (inf, "process has stopped itself");
          inf->stopped = 1;
          inf->stopped = 1;
        }
        }
    }
    }
  else
  else
    inf->wait.suppress = 1;     /* Something odd happened.  Ignore.  */
    inf->wait.suppress = 1;     /* Something odd happened.  Ignore.  */
 
 
  return 0;
  return 0;
}
}
 
 
error_t
error_t
S_proc_setmsgport_reply (mach_port_t reply, error_t err,
S_proc_setmsgport_reply (mach_port_t reply, error_t err,
                         mach_port_t old_msg_port)
                         mach_port_t old_msg_port)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 
error_t
error_t
S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port)
S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 


/* Msg_reply server routines.  We only use msg_sig_post_untraced_reply.  */
/* Msg_reply server routines.  We only use msg_sig_post_untraced_reply.  */
 
 
error_t
error_t
S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err)
S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err)
{
{
  struct inf *inf = waiting_inf;
  struct inf *inf = waiting_inf;
 
 
  if (err == EBUSY)
  if (err == EBUSY)
    /* EBUSY is what we get when the crash server has grabbed control of the
    /* EBUSY is what we get when the crash server has grabbed control of the
       process and doesn't like what signal we tried to send it.  Just act
       process and doesn't like what signal we tried to send it.  Just act
       like the process stopped (using a signal of 0 should mean that the
       like the process stopped (using a signal of 0 should mean that the
       *next* time the user continues, it will pass signal 0, which the crash
       *next* time the user continues, it will pass signal 0, which the crash
       server should like).  */
       server should like).  */
    {
    {
      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
      inf->wait.status.value.sig = TARGET_SIGNAL_0;
      inf->wait.status.value.sig = TARGET_SIGNAL_0;
    }
    }
  else if (err)
  else if (err)
    warning ("Signal delivery failed: %s", strerror (err));
    warning ("Signal delivery failed: %s", strerror (err));
 
 
  if (err)
  if (err)
    /* We only get this reply when we've posted a signal to a process which we
    /* We only get this reply when we've posted a signal to a process which we
       thought was stopped, and which we expected to continue after the signal.
       thought was stopped, and which we expected to continue after the signal.
       Given that the signal has failed for some reason, it's reasonable to
       Given that the signal has failed for some reason, it's reasonable to
       assume it's still stopped.  */
       assume it's still stopped.  */
    inf->stopped = 1;
    inf->stopped = 1;
  else
  else
    inf->wait.suppress = 1;
    inf->wait.suppress = 1;
 
 
  return 0;
  return 0;
}
}
 
 
error_t
error_t
S_msg_sig_post_reply (mach_port_t reply, error_t err)
S_msg_sig_post_reply (mach_port_t reply, error_t err)
{
{
  return ill_rpc (__FUNCTION__);
  return ill_rpc (__FUNCTION__);
}
}
 
 


/* Returns the number of messages queued for the receive right PORT.  */
/* Returns the number of messages queued for the receive right PORT.  */
static mach_port_msgcount_t
static mach_port_msgcount_t
port_msgs_queued (mach_port_t port)
port_msgs_queued (mach_port_t port)
{
{
  struct mach_port_status status;
  struct mach_port_status status;
  error_t err =
  error_t err =
  mach_port_get_receive_status (mach_task_self (), port, &status);
  mach_port_get_receive_status (mach_task_self (), port, &status);
 
 
  if (err)
  if (err)
    return 0;
    return 0;
  else
  else
    return status.mps_msgcount;
    return status.mps_msgcount;
}
}
 
 


/* 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.
 
 
   TID  STEP:
   TID  STEP:
   -1   true   Single step the current thread allowing other threads to run.
   -1   true   Single step the current thread allowing other threads to run.
   -1   false  Continue the current thread allowing other threads to run.
   -1   false  Continue the current thread allowing other threads to run.
   X    true   Single step the given thread, don't allow any others to run.
   X    true   Single step the given thread, don't allow any others to run.
   X    false  Continue the given thread, do not allow any others to run.
   X    false  Continue the given thread, do not allow any others to run.
   (Where X, of course, is anything except -1)
   (Where X, of course, is anything except -1)
 
 
   Note that a resume may not `take' if there are pending exceptions/&c
   Note that a resume may not `take' if there are pending exceptions/&c
   still unprocessed from the last resume we did (any given resume may result
   still unprocessed from the last resume we did (any given resume may result
   in multiple events returned by wait).
   in multiple events returned by wait).
 */
 */
static void
static void
gnu_resume (int tid, int step, enum target_signal sig)
gnu_resume (int tid, int step, enum target_signal sig)
{
{
  struct proc *step_thread = 0;
  struct proc *step_thread = 0;
  struct inf *inf = current_inferior;
  struct inf *inf = current_inferior;
 
 
  inf_debug (inf, "tid = %d, step = %d, sig = %d", tid, step, sig);
  inf_debug (inf, "tid = %d, step = %d, sig = %d", tid, step, sig);
 
 
  inf_validate_procinfo (inf);
  inf_validate_procinfo (inf);
 
 
  if (sig != TARGET_SIGNAL_0 || inf->stopped)
  if (sig != TARGET_SIGNAL_0 || inf->stopped)
    {
    {
      if (sig == TARGET_SIGNAL_0 && inf->nomsg)
      if (sig == TARGET_SIGNAL_0 && inf->nomsg)
        inf_continue (inf);
        inf_continue (inf);
      else
      else
        inf_signal (inf, sig);
        inf_signal (inf, sig);
    }
    }
  else if (inf->wait.exc.reply != MACH_PORT_NULL)
  else if (inf->wait.exc.reply != MACH_PORT_NULL)
    /* We received an exception to which we have chosen not to forward, so
    /* We received an exception to which we have chosen not to forward, so
       abort the faulting thread, which will perhaps retake it.  */
       abort the faulting thread, which will perhaps retake it.  */
    {
    {
      proc_abort (inf->wait.thread, 1);
      proc_abort (inf->wait.thread, 1);
      warning ("Aborting %s with unforwarded exception %s.",
      warning ("Aborting %s with unforwarded exception %s.",
               proc_string (inf->wait.thread),
               proc_string (inf->wait.thread),
               target_signal_to_name (inf->wait.status.value.sig));
               target_signal_to_name (inf->wait.status.value.sig));
    }
    }
 
 
  if (port_msgs_queued (inf->event_port))
  if (port_msgs_queued (inf->event_port))
    /* If there are still messages in our event queue, don't bother resuming
    /* If there are still messages in our event queue, don't bother resuming
       the process, as we're just going to stop it right away anyway. */
       the process, as we're just going to stop it right away anyway. */
    return;
    return;
 
 
  inf_update_procs (inf);
  inf_update_procs (inf);
 
 
  if (tid < 0)
  if (tid < 0)
    /* Allow all threads to run, except perhaps single-stepping one.  */
    /* Allow all threads to run, except perhaps single-stepping one.  */
    {
    {
      inf_debug (inf, "running all threads; tid = %d", inferior_pid);
      inf_debug (inf, "running all threads; tid = %d", inferior_pid);
      tid = inferior_pid;       /* What to step. */
      tid = inferior_pid;       /* What to step. */
      inf_set_threads_resume_sc (inf, 0, 1);
      inf_set_threads_resume_sc (inf, 0, 1);
    }
    }
  else
  else
    /* Just allow a single thread to run.  */
    /* Just allow a single thread to run.  */
    {
    {
      struct proc *thread = inf_tid_to_thread (inf, tid);
      struct proc *thread = inf_tid_to_thread (inf, tid);
      if (!thread)
      if (!thread)
        error ("Can't run single thread id %d: no such thread!");
        error ("Can't run single thread id %d: no such thread!");
      inf_debug (inf, "running one thread: %d/%d", inf->pid, thread->tid);
      inf_debug (inf, "running one thread: %d/%d", inf->pid, thread->tid);
      inf_set_threads_resume_sc (inf, thread, 0);
      inf_set_threads_resume_sc (inf, thread, 0);
    }
    }
 
 
  if (step)
  if (step)
    {
    {
      step_thread = inf_tid_to_thread (inf, tid);
      step_thread = inf_tid_to_thread (inf, tid);
      if (!step_thread)
      if (!step_thread)
        warning ("Can't step thread id %d: no such thread.", tid);
        warning ("Can't step thread id %d: no such thread.", tid);
      else
      else
        inf_debug (inf, "stepping thread: %d/%d", inf->pid, step_thread->tid);
        inf_debug (inf, "stepping thread: %d/%d", inf->pid, step_thread->tid);
    }
    }
  if (step_thread != inf->step_thread)
  if (step_thread != inf->step_thread)
    inf_set_step_thread (inf, step_thread);
    inf_set_step_thread (inf, step_thread);
 
 
  inf_debug (inf, "here we go...");
  inf_debug (inf, "here we go...");
  inf_resume (inf);
  inf_resume (inf);
}
}
 
 


static void
static void
gnu_kill_inferior ()
gnu_kill_inferior ()
{
{
  struct proc *task = current_inferior->task;
  struct proc *task = current_inferior->task;
  if (task)
  if (task)
    {
    {
      proc_debug (task, "terminating...");
      proc_debug (task, "terminating...");
      task_terminate (task->port);
      task_terminate (task->port);
      inf_set_pid (current_inferior, -1);
      inf_set_pid (current_inferior, -1);
    }
    }
  target_mourn_inferior ();
  target_mourn_inferior ();
}
}
 
 
/* Clean up after the inferior dies.  */
/* Clean up after the inferior dies.  */
static void
static void
gnu_mourn_inferior ()
gnu_mourn_inferior ()
{
{
  inf_debug (current_inferior, "rip");
  inf_debug (current_inferior, "rip");
  inf_detach (current_inferior);
  inf_detach (current_inferior);
  unpush_target (&gnu_ops);
  unpush_target (&gnu_ops);
  generic_mourn_inferior ();
  generic_mourn_inferior ();
}
}
 
 


/* Fork an inferior process, and start debugging it.  */
/* Fork an inferior process, and start debugging it.  */
 
 
/* Set INFERIOR_PID to the first thread available in the child, if any.  */
/* Set INFERIOR_PID to the first thread available in the child, if any.  */
static int
static int
inf_pick_first_thread ()
inf_pick_first_thread ()
{
{
  if (current_inferior->task && current_inferior->threads)
  if (current_inferior->task && current_inferior->threads)
    /* The first thread.  */
    /* The first thread.  */
    return current_inferior->threads->tid;
    return current_inferior->threads->tid;
  else
  else
    /* What may be the next thread.  */
    /* What may be the next thread.  */
    return next_thread_id;
    return next_thread_id;
}
}
 
 
static struct inf *
static struct inf *
cur_inf ()
cur_inf ()
{
{
  if (!current_inferior)
  if (!current_inferior)
    current_inferior = make_inf ();
    current_inferior = make_inf ();
  return current_inferior;
  return current_inferior;
}
}
 
 
static void
static void
gnu_create_inferior (exec_file, allargs, env)
gnu_create_inferior (exec_file, allargs, env)
     char *exec_file;
     char *exec_file;
     char *allargs;
     char *allargs;
     char **env;
     char **env;
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
 
 
  void trace_me ()
  void trace_me ()
  {
  {
    /* We're in the child; make this process stop as soon as it execs.  */
    /* We're in the child; make this process stop as soon as it execs.  */
    inf_debug (inf, "tracing self");
    inf_debug (inf, "tracing self");
    if (ptrace (PTRACE_TRACEME) != 0)
    if (ptrace (PTRACE_TRACEME) != 0)
      error ("ptrace (PTRACE_TRACEME) failed!");
      error ("ptrace (PTRACE_TRACEME) failed!");
  }
  }
  void attach_to_child (int pid)
  void attach_to_child (int pid)
  {
  {
    /* Attach to the now stopped child, which is actually a shell...  */
    /* Attach to the now stopped child, which is actually a shell...  */
    inf_debug (inf, "attaching to child: %d", pid);
    inf_debug (inf, "attaching to child: %d", pid);
 
 
    inf_attach (inf, pid);
    inf_attach (inf, pid);
 
 
    attach_flag = 0;
    attach_flag = 0;
    push_target (&gnu_ops);
    push_target (&gnu_ops);
 
 
    inf->pending_execs = 2;
    inf->pending_execs = 2;
    inf->nomsg = 1;
    inf->nomsg = 1;
    inf->traced = 1;
    inf->traced = 1;
 
 
    /* Now let the child run again, knowing that it will stop immediately
    /* Now let the child run again, knowing that it will stop immediately
       because of the ptrace. */
       because of the ptrace. */
    inf_resume (inf);
    inf_resume (inf);
    inferior_pid = inf_pick_first_thread ();
    inferior_pid = inf_pick_first_thread ();
 
 
    startup_inferior (inf->pending_execs);
    startup_inferior (inf->pending_execs);
  }
  }
 
 
  inf_debug (inf, "creating inferior");
  inf_debug (inf, "creating inferior");
 
 
  fork_inferior (exec_file, allargs, env, trace_me, attach_to_child,
  fork_inferior (exec_file, allargs, env, trace_me, attach_to_child,
                 NULL, NULL);
                 NULL, NULL);
 
 
  inf_validate_procinfo (inf);
  inf_validate_procinfo (inf);
  inf_update_signal_thread (inf);
  inf_update_signal_thread (inf);
  inf_set_traced (inf, inf->want_signals);
  inf_set_traced (inf, inf->want_signals);
 
 
  /* Execing the process will have trashed our exception ports; steal them
  /* Execing the process will have trashed our exception ports; steal them
     back (or make sure they're restored if the user wants that).  */
     back (or make sure they're restored if the user wants that).  */
  if (inf->want_exceptions)
  if (inf->want_exceptions)
    inf_steal_exc_ports (inf);
    inf_steal_exc_ports (inf);
  else
  else
    inf_restore_exc_ports (inf);
    inf_restore_exc_ports (inf);
 
 
  /* Here we go!  */
  /* Here we go!  */
  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
gnu_can_run ()
gnu_can_run ()
{
{
  return 1;
  return 1;
}
}
 
 


#ifdef ATTACH_DETACH
#ifdef ATTACH_DETACH
 
 
/* 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
gnu_attach (args, from_tty)
gnu_attach (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  int pid;
  int pid;
  char *exec_file;
  char *exec_file;
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
 
 
  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', pid %d\n",
        printf_unfiltered ("Attaching to program `%s', pid %d\n",
                           exec_file, pid);
                           exec_file, pid);
      else
      else
        printf_unfiltered ("Attaching to pid %d\n", pid);
        printf_unfiltered ("Attaching to pid %d\n", pid);
 
 
      gdb_flush (gdb_stdout);
      gdb_flush (gdb_stdout);
    }
    }
 
 
  inf_debug (inf, "attaching to pid: %d", pid);
  inf_debug (inf, "attaching to pid: %d", pid);
 
 
  inf_attach (inf, pid);
  inf_attach (inf, pid);
  inf_update_procs (inf);
  inf_update_procs (inf);
 
 
  inferior_pid = inf_pick_first_thread ();
  inferior_pid = inf_pick_first_thread ();
 
 
  attach_flag = 1;
  attach_flag = 1;
  push_target (&gnu_ops);
  push_target (&gnu_ops);
 
 
  /* We have to initialize the terminal settings now, since the code
  /* We have to initialize the terminal settings now, since the code
     below might try to restore them.  */
     below might try to restore them.  */
  target_terminal_init ();
  target_terminal_init ();
 
 
  /* If the process was stopped before we attached, make it continue the next
  /* If the process was stopped before we attached, make it continue the next
     time the user does a continue.  */
     time the user does a continue.  */
  inf_validate_procinfo (inf);
  inf_validate_procinfo (inf);
 
 
  inf_update_signal_thread (inf);
  inf_update_signal_thread (inf);
  inf_set_traced (inf, inf->want_signals);
  inf_set_traced (inf, inf->want_signals);
 
 
#if 0                           /* Do we need this? */
#if 0                           /* Do we need this? */
  renumber_threads (0);          /* Give our threads reasonable names. */
  renumber_threads (0);          /* Give our threads reasonable names. */
#endif
#endif
}
}
 
 


/* 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
gnu_detach (args, from_tty)
gnu_detach (args, from_tty)
     char *args;
     char *args;
     int from_tty;
     int from_tty;
{
{
  if (from_tty)
  if (from_tty)
    {
    {
      char *exec_file = get_exec_file (0);
      char *exec_file = get_exec_file (0);
      if (exec_file)
      if (exec_file)
        printf_unfiltered ("Detaching from program `%s' pid %d\n",
        printf_unfiltered ("Detaching from program `%s' pid %d\n",
                           exec_file, current_inferior->pid);
                           exec_file, current_inferior->pid);
      else
      else
        printf_unfiltered ("Detaching from pid %d\n", current_inferior->pid);
        printf_unfiltered ("Detaching from pid %d\n", current_inferior->pid);
      gdb_flush (gdb_stdout);
      gdb_flush (gdb_stdout);
    }
    }
 
 
  inf_detach (current_inferior);
  inf_detach (current_inferior);
 
 
  inferior_pid = 0;
  inferior_pid = 0;
 
 
  unpush_target (&gnu_ops);     /* Pop out of handling an inferior */
  unpush_target (&gnu_ops);     /* Pop out of handling an inferior */
}
}
#endif /* ATTACH_DETACH */
#endif /* ATTACH_DETACH */
 
 


static void
static void
gnu_terminal_init_inferior ()
gnu_terminal_init_inferior ()
{
{
  assert (current_inferior);
  assert (current_inferior);
  terminal_init_inferior_with_pgrp (current_inferior->pid);
  terminal_init_inferior_with_pgrp (current_inferior->pid);
}
}
 
 
/* 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
gnu_prepare_to_store ()
gnu_prepare_to_store ()
{
{
#ifdef CHILD_PREPARE_TO_STORE
#ifdef CHILD_PREPARE_TO_STORE
  CHILD_PREPARE_TO_STORE ();
  CHILD_PREPARE_TO_STORE ();
#endif
#endif
}
}
 
 
static void
static void
gnu_open (arg, from_tty)
gnu_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.");
}
}
 
 
static void
static void
gnu_stop ()
gnu_stop ()
{
{
  error ("to_stop target function not implemented");
  error ("to_stop target function not implemented");
}
}
 
 
static char *
static char *
gnu_pid_to_exec_file ()
gnu_pid_to_exec_file ()
{
{
  error ("to_pid_to_exec_file target function not implemented");
  error ("to_pid_to_exec_file target function not implemented");
  return NULL;
  return NULL;
}
}
 
 
 
 
static int
static int
gnu_thread_alive (int tid)
gnu_thread_alive (int tid)
{
{
  inf_update_procs (current_inferior);
  inf_update_procs (current_inferior);
  return !!inf_tid_to_thread (current_inferior, tid);
  return !!inf_tid_to_thread (current_inferior, tid);
}
}
 
 


/* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in
/* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in
   gdb's address space.  Return 0 on failure; number of bytes read
   gdb's address space.  Return 0 on failure; number of bytes read
   otherwise.  */
   otherwise.  */
int
int
gnu_read_inferior (task, addr, myaddr, length)
gnu_read_inferior (task, addr, myaddr, length)
     task_t task;
     task_t task;
     CORE_ADDR addr;
     CORE_ADDR addr;
     char *myaddr;
     char *myaddr;
     int length;
     int length;
{
{
  error_t err;
  error_t err;
  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;
  pointer_t copied;
  int copy_count;
  int copy_count;
 
 
  /* Get memory from inferior with page aligned addresses */
  /* Get memory from inferior with page aligned addresses */
  err = vm_read (task, low_address, aligned_length, &copied, &copy_count);
  err = vm_read (task, low_address, aligned_length, &copied, &copy_count);
  if (err)
  if (err)
    return 0;
    return 0;
 
 
  err = hurd_safe_copyin (myaddr, (void *) addr - low_address + copied, length);
  err = hurd_safe_copyin (myaddr, (void *) addr - low_address + copied, length);
  if (err)
  if (err)
    {
    {
      warning ("Read from inferior faulted: %s", strerror (err));
      warning ("Read from inferior faulted: %s", strerror (err));
      length = 0;
      length = 0;
    }
    }
 
 
  err = vm_deallocate (mach_task_self (), copied, copy_count);
  err = vm_deallocate (mach_task_self (), copied, copy_count);
  if (err)
  if (err)
    warning ("gnu_read_inferior vm_deallocate failed: %s", strerror (err));
    warning ("gnu_read_inferior vm_deallocate failed: %s", strerror (err));
 
 
  return length;
  return length;
}
}
 
 
#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)
 
 
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 gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
/* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
   task's address space.  */
   task's address space.  */
int
int
gnu_write_inferior (task, addr, myaddr, length)
gnu_write_inferior (task, addr, myaddr, length)
     task_t task;
     task_t task;
     CORE_ADDR addr;
     CORE_ADDR addr;
     char *myaddr;
     char *myaddr;
     int length;
     int length;
{
{
  error_t err = 0;
  error_t err = 0;
  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;
  pointer_t copied;
  int copy_count;
  int copy_count;
  int deallocate = 0;
  int deallocate = 0;
 
 
  char *errstr = "Bug in gnu_write_inferior";
  char *errstr = "Bug in gnu_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 */
  err = vm_read (task,
  err = vm_read (task,
                 low_address,
                 low_address,
                 aligned_length,
                 aligned_length,
                 &copied,
                 &copied,
                 &copy_count);
                 &copy_count);
  CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err);
  CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err);
 
 
  deallocate++;
  deallocate++;
 
 
  err = hurd_safe_copyout ((void *) addr - low_address + copied,
  err = hurd_safe_copyout ((void *) addr - low_address + copied,
                           myaddr, length);
                           myaddr, length);
  CHK_GOTO_OUT ("Write to inferior faulted", err);
  CHK_GOTO_OUT ("Write to inferior faulted", err);
 
 
  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;
 
 
        err = vm_region (task,
        err = vm_region (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", err);
        CHK_GOTO_OUT ("vm_region failed", err);
 
 
        /* 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);
            err = KERN_SUCCESS;
            err = 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);
            err = KERN_SUCCESS;
            err = 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)
      {
      {
        if (!(scan->protection & VM_PROT_WRITE))
        if (!(scan->protection & VM_PROT_WRITE))
          {
          {
            err = vm_protect (task,
            err = vm_protect (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", err);
            CHK_GOTO_OUT ("vm_protect: enable write failed", err);
          }
          }
      }
      }
 
 
    err = vm_write (task,
    err = vm_write (task,
                    low_address,
                    low_address,
                    copied,
                    copied,
                    aligned_length);
                    aligned_length);
    CHK_GOTO_OUT ("vm_write failed", err);
    CHK_GOTO_OUT ("vm_write failed", err);
 
 
    /* 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)
      {
      {
        if (!(scan->protection & VM_PROT_WRITE))
        if (!(scan->protection & VM_PROT_WRITE))
          {
          {
            err = vm_protect (task,
            err = vm_protect (task,
                              scan->start,
                              scan->start,
                              scan->length,
                              scan->length,
                              FALSE,
                              FALSE,
                              scan->protection);
                              scan->protection);
            CHK_GOTO_OUT ("vm_protect: enable write failed", err);
            CHK_GOTO_OUT ("vm_protect: enable write failed", err);
          }
          }
      }
      }
  }
  }
 
 
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,
                            copied,
                            copy_count);
                            copy_count);
    }
    }
 
 
  if (err != KERN_SUCCESS)
  if (err != KERN_SUCCESS)
    {
    {
      warning ("%s: %s", errstr, mach_error_string (err));
      warning ("%s: %s", errstr, mach_error_string (err));
      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
gnu_xfer_memory (memaddr, myaddr, len, write, target)
gnu_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 */
{
{
  task_t task = (current_inferior
  task_t task = (current_inferior
                 ? (current_inferior->task
                 ? (current_inferior->task
                    ? current_inferior->task->port : 0)
                    ? current_inferior->task->port : 0)
                 : 0);
                 : 0);
 
 
  if (task == MACH_PORT_NULL)
  if (task == MACH_PORT_NULL)
    return 0;
    return 0;
  else
  else
    {
    {
      inf_debug (current_inferior, "%s %p[%d] %s %p",
      inf_debug (current_inferior, "%s %p[%d] %s %p",
                 write ? "writing" : "reading", memaddr, len,
                 write ? "writing" : "reading", memaddr, len,
                 write ? "<--" : "-->", myaddr);
                 write ? "<--" : "-->", myaddr);
      if (write)
      if (write)
        return gnu_write_inferior (task, memaddr, myaddr, len);
        return gnu_write_inferior (task, memaddr, myaddr, len);
      else
      else
        return gnu_read_inferior (task, memaddr, myaddr, len);
        return gnu_read_inferior (task, memaddr, myaddr, len);
    }
    }
}
}
 
 


/* Return printable description of proc.  */
/* Return printable description of proc.  */
char *
char *
proc_string (struct proc *proc)
proc_string (struct proc *proc)
{
{
  static char tid_str[80];
  static char tid_str[80];
  if (proc_is_task (proc))
  if (proc_is_task (proc))
    sprintf (tid_str, "process %d", proc->inf->pid);
    sprintf (tid_str, "process %d", proc->inf->pid);
  else
  else
    sprintf (tid_str, "thread %d.%d",
    sprintf (tid_str, "thread %d.%d",
             proc->inf->pid, pid_to_thread_id (proc->tid));
             proc->inf->pid, pid_to_thread_id (proc->tid));
  return tid_str;
  return tid_str;
}
}
 
 
static char *
static char *
gnu_pid_to_str (int tid)
gnu_pid_to_str (int tid)
{
{
  struct inf *inf = current_inferior;
  struct inf *inf = current_inferior;
  struct proc *thread = inf_tid_to_thread (inf, tid);
  struct proc *thread = inf_tid_to_thread (inf, tid);
 
 
  if (thread)
  if (thread)
    return proc_string (thread);
    return proc_string (thread);
  else
  else
    {
    {
      static char tid_str[80];
      static char tid_str[80];
      sprintf (tid_str, "bogus thread id %d", tid);
      sprintf (tid_str, "bogus thread id %d", tid);
      return tid_str;
      return tid_str;
    }
    }
}
}
 
 


extern void gnu_store_registers (int regno);
extern void gnu_store_registers (int regno);
extern void gnu_fetch_registers (int regno);
extern void gnu_fetch_registers (int regno);
 
 
struct target_ops gnu_ops;
struct target_ops gnu_ops;
 
 
static void
static void
init_gnu_ops (void)
init_gnu_ops (void)
{
{
  gnu_ops.to_shortname = "GNU";         /* to_shortname */
  gnu_ops.to_shortname = "GNU";         /* to_shortname */
  gnu_ops.to_longname = "GNU Hurd process"; /* to_longname */
  gnu_ops.to_longname = "GNU Hurd process"; /* to_longname */
  gnu_ops.to_doc = "GNU Hurd process";  /* to_doc */
  gnu_ops.to_doc = "GNU Hurd process";  /* to_doc */
  gnu_ops.to_open = gnu_open;           /* to_open */
  gnu_ops.to_open = gnu_open;           /* to_open */
  gnu_ops.to_close = 0;                  /* to_close */
  gnu_ops.to_close = 0;                  /* to_close */
  gnu_ops.to_attach = gnu_attach;       /* to_attach */
  gnu_ops.to_attach = gnu_attach;       /* to_attach */
  gnu_ops.to_post_attach = NULL;
  gnu_ops.to_post_attach = NULL;
  gnu_ops.to_require_attach = NULL;     /* to_require_attach */
  gnu_ops.to_require_attach = NULL;     /* to_require_attach */
  gnu_ops.to_detach = gnu_detach;       /* to_detach */
  gnu_ops.to_detach = gnu_detach;       /* to_detach */
  gnu_ops.to_require_detach = NULL;     /* to_require_detach */
  gnu_ops.to_require_detach = NULL;     /* to_require_detach */
  gnu_ops.to_resume = gnu_resume;       /* to_resume */
  gnu_ops.to_resume = gnu_resume;       /* to_resume */
  gnu_ops.to_wait = gnu_wait;           /* to_wait */
  gnu_ops.to_wait = gnu_wait;           /* to_wait */
  gnu_ops.to_post_wait = NULL;          /* to_post_wait */
  gnu_ops.to_post_wait = NULL;          /* to_post_wait */
  gnu_ops.to_fetch_registers = gnu_fetch_registers;    /* to_fetch_registers */
  gnu_ops.to_fetch_registers = gnu_fetch_registers;    /* to_fetch_registers */
  gnu_ops.to_store_registers = gnu_store_registers;    /* to_store_registers */
  gnu_ops.to_store_registers = gnu_store_registers;    /* to_store_registers */
  gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
  gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
  gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
  gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
  gnu_ops.to_files_info = 0;             /* to_files_info */
  gnu_ops.to_files_info = 0;             /* to_files_info */
  gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
  gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
  gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
  gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
  gnu_ops.to_terminal_init = gnu_terminal_init_inferior;
  gnu_ops.to_terminal_init = gnu_terminal_init_inferior;
  gnu_ops.to_terminal_inferior = terminal_inferior;
  gnu_ops.to_terminal_inferior = terminal_inferior;
  gnu_ops.to_terminal_ours_for_output = terminal_ours_for_output;
  gnu_ops.to_terminal_ours_for_output = terminal_ours_for_output;
  gnu_ops.to_terminal_ours = terminal_ours;
  gnu_ops.to_terminal_ours = terminal_ours;
  gnu_ops.to_terminal_info = child_terminal_info;
  gnu_ops.to_terminal_info = child_terminal_info;
  gnu_ops.to_kill = gnu_kill_inferior;  /* to_kill */
  gnu_ops.to_kill = gnu_kill_inferior;  /* to_kill */
  gnu_ops.to_load = 0;                   /* to_load */
  gnu_ops.to_load = 0;                   /* to_load */
  gnu_ops.to_lookup_symbol = 0;          /* to_lookup_symbol */
  gnu_ops.to_lookup_symbol = 0;          /* to_lookup_symbol */
  gnu_ops.to_create_inferior = gnu_create_inferior; /* to_create_inferior */
  gnu_ops.to_create_inferior = gnu_create_inferior; /* to_create_inferior */
  gnu_ops.to_post_startup_inferior = NULL;    /* to_post_startup_inferior */
  gnu_ops.to_post_startup_inferior = NULL;    /* to_post_startup_inferior */
  /* to_acknowledge_created_inferior */
  /* to_acknowledge_created_inferior */
  gnu_ops.to_acknowledge_created_inferior = NULL;
  gnu_ops.to_acknowledge_created_inferior = NULL;
  /* to_clone_and_follow_inferior */
  /* to_clone_and_follow_inferior */
  gnu_ops.to_clone_and_follow_inferior = NULL;
  gnu_ops.to_clone_and_follow_inferior = NULL;
  /* to_post_follow_inferior_by_clone */
  /* to_post_follow_inferior_by_clone */
  gnu_ops.to_post_follow_inferior_by_clone = NULL;
  gnu_ops.to_post_follow_inferior_by_clone = NULL;
  gnu_ops.to_insert_fork_catchpoint = NULL;
  gnu_ops.to_insert_fork_catchpoint = NULL;
  gnu_ops.to_remove_fork_catchpoint = NULL;
  gnu_ops.to_remove_fork_catchpoint = NULL;
  gnu_ops.to_insert_vfork_catchpoint = NULL;
  gnu_ops.to_insert_vfork_catchpoint = NULL;
  gnu_ops.to_remove_vfork_catchpoint = NULL;
  gnu_ops.to_remove_vfork_catchpoint = NULL;
  gnu_ops.to_has_forked = NULL;         /* to_has_forked */
  gnu_ops.to_has_forked = NULL;         /* to_has_forked */
  gnu_ops.to_has_vforked = NULL;        /* to_has_vforked */
  gnu_ops.to_has_vforked = NULL;        /* to_has_vforked */
  gnu_ops.to_can_follow_vfork_prior_to_exec = NULL;
  gnu_ops.to_can_follow_vfork_prior_to_exec = NULL;
  gnu_ops.to_post_follow_vfork = NULL;  /* to_post_follow_vfork */
  gnu_ops.to_post_follow_vfork = NULL;  /* to_post_follow_vfork */
  gnu_ops.to_insert_exec_catchpoint = NULL;
  gnu_ops.to_insert_exec_catchpoint = NULL;
  gnu_ops.to_remove_exec_catchpoint = NULL;
  gnu_ops.to_remove_exec_catchpoint = NULL;
  gnu_ops.to_has_execd = NULL;
  gnu_ops.to_has_execd = NULL;
  gnu_ops.to_reported_exec_events_per_exec_call = NULL;
  gnu_ops.to_reported_exec_events_per_exec_call = NULL;
  gnu_ops.to_has_exited = NULL;
  gnu_ops.to_has_exited = NULL;
  gnu_ops.to_mourn_inferior = gnu_mourn_inferior;       /* to_mourn_inferior */
  gnu_ops.to_mourn_inferior = gnu_mourn_inferior;       /* to_mourn_inferior */
  gnu_ops.to_can_run = gnu_can_run;     /* to_can_run */
  gnu_ops.to_can_run = gnu_can_run;     /* to_can_run */
  gnu_ops.to_notice_signals = 0; /* to_notice_signals */
  gnu_ops.to_notice_signals = 0; /* to_notice_signals */
  gnu_ops.to_thread_alive = gnu_thread_alive;   /* to_thread_alive */
  gnu_ops.to_thread_alive = gnu_thread_alive;   /* to_thread_alive */
  gnu_ops.to_pid_to_str = gnu_pid_to_str;   /* to_pid_to_str */
  gnu_ops.to_pid_to_str = gnu_pid_to_str;   /* to_pid_to_str */
  gnu_ops.to_stop = gnu_stop;   /* to_stop */
  gnu_ops.to_stop = gnu_stop;   /* to_stop */
  gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
  gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
  gnu_ops.to_core_file_to_sym_file = NULL;
  gnu_ops.to_core_file_to_sym_file = NULL;
  gnu_ops.to_stratum = process_stratum;         /* to_stratum */
  gnu_ops.to_stratum = process_stratum;         /* to_stratum */
  gnu_ops.DONT_USE = 0;                  /* to_next */
  gnu_ops.DONT_USE = 0;                  /* to_next */
  gnu_ops.to_has_all_memory = 1;        /* to_has_all_memory */
  gnu_ops.to_has_all_memory = 1;        /* to_has_all_memory */
  gnu_ops.to_has_memory = 1;            /* to_has_memory */
  gnu_ops.to_has_memory = 1;            /* to_has_memory */
  gnu_ops.to_has_stack = 1;             /* to_has_stack */
  gnu_ops.to_has_stack = 1;             /* to_has_stack */
  gnu_ops.to_has_registers = 1;         /* to_has_registers */
  gnu_ops.to_has_registers = 1;         /* to_has_registers */
  gnu_ops.to_has_execution = 1;         /* to_has_execution */
  gnu_ops.to_has_execution = 1;         /* to_has_execution */
  gnu_ops.to_sections = 0;               /* sections */
  gnu_ops.to_sections = 0;               /* sections */
  gnu_ops.to_sections_end = 0;           /* sections_end */
  gnu_ops.to_sections_end = 0;           /* sections_end */
  gnu_ops.to_magic = OPS_MAGIC;         /* to_magic */
  gnu_ops.to_magic = OPS_MAGIC;         /* to_magic */
}                               /* init_gnu_ops */
}                               /* init_gnu_ops */
 
 


/* User task commands.  */
/* User task commands.  */
 
 
struct cmd_list_element *set_task_cmd_list = 0;
struct cmd_list_element *set_task_cmd_list = 0;
struct cmd_list_element *show_task_cmd_list = 0;
struct cmd_list_element *show_task_cmd_list = 0;
/* User thread commands.  */
/* User thread commands.  */
 
 
/* Commands with a prefix of `set/show thread'.  */
/* Commands with a prefix of `set/show thread'.  */
extern struct cmd_list_element *thread_cmd_list;
extern struct cmd_list_element *thread_cmd_list;
struct cmd_list_element *set_thread_cmd_list = NULL;
struct cmd_list_element *set_thread_cmd_list = NULL;
struct cmd_list_element *show_thread_cmd_list = NULL;
struct cmd_list_element *show_thread_cmd_list = NULL;
 
 
/* Commands with a prefix of `set/show thread default'.  */
/* Commands with a prefix of `set/show thread default'.  */
struct cmd_list_element *set_thread_default_cmd_list = NULL;
struct cmd_list_element *set_thread_default_cmd_list = NULL;
struct cmd_list_element *show_thread_default_cmd_list = NULL;
struct cmd_list_element *show_thread_default_cmd_list = NULL;
 
 
static void
static void
set_thread_cmd (char *args, int from_tty)
set_thread_cmd (char *args, int from_tty)
{
{
  printf_unfiltered ("\"set thread\" must be followed by the name of a thread property, or \"default\".\n");
  printf_unfiltered ("\"set thread\" must be followed by the name of a thread property, or \"default\".\n");
}
}
 
 
static void
static void
show_thread_cmd (char *args, int from_tty)
show_thread_cmd (char *args, int from_tty)
{
{
  printf_unfiltered ("\"show thread\" must be followed by the name of a thread property, or \"default\".\n");
  printf_unfiltered ("\"show thread\" must be followed by the name of a thread property, or \"default\".\n");
}
}
 
 
static void
static void
set_thread_default_cmd (char *args, int from_tty)
set_thread_default_cmd (char *args, int from_tty)
{
{
  printf_unfiltered ("\"set thread default\" must be followed by the name of a thread property.\n");
  printf_unfiltered ("\"set thread default\" must be followed by the name of a thread property.\n");
}
}
 
 
static void
static void
show_thread_default_cmd (char *args, int from_tty)
show_thread_default_cmd (char *args, int from_tty)
{
{
  printf_unfiltered ("\"show thread default\" must be followed by the name of a thread property.\n");
  printf_unfiltered ("\"show thread default\" must be followed by the name of a thread property.\n");
}
}
 
 
static int
static int
parse_int_arg (char *args, char *cmd_prefix)
parse_int_arg (char *args, char *cmd_prefix)
{
{
  if (args)
  if (args)
    {
    {
      char *arg_end;
      char *arg_end;
      int val = strtoul (args, &arg_end, 10);
      int val = strtoul (args, &arg_end, 10);
      if (*args && *arg_end == '\0')
      if (*args && *arg_end == '\0')
        return val;
        return val;
    }
    }
  error ("Illegal argument for \"%s\" command, should be an integer.", cmd_prefix);
  error ("Illegal argument for \"%s\" command, should be an integer.", cmd_prefix);
}
}
 
 
static int
static int
_parse_bool_arg (char *args, char *t_val, char *f_val, char *cmd_prefix)
_parse_bool_arg (char *args, char *t_val, char *f_val, char *cmd_prefix)
{
{
  if (!args || strcmp (args, t_val) == 0)
  if (!args || strcmp (args, t_val) == 0)
    return 1;
    return 1;
  else if (strcmp (args, f_val) == 0)
  else if (strcmp (args, f_val) == 0)
    return 0;
    return 0;
  else
  else
    error ("Illegal argument for \"%s\" command, should be \"%s\" or \"%s\".",
    error ("Illegal argument for \"%s\" command, should be \"%s\" or \"%s\".",
           cmd_prefix, t_val, f_val);
           cmd_prefix, t_val, f_val);
}
}
 
 
#define parse_bool_arg(args, cmd_prefix) \
#define parse_bool_arg(args, cmd_prefix) \
  _parse_bool_arg (args, "on", "off", cmd_prefix)
  _parse_bool_arg (args, "on", "off", cmd_prefix)
 
 
static void
static void
check_empty (char *args, char *cmd_prefix)
check_empty (char *args, char *cmd_prefix)
{
{
  if (args)
  if (args)
    error ("Garbage after \"%s\" command: `%s'", cmd_prefix, args);
    error ("Garbage after \"%s\" command: `%s'", cmd_prefix, args);
}
}
 
 
/* Returns the alive thread named by INFERIOR_PID, or signals an error.  */
/* Returns the alive thread named by INFERIOR_PID, or signals an error.  */
static struct proc *
static struct proc *
cur_thread ()
cur_thread ()
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  struct proc *thread = inf_tid_to_thread (inf, inferior_pid);
  struct proc *thread = inf_tid_to_thread (inf, inferior_pid);
  if (!thread)
  if (!thread)
    error ("No current thread.");
    error ("No current thread.");
  return thread;
  return thread;
}
}
 
 
/* Returns the current inferior, but signals an error if it has no task.  */
/* Returns the current inferior, but signals an error if it has no task.  */
static struct inf *
static struct inf *
active_inf ()
active_inf ()
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  if (!inf->task)
  if (!inf->task)
    error ("No current process.");
    error ("No current process.");
  return inf;
  return inf;
}
}
 
 


static void
static void
set_task_pause_cmd (char *args, int from_tty)
set_task_pause_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  int old_sc = inf->pause_sc;
  int old_sc = inf->pause_sc;
 
 
  inf->pause_sc = parse_bool_arg (args, "set task pause");
  inf->pause_sc = parse_bool_arg (args, "set task pause");
 
 
  if (old_sc == 0 && inf->pause_sc != 0)
  if (old_sc == 0 && inf->pause_sc != 0)
    /* If the task is currently unsuspended, immediately suspend it,
    /* If the task is currently unsuspended, immediately suspend it,
       otherwise wait until the next time it gets control.  */
       otherwise wait until the next time it gets control.  */
    inf_suspend (inf);
    inf_suspend (inf);
}
}
 
 
static void
static void
show_task_pause_cmd (char *args, int from_tty)
show_task_pause_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  check_empty (args, "show task pause");
  check_empty (args, "show task pause");
  printf_unfiltered ("The inferior task %s suspended while gdb has control.\n",
  printf_unfiltered ("The inferior task %s suspended while gdb has control.\n",
                     inf->task
                     inf->task
                     ? (inf->pause_sc == 0 ? "isn't" : "is")
                     ? (inf->pause_sc == 0 ? "isn't" : "is")
                     : (inf->pause_sc == 0 ? "won't be" : "will be"));
                     : (inf->pause_sc == 0 ? "won't be" : "will be"));
}
}
 
 
static void
static void
set_task_detach_sc_cmd (char *args, int from_tty)
set_task_detach_sc_cmd (char *args, int from_tty)
{
{
  cur_inf ()->detach_sc = parse_int_arg (args, "set task detach-suspend-count");
  cur_inf ()->detach_sc = parse_int_arg (args, "set task detach-suspend-count");
}
}
 
 
static void
static void
show_task_detach_sc_cmd (char *args, int from_tty)
show_task_detach_sc_cmd (char *args, int from_tty)
{
{
  check_empty (args, "show task detach-suspend-count");
  check_empty (args, "show task detach-suspend-count");
  printf_unfiltered ("The inferior task will be left with a suspend count of %d when detaching.\n",
  printf_unfiltered ("The inferior task will be left with a suspend count of %d when detaching.\n",
                     cur_inf ()->detach_sc);
                     cur_inf ()->detach_sc);
}
}
 
 


static void
static void
set_thread_default_pause_cmd (char *args, int from_tty)
set_thread_default_pause_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  inf->default_thread_pause_sc =
  inf->default_thread_pause_sc =
    parse_bool_arg (args, "set thread default pause") ? 0 : 1;
    parse_bool_arg (args, "set thread default pause") ? 0 : 1;
}
}
 
 
static void
static void
show_thread_default_pause_cmd (char *args, int from_tty)
show_thread_default_pause_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  int sc = inf->default_thread_pause_sc;
  int sc = inf->default_thread_pause_sc;
  check_empty (args, "show thread default pause");
  check_empty (args, "show thread default pause");
  printf_unfiltered ("New threads %s suspended while gdb has control%s.\n",
  printf_unfiltered ("New threads %s suspended while gdb has control%s.\n",
                     sc ? "are" : "aren't",
                     sc ? "are" : "aren't",
                     !sc && inf->pause_sc ? " (but the task is)" : "");
                     !sc && inf->pause_sc ? " (but the task is)" : "");
}
}
 
 
static void
static void
set_thread_default_run_cmd (char *args, int from_tty)
set_thread_default_run_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  inf->default_thread_run_sc =
  inf->default_thread_run_sc =
    parse_bool_arg (args, "set thread default run") ? 0 : 1;
    parse_bool_arg (args, "set thread default run") ? 0 : 1;
}
}
 
 
static void
static void
show_thread_default_run_cmd (char *args, int from_tty)
show_thread_default_run_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  check_empty (args, "show thread default run");
  check_empty (args, "show thread default run");
  printf_unfiltered ("New threads %s allowed to run.\n",
  printf_unfiltered ("New threads %s allowed to run.\n",
                     inf->default_thread_run_sc == 0 ? "are" : "aren't");
                     inf->default_thread_run_sc == 0 ? "are" : "aren't");
}
}
 
 
static void
static void
set_thread_default_detach_sc_cmd (char *args, int from_tty)
set_thread_default_detach_sc_cmd (char *args, int from_tty)
{
{
  cur_inf ()->default_thread_detach_sc =
  cur_inf ()->default_thread_detach_sc =
    parse_int_arg (args, "set thread default detach-suspend-count");
    parse_int_arg (args, "set thread default detach-suspend-count");
}
}
 
 
static void
static void
show_thread_default_detach_sc_cmd (char *args, int from_tty)
show_thread_default_detach_sc_cmd (char *args, int from_tty)
{
{
  check_empty (args, "show thread default detach-suspend-count");
  check_empty (args, "show thread default detach-suspend-count");
  printf_unfiltered ("New threads will get a detach-suspend-count of %d.\n",
  printf_unfiltered ("New threads will get a detach-suspend-count of %d.\n",
                     cur_inf ()->default_thread_detach_sc);
                     cur_inf ()->default_thread_detach_sc);
}
}
 
 


/* Steal a send right called NAME in the inferior task, and make it PROC's
/* Steal a send right called NAME in the inferior task, and make it PROC's
   saved exception port.  */
   saved exception port.  */
static void
static void
steal_exc_port (struct proc *proc, mach_port_t name)
steal_exc_port (struct proc *proc, mach_port_t name)
{
{
  error_t err;
  error_t err;
  mach_port_t port;
  mach_port_t port;
  mach_msg_type_name_t port_type;
  mach_msg_type_name_t port_type;
 
 
  if (!proc || !proc->inf->task)
  if (!proc || !proc->inf->task)
    error ("No inferior task.");
    error ("No inferior task.");
 
 
  err = mach_port_extract_right (proc->inf->task->port,
  err = mach_port_extract_right (proc->inf->task->port,
                                 name, MACH_MSG_TYPE_COPY_SEND,
                                 name, MACH_MSG_TYPE_COPY_SEND,
                                 &port, &port_type);
                                 &port, &port_type);
  if (err)
  if (err)
    error ("Couldn't extract send right %d from inferior: %s",
    error ("Couldn't extract send right %d from inferior: %s",
           name, strerror (err));
           name, strerror (err));
 
 
  if (proc->saved_exc_port)
  if (proc->saved_exc_port)
    /* Get rid of our reference to the old one.  */
    /* Get rid of our reference to the old one.  */
    mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
    mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
 
 
  proc->saved_exc_port = port;
  proc->saved_exc_port = port;
 
 
  if (!proc->exc_port)
  if (!proc->exc_port)
    /* If PROC is a thread, we may not have set its exception port before.
    /* If PROC is a thread, we may not have set its exception port before.
       We can't use proc_steal_exc_port because it also sets saved_exc_port. */
       We can't use proc_steal_exc_port because it also sets saved_exc_port. */
    {
    {
      proc->exc_port = proc->inf->event_port;
      proc->exc_port = proc->inf->event_port;
      err = proc_set_exception_port (proc, proc->exc_port);
      err = proc_set_exception_port (proc, proc->exc_port);
      error ("Can't set exception port for %s: %s",
      error ("Can't set exception port for %s: %s",
             proc_string (proc), strerror (err));
             proc_string (proc), strerror (err));
    }
    }
}
}
 
 
static void
static void
set_task_exc_port_cmd (char *args, int from_tty)
set_task_exc_port_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  if (!args)
  if (!args)
    error ("No argument to \"set task exception-port\" command.");
    error ("No argument to \"set task exception-port\" command.");
  steal_exc_port (inf->task, parse_and_eval_address (args));
  steal_exc_port (inf->task, parse_and_eval_address (args));
}
}
 
 
static void
static void
set_stopped_cmd (char *args, int from_tty)
set_stopped_cmd (char *args, int from_tty)
{
{
  cur_inf ()->stopped = _parse_bool_arg (args, "yes", "no", "set stopped");
  cur_inf ()->stopped = _parse_bool_arg (args, "yes", "no", "set stopped");
}
}
 
 
static void
static void
show_stopped_cmd (char *args, int from_tty)
show_stopped_cmd (char *args, int from_tty)
{
{
  struct inf *inf = active_inf ();
  struct inf *inf = active_inf ();
  check_empty (args, "show stopped");
  check_empty (args, "show stopped");
  printf_unfiltered ("The inferior process %s stopped.\n",
  printf_unfiltered ("The inferior process %s stopped.\n",
                     inf->stopped ? "is" : "isn't");
                     inf->stopped ? "is" : "isn't");
}
}
 
 
static void
static void
set_sig_thread_cmd (char *args, int from_tty)
set_sig_thread_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
 
 
  if (!args || (!isdigit (*args) && strcmp (args, "none") != 0))
  if (!args || (!isdigit (*args) && strcmp (args, "none") != 0))
    error ("Illegal argument to \"set signal-thread\" command.\n"
    error ("Illegal argument to \"set signal-thread\" command.\n"
           "Should be an integer thread ID, or `none'.");
           "Should be an integer thread ID, or `none'.");
 
 
  if (strcmp (args, "none") == 0)
  if (strcmp (args, "none") == 0)
    inf->signal_thread = 0;
    inf->signal_thread = 0;
  else
  else
    {
    {
      int tid = thread_id_to_pid (atoi (args));
      int tid = thread_id_to_pid (atoi (args));
      if (tid < 0)
      if (tid < 0)
        error ("Thread ID %s not known.  Use the \"info threads\" command to\n"
        error ("Thread ID %s not known.  Use the \"info threads\" command to\n"
               "see the IDs of currently known threads.", args);
               "see the IDs of currently known threads.", args);
      inf->signal_thread = inf_tid_to_thread (inf, tid);
      inf->signal_thread = inf_tid_to_thread (inf, tid);
    }
    }
}
}
 
 
static void
static void
show_sig_thread_cmd (char *args, int from_tty)
show_sig_thread_cmd (char *args, int from_tty)
{
{
  struct inf *inf = active_inf ();
  struct inf *inf = active_inf ();
  check_empty (args, "show signal-thread");
  check_empty (args, "show signal-thread");
  if (inf->signal_thread)
  if (inf->signal_thread)
    printf_unfiltered ("The signal thread is %s.\n",
    printf_unfiltered ("The signal thread is %s.\n",
                       proc_string (inf->signal_thread));
                       proc_string (inf->signal_thread));
  else
  else
    printf_unfiltered ("There is no signal thread.\n");
    printf_unfiltered ("There is no signal thread.\n");
}
}
 
 


static void
static void
set_signals_cmd (char *args, int from_tty)
set_signals_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
 
 
  inf->want_signals = parse_bool_arg (args, "set signals");
  inf->want_signals = parse_bool_arg (args, "set signals");
 
 
  if (inf->task && inf->want_signals != inf->traced)
  if (inf->task && inf->want_signals != inf->traced)
    /* Make this take effect immediately in a running process.  */
    /* Make this take effect immediately in a running process.  */
    inf_set_traced (inf, inf->want_signals);
    inf_set_traced (inf, inf->want_signals);
}
}
 
 
static void
static void
show_signals_cmd (char *args, int from_tty)
show_signals_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  check_empty (args, "show signals");
  check_empty (args, "show signals");
  printf_unfiltered ("The inferior process's signals %s intercepted.\n",
  printf_unfiltered ("The inferior process's signals %s intercepted.\n",
                     inf->task
                     inf->task
                     ? (inf->traced ? "are" : "aren't")
                     ? (inf->traced ? "are" : "aren't")
                     : (inf->want_signals ? "will be" : "won't be"));
                     : (inf->want_signals ? "will be" : "won't be"));
}
}
 
 
static void
static void
set_exceptions_cmd (char *args, int from_tty)
set_exceptions_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  int val = parse_bool_arg (args, "set exceptions");
  int val = parse_bool_arg (args, "set exceptions");
 
 
  if (inf->task && inf->want_exceptions != val)
  if (inf->task && inf->want_exceptions != val)
    /* Make this take effect immediately in a running process.  */
    /* Make this take effect immediately in a running process.  */
    /* XXX */ ;
    /* XXX */ ;
 
 
  inf->want_exceptions = val;
  inf->want_exceptions = val;
}
}
 
 
static void
static void
show_exceptions_cmd (char *args, int from_tty)
show_exceptions_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
  check_empty (args, "show exceptions");
  check_empty (args, "show exceptions");
  printf_unfiltered ("Exceptions in the inferior %s trapped.\n",
  printf_unfiltered ("Exceptions in the inferior %s trapped.\n",
                     inf->task
                     inf->task
                     ? (inf->want_exceptions ? "are" : "aren't")
                     ? (inf->want_exceptions ? "are" : "aren't")
                     : (inf->want_exceptions ? "will be" : "won't be"));
                     : (inf->want_exceptions ? "will be" : "won't be"));
}
}
 
 


static void
static void
set_task_cmd (char *args, int from_tty)
set_task_cmd (char *args, int from_tty)
{
{
  printf_unfiltered ("\"set task\" must be followed by the name"
  printf_unfiltered ("\"set task\" must be followed by the name"
                     " of a task property.\n");
                     " of a task property.\n");
}
}
 
 
static void
static void
show_task_cmd (char *args, int from_tty)
show_task_cmd (char *args, int from_tty)
{
{
  struct inf *inf = cur_inf ();
  struct inf *inf = cur_inf ();
 
 
  check_empty (args, "show task");
  check_empty (args, "show task");
 
 
  show_signals_cmd (0, from_tty);
  show_signals_cmd (0, from_tty);
  show_exceptions_cmd (0, from_tty);
  show_exceptions_cmd (0, from_tty);
  show_task_pause_cmd (0, from_tty);
  show_task_pause_cmd (0, from_tty);
 
 
  if (inf->pause_sc == 0)
  if (inf->pause_sc == 0)
    show_thread_default_pause_cmd (0, from_tty);
    show_thread_default_pause_cmd (0, from_tty);
  show_thread_default_run_cmd (0, from_tty);
  show_thread_default_run_cmd (0, from_tty);
 
 
  if (inf->task)
  if (inf->task)
    {
    {
      show_stopped_cmd (0, from_tty);
      show_stopped_cmd (0, from_tty);
      show_sig_thread_cmd (0, from_tty);
      show_sig_thread_cmd (0, from_tty);
    }
    }
 
 
  if (inf->detach_sc != 0)
  if (inf->detach_sc != 0)
    show_task_detach_sc_cmd (0, from_tty);
    show_task_detach_sc_cmd (0, from_tty);
  if (inf->default_thread_detach_sc != 0)
  if (inf->default_thread_detach_sc != 0)
    show_thread_default_detach_sc_cmd (0, from_tty);
    show_thread_default_detach_sc_cmd (0, from_tty);
}
}
 
 


static void
static void
set_noninvasive_cmd (char *args, int from_tty)
set_noninvasive_cmd (char *args, int from_tty)
{
{
  /* Invert the sense of the arg for each component.  */
  /* Invert the sense of the arg for each component.  */
  char *inv_args = parse_bool_arg (args, "set noninvasive") ? "off" : "on";
  char *inv_args = parse_bool_arg (args, "set noninvasive") ? "off" : "on";
 
 
  set_task_pause_cmd (inv_args, from_tty);
  set_task_pause_cmd (inv_args, from_tty);
  set_signals_cmd (inv_args, from_tty);
  set_signals_cmd (inv_args, from_tty);
  set_exceptions_cmd (inv_args, from_tty);
  set_exceptions_cmd (inv_args, from_tty);
}
}
 
 


static void
static void
info_port_rights (char *args, mach_port_type_t only)
info_port_rights (char *args, mach_port_type_t only)
{
{
  struct inf *inf = active_inf ();
  struct inf *inf = active_inf ();
  value_ptr vmark = value_mark ();
  value_ptr vmark = value_mark ();
 
 
  if (args)
  if (args)
    /* Explicit list of port rights.  */
    /* Explicit list of port rights.  */
    {
    {
      while (*args)
      while (*args)
        {
        {
          value_ptr val = parse_to_comma_and_eval (&args);
          value_ptr val = parse_to_comma_and_eval (&args);
          long right = value_as_long (val);
          long right = value_as_long (val);
          error_t err =
          error_t err =
          print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
          print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
                           stdout);
                           stdout);
          if (err)
          if (err)
            error ("%ld: %s.", right, strerror (err));
            error ("%ld: %s.", right, strerror (err));
        }
        }
    }
    }
  else
  else
    /* Print all of them.  */
    /* Print all of them.  */
    {
    {
      error_t err =
      error_t err =
      print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
      print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
                             stdout);
                             stdout);
      if (err)
      if (err)
        error ("%s.", strerror (err));
        error ("%s.", strerror (err));
    }
    }
 
 
  value_free_to_mark (vmark);
  value_free_to_mark (vmark);
}
}
 
 
static void
static void
info_send_rights_cmd (char *args, int from_tty)
info_send_rights_cmd (char *args, int from_tty)
{
{
  info_port_rights (args, MACH_PORT_TYPE_SEND);
  info_port_rights (args, MACH_PORT_TYPE_SEND);
}
}
 
 
static void
static void
info_recv_rights_cmd (char *args, int from_tty)
info_recv_rights_cmd (char *args, int from_tty)
{
{
  info_port_rights (args, MACH_PORT_TYPE_RECEIVE);
  info_port_rights (args, MACH_PORT_TYPE_RECEIVE);
}
}
 
 
static void
static void
info_port_sets_cmd (char *args, int from_tty)
info_port_sets_cmd (char *args, int from_tty)
{
{
  info_port_rights (args, MACH_PORT_TYPE_PORT_SET);
  info_port_rights (args, MACH_PORT_TYPE_PORT_SET);
}
}
 
 
static void
static void
info_dead_names_cmd (char *args, int from_tty)
info_dead_names_cmd (char *args, int from_tty)
{
{
  info_port_rights (args, MACH_PORT_TYPE_DEAD_NAME);
  info_port_rights (args, MACH_PORT_TYPE_DEAD_NAME);
}
}
 
 
static void
static void
info_port_rights_cmd (char *args, int from_tty)
info_port_rights_cmd (char *args, int from_tty)
{
{
  info_port_rights (args, ~0);
  info_port_rights (args, ~0);
}
}
 
 


static void
static void
add_task_commands (void)
add_task_commands (void)
{
{
  add_cmd ("pause", class_run, set_thread_default_pause_cmd,
  add_cmd ("pause", class_run, set_thread_default_pause_cmd,
           "Set whether the new threads are suspended while gdb has control.\n\
           "Set whether the new threads are suspended while gdb has control.\n\
This property normally has no effect because the whole task is\n\
This property normally has no effect because the whole task is\n\
suspended, however, that may be disabled with \"set task pause off\".\n\
suspended, however, that may be disabled with \"set task pause off\".\n\
The default value is \"off\".",
The default value is \"off\".",
           &set_thread_default_cmd_list);
           &set_thread_default_cmd_list);
  add_cmd ("pause", no_class, show_thread_default_pause_cmd,
  add_cmd ("pause", no_class, show_thread_default_pause_cmd,
           "Show whether new threads are suspended while gdb has control.",
           "Show whether new threads are suspended while gdb has control.",
           &show_thread_default_cmd_list);
           &show_thread_default_cmd_list);
 
 
  add_cmd ("run", class_run, set_thread_default_run_cmd,
  add_cmd ("run", class_run, set_thread_default_run_cmd,
           "Set whether new threads are allowed to run \
           "Set whether new threads are allowed to run \
(once gdb has noticed them).",
(once gdb has noticed them).",
           &set_thread_default_cmd_list);
           &set_thread_default_cmd_list);
  add_cmd ("run", no_class, show_thread_default_run_cmd,
  add_cmd ("run", no_class, show_thread_default_run_cmd,
           "Show whether new threads are allowed to run \
           "Show whether new threads are allowed to run \
(once gdb has noticed them).",
(once gdb has noticed them).",
           &show_thread_default_cmd_list);
           &show_thread_default_cmd_list);
 
 
  add_cmd ("detach-suspend-count", class_run, set_thread_default_detach_sc_cmd,
  add_cmd ("detach-suspend-count", class_run, set_thread_default_detach_sc_cmd,
           "Set the default detach-suspend-count value for new threads.",
           "Set the default detach-suspend-count value for new threads.",
           &set_thread_default_cmd_list);
           &set_thread_default_cmd_list);
  add_cmd ("detach-suspend-count", no_class, show_thread_default_detach_sc_cmd,
  add_cmd ("detach-suspend-count", no_class, show_thread_default_detach_sc_cmd,
           "Show the default detach-suspend-count value for new threads.",
           "Show the default detach-suspend-count value for new threads.",
           &show_thread_default_cmd_list);
           &show_thread_default_cmd_list);
 
 
  add_cmd ("signals", class_run, set_signals_cmd,
  add_cmd ("signals", class_run, set_signals_cmd,
           "Set whether the inferior process's signals will be intercepted.\n\
           "Set whether the inferior process's signals will be intercepted.\n\
Mach exceptions (such as breakpoint traps) are not affected.",
Mach exceptions (such as breakpoint traps) are not affected.",
           &setlist);
           &setlist);
  add_alias_cmd ("sigs", "signals", class_run, 1, &setlist);
  add_alias_cmd ("sigs", "signals", class_run, 1, &setlist);
  add_cmd ("signals", no_class, show_signals_cmd,
  add_cmd ("signals", no_class, show_signals_cmd,
           "Show whether the inferior process's signals will be intercepted.",
           "Show whether the inferior process's signals will be intercepted.",
           &showlist);
           &showlist);
  add_alias_cmd ("sigs", "signals", no_class, 1, &showlist);
  add_alias_cmd ("sigs", "signals", no_class, 1, &showlist);
 
 
  add_cmd ("signal-thread", class_run, set_sig_thread_cmd,
  add_cmd ("signal-thread", class_run, set_sig_thread_cmd,
           "Set the thread that gdb thinks is the libc signal thread.\n\
           "Set the thread that gdb thinks is the libc signal thread.\n\
This thread is run when delivering a signal to a non-stopped process.",
This thread is run when delivering a signal to a non-stopped process.",
           &setlist);
           &setlist);
  add_alias_cmd ("sigthread", "signal-thread", class_run, 1, &setlist);
  add_alias_cmd ("sigthread", "signal-thread", class_run, 1, &setlist);
  add_cmd ("signal-thread", no_class, show_sig_thread_cmd,
  add_cmd ("signal-thread", no_class, show_sig_thread_cmd,
           "Set the thread that gdb thinks is the libc signal thread.",
           "Set the thread that gdb thinks is the libc signal thread.",
           &showlist);
           &showlist);
  add_alias_cmd ("sigthread", "signal-thread", no_class, 1, &showlist);
  add_alias_cmd ("sigthread", "signal-thread", no_class, 1, &showlist);
 
 
  add_cmd ("stopped", class_run, set_stopped_cmd,
  add_cmd ("stopped", class_run, set_stopped_cmd,
           "Set whether gdb thinks the inferior process is stopped \
           "Set whether gdb thinks the inferior process is stopped \
as with SIGSTOP.\n\
as with SIGSTOP.\n\
Stopped process will be continued by sending them a signal.",
Stopped process will be continued by sending them a signal.",
           &setlist);
           &setlist);
  add_cmd ("stopped", no_class, show_signals_cmd,
  add_cmd ("stopped", no_class, show_signals_cmd,
           "Show whether gdb thinks the inferior process is stopped \
           "Show whether gdb thinks the inferior process is stopped \
as with SIGSTOP.",
as with SIGSTOP.",
           &showlist);
           &showlist);
 
 
  add_cmd ("exceptions", class_run, set_exceptions_cmd,
  add_cmd ("exceptions", class_run, set_exceptions_cmd,
           "Set whether exceptions in the inferior process will be trapped.\n\
           "Set whether exceptions in the inferior process will be trapped.\n\
When exceptions are turned off, neither breakpoints nor single-stepping\n\
When exceptions are turned off, neither breakpoints nor single-stepping\n\
will work.",
will work.",
           &setlist);
           &setlist);
  /* Allow `set exc' despite conflict with `set exception-port'.  */
  /* Allow `set exc' despite conflict with `set exception-port'.  */
  add_alias_cmd ("exc", "exceptions", class_run, 1, &setlist);
  add_alias_cmd ("exc", "exceptions", class_run, 1, &setlist);
  add_cmd ("exceptions", no_class, show_exceptions_cmd,
  add_cmd ("exceptions", no_class, show_exceptions_cmd,
           "Show whether exceptions in the inferior process will be trapped.",
           "Show whether exceptions in the inferior process will be trapped.",
           &showlist);
           &showlist);
 
 
  add_prefix_cmd ("task", no_class, set_task_cmd,
  add_prefix_cmd ("task", no_class, set_task_cmd,
                  "Command prefix for setting task attributes.",
                  "Command prefix for setting task attributes.",
                  &set_task_cmd_list, "set task ", 0, &setlist);
                  &set_task_cmd_list, "set task ", 0, &setlist);
  add_prefix_cmd ("task", no_class, show_task_cmd,
  add_prefix_cmd ("task", no_class, show_task_cmd,
                  "Command prefix for showing task attributes.",
                  "Command prefix for showing task attributes.",
                  &show_task_cmd_list, "show task ", 0, &showlist);
                  &show_task_cmd_list, "show task ", 0, &showlist);
 
 
  add_cmd ("pause", class_run, set_task_pause_cmd,
  add_cmd ("pause", class_run, set_task_pause_cmd,
           "Set whether the task is suspended while gdb has control.\n\
           "Set whether the task is suspended while gdb has control.\n\
A value of \"on\" takes effect immediately, otherwise nothing happens\n\
A value of \"on\" takes effect immediately, otherwise nothing happens\n\
until the next time the program is continued.\n\
until the next time the program is continued.\n\
When setting this to \"off\", \"set thread default pause on\" can be\n\
When setting this to \"off\", \"set thread default pause on\" can be\n\
used to pause individual threads by default instead.",
used to pause individual threads by default instead.",
           &set_task_cmd_list);
           &set_task_cmd_list);
  add_cmd ("pause", no_class, show_task_pause_cmd,
  add_cmd ("pause", no_class, show_task_pause_cmd,
           "Show whether the task is suspended while gdb has control.",
           "Show whether the task is suspended while gdb has control.",
           &show_task_cmd_list);
           &show_task_cmd_list);
 
 
  add_cmd ("detach-suspend-count", class_run, set_task_detach_sc_cmd,
  add_cmd ("detach-suspend-count", class_run, set_task_detach_sc_cmd,
           "Set the suspend count will leave on the thread when detaching.",
           "Set the suspend count will leave on the thread when detaching.",
           &set_task_cmd_list);
           &set_task_cmd_list);
  add_cmd ("detach-suspend-count", no_class, show_task_detach_sc_cmd,
  add_cmd ("detach-suspend-count", no_class, show_task_detach_sc_cmd,
           "Show the suspend count will leave on the thread when detaching.",
           "Show the suspend count will leave on the thread when detaching.",
           &show_task_cmd_list);
           &show_task_cmd_list);
 
 
  add_cmd ("exception-port", no_class, set_task_exc_port_cmd,
  add_cmd ("exception-port", no_class, set_task_exc_port_cmd,
           "Set the task exception port to which we forward exceptions.\n\
           "Set the task exception port to which we forward exceptions.\n\
The argument should be the value of the send right in the task.",
The argument should be the value of the send right in the task.",
           &set_task_cmd_list);
           &set_task_cmd_list);
  add_alias_cmd ("excp", "exception-port", no_class, 1, &set_task_cmd_list);
  add_alias_cmd ("excp", "exception-port", no_class, 1, &set_task_cmd_list);
  add_alias_cmd ("exc-port", "exception-port", no_class, 1,
  add_alias_cmd ("exc-port", "exception-port", no_class, 1,
                 &set_task_cmd_list);
                 &set_task_cmd_list);
 
 
  /* A convenient way of turning on all options require to noninvasively
  /* A convenient way of turning on all options require to noninvasively
     debug running tasks.  */
     debug running tasks.  */
  add_cmd ("noninvasive", no_class, set_noninvasive_cmd,
  add_cmd ("noninvasive", no_class, set_noninvasive_cmd,
           "Set task options so that we interfere as little as possible.\n\
           "Set task options so that we interfere as little as possible.\n\
This is the same as setting `task pause', `exceptions', and\n\
This is the same as setting `task pause', `exceptions', and\n\
`signals' to the opposite value.",
`signals' to the opposite value.",
           &setlist);
           &setlist);
 
 
  /* Commands to show information about the task's ports.  */
  /* Commands to show information about the task's ports.  */
  add_cmd ("send-rights", class_info, info_send_rights_cmd,
  add_cmd ("send-rights", class_info, info_send_rights_cmd,
           "Show information about the task's send rights",
           "Show information about the task's send rights",
           &infolist);
           &infolist);
  add_cmd ("receive-rights", class_info, info_recv_rights_cmd,
  add_cmd ("receive-rights", class_info, info_recv_rights_cmd,
           "Show information about the task's receive rights",
           "Show information about the task's receive rights",
           &infolist);
           &infolist);
  add_cmd ("port-rights", class_info, info_port_rights_cmd,
  add_cmd ("port-rights", class_info, info_port_rights_cmd,
           "Show information about the task's port rights",
           "Show information about the task's port rights",
           &infolist);
           &infolist);
  add_cmd ("port-sets", class_info, info_port_sets_cmd,
  add_cmd ("port-sets", class_info, info_port_sets_cmd,
           "Show information about the task's port sets",
           "Show information about the task's port sets",
           &infolist);
           &infolist);
  add_cmd ("dead-names", class_info, info_dead_names_cmd,
  add_cmd ("dead-names", class_info, info_dead_names_cmd,
           "Show information about the task's dead names",
           "Show information about the task's dead names",
           &infolist);
           &infolist);
  add_info_alias ("ports", "port-rights", 1);
  add_info_alias ("ports", "port-rights", 1);
  add_info_alias ("port", "port-rights", 1);
  add_info_alias ("port", "port-rights", 1);
  add_info_alias ("psets", "port-sets", 1);
  add_info_alias ("psets", "port-sets", 1);
}
}
 
 


static void
static void
set_thread_pause_cmd (char *args, int from_tty)
set_thread_pause_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  int old_sc = thread->pause_sc;
  int old_sc = thread->pause_sc;
  thread->pause_sc = parse_bool_arg (args, "set thread pause");
  thread->pause_sc = parse_bool_arg (args, "set thread pause");
  if (old_sc == 0 && thread->pause_sc != 0 && thread->inf->pause_sc == 0)
  if (old_sc == 0 && thread->pause_sc != 0 && thread->inf->pause_sc == 0)
    /* If the task is currently unsuspended, immediately suspend it,
    /* If the task is currently unsuspended, immediately suspend it,
       otherwise wait until the next time it gets control.  */
       otherwise wait until the next time it gets control.  */
    inf_suspend (thread->inf);
    inf_suspend (thread->inf);
}
}
 
 
static void
static void
show_thread_pause_cmd (char *args, int from_tty)
show_thread_pause_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  int sc = thread->pause_sc;
  int sc = thread->pause_sc;
  check_empty (args, "show task pause");
  check_empty (args, "show task pause");
  printf_unfiltered ("Thread %s %s suspended while gdb has control%s.\n",
  printf_unfiltered ("Thread %s %s suspended while gdb has control%s.\n",
                     proc_string (thread),
                     proc_string (thread),
                     sc ? "is" : "isn't",
                     sc ? "is" : "isn't",
                     !sc && thread->inf->pause_sc ? " (but the task is)" : "");
                     !sc && thread->inf->pause_sc ? " (but the task is)" : "");
}
}
 
 
static void
static void
set_thread_run_cmd (char *args, int from_tty)
set_thread_run_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  thread->run_sc = parse_bool_arg (args, "set thread run") ? 0 : 1;
  thread->run_sc = parse_bool_arg (args, "set thread run") ? 0 : 1;
}
}
 
 
static void
static void
show_thread_run_cmd (char *args, int from_tty)
show_thread_run_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  check_empty (args, "show thread run");
  check_empty (args, "show thread run");
  printf_unfiltered ("Thread %s %s allowed to run.",
  printf_unfiltered ("Thread %s %s allowed to run.",
                     proc_string (thread),
                     proc_string (thread),
                     thread->run_sc == 0 ? "is" : "isn't");
                     thread->run_sc == 0 ? "is" : "isn't");
}
}
 
 
static void
static void
set_thread_detach_sc_cmd (char *args, int from_tty)
set_thread_detach_sc_cmd (char *args, int from_tty)
{
{
  cur_thread ()->detach_sc = parse_int_arg (args,
  cur_thread ()->detach_sc = parse_int_arg (args,
                                            "set thread detach-suspend-count");
                                            "set thread detach-suspend-count");
}
}
 
 
static void
static void
show_thread_detach_sc_cmd (char *args, int from_tty)
show_thread_detach_sc_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  check_empty (args, "show thread detach-suspend-count");
  check_empty (args, "show thread detach-suspend-count");
  printf_unfiltered ("Thread %s will be left with a suspend count"
  printf_unfiltered ("Thread %s will be left with a suspend count"
                     " of %d when detaching.\n",
                     " of %d when detaching.\n",
                     proc_string (thread),
                     proc_string (thread),
                     thread->detach_sc);
                     thread->detach_sc);
}
}
 
 
static void
static void
set_thread_exc_port_cmd (char *args, int from_tty)
set_thread_exc_port_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  if (!args)
  if (!args)
    error ("No argument to \"set thread exception-port\" command.");
    error ("No argument to \"set thread exception-port\" command.");
  steal_exc_port (thread, parse_and_eval_address (args));
  steal_exc_port (thread, parse_and_eval_address (args));
}
}
 
 
#if 0
#if 0
static void
static void
show_thread_cmd (char *args, int from_tty)
show_thread_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  check_empty (args, "show thread");
  check_empty (args, "show thread");
  show_thread_run_cmd (0, from_tty);
  show_thread_run_cmd (0, from_tty);
  show_thread_pause_cmd (0, from_tty);
  show_thread_pause_cmd (0, from_tty);
  if (thread->detach_sc != 0)
  if (thread->detach_sc != 0)
    show_thread_detach_sc_cmd (0, from_tty);
    show_thread_detach_sc_cmd (0, from_tty);
}
}
#endif
#endif
 
 
static void
static void
thread_takeover_sc_cmd (char *args, int from_tty)
thread_takeover_sc_cmd (char *args, int from_tty)
{
{
  struct proc *thread = cur_thread ();
  struct proc *thread = cur_thread ();
  thread_basic_info_data_t _info;
  thread_basic_info_data_t _info;
  thread_basic_info_t info = &_info;
  thread_basic_info_t info = &_info;
  mach_msg_type_number_t info_len = THREAD_BASIC_INFO_COUNT;
  mach_msg_type_number_t info_len = THREAD_BASIC_INFO_COUNT;
  error_t err =
  error_t err =
  thread_info (thread->port, THREAD_BASIC_INFO, (int *) &info, &info_len);
  thread_info (thread->port, THREAD_BASIC_INFO, (int *) &info, &info_len);
  if (err)
  if (err)
    error ("%s.", strerror (err));
    error ("%s.", strerror (err));
  thread->sc = info->suspend_count;
  thread->sc = info->suspend_count;
  if (from_tty)
  if (from_tty)
    printf_unfiltered ("Suspend count was %d.\n", thread->sc);
    printf_unfiltered ("Suspend count was %d.\n", thread->sc);
  if (info != &_info)
  if (info != &_info)
    vm_deallocate (mach_task_self (), (vm_address_t) info,
    vm_deallocate (mach_task_self (), (vm_address_t) info,
                   info_len * sizeof (int));
                   info_len * sizeof (int));
}
}
 
 


static void
static void
add_thread_commands (void)
add_thread_commands (void)
{
{
  add_prefix_cmd ("thread", no_class, set_thread_cmd,
  add_prefix_cmd ("thread", no_class, set_thread_cmd,
                  "Command prefix for setting thread properties.",
                  "Command prefix for setting thread properties.",
                  &set_thread_cmd_list, "set thread ", 0, &setlist);
                  &set_thread_cmd_list, "set thread ", 0, &setlist);
  add_prefix_cmd ("default", no_class, show_thread_cmd,
  add_prefix_cmd ("default", no_class, show_thread_cmd,
                  "Command prefix for setting default thread properties.",
                  "Command prefix for setting default thread properties.",
                  &set_thread_default_cmd_list, "set thread default ", 0,
                  &set_thread_default_cmd_list, "set thread default ", 0,
                  &set_thread_cmd_list);
                  &set_thread_cmd_list);
  add_prefix_cmd ("thread", no_class, set_thread_default_cmd,
  add_prefix_cmd ("thread", no_class, set_thread_default_cmd,
                  "Command prefix for showing thread properties.",
                  "Command prefix for showing thread properties.",
                  &show_thread_cmd_list, "show thread ", 0, &showlist);
                  &show_thread_cmd_list, "show thread ", 0, &showlist);
  add_prefix_cmd ("default", no_class, show_thread_default_cmd,
  add_prefix_cmd ("default", no_class, show_thread_default_cmd,
                  "Command prefix for showing default thread properties.",
                  "Command prefix for showing default thread properties.",
                  &show_thread_default_cmd_list, "show thread default ", 0,
                  &show_thread_default_cmd_list, "show thread default ", 0,
                  &show_thread_cmd_list);
                  &show_thread_cmd_list);
 
 
  add_cmd ("pause", class_run, set_thread_pause_cmd,
  add_cmd ("pause", class_run, set_thread_pause_cmd,
           "Set whether the current thread is suspended \
           "Set whether the current thread is suspended \
while gdb has control.\n\
while gdb has control.\n\
A value of \"on\" takes effect immediately, otherwise nothing happens\n\
A value of \"on\" takes effect immediately, otherwise nothing happens\n\
until the next time the program is continued.  This property normally\n\
until the next time the program is continued.  This property normally\n\
has no effect because the whole task is suspended, however, that may\n\
has no effect because the whole task is suspended, however, that may\n\
be disabled with \"set task pause off\".\n\
be disabled with \"set task pause off\".\n\
The default value is \"off\".",
The default value is \"off\".",
           &set_thread_cmd_list);
           &set_thread_cmd_list);
  add_cmd ("pause", no_class, show_thread_pause_cmd,
  add_cmd ("pause", no_class, show_thread_pause_cmd,
           "Show whether the current thread is suspended \
           "Show whether the current thread is suspended \
while gdb has control.",
while gdb has control.",
           &show_thread_cmd_list);
           &show_thread_cmd_list);
 
 
  add_cmd ("run", class_run, set_thread_run_cmd,
  add_cmd ("run", class_run, set_thread_run_cmd,
           "Set whether the current thread is allowed to run.",
           "Set whether the current thread is allowed to run.",
           &set_thread_cmd_list);
           &set_thread_cmd_list);
  add_cmd ("run", no_class, show_thread_run_cmd,
  add_cmd ("run", no_class, show_thread_run_cmd,
           "Show whether the current thread is allowed to run.",
           "Show whether the current thread is allowed to run.",
           &show_thread_cmd_list);
           &show_thread_cmd_list);
 
 
  add_cmd ("detach-suspend-count", class_run, set_thread_detach_sc_cmd,
  add_cmd ("detach-suspend-count", class_run, set_thread_detach_sc_cmd,
           "Set the suspend count will leave on the thread when detaching.\n\
           "Set the suspend count will leave on the thread when detaching.\n\
Note that this is relative to suspend count when gdb noticed the thread;\n\
Note that this is relative to suspend count when gdb noticed the thread;\n\
use the `thread takeover-suspend-count' to force it to an absolute value.",
use the `thread takeover-suspend-count' to force it to an absolute value.",
           &set_thread_cmd_list);
           &set_thread_cmd_list);
  add_cmd ("detach-suspend-count", no_class, show_thread_detach_sc_cmd,
  add_cmd ("detach-suspend-count", no_class, show_thread_detach_sc_cmd,
           "Show the suspend count will leave on the thread when detaching.\n\
           "Show the suspend count will leave on the thread when detaching.\n\
Note that this is relative to suspend count when gdb noticed the thread;\n\
Note that this is relative to suspend count when gdb noticed the thread;\n\
use the `thread takeover-suspend-count' to force it to an absolute value.",
use the `thread takeover-suspend-count' to force it to an absolute value.",
           &show_thread_cmd_list);
           &show_thread_cmd_list);
 
 
  add_cmd ("exception-port", no_class, set_thread_exc_port_cmd,
  add_cmd ("exception-port", no_class, set_thread_exc_port_cmd,
           "Set the thread exception port to which we forward exceptions.\n\
           "Set the thread exception port to which we forward exceptions.\n\
This overrides the task exception port.\n\
This overrides the task exception port.\n\
The argument should be the value of the send right in the task.",
The argument should be the value of the send right in the task.",
           &set_thread_cmd_list);
           &set_thread_cmd_list);
  add_alias_cmd ("excp", "exception-port", no_class, 1, &set_thread_cmd_list);
  add_alias_cmd ("excp", "exception-port", no_class, 1, &set_thread_cmd_list);
  add_alias_cmd ("exc-port", "exception-port", no_class, 1,
  add_alias_cmd ("exc-port", "exception-port", no_class, 1,
                 &set_thread_cmd_list);
                 &set_thread_cmd_list);
 
 
  add_cmd ("takeover-suspend-count", no_class, thread_takeover_sc_cmd,
  add_cmd ("takeover-suspend-count", no_class, thread_takeover_sc_cmd,
           "Force the threads absolute suspend-count to be gdb's.\n\
           "Force the threads absolute suspend-count to be gdb's.\n\
Prior to giving this command, gdb's thread suspend-counts are relative\n\
Prior to giving this command, gdb's thread suspend-counts are relative\n\
to the thread's initial suspend-count when gdb notices the threads.",
to the thread's initial suspend-count when gdb notices the threads.",
           &thread_cmd_list);
           &thread_cmd_list);
}
}
 
 


void
void
_initialize_gnu_nat (void)
_initialize_gnu_nat (void)
{
{
  proc_server = getproc ();
  proc_server = getproc ();
 
 
  init_gnu_ops ();
  init_gnu_ops ();
  add_target (&gnu_ops);
  add_target (&gnu_ops);
 
 
  add_task_commands ();
  add_task_commands ();
  add_thread_commands ();
  add_thread_commands ();
  add_set_cmd ("gnu-debug", class_maintenance,
  add_set_cmd ("gnu-debug", class_maintenance,
               var_boolean, (char *) &gnu_debug_flag,
               var_boolean, (char *) &gnu_debug_flag,
               "Set debugging output for the gnu backend.", &maintenancelist);
               "Set debugging output for the gnu backend.", &maintenancelist);
}
}


#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 */
 
 
void
void
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;
  error_t ret;
  error_t ret;
 
 
  ret = vm_machine_attribute (current_inferior->task->port,
  ret = vm_machine_attribute (current_inferior->task->port,
                              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", strerror (ret));
    warning ("Error flushing inferior's cache : %s", strerror (ret));
}
}
#endif /* FLUSH_INFERIOR_CACHE */
#endif /* FLUSH_INFERIOR_CACHE */
 
 

powered by: WebSVN 2.1.0

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