/* Interface GDB to the GNU Hurd.
- Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1995-2001, 2006-2012 Free Software Foundation,
+ Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "defs.h"
+
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <portinfo.h>
-#include "defs.h"
#include "inferior.h"
#include "symtab.h"
#include "value.h"
#include "gdb_obstack.h"
#include "gnu-nat.h"
+#include "inf-child.h"
#include "exc_request_S.h"
#include "notify_S.h"
/* Forward decls */
-extern struct target_ops gnu_ops;
-
struct inf *make_inf ();
void inf_clear_wait (struct inf *inf);
void inf_cleanup (struct inf *inf);
void inf_set_step_thread (struct inf *inf, struct proc *proc);
void inf_detach (struct inf *inf);
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 gdb_signal sig);
void inf_continue (struct inf *inf);
#define inf_debug(_inf, msg, args...) \
do { struct inf *__inf = (_inf); \
- debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
+ debug ("{inf %d %s}: " msg, __inf->pid, \
+ host_address_to_string (__inf) , ##args); } while (0)
void proc_abort (struct proc *proc, int force);
struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
/* The state passed by an exception message. */
struct exc_state
{
- int exception; /* The exception code */
+ int exception; /* The exception code. */
int code, subcode;
- 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 handler; /* The real exception port to handle this. */
+ 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 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. */
int suppress; /* Something trivial happened. */
};
struct proc *task; /* The mach 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
- 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
- THREADS changing. */
+ /* 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, so as long as we don't let any code
+ run, we don't have to worry about THREADS changing. */
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. */
- /* 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;
/* The thread we think is the signal thread. */
expect to happen. */
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
make things easier for us, but sometimes (like when attaching to vital
proc_debug (proc, "sc: %d --> %d", proc->cur_sc, proc->sc);
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. */
{
gdb_assert (proc_is_thread (proc));
proc_debug (proc, "storing back changed thread state");
{
mach_msg_type_number_t state_size = THREAD_STATE_SIZE;
error_t err =
- thread_get_state (proc->port, THREAD_STATE_FLAVOR,
- (thread_state_t) &proc->state, &state_size);
+ thread_get_state (proc->port, THREAD_STATE_FLAVOR,
+ (thread_state_t) &proc->state, &state_size);
+
proc_debug (proc, "getting thread state");
proc->state_valid = !err;
}
return exc_port;
}
-/* 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. */
+/* 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. */
void
proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
{
mach_port_deallocate (mach_task_self (), cur_exc_port);
}
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)
mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
thread_state_t state = proc_get_state (proc, 1);
if (!state)
- return 0; /* the thread must be dead. */
+ return 0; /* The thread must be dead. */
proc_debug (proc, "tracing %s", set ? "on" : "off");
if (set)
{
/* XXX We don't get the exception unless the thread has its own
- exception port???? */
+ exception port???? */
if (proc->exc_port == MACH_PORT_NULL)
proc_steal_exc_port (proc, proc->inf->event_port);
THREAD_STATE_SET_TRACED (state);
else
{
error_t err = proc_pid2task (proc_server, pid, &task_port);
+
if (err)
- error (_("Error getting task for pid %d: %s"), pid, safe_strerror (err));
+ error (_("Error getting task for pid %d: %s"),
+ pid, safe_strerror (err));
}
inf_debug (inf, "setting task: %d", task_port);
if (task && task->port != task_port)
{
inf->task = 0;
- inf_validate_procs (inf); /* Trash all the threads. */
- _proc_free (task); /* And the task. */
+ inf_validate_procs (inf); /* Trash all the threads. */
+ _proc_free (task); /* And the task. */
}
if (task_port != MACH_PORT_NULL)
mach_msg_type_number_t pi_len = 0;
int info_flags = 0;
error_t err =
- proc_getprocinfo (proc_server, inf->pid, &info_flags,
- (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
+ proc_getprocinfo (proc_server, inf->pid, &info_flags,
+ (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
if (!err)
{
int abort;
target_terminal_ours (); /* Allow I/O. */
- abort = !query ("Pid %d has an additional task suspend count of %d;"
- " clear it? ", inf->pid,
+ abort = !query (_("Pid %d has an additional task suspend count of %d;"
+ " clear it? "), inf->pid,
suspend_count - inf->task->cur_sc);
target_terminal_inferior (); /* Give it back to the child. */
error_t err =
INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
INIT_TRACEMASK, mask));
+
if (err == EIEIO)
{
if (on)
/* Makes all the real suspend count deltas of all the procs in INF
match the desired values. Careful to always do thread/task suspend
counts in the safe order. Returns true if at least one thread is
- thought to be running. */
+ thought to be running. */
int
inf_update_suspends (struct inf *inf)
{
struct proc *task = inf->task;
+
/* 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
entry. */
-
inf_debug (inf, "updating suspend counts");
if (task)
inf_port_to_thread (struct inf *inf, mach_port_t port)
{
struct proc *thread = inf->threads;
+
while (thread)
if (thread->port == port)
return thread;
if (task)
{
error_t err = task_threads (task->port, &threads, &num_threads);
+
inf_debug (inf, "fetching threads");
if (err)
/* TASK must be dead. */
struct proc *matched[num_threads + 1];
/* The last thread in INF->threads, so we can add to the end. */
struct proc *last = 0;
- /* The current thread we're considering. */
+ /* The current thread we're considering. */
struct proc *thread = inf->threads;
memset (matched, 0, sizeof (matched));
struct proc *run_thread, int run_others)
{
struct proc *thread;
+
inf_update_procs (inf);
for (thread = inf->threads; thread; thread = thread->next)
if (thread == run_thread)
if (inf->nomsg)
inf_continue (inf);
else
- inf_signal (inf, TARGET_SIGNAL_0);
+ inf_signal (inf, GDB_SIGNAL_0);
}
proc_restore_exc_port (task);
}
\f
-/* 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
inf_steal_exc_ports (struct inf *inf)
{
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);
for (thread = inf->threads; thread; thread = thread->next)
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);
for (thread = inf->threads; thread; thread = thread->next)
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. */
void
-inf_signal (struct inf *inf, enum target_signal sig)
+inf_signal (struct inf *inf, enum gdb_signal sig)
{
error_t err = 0;
- int host_sig = target_signal_to_host (sig);
+ int host_sig = gdb_signal_to_host (sig);
-#define NAME target_signal_to_name (sig)
+#define NAME gdb_signal_to_name (sig)
if (host_sig >= _NSIG)
/* A mach exception. Exceptions are encoded in the signal space by
extremely large)! */
{
struct inf_wait *w = &inf->wait;
+
if (w->status.kind == TARGET_WAITKIND_STOPPED
&& w->status.value.sig == sig
&& w->thread && !w->thread->aborted)
i.e., we pretend it's global. */
{
struct exc_state *e = &w->exc;
+
inf_debug (inf, "passing through exception:"
" task = %d, thread = %d, exc = %d"
", code = %d, subcode = %d",
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
process the signal we request will be the very first thing that
- happens. */
+ happens. */
{
inf_debug (inf, "sending %s to unstopped process"
" (so resuming signal thread)", NAME);
}
if (err == EIEIO)
- /* Can't do too much... */
+ /* Can't do too much... */
warning (_("Can't deliver signal %s: No signal thread."), NAME);
else if (err)
warning (_("Delivering signal %s: %s"), NAME, safe_strerror (err));
multi-threaded, we don't bother to lock this. */
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 ptid_t
-gnu_wait (ptid_t ptid, struct target_waitstatus *status)
+gnu_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status, int options)
{
struct msg
{
if (proc_wait_pid)
/* 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);
interrupt_operation (proc_server, 0);
get any other replies, because it was either from a
different INF, or a different process attached to INF --
and the event port, which is the wait reply port, changes
- when you switch processes. */
+ when you switch processes. */
proc_waits_pending = 1;
}
}
inf->pending_execs);
}
else if (kind == TARGET_WAITKIND_STOPPED
- && w->status.value.sig == TARGET_SIGNAL_TRAP)
+ && w->status.value.sig == GDB_SIGNAL_TRAP)
/* Ah hah! A SIGTRAP from the inferior while starting up probably
means we've succesfully completed an exec! */
{
if (--inf->pending_execs == 0)
/* We're done! */
{
-#if 0 /* do we need this? */
- prune_threads (1); /* Get rid of the old shell threads */
- renumber_threads (0); /* Give our threads reasonable names. */
+#if 0 /* do we need this? */
+ prune_threads (1); /* Get rid of the old shell
+ threads. */
+ renumber_threads (0); /* Give our threads reasonable
+ names. */
#endif
}
inf_debug (inf, "pending exec completed, pending_execs => %d",
{
/* TID is dead; try and find a new thread. */
if (inf_update_procs (inf) && inf->threads)
- ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first available thread. */
+ ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
+ available
+ thread. */
else
ptid = inferior_ptid; /* let wait_for_inferior handle exit case */
}
if (exception == EXC_BREAKPOINT)
/* GDB likes to get SIGTRAP for breakpoints. */
{
- inf->wait.status.value.sig = TARGET_SIGNAL_TRAP;
+ inf->wait.status.value.sig = GDB_SIGNAL_TRAP;
mach_port_deallocate (mach_task_self (), reply_port);
}
else
gdb_assert (inf->task->exc_port == port);
}
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 (),
inf->wait.exc.handler, MACH_PORT_RIGHT_SEND,
1);
inf->wait.exc.subcode = subcode;
inf->wait.exc.reply = reply_port;
- /* Exceptions are encoded in the signal space by putting them after
- _NSIG; this assumes they're positive (and not extremely large)! */
+ /* Exceptions are encoded in the signal space by putting
+ them after _NSIG; this assumes they're positive (and not
+ extremely large)! */
inf->wait.status.value.sig =
- target_signal_from_host (_NSIG + exception);
+ gdb_signal_from_host (_NSIG + exception);
}
}
else
void
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.value.sig = TARGET_SIGNAL_KILL;
+ inf->wait.status.value.sig = GDB_SIGNAL_KILL;
}
/* Notify server routines. The only real one is dead name notification. */
else
{
struct proc *thread = inf_port_to_thread (inf, dead_port);
+
if (thread)
{
proc_debug (thread, "is dead");
}
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;
}
{
if (err != EINTR)
{
- warning (_("Can't wait for pid %d: %s"), inf->pid, safe_strerror (err));
+ warning (_("Can't wait for pid %d: %s"),
+ inf->pid, safe_strerror (err));
inf->no_wait = 1;
/* Since we can't see the inferior's signals, don't trap them. */
server should like). */
{
inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
- inf->wait.status.value.sig = TARGET_SIGNAL_0;
+ inf->wait.status.value.sig = GDB_SIGNAL_0;
}
else if (err)
warning (_("Signal delivery failed: %s"), safe_strerror (err));
{
struct mach_port_status status;
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)
return 0;
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
- in multiple events returned by wait).
- */
+ in multiple events returned by wait). */
+
static void
-gnu_resume (ptid_t ptid, int step, enum target_signal sig)
+gnu_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum gdb_signal sig)
{
struct proc *step_thread = 0;
int resume_all;
inf_validate_procinfo (inf);
- if (sig != TARGET_SIGNAL_0 || inf->stopped)
+ if (sig != GDB_SIGNAL_0 || inf->stopped)
{
- if (sig == TARGET_SIGNAL_0 && inf->nomsg)
+ if (sig == GDB_SIGNAL_0 && inf->nomsg)
inf_continue (inf);
else
inf_signal (inf, sig);
proc_abort (inf->wait.thread, 1);
warning (_("Aborting %s with unforwarded exception %s."),
proc_string (inf->wait.thread),
- target_signal_to_name (inf->wait.status.value.sig));
+ gdb_signal_to_name (inf->wait.status.value.sig));
}
if (port_msgs_queued (inf->event_port))
/* 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;
inf_update_procs (inf);
/* Allow all threads to run, except perhaps single-stepping one. */
{
inf_debug (inf, "running all threads; tid = %d", PIDGET (inferior_ptid));
- ptid = inferior_ptid; /* What to step. */
+ ptid = inferior_ptid; /* What to step. */
inf_set_threads_resume_sc (inf, 0, 1);
}
else
/* Just allow a single thread to run. */
{
struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+
if (!thread)
error (_("Can't run single thread id %s: no such thread!"),
target_pid_to_str (ptid));
\f
static void
-gnu_kill_inferior (void)
+gnu_kill_inferior (struct target_ops *ops)
{
struct proc *task = gnu_current_inf->task;
+
if (task)
{
proc_debug (task, "terminating...");
{
inf_debug (gnu_current_inf, "rip");
inf_detach (gnu_current_inf);
- unpush_target (&gnu_ops);
+ unpush_target (ops);
generic_mourn_inferior ();
}
int from_tty)
{
struct inf *inf = cur_inf ();
+ int pid;
void trace_me ()
{
if (ptrace (PTRACE_TRACEME) != 0)
error (_("ptrace (PTRACE_TRACEME) failed!"));
}
- void attach_to_child (int pid)
- {
- /* Attach to the now stopped child, which is actually a shell... */
- inf_debug (inf, "attaching to child: %d", pid);
- inf_attach (inf, pid);
+ inf_debug (inf, "creating inferior");
- push_target (&gnu_ops);
+ pid = fork_inferior (exec_file, allargs, env, trace_me,
+ NULL, NULL, NULL, NULL);
- inf->pending_execs = 2;
- inf->nomsg = 1;
- inf->traced = 1;
+ /* Attach to the now stopped child, which is actually a shell... */
+ inf_debug (inf, "attaching to child: %d", pid);
- /* Now let the child run again, knowing that it will stop immediately
- because of the ptrace. */
- inf_resume (inf);
+ inf_attach (inf, pid);
- /* We now have thread info. */
- thread_change_ptid (inferior_ptid,
- ptid_build (inf->pid, 0, inf_pick_first_thread ()));
+ push_target (ops);
- startup_inferior (inf->pending_execs);
- }
+ inf->pending_execs = 2;
+ inf->nomsg = 1;
+ inf->traced = 1;
- inf_debug (inf, "creating inferior");
+ /* Now let the child run again, knowing that it will stop
+ immediately because of the ptrace. */
+ inf_resume (inf);
- fork_inferior (exec_file, allargs, env, trace_me, attach_to_child,
- NULL, NULL);
+ /* We now have thread info. */
+ thread_change_ptid (inferior_ptid,
+ ptid_build (inf->pid, 0, inf_pick_first_thread ()));
+
+ startup_inferior (inf->pending_execs);
inf_validate_procinfo (inf);
inf_update_signal_thread (inf);
inf_restore_exc_ports (inf);
}
-/* Mark our target-struct as eligible for stray "run" and "attach"
- commands. */
-static int
-gnu_can_run (void)
-{
- return 1;
-}
-
\f
/* Attach to process PID, then initialize for debugging it
and wait for the trace-trap that results from attaching. */
struct inf *inf = cur_inf ();
struct inferior *inferior;
- if (!args)
- error_no_arg (_("process-id to attach"));
+ pid = parse_pid_to_attach (args);
- pid = atoi (args);
-
- if (pid == getpid ()) /* Trying to masturbate? */
+ if (pid == getpid ()) /* Trying to masturbate? */
error (_("I refuse to debug myself!"));
if (from_tty)
inf_attach (inf, pid);
- push_target (&gnu_ops);
+ push_target (ops);
- inferior = add_inferior (pid);
+ inferior = current_inferior ();
+ inferior_appeared (inferior, pid);
inferior->attach_flag = 1;
inf_update_procs (inf);
inf_update_signal_thread (inf);
inf_set_traced (inf, inf->want_signals);
-#if 0 /* Do we need this? */
- renumber_threads (0); /* Give our threads reasonable names. */
+#if 0 /* Do we need this? */
+ renumber_threads (0); /* Give our threads reasonable names. */
#endif
}
if (from_tty)
{
char *exec_file = get_exec_file (0);
+
if (exec_file)
printf_unfiltered ("Detaching from program `%s' pid %d\n",
exec_file, gnu_current_inf->pid);
inferior_ptid = null_ptid;
detach_inferior (pid);
- unpush_target (&gnu_ops); /* Pop out of handling an inferior */
+ unpush_target (ops); /* Pop out of handling an inferior. */
}
\f
static void
terminal_init_inferior_with_pgrp (gnu_current_inf->pid);
}
-/* Get ready to modify the registers array. On machines which store
- individual registers, this doesn't need to do anything. On machines
- which store all the registers in one fell swoop, this makes sure
- that registers contains all the registers from the program being
- debugged. */
-static void
-gnu_prepare_to_store (struct regcache *regcache)
-{
-}
-
-static void
-gnu_open (char *arg, int from_tty)
-{
- error (_("Use the \"run\" command to start a Unix child process."));
-}
-
static void
gnu_stop (ptid_t ptid)
{
}
static int
-gnu_thread_alive (ptid_t ptid)
+gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
{
inf_update_procs (gnu_current_inf);
return !!inf_tid_to_thread (gnu_current_inf,
pointer_t copied;
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, ©_count);
if (err)
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)
{
warning (_("Read from inferior faulted: %s"), safe_strerror (err));
err = vm_deallocate (mach_task_self (), copied, copy_count);
if (err)
- warning (_("gnu_read_inferior vm_deallocate failed: %s"), safe_strerror (err));
+ warning (_("gnu_read_inferior vm_deallocate failed: %s"),
+ safe_strerror (err));
return length;
}
struct vm_region_list *region_element;
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,
low_address,
aligned_length,
&offset);
CHK_GOTO_OUT ("vm_region failed", err);
- /* Check for holes in memory */
+ /* Check for holes in memory. */
if (old_address != region_address)
{
warning (_("No memory at 0x%x. Nothing written"),
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);
err = KERN_SUCCESS;
length = 0;
goto out;
}
- /* Chain the regions for later use */
+ /* Chain the regions for later use. */
region_element =
(struct vm_region_list *)
obstack_alloc (®ion_obstack, sizeof (struct vm_region_list));
region_element->start = region_address;
region_element->length = region_length;
- /* Chain the regions along with protections */
+ /* Chain the regions along with protections. */
region_element->next = region_head;
region_head = region_element;
/* If things fail after this, we give up.
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)
{
if (!(scan->protection & VM_PROT_WRITE))
aligned_length);
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)
{
if (!(scan->protection & VM_PROT_WRITE))
\f
/* Return 0 on failure, number of bytes handled otherwise. TARGET
- is ignored. */
+ is ignored. */
static int
gnu_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
struct mem_attrib *attrib,
return 0;
else
{
- inf_debug (gnu_current_inf, "%s %p[%d] %s %p",
- write ? "writing" : "reading", (void *) memaddr, len,
- write ? "<--" : "-->", myaddr);
+ inf_debug (gnu_current_inf, "%s %s[%d] %s %s",
+ write ? "writing" : "reading",
+ paddress (target_gdbarch (), memaddr), len,
+ write ? "<--" : "-->", host_address_to_string (myaddr));
if (write)
return gnu_write_inferior (task, memaddr, myaddr, len);
else
/* Call FUNC on each memory region in the task. */
static int
-gnu_find_memory_regions (int (*func) (CORE_ADDR,
- unsigned long,
- int, int, int,
- void *),
- void *data)
+gnu_find_memory_regions (find_memory_region_ftype func, void *data)
{
error_t err;
task_t task;
last_protection & VM_PROT_READ,
last_protection & VM_PROT_WRITE,
last_protection & VM_PROT_EXECUTE,
+ 1, /* MODIFIED is unknown, pass it as true. */
data);
last_region_address = region_address;
last_region_end = region_address += region_length;
last_protection & VM_PROT_READ,
last_protection & VM_PROT_WRITE,
last_protection & VM_PROT_EXECUTE,
+ 1, /* MODIFIED is unknown, pass it as true. */
data);
return 0;
proc_string (struct proc *proc)
{
static char tid_str[80];
+
if (proc_is_task (proc))
sprintf (tid_str, "process %d", proc->inf->pid);
else
}
static char *
-gnu_pid_to_str (ptid_t ptid)
+gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
struct inf *inf = gnu_current_inf;
int tid = ptid_get_tid (ptid);
else
{
static char tid_str[80];
+
sprintf (tid_str, "bogus thread id %d", tid);
return tid_str;
}
}
\f
-extern void gnu_store_registers (struct regcache *regcache, int regno);
-extern void gnu_fetch_registers (struct regcache *regcache, int regno);
+/* Create a prototype generic GNU/Hurd target. The client can
+ override it with local methods. */
-struct target_ops gnu_ops;
+struct target_ops *
+gnu_target (void)
+{
+ struct target_ops *t = inf_child_target ();
-static void
-init_gnu_ops (void)
-{
- gnu_ops.to_shortname = "GNU"; /* to_shortname */
- gnu_ops.to_longname = "GNU Hurd process"; /* to_longname */
- gnu_ops.to_doc = "GNU Hurd process"; /* to_doc */
- gnu_ops.to_open = gnu_open; /* to_open */
- gnu_ops.to_attach = gnu_attach; /* to_attach */
- gnu_ops.to_attach_no_wait = 1; /* to_attach_no_wait */
- gnu_ops.to_detach = gnu_detach; /* to_detach */
- gnu_ops.to_resume = gnu_resume; /* to_resume */
- gnu_ops.to_wait = gnu_wait; /* to_wait */
- 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_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
- gnu_ops.deprecated_xfer_memory = gnu_xfer_memory;
- gnu_ops.to_find_memory_regions = gnu_find_memory_regions;
- gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
- gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
- gnu_ops.to_terminal_init = gnu_terminal_init_inferior;
- gnu_ops.to_terminal_inferior = terminal_inferior;
- gnu_ops.to_terminal_ours_for_output = terminal_ours_for_output;
- gnu_ops.to_terminal_save_ours = terminal_save_ours;
- gnu_ops.to_terminal_ours = terminal_ours;
- gnu_ops.to_terminal_info = child_terminal_info;
- gnu_ops.to_kill = gnu_kill_inferior; /* to_kill */
- gnu_ops.to_create_inferior = gnu_create_inferior; /* to_create_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_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_stop = gnu_stop; /* to_stop */
- gnu_ops.to_stratum = process_stratum; /* to_stratum */
- gnu_ops.to_has_all_memory = 1; /* to_has_all_memory */
- gnu_ops.to_has_memory = 1; /* to_has_memory */
- gnu_ops.to_has_stack = 1; /* to_has_stack */
- gnu_ops.to_has_registers = 1; /* to_has_registers */
- gnu_ops.to_has_execution = 1; /* to_has_execution */
- gnu_ops.to_magic = OPS_MAGIC; /* to_magic */
-} /* init_gnu_ops */
+ t->to_shortname = "GNU";
+ t->to_longname = "GNU Hurd process";
+ t->to_doc = "GNU Hurd process";
+
+ t->to_attach = gnu_attach;
+ t->to_attach_no_wait = 1;
+ t->to_detach = gnu_detach;
+ t->to_resume = gnu_resume;
+ t->to_wait = gnu_wait;
+ t->deprecated_xfer_memory = gnu_xfer_memory;
+ t->to_find_memory_regions = gnu_find_memory_regions;
+ t->to_terminal_init = gnu_terminal_init_inferior;
+ t->to_kill = gnu_kill_inferior;
+ t->to_create_inferior = gnu_create_inferior;
+ t->to_mourn_inferior = gnu_mourn_inferior;
+ t->to_thread_alive = gnu_thread_alive;
+ t->to_pid_to_str = gnu_pid_to_str;
+ t->to_stop = gnu_stop;
+
+ return t;
+}
\f
/* User task commands. */
-struct cmd_list_element *set_task_cmd_list = 0;
-struct cmd_list_element *show_task_cmd_list = 0;
+static struct cmd_list_element *set_task_cmd_list = 0;
+static struct cmd_list_element *show_task_cmd_list = 0;
/* User thread commands. */
/* Commands with a prefix of `set/show thread'. */
static void
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
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
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
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
{
char *arg_end;
int val = strtoul (args, &arg_end, 10);
+
if (*args && *arg_end == '\0')
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
else if (strcmp (args, f_val) == 0)
return 0;
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);
}
active_inf (void)
{
struct inf *inf = cur_inf ();
+
if (!inf->task)
error (_("No current process."));
return inf;
show_task_pause_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
check_empty (args, "show task pause");
printf_unfiltered ("The inferior task %s suspended while gdb has control.\n",
inf->task
static void
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
show_task_detach_sc_cmd (char *args, int from_tty)
{
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);
}
set_thread_default_pause_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
inf->default_thread_pause_sc =
parse_bool_arg (args, "set thread default pause") ? 0 : 1;
}
{
struct inf *inf = cur_inf ();
int sc = inf->default_thread_pause_sc;
+
check_empty (args, "show thread default pause");
printf_unfiltered ("New threads %s suspended while gdb has control%s.\n",
sc ? "are" : "aren't",
set_thread_default_run_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
inf->default_thread_run_sc =
parse_bool_arg (args, "set thread default run") ? 0 : 1;
}
show_thread_default_run_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
check_empty (args, "show thread default run");
printf_unfiltered ("New threads %s allowed to run.\n",
inf->default_thread_run_sc == 0 ? "are" : "aren't");
proc->saved_exc_port = port;
if (!proc->exc_port)
- /* 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. */
+ /* 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. */
{
proc->exc_port = proc->inf->event_port;
err = proc_set_exception_port (proc, proc->exc_port);
set_task_exc_port_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
if (!args)
error (_("No argument to \"set task exception-port\" command."));
steal_exc_port (inf->task, parse_and_eval_address (args));
show_stopped_cmd (char *args, int from_tty)
{
struct inf *inf = active_inf ();
+
check_empty (args, "show stopped");
printf_unfiltered ("The inferior process %s stopped.\n",
inf->stopped ? "is" : "isn't");
else
{
int tid = ptid_get_tid (thread_id_to_pid (atoi (args)));
+
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);
inf->signal_thread = inf_tid_to_thread (inf, tid);
}
show_sig_thread_cmd (char *args, int from_tty)
{
struct inf *inf = active_inf ();
+
check_empty (args, "show signal-thread");
if (inf->signal_thread)
printf_unfiltered ("The signal thread is %s.\n",
show_signals_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
check_empty (args, "show signals");
printf_unfiltered ("The inferior process's signals %s intercepted.\n",
inf->task
show_exceptions_cmd (char *args, int from_tty)
{
struct inf *inf = cur_inf ();
+
check_empty (args, "show exceptions");
printf_unfiltered ("Exceptions in the inferior %s trapped.\n",
inf->task
struct value *val = parse_to_comma_and_eval (&args);
long right = value_as_long (val);
error_t err =
- print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
- stdout);
+ print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
+ stdout);
+
if (err)
error (_("%ld: %s."), right, safe_strerror (err));
}
/* Print all of them. */
{
error_t err =
- print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
- stdout);
+ print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
+ stdout);
if (err)
error (_("%s."), safe_strerror (err));
}
Set whether gdb thinks the inferior process is stopped as with SIGSTOP.\n\
Stopped process will be continued by sending them a signal."),
&setlist);
- add_cmd ("stopped", no_class, show_signals_cmd, _("\
+ add_cmd ("stopped", no_class, show_stopped_cmd, _("\
Show whether gdb thinks the inferior process is stopped as with SIGSTOP."),
&showlist);
_("Set the suspend count will leave on the thread when detaching."),
&set_task_cmd_list);
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);
add_cmd ("exception-port", no_class, set_task_exc_port_cmd, _("\
{
struct proc *thread = cur_thread ();
int old_sc = thread->pause_sc;
+
thread->pause_sc = parse_bool_arg (args, "set thread pause");
if (old_sc == 0 && thread->pause_sc != 0 && thread->inf->pause_sc == 0)
/* If the task is currently unsuspended, immediately suspend it,
{
struct proc *thread = cur_thread ();
int sc = thread->pause_sc;
+
check_empty (args, "show task pause");
printf_unfiltered ("Thread %s %s suspended while gdb has control%s.\n",
proc_string (thread),
set_thread_run_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
thread->run_sc = parse_bool_arg (args, "set thread run") ? 0 : 1;
}
show_thread_run_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
check_empty (args, "show thread run");
printf_unfiltered ("Thread %s %s allowed to run.",
proc_string (thread),
show_thread_detach_sc_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
check_empty (args, "show thread detach-suspend-count");
printf_unfiltered ("Thread %s will be left with a suspend count"
" of %d when detaching.\n",
set_thread_exc_port_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
if (!args)
error (_("No argument to \"set thread exception-port\" command."));
steal_exc_port (thread, parse_and_eval_address (args));
show_thread_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
check_empty (args, "show thread");
show_thread_run_cmd (0, from_tty);
show_thread_pause_cmd (0, from_tty);
thread_takeover_sc_cmd (char *args, int from_tty)
{
struct proc *thread = cur_thread ();
+
thread_basic_info_data_t _info;
thread_basic_info_t info = &_info;
mach_msg_type_number_t info_len = THREAD_BASIC_INFO_COUNT;
_initialize_gnu_nat (void)
{
proc_server = getproc ();
-
- init_gnu_ops ();
- add_target (&gnu_ops);
add_task_commands ();
add_thread_commands ();
- deprecated_add_set_cmd ("gnu-debug", class_maintenance,
- var_boolean, (char *) &gnu_debug_flag,
- "Set debugging output for the gnu backend.",
- &maintenancelist);
+ add_setshow_boolean_cmd ("gnu-nat", class_maintenance,
+ &gnu_debug_flag,
+ _("Set debugging output for the gnu backend."),
+ _("Show debugging output for the gnu backend."),
+ NULL,
+ NULL,
+ NULL,
+ &setdebuglist,
+ &showdebuglist);
}
\f
#ifdef FLUSH_INFERIOR_CACHE
/* When over-writing code on some machines the I-Cache must be flushed
explicitly, because it is not kept coherent by the lazy hardware.
This definitely includes breakpoints, for instance, or else we
- end up looping in mysterious Bpt traps */
+ end up looping in mysterious Bpt traps. */
void
flush_inferior_icache (CORE_ADDR pc, int amount)