X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Flinux-nat.c;h=fc63fa30878c7928a79c18af1808a95a96c265b5;hb=fa2c6a57ca78416ad3546b9aea4e2a0b77e78989;hp=80771a7cc7ed60786de59d81ef0fded238ded0f3;hpb=b260b6c1289a49a1e8f50cd78566a3e17a960781;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 80771a7cc7..fc63fa3087 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1,13 +1,13 @@ /* GNU/Linux native-dependent code common to multiple platforms. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GDB. 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 - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,9 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "inferior.h" @@ -86,11 +84,18 @@ #define __WALL 0x40000000 /* Wait for any child. */ #endif +#ifndef PTRACE_GETSIGINFO +#define PTRACE_GETSIGINFO 0x4202 +#endif + /* The single-threaded native GNU/Linux target_ops. We save a pointer for the use of the multi-threaded target. */ 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 *, @@ -335,8 +340,8 @@ linux_enable_event_reporting (ptid_t ptid) ptrace (PTRACE_SETOPTIONS, pid, 0, options); } -void -child_post_attach (int pid) +static void +linux_child_post_attach (int pid) { linux_enable_event_reporting (pid_to_ptid (pid)); check_for_thread_db (); @@ -349,8 +354,8 @@ linux_child_post_startup_inferior (ptid_t ptid) check_for_thread_db (); } -int -child_follow_fork (struct target_ops *ops, int follow_child) +static int +linux_child_follow_fork (struct target_ops *ops, int follow_child) { ptid_t last_ptid; struct target_waitstatus last_status; @@ -378,7 +383,7 @@ child_follow_fork (struct target_ops *ops, int follow_child) /* Detach new forked process? */ if (detach_fork) { - if (debug_linux_nat) + if (info_verbose || debug_linux_nat) { target_terminal_ours (); fprintf_filtered (gdb_stdlog, @@ -463,7 +468,7 @@ child_follow_fork (struct target_ops *ops, int follow_child) /* Before detaching from the parent, remove all breakpoints from it. */ remove_breakpoints (); - if (debug_linux_nat) + if (info_verbose || debug_linux_nat) { target_terminal_ours (); fprintf_filtered (gdb_stdlog, @@ -505,12 +510,14 @@ 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); + check_for_thread_db (); /* Reset breakpoints in the child as appropriate. */ follow_inferior_reset_breakpoints (); @@ -520,22 +527,22 @@ child_follow_fork (struct target_ops *ops, int follow_child) } -void -child_insert_fork_catchpoint (int pid) +static void +linux_child_insert_fork_catchpoint (int pid) { if (! linux_supports_tracefork (pid)) error (_("Your system does not support fork catchpoints.")); } -void -child_insert_vfork_catchpoint (int pid) +static void +linux_child_insert_vfork_catchpoint (int pid) { if (!linux_supports_tracefork (pid)) error (_("Your system does not support vfork catchpoints.")); } -void -child_insert_exec_catchpoint (int pid) +static void +linux_child_insert_exec_catchpoint (int pid) { if (!linux_supports_tracefork (pid)) error (_("Your system does not support exec catchpoints.")); @@ -575,7 +582,7 @@ 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; @@ -616,6 +623,7 @@ static sigset_t blocked_mask; /* Prototypes for local functions. */ static int stop_wait_callback (struct lwp_info *lp, void *data); static int linux_nat_thread_alive (ptid_t ptid); +static char *linux_child_pid_to_exec_file (int pid); /* Convert wait status STATUS to a string. Used for printing debug messages only. */ @@ -658,7 +666,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) @@ -679,6 +688,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; } @@ -859,7 +871,7 @@ exit_lwp (struct lwp_info *lp) be attached. */ int -lin_lwp_attach_lwp (ptid_t ptid, int verbose) +lin_lwp_attach_lwp (ptid_t ptid) { struct lwp_info *lp; @@ -885,12 +897,13 @@ 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) { /* If we fail to attach to the thread, issue a warning, but continue. One way this can happen is if thread - creation is interrupted; as of Linux 2.6.19, a kernel + creation is interrupted; as of Linux kernel 2.6.19, a bug may place threads in the thread list and then fail to create them. */ warning (_("Can't attach %s: %s"), target_pid_to_str (ptid), @@ -898,9 +911,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", @@ -911,12 +921,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; @@ -942,9 +956,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) lp->stopped = 1; } - if (verbose) - printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid)); - return 0; } @@ -954,15 +965,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. */ @@ -973,12 +981,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. */ @@ -1078,8 +1091,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) @@ -1088,6 +1099,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; @@ -1137,68 +1149,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", @@ -1325,7 +1338,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, { ourstatus->kind = TARGET_WAITKIND_EXECD; ourstatus->value.execd_pathname - = xstrdup (child_pid_to_exec_file (pid)); + = xstrdup (linux_child_pid_to_exec_file (pid)); if (linux_parent_pid) { @@ -1417,6 +1430,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 @@ -1502,6 +1531,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); @@ -1766,7 +1798,8 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data) if (lp->status != 0 && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) - - DECR_PC_AFTER_BREAK)) + gdbarch_decr_pc_after_break + (current_gdbarch))) { if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, @@ -1774,8 +1807,10 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data) target_pid_to_str (lp->ptid)); /* Back up the PC if necessary. */ - if (DECR_PC_AFTER_BREAK) - write_pc_pid (read_pc_pid (lp->ptid) - DECR_PC_AFTER_BREAK, lp->ptid); + if (gdbarch_decr_pc_after_break (current_gdbarch)) + write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break + (current_gdbarch), + lp->ptid); /* Throw away the SIGTRAP. */ lp->status = 0; @@ -1867,6 +1902,173 @@ stop_and_resume_callback (struct lwp_info *lp, void *data) return 0; } +/* Check if we should go on and pass this event to common code. + Return the affected lwp if we are, or NULL otherwise. */ +static struct lwp_info * +linux_nat_filter_event (int lwpid, int status, int options) +{ + struct lwp_info *lp; + + lp = find_lwp_pid (pid_to_ptid (lwpid)); + + /* Check for stop events reported by a process we didn't already + know about - anything not already in our LWP list. + + If we're expecting to receive stopped processes after + fork, vfork, and clone events, then we'll just add the + new one to our list and go back to waiting for the event + to be reported - the stopped process might be returned + from waitpid before or after the event is. */ + if (WIFSTOPPED (status) && !lp) + { + linux_record_stopped_pid (lwpid, status); + return NULL; + } + + /* Make sure we don't report an event for the exit of an LWP not in + our list, i.e. not part of the current process. This can happen + if we detach from a program we original forked and then it + exits. */ + if (!WIFSTOPPED (status) && !lp) + return NULL; + + /* NOTE drow/2003-06-17: This code seems to be meant for debugging + CLONE_PTRACE processes which do not use the thread library - + otherwise we wouldn't find the new LWP this way. That doesn't + currently work, and the following code is currently unreachable + due to the two blocks above. If it's fixed some day, this code + should be broken out into a function so that we can also pick up + LWPs from the new interface. */ + if (!lp) + { + lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid))); + if (options & __WCLONE) + lp->cloned = 1; + + gdb_assert (WIFSTOPPED (status) + && WSTOPSIG (status) == SIGSTOP); + lp->signalled = 1; + + if (!in_thread_list (inferior_ptid)) + { + inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), + GET_PID (inferior_ptid)); + add_thread (inferior_ptid); + } + + add_thread (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) + { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: Handling extended status 0x%06x\n", + status); + if (linux_handle_extended_wait (lp, status, 0)) + return NULL; + } + + /* Check if the thread has exited. */ + if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) + { + /* If this is the main thread, we must stop all threads and + verify if they are still alive. This is because in the nptl + thread model, there is no signal issued for exiting LWPs + other than the main thread. We only get the main thread exit + signal once all child threads have already exited. If we + stop all the threads and use the stop_wait_callback to check + if they have exited we can determine whether this signal + should be ignored or whether it means the end of the debugged + application, regardless of which threading model is being + used. */ + if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)) + { + lp->stopped = 1; + iterate_over_lwps (stop_and_resume_callback, NULL); + } + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s exited.\n", + target_pid_to_str (lp->ptid)); + + exit_lwp (lp); + + /* If there is at least one more LWP, then the exit signal was + not the end of the debugged application and should be + ignored. */ + if (num_lwps > 0) + { + /* Make sure there is at least one thread running. */ + gdb_assert (iterate_over_lwps (running_callback, NULL)); + + /* Discard the event. */ + return NULL; + } + } + + /* Check if the current LWP has previously exited. In the nptl + thread model, LWPs other than the main thread do not issue + signals when they exit so we must check whenever the thread has + stopped. A similar check is made in stop_wait_callback(). */ + if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid)) + { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s exited.\n", + target_pid_to_str (lp->ptid)); + + exit_lwp (lp); + + /* Make sure there is at least one thread running. */ + gdb_assert (iterate_over_lwps (running_callback, NULL)); + + /* Discard the event. */ + return NULL; + } + + /* Make sure we don't report a SIGSTOP that we sent ourselves in + an attempt to stop an LWP. */ + if (lp->signalled + && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP) + { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: Delayed SIGSTOP caught for %s.\n", + target_pid_to_str (lp->ptid)); + + /* This is a delayed SIGSTOP. */ + lp->signalled = 0; + + registers_changed (); + + linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)), + lp->step, TARGET_SIGNAL_0); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, 0, 0 (discard SIGSTOP)\n", + lp->step ? + "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid)); + + lp->stopped = 0; + gdb_assert (lp->resumed); + + /* Discard the event. */ + return NULL; + } + + /* An interesting event. */ + gdb_assert (lp); + return lp; +} + static ptid_t linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { @@ -1999,165 +2201,10 @@ retry: (long) lwpid, status_to_str (status)); } - lp = find_lwp_pid (pid_to_ptid (lwpid)); - - /* Check for stop events reported by a process we didn't - already know about - anything not already in our LWP - list. - - If we're expecting to receive stopped processes after - fork, vfork, and clone events, then we'll just add the - new one to our list and go back to waiting for the event - to be reported - the stopped process might be returned - from waitpid before or after the event is. */ - if (WIFSTOPPED (status) && !lp) - { - linux_record_stopped_pid (lwpid, status); - status = 0; - continue; - } - - /* Make sure we don't report an event for the exit of an LWP not in - our list, i.e. not part of the current process. This can happen - if we detach from a program we original forked and then it - exits. */ - if (!WIFSTOPPED (status) && !lp) - { - status = 0; - continue; - } - - /* NOTE drow/2003-06-17: This code seems to be meant for debugging - CLONE_PTRACE processes which do not use the thread library - - otherwise we wouldn't find the new LWP this way. That doesn't - currently work, and the following code is currently unreachable - due to the two blocks above. If it's fixed some day, this code - should be broken out into a function so that we can also pick up - LWPs from the new interface. */ + lp = linux_nat_filter_event (lwpid, status, options); if (!lp) { - lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid))); - if (options & __WCLONE) - lp->cloned = 1; - - gdb_assert (WIFSTOPPED (status) - && WSTOPSIG (status) == SIGSTOP); - lp->signalled = 1; - - if (!in_thread_list (inferior_ptid)) - { - inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), - GET_PID (inferior_ptid)); - add_thread (inferior_ptid); - } - - add_thread (lp->ptid); - printf_unfiltered (_("[New %s]\n"), - target_pid_to_str (lp->ptid)); - } - - /* Handle GNU/Linux's extended waitstatus for trace events. */ - if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: Handling extended status 0x%06x\n", - status); - if (linux_handle_extended_wait (lp, status, 0)) - { - status = 0; - continue; - } - } - - /* Check if the thread has exited. */ - if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) - { - /* If this is the main thread, we must stop all threads and - verify if they are still alive. This is because in the nptl - thread model, there is no signal issued for exiting LWPs - other than the main thread. We only get the main thread - exit signal once all child threads have already exited. - If we stop all the threads and use the stop_wait_callback - to check if they have exited we can determine whether this - signal should be ignored or whether it means the end of the - debugged application, regardless of which threading model - is being used. */ - if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)) - { - lp->stopped = 1; - iterate_over_lwps (stop_and_resume_callback, NULL); - } - - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: %s exited.\n", - target_pid_to_str (lp->ptid)); - - exit_lwp (lp); - - /* If there is at least one more LWP, then the exit signal - was not the end of the debugged application and should be - ignored. */ - if (num_lwps > 0) - { - /* Make sure there is at least one thread running. */ - gdb_assert (iterate_over_lwps (running_callback, NULL)); - - /* Discard the event. */ - status = 0; - continue; - } - } - - /* Check if the current LWP has previously exited. In the nptl - thread model, LWPs other than the main thread do not issue - signals when they exit so we must check whenever the thread - has stopped. A similar check is made in stop_wait_callback(). */ - if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid)) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: %s exited.\n", - target_pid_to_str (lp->ptid)); - - exit_lwp (lp); - - /* Make sure there is at least one thread running. */ - gdb_assert (iterate_over_lwps (running_callback, NULL)); - - /* Discard the event. */ - status = 0; - continue; - } - - /* Make sure we don't report a SIGSTOP that we sent - ourselves in an attempt to stop an LWP. */ - if (lp->signalled - && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: Delayed SIGSTOP caught for %s.\n", - target_pid_to_str (lp->ptid)); - - /* This is a delayed SIGSTOP. */ - lp->signalled = 0; - - registers_changed (); - linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)), - lp->step, TARGET_SIGNAL_0); - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: %s %s, 0, 0 (discard SIGSTOP)\n", - lp->step ? - "PTRACE_SINGLESTEP" : "PTRACE_CONT", - target_pid_to_str (lp->ptid)); - - lp->stopped = 0; - gdb_assert (lp->resumed); - - /* Discard the event. */ + /* A discarded event. */ status = 0; continue; } @@ -2311,11 +2358,18 @@ kill_wait_callback (struct lwp_info *lp, void *data) do { pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE); - if (pid != (pid_t) -1 && debug_linux_nat) + if (pid != (pid_t) -1) { - fprintf_unfiltered (gdb_stdlog, - "KWC: wait %s received unknown.\n", - target_pid_to_str (lp->ptid)); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "KWC: wait %s received unknown.\n", + target_pid_to_str (lp->ptid)); + /* The Linux kernel sometimes fails to kill a thread + completely after PTRACE_KILL; that goes from the stop + point in do_fork out to the one in + get_signal_to_deliever and waits again. So kill it + again. */ + kill_callback (lp, NULL); } } while (pid == GET_LWP (lp->ptid)); @@ -2326,11 +2380,14 @@ kill_wait_callback (struct lwp_info *lp, void *data) do { pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0); - if (pid != (pid_t) -1 && debug_linux_nat) + if (pid != (pid_t) -1) { - fprintf_unfiltered (gdb_stdlog, - "KWC: wait %s received unk.\n", - target_pid_to_str (lp->ptid)); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "KWC: wait %s received unk.\n", + target_pid_to_str (lp->ptid)); + /* See the call to kill_callback above. */ + kill_callback (lp, NULL); } } while (pid == GET_LWP (lp->ptid)); @@ -2463,8 +2520,8 @@ sigchld_handler (int signo) /* Accepts an integer PID; Returns a string representing a file that can be opened to get the symbols for the child process. */ -char * -child_pid_to_exec_file (int pid) +static char * +linux_child_pid_to_exec_file (int pid) { char *name1, *name2; @@ -2579,19 +2636,26 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid, gdb_fpxregset_t fpxregs; #endif unsigned long lwp = ptid_get_lwp (ptid); - struct gdbarch *gdbarch = current_gdbarch; + struct regcache *regcache = get_thread_regcache (ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); const struct regset *regset; int core_regset_p; + struct cleanup *old_chain; + + old_chain = save_inferior_ptid (); + inferior_ptid = ptid; + target_fetch_registers (regcache, -1); + do_cleanups (old_chain); core_regset_p = gdbarch_regset_from_core_section_p (gdbarch); if (core_regset_p && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg", sizeof (gregs))) != NULL && regset->collect_regset != NULL) - regset->collect_regset (regset, current_regcache, -1, + regset->collect_regset (regset, regcache, -1, &gregs, sizeof (gregs)); else - fill_gregset (&gregs, -1); + fill_gregset (regcache, &gregs, -1); note_data = (char *) elfcore_write_prstatus (obfd, note_data, @@ -2603,10 +2667,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid, && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2", sizeof (fpregs))) != NULL && regset->collect_regset != NULL) - regset->collect_regset (regset, current_regcache, -1, + regset->collect_regset (regset, regcache, -1, &fpregs, sizeof (fpregs)); else - fill_fpregset (&fpregs, -1); + fill_fpregset (regcache, &fpregs, -1); note_data = (char *) elfcore_write_prfpreg (obfd, note_data, @@ -2618,10 +2682,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid, && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp", sizeof (fpxregs))) != NULL && regset->collect_regset != NULL) - regset->collect_regset (regset, current_regcache, -1, + regset->collect_regset (regset, regcache, -1, &fpxregs, sizeof (fpxregs)); else - fill_fpxregset (&fpxregs, -1); + fill_fpxregset (regcache, &fpxregs, -1); note_data = (char *) elfcore_write_prxfpreg (obfd, note_data, @@ -2646,21 +2710,13 @@ static int linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data) { struct linux_nat_corefile_thread_data *args = data; - ptid_t saved_ptid = inferior_ptid; - inferior_ptid = ti->ptid; - registers_changed (); - target_fetch_registers (-1); /* FIXME should not be necessary; - fill_gregset should do it automatically. */ args->note_data = linux_nat_do_thread_registers (args->obfd, ti->ptid, args->note_data, args->note_size); args->num_notes++; - inferior_ptid = saved_ptid; - registers_changed (); - target_fetch_registers (-1); /* FIXME should not be necessary; - fill_gregset should do it automatically. */ + return 0; } @@ -2670,15 +2726,11 @@ static char * linux_nat_do_registers (bfd *obfd, ptid_t ptid, char *note_data, int *note_size) { - registers_changed (); - target_fetch_registers (-1); /* FIXME should not be necessary; - fill_gregset should do it automatically. */ return linux_nat_do_thread_registers (obfd, ptid_build (ptid_get_pid (inferior_ptid), ptid_get_pid (inferior_ptid), 0), note_data, note_size); - return note_data; } /* Fills the "to_make_corefile_note" target vector. Builds the note @@ -2689,7 +2741,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size) { struct linux_nat_corefile_thread_data thread_args; struct cleanup *old_chain; + /* The variable size must be >= sizeof (prpsinfo_t.pr_fname). */ char fname[16] = { '\0' }; + /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs). */ char psargs[80] = { '\0' }; char *note_data = NULL; ptid_t current_ptid = inferior_ptid; @@ -2702,9 +2756,18 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size) strncpy (psargs, get_exec_file (0), sizeof (psargs)); if (get_inferior_args ()) { - strncat (psargs, " ", sizeof (psargs) - strlen (psargs)); - strncat (psargs, get_inferior_args (), - sizeof (psargs) - strlen (psargs)); + char *string_end; + char *psargs_end = psargs + sizeof (psargs); + + /* linux_elfcore_write_prpsinfo () handles zero unterminated + strings fine. */ + string_end = memchr (psargs, 0, sizeof (psargs)); + if (string_end != NULL) + { + *string_end++ = ' '; + strncpy (string_end, get_inferior_args (), + psargs_end - string_end); + } } note_data = (char *) elfcore_write_prpsinfo (obfd, note_data, @@ -2857,7 +2920,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty) char permissions[8], device[8], filename[MAXPATHLEN]; printf_filtered (_("Mapped address spaces:\n\n")); - if (TARGET_ADDR_BIT == 32) + if (gdbarch_addr_bit (current_gdbarch) == 32) { printf_filtered ("\t%10s %10s %10s %10s %7s\n", "Start Addr", @@ -2883,7 +2946,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty) a generic local_address_string instead to print out the addresses; that makes sense to me, too. */ - if (TARGET_ADDR_BIT == 32) + if (gdbarch_addr_bit (current_gdbarch) == 32) { printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", (unsigned long) addr, /* FIXME: pr_addr */ @@ -2927,10 +2990,11 @@ linux_nat_info_proc_cmd (char *args, int from_tty) { int itmp; char ctmp; + long ltmp; if (fscanf (procfile, "%d ", &itmp) > 0) printf_filtered (_("Process: %d\n"), itmp); - if (fscanf (procfile, "%s ", &buffer[0]) > 0) + if (fscanf (procfile, "(%[^)]) ", &buffer[0]) > 0) printf_filtered (_("Exec file: %s\n"), buffer); if (fscanf (procfile, "%c ", &ctmp) > 0) printf_filtered (_("State: %c\n"), ctmp); @@ -2944,71 +3008,71 @@ linux_nat_info_proc_cmd (char *args, int from_tty) printf_filtered (_("TTY: %d\n"), itmp); if (fscanf (procfile, "%d ", &itmp) > 0) printf_filtered (_("TTY owner process group: %d\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Flags: 0x%x\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Minor faults (no memory page): %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Minor faults, children: %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Major faults (memory page faults): %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Major faults, children: %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered ("utime: %d\n", itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered ("stime: %d\n", itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered ("utime, children: %d\n", itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered ("stime, children: %d\n", itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("jiffies remaining in current time slice: %d\n"), - itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered ("'nice' value: %d\n", itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("jiffies until next timeout: %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered ("jiffies until next SIGALRM: %u\n", - (unsigned int) itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("start time (jiffies since system boot): %d\n"), - itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Virtual memory size: %u\n"), - (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Resident set size: %u\n"), (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered ("rlim: %u\n", (unsigned int) itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Start of text: 0x%x\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("End of text: 0x%x\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) - printf_filtered (_("Start of stack: 0x%x\n"), itmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Flags: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Minor faults (no memory page): %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Minor faults, children: %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Major faults (memory page faults): %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Major faults, children: %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("utime: %ld\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("stime: %ld\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("utime, children: %ld\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("stime, children: %ld\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("jiffies remaining in current time slice: %ld\n"), + ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("'nice' value: %ld\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("jiffies until next timeout: %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("jiffies until next SIGALRM: %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("start time (jiffies since system boot): %ld\n"), + ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Virtual memory size: %lu\n"), + (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Resident set size: %lu\n"), (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Start of text: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("End of text: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) + printf_filtered (_("Start of stack: 0x%lx\n"), ltmp); #if 0 /* Don't know how architecture-dependent the rest is... Anyway the signal bitmap info is available from "status". */ - if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ - printf_filtered (_("Kernel stack pointer: 0x%x\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ - printf_filtered (_("Kernel instr pointer: 0x%x\n"), itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("Pending signals bitmap: 0x%x\n"), itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("Blocked signals bitmap: 0x%x\n"), itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("Ignored signals bitmap: 0x%x\n"), itmp); - if (fscanf (procfile, "%d ", &itmp) > 0) - printf_filtered (_("Catched signals bitmap: 0x%x\n"), itmp); - if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ - printf_filtered (_("wchan (system call): 0x%x\n"), itmp); + if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */ + printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */ + printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("Blocked signals bitmap: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%ld ", <mp) > 0) + printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp); + if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */ + printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp); #endif fclose (procfile); } @@ -3164,47 +3228,44 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object, offset, len); } -#ifndef FETCH_INFERIOR_REGISTERS - -/* Return the address in the core dump or inferior of register - REGNO. */ +/* Create a prototype generic GNU/Linux target. The client can override + it with local methods. */ -static CORE_ADDR -linux_register_u_offset (int regno) +static void +linux_target_install_ops (struct target_ops *t) { - /* FIXME drow/2005-09-04: The hardcoded use of register_addr should go - away. This requires disentangling the various definitions of it - (particularly alpha-nat.c's). */ - return register_addr (regno, 0); -} - -#endif + t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint; + t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint; + t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint; + t->to_pid_to_exec_file = linux_child_pid_to_exec_file; + t->to_post_startup_inferior = linux_child_post_startup_inferior; + t->to_post_attach = linux_child_post_attach; + t->to_follow_fork = linux_child_follow_fork; + t->to_find_memory_regions = linux_nat_find_memory_regions; + t->to_make_corefile_notes = linux_nat_make_corefile_notes; -/* Create a prototype generic Linux target. The client can override - it with local methods. */ + super_xfer_partial = t->to_xfer_partial; + t->to_xfer_partial = linux_xfer_partial; +} struct target_ops * linux_target (void) { struct target_ops *t; -#ifdef FETCH_INFERIOR_REGISTERS t = inf_ptrace_target (); -#else - t = inf_ptrace_trad_target (linux_register_u_offset); -#endif - t->to_insert_fork_catchpoint = child_insert_fork_catchpoint; - t->to_insert_vfork_catchpoint = child_insert_vfork_catchpoint; - t->to_insert_exec_catchpoint = child_insert_exec_catchpoint; - t->to_pid_to_exec_file = child_pid_to_exec_file; - t->to_post_startup_inferior = linux_child_post_startup_inferior; - t->to_post_attach = child_post_attach; - t->to_follow_fork = child_follow_fork; - t->to_find_memory_regions = linux_nat_find_memory_regions; - t->to_make_corefile_notes = linux_nat_make_corefile_notes; + linux_target_install_ops (t); - super_xfer_partial = t->to_xfer_partial; - t->to_xfer_partial = linux_xfer_partial; + return t; +} + +struct target_ops * +linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int)) +{ + struct target_ops *t; + + t = inf_ptrace_trad_target (register_u_offset); + linux_target_install_ops (t); return t; } @@ -3244,6 +3305,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) {