aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/gdbthread.h3
-rw-r--r--gdb/gnu-nat.c214
-rw-r--r--gdb/thread.c83
3 files changed, 158 insertions, 142 deletions
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 33c2b11..f71276f 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -43,4 +43,7 @@ extern void save_infrun_state PARAMS ((int, CORE_ADDR, CORE_ADDR, char *,
struct breakpoint *, CORE_ADDR,
CORE_ADDR, CORE_ADDR, int, int));
+/* Commands with a prefix of `thread'. */
+extern struct cmd_list_element *thread_cmd_list;
+
#endif /* GDBTHREAD_H */
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index fd05467..367302d 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1,5 +1,5 @@
/* Interface GDB to the GNU Hurd
- Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GDB.
@@ -88,26 +88,26 @@ extern struct target_ops gnu_ops;
extern char *strerror();
int inf_update_procs (struct inf *inf);
-static struct inf *make_inf ();
-static void inf_clear_wait (struct inf *inf);
-static void inf_cleanup (struct inf *inf);
-static void inf_startup (struct inf *inf, int pid, task_t task);
-static int inf_update_suspends (struct inf *inf);
-static void inf_set_task (struct inf *inf, task_t port);
-static void inf_validate_procs (struct inf *inf);
-static void inf_steal_exc_ports (struct inf *inf);
-static void inf_restore_exc_ports (struct inf *inf);
-static struct proc *inf_tid_to_proc (struct inf *inf, int tid);
-static inline void inf_set_threads_resume_sc (struct inf *inf,
- struct proc *run_thread,
- int run_others);
-static inline int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
-static inline void inf_suspend (struct inf *inf);
-static inline void inf_resume (struct inf *inf);
-static void inf_set_step_thread (struct inf *inf, struct proc *proc);
-static void inf_detach (struct inf *inf);
-static void inf_attach (struct inf *inf, int pid);
-static void inf_signal (struct inf *inf, enum target_signal sig);
+struct inf *make_inf ();
+void inf_clear_wait (struct inf *inf);
+void inf_cleanup (struct inf *inf);
+void inf_startup (struct inf *inf, int pid);
+int inf_update_suspends (struct inf *inf);
+void inf_set_pid (struct inf *inf, pid_t pid);
+void inf_validate_procs (struct inf *inf);
+void inf_steal_exc_ports (struct inf *inf);
+void inf_restore_exc_ports (struct inf *inf);
+struct proc *inf_tid_to_proc (struct inf *inf, int tid);
+inline void inf_set_threads_resume_sc (struct inf *inf,
+ struct proc *run_thread,
+ int run_others);
+inline int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
+inline void inf_suspend (struct inf *inf);
+inline void inf_resume (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);
#define inf_debug(_inf, msg, args...) \
do { struct inf *__inf = (_inf); \
@@ -115,15 +115,15 @@ static void inf_signal (struct inf *inf, enum target_signal sig);
void proc_abort (struct proc *proc, int force);
thread_state_t proc_get_state (struct proc *proc, int force);
-static struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
-static struct proc *_proc_free (struct proc *proc);
-static int proc_update_sc (struct proc *proc);
-static error_t proc_get_exception_port (struct proc *proc, mach_port_t *port);
-static error_t proc_set_exception_port (struct proc *proc, mach_port_t port);
+struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
+struct proc *_proc_free (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_set_exception_port (struct proc *proc, mach_port_t port);
static mach_port_t _proc_get_exc_port (struct proc *proc);
-static void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
-static void proc_restore_exc_port (struct proc *proc);
-static int proc_trace (struct proc *proc, int set);
+void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
+void proc_restore_exc_port (struct proc *proc);
+int proc_trace (struct proc *proc, int set);
char *proc_string (struct proc *proc);
/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
@@ -248,7 +248,7 @@ int __proc_pid (struct proc *proc)
/* Update PROC's real suspend count to match it's desired one. Returns true
if we think PROC is now in a runnable state. */
-static int
+int
proc_update_sc (struct proc *proc)
{
int running;
@@ -378,7 +378,7 @@ proc_get_state (struct proc *proc, int will_modify)
}
/* Set PORT to PROC's exception port. */
-static error_t
+error_t
proc_get_exception_port (struct proc *proc, mach_port_t *port)
{
if (proc_is_task (proc))
@@ -388,7 +388,7 @@ proc_get_exception_port (struct proc *proc, mach_port_t *port)
}
/* Set PROC's exception port to PORT. */
-static error_t
+error_t
proc_set_exception_port (struct proc *proc, mach_port_t port)
{
proc_debug (proc, "setting exception port: %d", port);
@@ -421,7 +421,7 @@ _proc_get_exc_port (struct proc *proc)
/* 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. */
-static void
+void
proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
{
mach_port_t cur_exc_port = _proc_get_exc_port (proc);
@@ -464,7 +464,7 @@ proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
/* If we previously replaced PROC's exception port, put back what we
found there at the time, unless *our* exception port has since been
overwritten, in which case who knows what's going on. */
-static void
+void
proc_restore_exc_port (struct proc *proc)
{
mach_port_t cur_exc_port = _proc_get_exc_port (proc);
@@ -493,7 +493,7 @@ proc_restore_exc_port (struct proc *proc)
/* Turns hardware tracing in PROC on or off when SET is true or false,
respectively. Returns true on success. */
-static int
+int
proc_trace (struct proc *proc, int set)
{
thread_state_t state = proc_get_state (proc, 1);
@@ -583,7 +583,7 @@ make_proc (struct inf *inf, mach_port_t port, int tid)
/* Frees PROC and any resources it uses, and returns the value of PROC's
next field. */
-static struct proc *
+struct proc *
_proc_free (struct proc *proc)
{
struct inf *inf = proc->inf;
@@ -652,7 +652,7 @@ struct inf *make_inf ()
}
/* clear INF's target wait status. */
-static void
+void
inf_clear_wait (struct inf *inf)
{
inf_debug (inf, "clearing wait");
@@ -671,14 +671,14 @@ inf_clear_wait (struct inf *inf)
}
}
-static void
+void
inf_cleanup (struct inf *inf)
{
inf_debug (inf, "cleanup");
inf_clear_wait (inf);
- inf_set_task (inf, MACH_PORT_NULL);
+ inf_set_pid (inf, -1);
inf->pid = 0;
inf->traced = 0;
inf->no_wait = 0;
@@ -693,12 +693,12 @@ inf_cleanup (struct inf *inf)
}
}
-static void
-inf_startup (struct inf *inf, int pid, task_t task)
+void
+inf_startup (struct inf *inf, int pid)
{
error_t err;
- inf_debug (inf, "startup: pid = %d, task = %d", pid, task);
+ inf_debug (inf, "startup: pid = %d", pid);
inf_cleanup (inf);
@@ -711,40 +711,53 @@ inf_startup (struct inf *inf, int pid, task_t task)
/* 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,
inf->event_port, MACH_MSG_TYPE_MAKE_SEND);
-
- if (inf->pause_sc)
- task_suspend (task);
-
- inf_set_task (inf, task);
-
- if (inf->task)
- {
- inf->pid = pid;
- if (inf->pause_sc)
- inf->task->sc = inf->task->cur_sc = 1; /* Reflect task_suspend above */
- }
+ inf_set_pid (inf, pid);
}
/* close current process, if any, and attach INF to process PORT */
-static void
-inf_set_task (struct inf *inf, mach_port_t port)
+void
+inf_set_pid (struct inf *inf, pid_t pid)
{
+ task_t task_port;
struct proc *task = inf->task;
- inf_debug (inf, "setting task: %d", port);
+ inf_debug (inf, "setting pid: %d", pid);
- if (task && task->port != port)
+ if (pid < 0)
+ task_port = MACH_PORT_NULL;
+ else
+ {
+ error_t err = proc_pid2task (proc_server, pid, &task_port);
+ if (err)
+ error ("Error getting task for pid %d: %s", pid, strerror (err));
+ }
+
+ inf_debug (inf, "setting task: %d", task_port);
+
+ if (inf->pause_sc)
+ task_suspend (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. */
}
- if (port != MACH_PORT_NULL)
+ if (task_port != MACH_PORT_NULL)
{
- inf->task = make_proc (inf, port, PROC_TID_TASK);
+ inf->task = make_proc (inf, task_port, PROC_TID_TASK);
inf->threads_up_to_date = 0;
}
+
+ if (inf->task)
+ {
+ inf->pid = pid;
+ if (inf->pause_sc)
+ inf->task->sc = inf->task->cur_sc = 1; /* Reflect task_suspend above */
+ }
+ else
+ inf->pid = -1;
}
/* Validates INF's stopped field from the actual proc server state. */
@@ -801,7 +814,7 @@ inf_validate_task_sc (struct inf *inf)
/* 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 be modified,
and the signal thread will briefly be run to change the trace state. */
-static void
+void
inf_set_traced (struct inf *inf, int on)
{
if (on != inf->traced)
@@ -832,7 +845,7 @@ inf_set_traced (struct inf *inf, int 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.*/
-static int
+int
inf_update_suspends (struct inf *inf)
{
struct proc *task = inf->task;
@@ -886,8 +899,7 @@ struct proc *
inf_tid_to_thread (struct inf *inf, int tid)
{
struct proc *thread = inf->threads;
- if (tid == inf->pid) /* main thread */
- return thread;
+
while (thread)
if (thread->tid == tid)
return thread;
@@ -897,7 +909,7 @@ inf_tid_to_thread (struct inf *inf, int tid)
}
/* Converts a thread port to a struct proc. */
-static struct proc *
+struct proc *
inf_port_to_thread (struct inf *inf, mach_port_t port)
{
struct proc *thread = inf->threads;
@@ -910,7 +922,7 @@ inf_port_to_thread (struct inf *inf, mach_port_t port)
}
/* Make INF's list of threads be consistent with reality of TASK. */
-static void
+void
inf_validate_procs (struct inf *inf)
{
int i;
@@ -988,23 +1000,11 @@ inf_validate_procs (struct inf *inf)
else
/* THREADS[I] is a thread we don't know about yet! */
{
-#if 0
thread = make_proc (inf, threads[i], next_thread_id++);
-#else
- thread = make_proc (inf, threads[i], threads[i]);
-#endif
(last ? last->next : inf->threads) = thread;
last = thread;
proc_debug (thread, "new thread: %d", threads[i]);
-#if 1 /* try leaving this out, see what happens */
add_thread (thread->tid); /* Tell GDB's generic thread code. */
-#if 0 /* seems to cause kernel exceptions??? */
- target_terminal_ours_for_output (); /* allow debugger I/O */
- printf_filtered ("[gnu-nat: New %s]\n",
- target_pid_to_str (thread->tid));
- target_terminal_inferior (); /* give it back */
-#endif
-#endif
}
vm_deallocate(mach_task_self(),
@@ -1026,7 +1026,7 @@ inf_update_procs (struct inf *inf)
/* 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
their pause_sc. */
-static inline void
+inline void
inf_set_threads_resume_sc (struct inf *inf,
struct proc *run_thread, int run_others)
{
@@ -1043,7 +1043,7 @@ inf_set_threads_resume_sc (struct inf *inf,
/* Cause INF to continue execution immediately; individual threads may still
be suspended (but their suspend counts will be updated). */
-static inline void
+inline void
inf_resume (struct inf *inf)
{
struct proc *thread;
@@ -1068,7 +1068,7 @@ inf_resume (struct inf *inf)
/* Cause INF to stop execution immediately; individual threads may still
be running. */
-static inline void
+inline void
inf_suspend (struct inf *inf)
{
struct proc *thread;
@@ -1087,7 +1087,7 @@ inf_suspend (struct inf *inf)
/* 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 a normal one. A
PROC of 0 clears any existing value. */
-static void
+void
inf_set_step_thread (struct inf *inf, struct proc *thread)
{
assert (!thread || proc_is_thread (thread));
@@ -1112,7 +1112,7 @@ inf_set_step_thread (struct inf *inf, struct proc *thread)
/* 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
did so, or false if we can't find a signal thread. */
-static inline int
+inline int
inf_set_threads_resume_sc_for_signal_thread (struct inf *inf)
{
if (inf->signal_thread)
@@ -1133,7 +1133,7 @@ inf_update_signal_thread (struct inf *inf)
}
/* Detachs from INF's inferior task, letting it run once again... */
-static void
+void
inf_detach (struct inf *inf)
{
struct proc *task = inf->task;
@@ -1168,22 +1168,15 @@ inf_detach (struct inf *inf)
/* Attaches INF to the process with process id PID, returning it in a suspended
state suitable for debugging. */
-static void
+void
inf_attach (struct inf *inf, int pid)
{
- error_t err;
- task_t task;
-
inf_debug (inf, "attaching: %d", pid);
- err = proc_pid2task (proc_server, pid, &task);
- if (err)
- error ("Error getting task for pid %d: %s", pid, strerror (err));
-
if (inf->pid)
inf_detach (inf);
- inf_startup (inf, pid, task);
+ inf_startup (inf, pid);
}
/* Makes sure that we've got our exception ports entrenched in the process. */
@@ -1217,7 +1210,7 @@ void inf_restore_exc_ports (struct inf *inf)
/* 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
the resume_sc's of INF's threads may be affected. */
-static void
+void
inf_signal (struct inf *inf, enum target_signal sig)
{
error_t err = 0;
@@ -1377,6 +1370,12 @@ gnu_wait (int tid, struct target_waitstatus *status)
/* Re-suspend the task. */
inf_suspend (inf);
+ if (!inf->task && inf->pending_execs)
+ /* 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,
+ attempt to refetch it, as the pid should still be the same. */
+ inf_set_pid (inf, inf->pid);
+
if (err == EMACH_RCV_INTERRUPTED)
inf_debug (inf, "interrupted");
else if (err)
@@ -1425,17 +1424,24 @@ gnu_wait (int tid, struct target_waitstatus *status)
/* Ah hah! A SIGTRAP from the inferior while starting up probably
means we've succesfully completed an exec! */
{
-#if 0 /* do we need this? */
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. */
- }
#endif
+ }
inf_debug (inf, "pending exec completed, pending_execs => %d",
inf->pending_execs);
}
+ else if (kind == TARGET_WAITKIND_STOPPED)
+ /* It's possible that this signal is because of a crashed 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.
+ Since the code in inf_resume that normally checks for this is
+ disabled while INF->pending_execs, we do the check here instead. */
+ inf_validate_task_sc (inf);
}
if (inf->wait.suppress)
@@ -1569,7 +1575,7 @@ S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
/* Fill in INF's wait field after a task has died without giving us more
detailed information. */
-static void
+void
inf_task_died_status (struct inf *inf)
{
warning ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid);
@@ -1853,7 +1859,7 @@ gnu_kill_inferior ()
{
proc_debug (task, "terminating...");
task_terminate (task->port);
- inf_set_task (current_inferior, MACH_PORT_NULL);
+ inf_set_pid (current_inferior, -1);
}
target_mourn_inferior ();
}
@@ -2006,9 +2012,7 @@ gnu_attach (args, from_tty)
time the user does a continue. */
inf_validate_stopped (inf);
-#if 0 /* Do we need this? Actually I can see where it
- might be helpful here, but it's just cosmetic.
- Let's come back to it later. XXX Fix me. */
+#if 0 /* Do we need this? */
renumber_threads (0); /* Give our threads reasonable names. */
#endif
}
@@ -2389,13 +2393,7 @@ char *proc_string (struct proc *proc)
sprintf (tid_str, "process %d", proc->inf->pid);
else
sprintf (tid_str, "thread %d.%d",
- proc->inf->pid,
-#if 0
- pid_to_thread_id (proc->tid)
-#else
- proc->tid
-#endif
-);
+ proc->inf->pid, pid_to_thread_id (proc->tid));
return tid_str;
}
diff --git a/gdb/thread.c b/gdb/thread.c
index cd7fb02..7ffc65a 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -270,25 +270,41 @@ void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
tp->another_trap = another_trap;
}
+/* Return true if TP is an active thread. */
+static int
+thread_alive (tp)
+ struct thread_info *tp;
+{
+ if (tp->pid == -1)
+ return 0;
+ if (! target_thread_alive (tp->pid))
+ {
+ tp->pid = -1; /* Mark it as dead */
+ return 0;
+ }
+ return 1;
+}
+
static void
prune_threads ()
{
- struct thread_info *tp, *tpprev;
+ struct thread_info *tp, *tpprev, *next;
tpprev = 0;
-
- for (tp = thread_list; tp; tp = tp->next)
- if (tp->pid == -1)
- {
- if (tpprev)
- tpprev->next = tp->next;
- else
- thread_list = NULL;
-
- free (tp);
- }
- else
- tpprev = tp;
+ for (tp = thread_list; tp; tp = next)
+ {
+ next = tp->next;
+ if (!thread_alive (tp))
+ {
+ if (tpprev)
+ tpprev->next = next;
+ else
+ thread_list = next;
+ free (tp);
+ }
+ else
+ tpprev = tp;
+ }
}
/* Print information about currently known threads */
@@ -305,14 +321,9 @@ info_threads_command (arg, from_tty)
selected_frame. */
if (!target_has_stack) error ("No stack.");
+ prune_threads ();
for (tp = thread_list; tp; tp = tp->next)
{
- if (! target_thread_alive (tp->pid))
- {
- tp->pid = -1; /* Mark it as dead */
- continue;
- }
-
if (tp->pid == current_pid)
printf_filtered ("* ");
else
@@ -325,7 +336,6 @@ info_threads_command (arg, from_tty)
}
switch_to_thread (current_pid);
- prune_threads ();
}
/* Switch from one thread to another. */
@@ -375,12 +385,13 @@ thread_apply_all_command (cmd, from_tty)
old_chain = make_cleanup (restore_current_thread, inferior_pid);
for (tp = thread_list; tp; tp = tp->next)
- {
- switch_to_thread (tp->pid);
- printf_filtered ("\nThread %d (%s):\n", tp->num,
- target_pid_to_str (inferior_pid));
- execute_command (cmd, from_tty);
- }
+ if (thread_alive (tp))
+ {
+ switch_to_thread (tp->pid);
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_pid));
+ execute_command (cmd, from_tty);
+ }
}
static void
@@ -434,15 +445,16 @@ thread_apply_command (tidlist, from_tty)
tp = find_thread_id (start);
if (!tp)
+ warning ("Unknown thread %d.", start);
+ else if (!thread_alive (tp))
+ warning ("Thread %d has terminated.", start);
+ else
{
- warning ("Unknown thread %d.", start);
- continue;
+ switch_to_thread (tp->pid);
+ printf_filtered ("\nThread %d (%s):\n", tp->num,
+ target_pid_to_str (inferior_pid));
+ execute_command (cmd, from_tty);
}
-
- switch_to_thread (tp->pid);
- printf_filtered ("\nThread %d (%s):\n", tp->num,
- target_pid_to_str (inferior_pid));
- execute_command (cmd, from_tty);
}
}
}
@@ -470,6 +482,9 @@ see the IDs of currently known threads.");
error ("Thread ID %d not known. Use the \"info threads\" command to\n\
see the IDs of currently known threads.", num);
+ if (!thread_alive (tp))
+ error ("Thread ID %d has terminated.\n", num);
+
switch_to_thread (tp->pid);
printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));