aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-nat.c
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2007-10-01 00:22:50 +0000
committerDaniel Jacobowitz <drow@false.org>2007-10-01 00:22:50 +0000
commit9f0bdab8028f185719d163f3bfeafd1406ba5a58 (patch)
treea4c91496632a8629237eb3766c4fe11e1c5bd8e0 /gdb/linux-nat.c
parentd983da9c3dfa91e6840fee2a7479d98ee4759f13 (diff)
downloadgdb-9f0bdab8028f185719d163f3bfeafd1406ba5a58.zip
gdb-9f0bdab8028f185719d163f3bfeafd1406ba5a58.tar.gz
gdb-9f0bdab8028f185719d163f3bfeafd1406ba5a58.tar.bz2
* linux-nat.c (linux_nat_new_thread): New variable.
(linux_child_follow_fork): Set inferior_ptid to include LWP ID. Use linux_nat_switch_fork. (lwp_list): Make public. (add_lwp): Call linux_nat_new_thread. (lin_lwp_attach_lwp, linux_nat_attach): Call add_lwp after stopping the new thread. (resume_callback): Clear lp->siginfo. Remove unused variable. (linux_nat_resume): Assert that the LWP list is already initialized. Clear lp->siginfo. (save_siginfo): New. (stop_wait_callback, linux_nat_wait): Call it. (linux_nat_set_new_thread, linux_nat_get_siginfo): New. * linux-nat.h (struct lwp_info): Add siginfo. (lwp_list, linux_nat_set_new_thread, linux_nat_get_siginfo): Declare. (ALL_LWPS): Define. * amd64-linux-nat.c (amd64_linux_dr): New. (amd64_linux_dr_get): Take a PTID argument. Correct typo. (amd64_linux_dr_set): Take a PTID argument. (amd64_linux_dr_set_control, amd64_linux_dr_set_addr): Use ALL_LWPS. (amd64_linux_dr_reset_addr): Use amd64_linux_dr_set_addr. (amd64_linux_dr_get_status): Pass inferior_ptid to amd64_linux_dr_get. (amd64_linux_new_thread): New. (_initialize_amd64_linux_nat): Call linux_nat_set_new_thread. * i386-linux-nat.c (i386_linux_dr): New. (i386_linux_dr_get, i386_linux_dr_set): Take a PTID argument. (i386_linux_dr_set_control, i386_linux_dr_set_addr): Use ALL_LWPS. (i386_linux_dr_reset_addr): Use i386_linux_dr_set_addr. (i386_linux_dr_get_status): Pass inferior_ptid to i386_linux_dr_get. (i386_linux_new_thread): New. (i386_linux_resume): Remove unnecessary PID check. (_initialize_i386_linux_nat): Call linux_nat_set_new_thread. * ia64-linux-nat.c (enable_watchpoints_in_psr): Take PTID argument. (fetch_debug_register, fetch_debug_register_pair): Delete. (debug_registers): New. (ia64_linux_insert_watchpoint, ia64_linux_remove_watchpoint): Use ALL_LWPS and debug_registers. (ia64_linux_new_thread): New. (ia64_linux_stopped_data_address): Use linux_nat_get_siginfo. (_initialize_ia64_linux_nat): Call linux_nat_set_new_thread. * ppc-linux-nat.c (last_stopped_data_address): Delete. (saved_dabr_value): New. (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use ALL_LWPS. (ppc_linux_new_thread): New. (ppc_linux_stopped_data_address): Use linux_nat_get_siginfo. (ppc_linux_stopped_by_watchpoint): Call ppc_linux_stopped_data_address. (_initialize_ppc_linux_nat): Call linux_nat_set_new_thread. * s390-nat.c (s390_stopped_by_watchpoint): Clear the watchpoint status after reading it. (s390_fix_watch_points): Take a PTID argument. (s390_insert_watchpoint, s390_remove_watchpoint): Use ALL_LWPS. (_initialize_s390_nat): Call linux_nat_set_new_thread.
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r--gdb/linux-nat.c170
1 files changed, 113 insertions, 57 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 90b8a3b..18c2800 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -89,6 +89,9 @@
static struct target_ops *linux_ops;
static struct target_ops linux_ops_saved;
+/* The method to call, if any, when a new thread is attached. */
+static void (*linux_nat_new_thread) (ptid_t);
+
/* The saved to_xfer_partial method, inherited from inf-ptrace.c.
Called by our to_xfer_partial. */
static LONGEST (*super_xfer_partial) (struct target_ops *,
@@ -503,12 +506,13 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
target_detach (NULL, 0);
}
- inferior_ptid = pid_to_ptid (child_pid);
+ inferior_ptid = ptid_build (child_pid, child_pid, 0);
/* Reinstall ourselves, since we might have been removed in
target_detach (which does other necessary cleanup). */
push_target (ops);
+ linux_nat_switch_fork (inferior_ptid);
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
@@ -573,7 +577,7 @@ linux_child_insert_exec_catchpoint (int pid)
because the "zombies" stay around. */
/* List of known LWPs. */
-static struct lwp_info *lwp_list;
+struct lwp_info *lwp_list;
/* Number of LWPs in the list. */
static int num_lwps;
@@ -657,7 +661,8 @@ init_lwp_list (void)
}
/* Add the LWP specified by PID to the list. Return a pointer to the
- structure describing the new LWP. */
+ structure describing the new LWP. The LWP should already be stopped
+ (with an exception for the very first LWP). */
static struct lwp_info *
add_lwp (ptid_t ptid)
@@ -678,6 +683,9 @@ add_lwp (ptid_t ptid)
lwp_list = lp;
++num_lwps;
+ if (num_lwps > 1 && linux_nat_new_thread != NULL)
+ linux_nat_new_thread (ptid);
+
return lp;
}
@@ -884,6 +892,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
{
pid_t pid;
int status;
+ int cloned = 0;
if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
{
@@ -897,9 +906,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
return -1;
}
- if (lp == NULL)
- lp = add_lwp (ptid);
-
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
@@ -910,12 +916,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
{
/* Try again with __WCLONE to check cloned processes. */
pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
- lp->cloned = 1;
+ cloned = 1;
}
gdb_assert (pid == GET_LWP (ptid)
&& WIFSTOPPED (status) && WSTOPSIG (status));
+ if (lp == NULL)
+ lp = add_lwp (ptid);
+ lp->cloned = cloned;
+
target_post_attach (pid);
lp->stopped = 1;
@@ -953,15 +963,12 @@ linux_nat_attach (char *args, int from_tty)
struct lwp_info *lp;
pid_t pid;
int status;
+ int cloned = 0;
/* FIXME: We should probably accept a list of process id's, and
attach all of them. */
linux_ops->to_attach (args, from_tty);
- /* Add the initial process as the first LWP to the list. */
- inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
- lp = add_lwp (inferior_ptid);
-
/* Make sure the initial process is stopped. The user-level threads
layer might want to poke around in the inferior, and that won't
work if things haven't stabilized yet. */
@@ -972,12 +979,17 @@ linux_nat_attach (char *args, int from_tty)
/* Try again with __WCLONE to check cloned processes. */
pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
- lp->cloned = 1;
+ cloned = 1;
}
gdb_assert (pid == GET_PID (inferior_ptid)
&& WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
+ /* Add the initial process as the first LWP to the list. */
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+ lp = add_lwp (inferior_ptid);
+ lp->cloned = cloned;
+
lp->stopped = 1;
/* Fake the SIGSTOP that core GDB expects. */
@@ -1077,8 +1089,6 @@ resume_callback (struct lwp_info *lp, void *data)
{
if (lp->stopped && lp->status == 0)
{
- struct thread_info *tp;
-
linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
0, TARGET_SIGNAL_0);
if (debug_linux_nat)
@@ -1087,6 +1097,7 @@ resume_callback (struct lwp_info *lp, void *data)
target_pid_to_str (lp->ptid));
lp->stopped = 0;
lp->step = 0;
+ memset (&lp->siginfo, 0, sizeof (lp->siginfo));
}
return 0;
@@ -1136,68 +1147,69 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
ptid = inferior_ptid;
lp = find_lwp_pid (ptid);
- if (lp)
- {
- ptid = pid_to_ptid (GET_LWP (lp->ptid));
+ gdb_assert (lp != NULL);
- /* Remember if we're stepping. */
- lp->step = step;
+ ptid = pid_to_ptid (GET_LWP (lp->ptid));
- /* Mark this LWP as resumed. */
- lp->resumed = 1;
+ /* Remember if we're stepping. */
+ lp->step = step;
- /* If we have a pending wait status for this thread, there is no
- point in resuming the process. But first make sure that
- linux_nat_wait won't preemptively handle the event - we
- should never take this short-circuit if we are going to
- leave LP running, since we have skipped resuming all the
- other threads. This bit of code needs to be synchronized
- with linux_nat_wait. */
+ /* Mark this LWP as resumed. */
+ lp->resumed = 1;
- if (lp->status && WIFSTOPPED (lp->status))
- {
- int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+ /* If we have a pending wait status for this thread, there is no
+ point in resuming the process. But first make sure that
+ linux_nat_wait won't preemptively handle the event - we
+ should never take this short-circuit if we are going to
+ leave LP running, since we have skipped resuming all the
+ other threads. This bit of code needs to be synchronized
+ with linux_nat_wait. */
- if (signal_stop_state (saved_signo) == 0
- && signal_print_state (saved_signo) == 0
- && signal_pass_state (saved_signo) == 1)
- {
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLR: Not short circuiting for ignored "
- "status 0x%x\n", lp->status);
-
- /* FIXME: What should we do if we are supposed to continue
- this thread with a signal? */
- gdb_assert (signo == TARGET_SIGNAL_0);
- signo = saved_signo;
- lp->status = 0;
- }
- }
+ if (lp->status && WIFSTOPPED (lp->status))
+ {
+ int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
- if (lp->status)
+ if (signal_stop_state (saved_signo) == 0
+ && signal_print_state (saved_signo) == 0
+ && signal_pass_state (saved_signo) == 1)
{
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLR: Not short circuiting for ignored "
+ "status 0x%x\n", lp->status);
+
/* FIXME: What should we do if we are supposed to continue
this thread with a signal? */
gdb_assert (signo == TARGET_SIGNAL_0);
+ signo = saved_signo;
+ lp->status = 0;
+ }
+ }
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLR: Short circuiting for status 0x%x\n",
- lp->status);
+ if (lp->status)
+ {
+ /* FIXME: What should we do if we are supposed to continue
+ this thread with a signal? */
+ gdb_assert (signo == TARGET_SIGNAL_0);
- return;
- }
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLR: Short circuiting for status 0x%x\n",
+ lp->status);
- /* Mark LWP as not stopped to prevent it from being continued by
- resume_callback. */
- lp->stopped = 0;
+ return;
}
+ /* Mark LWP as not stopped to prevent it from being continued by
+ resume_callback. */
+ lp->stopped = 0;
+
if (resume_all)
iterate_over_lwps (resume_callback, NULL);
linux_ops->to_resume (ptid, step, signo);
+ memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: %s %s, %s (resume event thread)\n",
@@ -1416,6 +1428,22 @@ wait_lwp (struct lwp_info *lp)
return status;
}
+/* Save the most recent siginfo for LP. This is currently only called
+ for SIGTRAP; some ports use the si_addr field for
+ target_stopped_data_address. In the future, it may also be used to
+ restore the siginfo of requeued signals. */
+
+static void
+save_siginfo (struct lwp_info *lp)
+{
+ errno = 0;
+ ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
+ (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
+
+ if (errno != 0)
+ memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+}
+
/* Send a SIGSTOP to LP. */
static int
@@ -1501,6 +1529,9 @@ stop_wait_callback (struct lwp_info *lp, void *data)
user will delete or disable the breakpoint, but the
thread will have already tripped on it. */
+ /* Save the trap's siginfo in case we need it later. */
+ save_siginfo (lp);
+
/* Now resume this LWP and get the SIGSTOP event. */
errno = 0;
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -2058,6 +2089,10 @@ retry:
target_pid_to_str (lp->ptid));
}
+ /* Save the trap's siginfo in case we need it later. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+ save_siginfo (lp);
+
/* Handle GNU/Linux's extended waitstatus for trace events. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
{
@@ -3250,6 +3285,27 @@ linux_nat_add_target (struct target_ops *t)
thread_db_init (t);
}
+/* Register a method to call whenever a new thread is attached. */
+void
+linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+{
+ /* Save the pointer. We only support a single registered instance
+ of the GNU/Linux native target, so we do not need to map this to
+ T. */
+ linux_nat_new_thread = new_thread;
+}
+
+/* Return the saved siginfo associated with PTID. */
+struct siginfo *
+linux_nat_get_siginfo (ptid_t ptid)
+{
+ struct lwp_info *lp = find_lwp_pid (ptid);
+
+ gdb_assert (lp != NULL);
+
+ return &lp->siginfo;
+}
+
void
_initialize_linux_nat (void)
{