X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Flinux-nat.c;h=90b8a3b84502e261963d48c450d7b28400944174;hb=d99148ef7338d24780a2ca8eed4ee228bcb1d4af;hp=b08943298b64b68794f47f321f2b79fc7c3c7342;hpb=e26af52fd134ceb47298a102d3a0d6ab46e7d69a;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b08943298b..90b8a3b845 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
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
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"
@@ -36,6 +34,7 @@
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
+#include "regset.h"
#include "inf-ptrace.h"
#include "auxv.h"
#include /* for MAXPATHLEN */
@@ -88,6 +87,7 @@
/* 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 saved to_xfer_partial method, inherited from inf-ptrace.c.
Called by our to_xfer_partial. */
@@ -97,10 +97,6 @@ static LONGEST (*super_xfer_partial) (struct target_ops *,
const gdb_byte *,
ULONGEST, LONGEST);
-/* The saved to_mourn_inferior method, inherited from inf-ptrace.c.
- Called by our to_mourn_inferior. */
-static void (*super_mourn_inferior) (void);
-
static int debug_linux_nat;
static void
show_debug_linux_nat (struct ui_file *file, int from_tty,
@@ -115,6 +111,7 @@ static int linux_parent_pid;
struct simple_pid_list
{
int pid;
+ int status;
struct simple_pid_list *next;
};
struct simple_pid_list *stopped_pids;
@@ -133,16 +130,17 @@ static int linux_supports_tracevforkdone_flag = -1;
/* Trivial list manipulation functions to keep track of a list of
new stopped processes. */
static void
-add_to_pid_list (struct simple_pid_list **listp, int pid)
+add_to_pid_list (struct simple_pid_list **listp, int pid, int status)
{
struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
new_pid->pid = pid;
+ new_pid->status = status;
new_pid->next = *listp;
*listp = new_pid;
}
static int
-pull_pid_from_list (struct simple_pid_list **listp, int pid)
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *status)
{
struct simple_pid_list **p;
@@ -150,6 +148,7 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid)
if ((*p)->pid == pid)
{
struct simple_pid_list *next = (*p)->next;
+ *status = (*p)->status;
xfree (*p);
*p = next;
return 1;
@@ -157,10 +156,10 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid)
return 0;
}
-void
-linux_record_stopped_pid (int pid)
+static void
+linux_record_stopped_pid (int pid, int status)
{
- add_to_pid_list (&stopped_pids, pid);
+ add_to_pid_list (&stopped_pids, pid, status);
}
@@ -278,6 +277,7 @@ linux_test_for_tracefork (int original_pid)
ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
if (ret != 0)
warning (_("linux_test_for_tracefork: failed to kill second child"));
+ my_waitpid (second_pid, &status, 0);
}
}
else
@@ -333,20 +333,22 @@ 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 ();
}
static void
linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (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;
@@ -515,141 +517,28 @@ child_follow_fork (struct target_ops *ops, int follow_child)
return 0;
}
-ptid_t
-linux_handle_extended_wait (int pid, int status,
- struct target_waitstatus *ourstatus)
-{
- int event = status >> 16;
-
- if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
- || event == PTRACE_EVENT_CLONE)
- {
- unsigned long new_pid;
- int ret;
-
- ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
-
- /* If we haven't already seen the new PID stop, wait for it now. */
- if (! pull_pid_from_list (&stopped_pids, new_pid))
- {
- /* The new child has a pending SIGSTOP. We can't affect it until it
- hits the SIGSTOP, but we're already attached. */
- ret = my_waitpid (new_pid, &status,
- (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
- if (ret == -1)
- perror_with_name (_("waiting for new child"));
- else if (ret != new_pid)
- internal_error (__FILE__, __LINE__,
- _("wait returned unexpected PID %d"), ret);
- else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP)
- internal_error (__FILE__, __LINE__,
- _("wait returned unexpected status 0x%x"), status);
- }
-
- if (event == PTRACE_EVENT_FORK)
- ourstatus->kind = TARGET_WAITKIND_FORKED;
- else if (event == PTRACE_EVENT_VFORK)
- ourstatus->kind = TARGET_WAITKIND_VFORKED;
- else
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-
- ourstatus->value.related_pid = new_pid;
- return inferior_ptid;
- }
-
- if (event == PTRACE_EVENT_EXEC)
- {
- ourstatus->kind = TARGET_WAITKIND_EXECD;
- ourstatus->value.execd_pathname
- = xstrdup (child_pid_to_exec_file (pid));
-
- if (linux_parent_pid)
- {
- detach_breakpoints (linux_parent_pid);
- ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
-
- linux_parent_pid = 0;
- }
-
- return inferior_ptid;
- }
-
- internal_error (__FILE__, __LINE__,
- _("unknown ptrace event %d"), event);
-}
-
-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."));
}
-void
-kill_inferior (void)
-{
- int status;
- int pid = PIDGET (inferior_ptid);
- struct target_waitstatus last;
- ptid_t last_ptid;
- int ret;
-
- if (pid == 0)
- return;
-
- /* First cut -- let's crudely do everything inline. */
- if (forks_exist_p ())
- {
- linux_fork_killall ();
- pop_target ();
- generic_mourn_inferior ();
- }
- else
- {
- /* If we're stopped while forking and we haven't followed yet,
- kill the other task. We need to do this first because the
- parent will be sleeping if this is a vfork. */
-
- get_last_target_status (&last_ptid, &last);
-
- if (last.kind == TARGET_WAITKIND_FORKED
- || last.kind == TARGET_WAITKIND_VFORKED)
- {
- ptrace (PT_KILL, last.value.related_pid, 0, 0);
- wait (&status);
- }
-
- /* Kill the current process. */
- ptrace (PT_KILL, pid, 0, 0);
- ret = wait (&status);
-
- /* We might get a SIGCHLD instead of an exit status. This is
- aggravated by the first kill above - a child has just died. */
-
- while (ret == pid && WIFSTOPPED (status))
- {
- ptrace (PT_KILL, pid, 0, 0);
- ret = wait (&status);
- }
- target_mourn_inferior ();
- }
-}
-
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
are processes sharing the same VM space. A multi-threaded process
is basically a group of such processes. However, such a grouping
@@ -688,9 +577,6 @@ static struct lwp_info *lwp_list;
/* Number of LWPs in the list. */
static int num_lwps;
-
-/* Non-zero if we're running in "threaded" mode. */
-static int threaded;
#define GET_LWP(ptid) ptid_get_lwp (ptid)
@@ -703,9 +589,6 @@ static int threaded;
ptid_t trap_ptid;
-/* This module's target-specific operations. */
-static struct target_ops linux_nat_ops;
-
/* Since we cannot wait (in linux_nat_wait) for the initial process and
any cloned processes with a single call to waitpid, we have to use
the WNOHANG flag and call waitpid in a loop. To optimize
@@ -731,6 +614,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. */
@@ -770,12 +654,10 @@ init_lwp_list (void)
lwp_list = NULL;
num_lwps = 0;
- threaded = 0;
}
-/* Add the LWP specified by PID to the list. If this causes the
- number of LWPs to become larger than one, go into "threaded" mode.
- Return a pointer to the structure describing the new LWP. */
+/* Add the LWP specified by PID to the list. Return a pointer to the
+ structure describing the new LWP. */
static struct lwp_info *
add_lwp (ptid_t ptid)
@@ -794,8 +676,7 @@ add_lwp (ptid_t ptid)
lp->next = lwp_list;
lwp_list = lp;
- if (++num_lwps > 1)
- threaded = 1;
+ ++num_lwps;
return lp;
}
@@ -816,8 +697,6 @@ delete_lwp (ptid_t ptid)
if (!lp)
return;
- /* We don't go back to "non-threaded" mode if the number of threads
- becomes less than two. */
num_lwps--;
if (lpprev)
@@ -869,6 +748,21 @@ iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
return NULL;
}
+/* Update our internal state when changing from one fork (checkpoint,
+ et cetera) to another indicated by NEW_PTID. We can only switch
+ single-threaded applications, so we only create one new LWP, and
+ the previous list is discarded. */
+
+void
+linux_nat_switch_fork (ptid_t new_ptid)
+{
+ struct lwp_info *lp;
+
+ init_lwp_list ();
+ lp = add_lwp (new_ptid);
+ lp->stopped = 1;
+}
+
/* Record a PTID for later deletion. */
struct saved_ptids
@@ -946,10 +840,13 @@ exit_lwp (struct lwp_info *lp)
struct thread_info *thr;
thr = iterate_over_threads (find_thread_from_lwp, &lp->ptid);
- if (thr && !ptid_equal (thr->ptid, inferior_ptid))
- delete_thread (thr->ptid);
- else
- record_dead_thread (thr->ptid);
+ if (thr)
+ {
+ if (!ptid_equal (thr->ptid, inferior_ptid))
+ delete_thread (thr->ptid);
+ else
+ record_dead_thread (thr->ptid);
+ }
}
delete_lwp (lp->ptid);
@@ -957,12 +854,13 @@ exit_lwp (struct lwp_info *lp)
/* Attach to the LWP specified by PID. If VERBOSE is non-zero, print
a message telling the user that a new LWP has been added to the
- process. */
+ process. Return 0 if successful or -1 if the new LWP could not
+ be attached. */
-void
+int
lin_lwp_attach_lwp (ptid_t ptid, int verbose)
{
- struct lwp_info *lp, *found_lp;
+ struct lwp_info *lp;
gdb_assert (is_lwp (ptid));
@@ -974,12 +872,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
}
- if (verbose)
- printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
-
- found_lp = lp = find_lwp_pid (ptid);
- if (lp == NULL)
- lp = add_lwp (ptid);
+ lp = find_lwp_pid (ptid);
/* We assume that we're already attached to any LWP that has an id
equal to the overall process id, and to any LWP that is already
@@ -987,14 +880,25 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
and we've had PID wraparound since we last tried to stop all threads,
this assumption might be wrong; fortunately, this is very unlikely
to happen. */
- if (GET_LWP (ptid) != GET_PID (ptid) && found_lp == NULL)
+ if (GET_LWP (ptid) != GET_PID (ptid) && lp == NULL)
{
pid_t pid;
int status;
if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
- error (_("Can't attach %s: %s"), target_pid_to_str (ptid),
- safe_strerror (errno));
+ {
+ /* 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
+ 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),
+ safe_strerror (errno));
+ return -1;
+ }
+
+ if (lp == NULL)
+ lp = add_lwp (ptid);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -1012,7 +916,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
gdb_assert (pid == GET_LWP (ptid)
&& WIFSTOPPED (status) && WSTOPSIG (status));
- child_post_attach (pid);
+ target_post_attach (pid);
lp->stopped = 1;
@@ -1028,12 +932,19 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
{
/* We assume that the LWP representing the original process is
already stopped. Mark it as stopped in the data structure
- that the linux ptrace layer uses to keep track of threads.
- Note that this won't have already been done since the main
- thread will have, we assume, been stopped by an attach from a
- different layer. */
+ that the GNU/linux ptrace layer uses to keep track of
+ threads. Note that this won't have already been done since
+ the main thread will have, we assume, been stopped by an
+ attach from a different layer. */
+ if (lp == NULL)
+ lp = add_lwp (ptid);
lp->stopped = 1;
}
+
+ if (verbose)
+ printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
+
+ return 0;
}
static void
@@ -1048,7 +959,8 @@ linux_nat_attach (char *args, int from_tty)
linux_ops->to_attach (args, from_tty);
/* Add the initial process as the first LWP to the list. */
- lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)));
+ 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
@@ -1320,39 +1232,113 @@ kill_lwp (int lwpid, int signo)
return kill (lwpid, signo);
}
-/* Handle a GNU/Linux extended wait response. Most of the work we
- just pass off to linux_handle_extended_wait, but if it reports a
- clone event we need to add the new LWP to our list (and not report
- the trap to higher layers). This function returns non-zero if
- the event should be ignored and we should wait again. */
+/* Handle a GNU/Linux extended wait response. If we see a clone
+ event, we need to add the new LWP to our list (and not report the
+ trap to higher layers). This function returns non-zero if the
+ event should be ignored and we should wait again. If STOPPING is
+ true, the new LWP remains stopped, otherwise it is continued. */
static int
-linux_nat_handle_extended (struct lwp_info *lp, int status)
+linux_handle_extended_wait (struct lwp_info *lp, int status,
+ int stopping)
{
- linux_handle_extended_wait (GET_LWP (lp->ptid), status,
- &lp->waitstatus);
+ int pid = GET_LWP (lp->ptid);
+ struct target_waitstatus *ourstatus = &lp->waitstatus;
+ struct lwp_info *new_lp = NULL;
+ int event = status >> 16;
- /* TARGET_WAITKIND_SPURIOUS is used to indicate clone events. */
- if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS)
+ if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
+ || event == PTRACE_EVENT_CLONE)
{
- struct lwp_info *new_lp;
- new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
- GET_PID (inferior_ptid)));
- new_lp->cloned = 1;
- new_lp->stopped = 1;
+ unsigned long new_pid;
+ int ret;
- lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+ ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLHE: Got clone event from LWP %ld, resuming\n",
- GET_LWP (lp->ptid));
- ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ /* If we haven't already seen the new PID stop, wait for it now. */
+ if (! pull_pid_from_list (&stopped_pids, new_pid, &status))
+ {
+ /* The new child has a pending SIGSTOP. We can't affect it until it
+ hits the SIGSTOP, but we're already attached. */
+ ret = my_waitpid (new_pid, &status,
+ (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
+ if (ret == -1)
+ perror_with_name (_("waiting for new child"));
+ else if (ret != new_pid)
+ internal_error (__FILE__, __LINE__,
+ _("wait returned unexpected PID %d"), ret);
+ else if (!WIFSTOPPED (status))
+ internal_error (__FILE__, __LINE__,
+ _("wait returned unexpected status 0x%x"), status);
+ }
- return 1;
+ ourstatus->value.related_pid = new_pid;
+
+ if (event == PTRACE_EVENT_FORK)
+ ourstatus->kind = TARGET_WAITKIND_FORKED;
+ else if (event == PTRACE_EVENT_VFORK)
+ ourstatus->kind = TARGET_WAITKIND_VFORKED;
+ else
+ {
+ ourstatus->kind = TARGET_WAITKIND_IGNORE;
+ new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
+ new_lp->cloned = 1;
+
+ if (WSTOPSIG (status) != SIGSTOP)
+ {
+ /* This can happen if someone starts sending signals to
+ the new thread before it gets a chance to run, which
+ have a lower number than SIGSTOP (e.g. SIGUSR1).
+ This is an unlikely case, and harder to handle for
+ fork / vfork than for clone, so we do not try - but
+ we handle it for clone events here. We'll send
+ the other signal on to the thread below. */
+
+ new_lp->signalled = 1;
+ }
+ else
+ status = 0;
+
+ if (stopping)
+ new_lp->stopped = 1;
+ else
+ {
+ new_lp->resumed = 1;
+ ptrace (PTRACE_CONT, lp->waitstatus.value.related_pid, 0,
+ status ? WSTOPSIG (status) : 0);
+ }
+
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: Got clone event from LWP %ld, resuming\n",
+ GET_LWP (lp->ptid));
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+
+ return 1;
+ }
+
+ return 0;
}
- return 0;
+ if (event == PTRACE_EVENT_EXEC)
+ {
+ ourstatus->kind = TARGET_WAITKIND_EXECD;
+ ourstatus->value.execd_pathname
+ = xstrdup (linux_child_pid_to_exec_file (pid));
+
+ if (linux_parent_pid)
+ {
+ detach_breakpoints (linux_parent_pid);
+ ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
+
+ linux_parent_pid = 0;
+ }
+
+ return 0;
+ }
+
+ internal_error (__FILE__, __LINE__,
+ _("unknown ptrace event %d"), event);
}
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
@@ -1423,7 +1409,7 @@ wait_lwp (struct lwp_info *lp)
fprintf_unfiltered (gdb_stdlog,
"WL: Handling extended status 0x%06x\n",
status);
- if (linux_nat_handle_extended (lp, status))
+ if (linux_handle_extended_wait (lp, status, 1))
return wait_lwp (lp);
}
@@ -1663,7 +1649,15 @@ flush_callback (struct lwp_info *lp, void *data)
lp->status = 0;
}
- while (linux_nat_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
+ /* While there is a pending signal we would like to flush, continue
+ the inferior and collect another signal. But if there's already
+ a saved status that we don't want to flush, we can't resume the
+ inferior - if it stopped for some other reason we wouldn't have
+ anywhere to save the new status. In that case, we must leave the
+ signal unflushed (and possibly generate an extra SIGINT stop).
+ That's much less bad than losing a signal. */
+ while (lp->status == 0
+ && linux_nat_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
{
int ret;
@@ -1771,7 +1765,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,
@@ -1779,8 +1774,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;
@@ -1850,134 +1847,6 @@ resumed_callback (struct lwp_info *lp, void *data)
return lp->resumed;
}
-/* Local mourn_inferior -- we need to override mourn_inferior
- so that we can do something clever if one of several forks
- has exited. */
-
-static void
-child_mourn_inferior (void)
-{
- int status;
-
- if (! forks_exist_p ())
- {
- /* Normal case, no other forks available. */
- super_mourn_inferior ();
- return;
- }
- else
- {
- /* Multi-fork case. The current inferior_ptid has exited, but
- there are other viable forks to debug. Delete the exiting
- one and context-switch to the first available. */
- linux_fork_mourn_inferior ();
- }
-}
-
-/* We need to override child_wait to support attaching to cloned
- processes, since a normal wait (as done by the default version)
- ignores those processes. */
-
-/* Wait for child PTID to do something. Return id of the child,
- minus_one_ptid in case of error; store status into *OURSTATUS. */
-
-ptid_t
-child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
-{
- int save_errno;
- int status;
- pid_t pid;
-
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
-
- do
- {
- set_sigint_trap (); /* Causes SIGINT to be passed on to the
- attached process. */
- set_sigio_trap ();
-
- pid = my_waitpid (GET_PID (ptid), &status, 0);
- if (pid == -1 && errno == ECHILD)
- /* Try again with __WCLONE to check cloned processes. */
- pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
-
- if (debug_linux_nat)
- {
- fprintf_unfiltered (gdb_stdlog,
- "CW: waitpid %ld received %s\n",
- (long) pid, status_to_str (status));
- }
-
- save_errno = errno;
-
- /* Make sure we don't report an event for the exit of the
- original program, if we've detached from it. */
- if (pid != -1 && !WIFSTOPPED (status) && pid != GET_PID (inferior_ptid))
- {
- pid = -1;
- save_errno = EINTR;
- }
-
- /* Check for stop events reported by a process we didn't already
- know about - in this case, anything other than inferior_ptid.
-
- 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 we want to handle debugging of
- CLONE_PTRACE processes we need to do more here, i.e. switch
- to multi-threaded mode. */
- if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
- && pid != GET_PID (inferior_ptid))
- {
- linux_record_stopped_pid (pid);
- pid = -1;
- save_errno = EINTR;
- }
-
- /* Handle GNU/Linux's extended waitstatus for trace events. */
- if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
- && status >> 16 != 0)
- {
- linux_handle_extended_wait (pid, status, ourstatus);
-
- /* If we see a clone event, detach the child, and don't
- report the event. It would be nice to offer some way to
- switch into a non-thread-db based threaded mode at this
- point. */
- if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
- {
- ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0);
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- ptrace (PTRACE_CONT, pid, 0, 0);
- pid = -1;
- save_errno = EINTR;
- }
- }
-
- clear_sigio_trap ();
- clear_sigint_trap ();
- }
- while (pid == -1 && save_errno == EINTR);
-
- if (pid == -1)
- {
- warning (_("Child process unexpectedly missing: %s"),
- safe_strerror (errno));
-
- /* Claim it exited with unknown signal. */
- ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
- return minus_one_ptid;
- }
-
- if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
- store_waitstatus (ourstatus, status);
-
- return pid_to_ptid (pid);
-}
-
/* Stop an active thread, verify it still exists, then resume it. */
static int
@@ -2009,6 +1878,19 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
pid_t pid = PIDGET (ptid);
sigset_t flush_mask;
+ /* The first time we get here after starting a new inferior, we may
+ not have added it to the LWP list yet - this is the earliest
+ moment at which we know its PID. */
+ if (num_lwps == 0)
+ {
+ gdb_assert (!is_lwp (inferior_ptid));
+
+ inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+ GET_PID (inferior_ptid));
+ lp = add_lwp (inferior_ptid);
+ lp->resumed = 1;
+ }
+
sigemptyset (&flush_mask);
/* Make sure SIGCHLD is blocked. */
@@ -2020,9 +1902,8 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
retry:
- /* Make sure there is at least one LWP that has been resumed, at
- least if there are any LWPs at all. */
- gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
+ /* Make sure there is at least one LWP that has been resumed. */
+ gdb_assert (iterate_over_lwps (resumed_callback, NULL));
/* First check if there is a LWP with a wait status pending. */
if (pid == -1)
@@ -2133,7 +2014,7 @@ retry:
from waitpid before or after the event is. */
if (WIFSTOPPED (status) && !lp)
{
- linux_record_stopped_pid (lwpid);
+ linux_record_stopped_pid (lwpid, status);
status = 0;
continue;
}
@@ -2161,23 +2042,20 @@ retry:
if (options & __WCLONE)
lp->cloned = 1;
- if (threaded)
- {
- gdb_assert (WIFSTOPPED (status)
- && WSTOPSIG (status) == SIGSTOP);
- lp->signalled = 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));
+ 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. */
@@ -2187,7 +2065,7 @@ retry:
fprintf_unfiltered (gdb_stdlog,
"LLW: Handling extended status 0x%06x\n",
status);
- if (linux_nat_handle_extended (lp, status))
+ if (linux_handle_extended_wait (lp, status, 0))
{
status = 0;
continue;
@@ -2319,7 +2197,10 @@ retry:
{
int signo = target_signal_from_host (WSTOPSIG (status));
- if (signal_stop_state (signo) == 0
+ /* If we get a signal while single-stepping, we may need special
+ care, e.g. to skip the signal handler. Defer to common code. */
+ if (!lp->step
+ && signal_stop_state (signo) == 0
&& signal_print_state (signo) == 0
&& signal_pass_state (signo) == 1)
{
@@ -2379,12 +2260,9 @@ retry:
the comment in cancel_breakpoints_callback to find out why. */
iterate_over_lwps (cancel_breakpoints_callback, lp);
- /* If we're not running in "threaded" mode, we'll report the bare
- process id. */
-
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
{
- trap_ptid = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+ trap_ptid = lp->ptid;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: trap_ptid is %s.\n",
@@ -2401,7 +2279,7 @@ retry:
else
store_waitstatus (ourstatus, status);
- return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+ return lp->ptid;
}
static int
@@ -2466,20 +2344,35 @@ kill_wait_callback (struct lwp_info *lp, void *data)
static void
linux_nat_kill (void)
{
- /* Kill all LWP's ... */
- iterate_over_lwps (kill_callback, NULL);
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+ int status;
- /* ... and wait until we've flushed all events. */
- iterate_over_lwps (kill_wait_callback, NULL);
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the other task. We need to do this first because the
+ parent will be sleeping if this is a vfork. */
- target_mourn_inferior ();
-}
+ get_last_target_status (&last_ptid, &last);
-static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
- int from_tty)
-{
- linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+ if (last.kind == TARGET_WAITKIND_FORKED
+ || last.kind == TARGET_WAITKIND_VFORKED)
+ {
+ ptrace (PT_KILL, last.value.related_pid, 0, 0);
+ wait (&status);
+ }
+
+ if (forks_exist_p ())
+ linux_fork_killall ();
+ else
+ {
+ /* Kill all LWP's ... */
+ iterate_over_lwps (kill_callback, NULL);
+
+ /* ... and wait until we've flushed all events. */
+ iterate_over_lwps (kill_wait_callback, NULL);
+ }
+
+ target_mourn_inferior ();
}
static void
@@ -2494,7 +2387,14 @@ linux_nat_mourn_inferior (void)
sigprocmask (SIG_SETMASK, &normal_mask, NULL);
sigemptyset (&blocked_mask);
- linux_ops->to_mourn_inferior ();
+ if (! forks_exist_p ())
+ /* Normal case, no other forks available. */
+ linux_ops->to_mourn_inferior ();
+ else
+ /* Multi-fork case. The current inferior_ptid has exited, but
+ there are other viable forks to debug. Delete the exiting
+ one and context-switch to the first available. */
+ linux_fork_mourn_inferior ();
}
static LONGEST
@@ -2528,7 +2428,13 @@ linux_nat_thread_alive (ptid_t ptid)
"LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n",
target_pid_to_str (ptid),
errno ? safe_strerror (errno) : "OK");
- if (errno)
+
+ /* Not every Linux kernel implements PTRACE_PEEKUSER. But we can
+ handle that case gracefully since ptrace will first do a lookup
+ for the process based upon the passed-in pid. If that fails we
+ will get either -ESRCH or -EPERM, otherwise the child exists and
+ is alive. */
+ if (errno == ESRCH || errno == EPERM)
return 0;
return 1;
@@ -2539,7 +2445,7 @@ linux_nat_pid_to_str (ptid_t ptid)
{
static char buf[64];
- if (is_lwp (ptid))
+ if (lwp_list && lwp_list->next && is_lwp (ptid))
{
snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
return buf;
@@ -2548,59 +2454,6 @@ linux_nat_pid_to_str (ptid_t ptid)
return normal_pid_to_str (ptid);
}
-static void
-linux_nat_fetch_registers (int regnum)
-{
- /* to_fetch_registers will honor the LWP ID, so we can use it directly. */
- linux_ops->to_fetch_registers (regnum);
-}
-
-static void
-linux_nat_store_registers (int regnum)
-{
- /* to_store_registers will honor the LWP ID, so we can use it directly. */
- linux_ops->to_store_registers (regnum);
-}
-
-static void
-linux_nat_child_post_startup_inferior (ptid_t ptid)
-{
- linux_ops->to_post_startup_inferior (ptid);
-}
-
-static void
-init_linux_nat_ops (void)
-{
-#if 0
- linux_nat_ops.to_open = linux_nat_open;
-#endif
- linux_nat_ops.to_shortname = "lwp-layer";
- linux_nat_ops.to_longname = "lwp-layer";
- linux_nat_ops.to_doc = "Low level threads support (LWP layer)";
- linux_nat_ops.to_attach = linux_nat_attach;
- linux_nat_ops.to_detach = linux_nat_detach;
- linux_nat_ops.to_resume = linux_nat_resume;
- linux_nat_ops.to_wait = linux_nat_wait;
- linux_nat_ops.to_fetch_registers = linux_nat_fetch_registers;
- linux_nat_ops.to_store_registers = linux_nat_store_registers;
- linux_nat_ops.to_xfer_partial = linux_nat_xfer_partial;
- linux_nat_ops.to_kill = linux_nat_kill;
- linux_nat_ops.to_create_inferior = linux_nat_create_inferior;
- linux_nat_ops.to_mourn_inferior = linux_nat_mourn_inferior;
- linux_nat_ops.to_thread_alive = linux_nat_thread_alive;
- linux_nat_ops.to_pid_to_str = linux_nat_pid_to_str;
- linux_nat_ops.to_post_startup_inferior
- = linux_nat_child_post_startup_inferior;
- linux_nat_ops.to_post_attach = child_post_attach;
- linux_nat_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint;
- linux_nat_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
- linux_nat_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
-
- linux_nat_ops.to_stratum = thread_stratum;
- linux_nat_ops.to_has_thread_control = tc_schedlock;
- linux_nat_ops.to_magic = OPS_MAGIC;
-}
-
static void
sigchld_handler (int signo)
{
@@ -2612,8 +2465,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;
@@ -2702,7 +2555,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
size, paddr_nz (addr),
read ? 'r' : ' ',
write ? 'w' : ' ', exec ? 'x' : ' ');
- if (filename && filename[0])
+ if (filename[0])
fprintf_filtered (gdb_stdout, " for %s", filename);
fprintf_filtered (gdb_stdout, "\n");
}
@@ -2728,21 +2581,57 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
gdb_fpxregset_t fpxregs;
#endif
unsigned long lwp = ptid_get_lwp (ptid);
+ 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, regcache, -1,
+ &gregs, sizeof (gregs));
+ else
+ fill_gregset (regcache, &gregs, -1);
- fill_gregset (&gregs, -1);
note_data = (char *) elfcore_write_prstatus (obfd,
note_data,
note_size,
lwp,
stop_signal, &gregs);
- fill_fpregset (&fpregs, -1);
+ if (core_regset_p
+ && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
+ sizeof (fpregs))) != NULL
+ && regset->collect_regset != NULL)
+ regset->collect_regset (regset, regcache, -1,
+ &fpregs, sizeof (fpregs));
+ else
+ fill_fpregset (regcache, &fpregs, -1);
+
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
&fpregs, sizeof (fpregs));
+
#ifdef FILL_FPXREGSET
- fill_fpxregset (&fpxregs, -1);
+ if (core_regset_p
+ && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp",
+ sizeof (fpxregs))) != NULL
+ && regset->collect_regset != NULL)
+ regset->collect_regset (regset, regcache, -1,
+ &fpxregs, sizeof (fpxregs));
+ else
+ fill_fpxregset (regcache, &fpxregs, -1);
+
note_data = (char *) elfcore_write_prxfpreg (obfd,
note_data,
note_size,
@@ -2766,21 +2655,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;
}
@@ -2790,15 +2671,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
@@ -2809,7 +2686,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;
@@ -2822,9 +2701,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,
@@ -2849,7 +2737,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
note_data = thread_args.note_data;
}
- auxv_len = target_auxv_read (¤t_target, &auxv);
+ auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV,
+ NULL, &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
@@ -2940,7 +2829,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
if (cmdline_f || all)
{
sprintf (fname1, "/proc/%lld/cmdline", pid);
- if ((procfile = fopen (fname1, "r")) > 0)
+ if ((procfile = fopen (fname1, "r")) != NULL)
{
fgets (buffer, sizeof (buffer), procfile);
printf_filtered ("cmdline = '%s'\n", buffer);
@@ -2970,13 +2859,13 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
if (mappings_f || all)
{
sprintf (fname1, "/proc/%lld/maps", pid);
- if ((procfile = fopen (fname1, "r")) > 0)
+ if ((procfile = fopen (fname1, "r")) != NULL)
{
long long addr, endaddr, size, offset, inode;
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",
@@ -3002,7 +2891,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 */
@@ -3030,7 +2919,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
if (status_f || all)
{
sprintf (fname1, "/proc/%lld/status", pid);
- if ((procfile = fopen (fname1, "r")) > 0)
+ if ((procfile = fopen (fname1, "r")) != NULL)
{
while (fgets (buffer, sizeof (buffer), procfile) != NULL)
puts_filtered (buffer);
@@ -3042,14 +2931,15 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
if (stat_f || all)
{
sprintf (fname1, "/proc/%lld/stat", pid);
- if ((procfile = fopen (fname1, "r")) > 0)
+ if ((procfile = fopen (fname1, "r")) != NULL)
{
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);
@@ -3063,71 +2953,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);
}
@@ -3283,62 +3173,87 @@ 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 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_wait = child_wait;
- t->to_kill = kill_inferior;
- 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;
- super_mourn_inferior = t->to_mourn_inferior;
- t->to_mourn_inferior = child_mourn_inferior;
+ t = inf_ptrace_trad_target (register_u_offset);
+ linux_target_install_ops (t);
- linux_ops = t;
return t;
}
+void
+linux_nat_add_target (struct target_ops *t)
+{
+ /* Save the provided single-threaded target. We save this in a separate
+ variable because another target we've inherited from (e.g. inf-ptrace)
+ may have saved a pointer to T; we want to use it for the final
+ process stratum target. */
+ linux_ops_saved = *t;
+ linux_ops = &linux_ops_saved;
+
+ /* Override some methods for multithreading. */
+ t->to_attach = linux_nat_attach;
+ t->to_detach = linux_nat_detach;
+ t->to_resume = linux_nat_resume;
+ t->to_wait = linux_nat_wait;
+ t->to_xfer_partial = linux_nat_xfer_partial;
+ t->to_kill = linux_nat_kill;
+ t->to_mourn_inferior = linux_nat_mourn_inferior;
+ t->to_thread_alive = linux_nat_thread_alive;
+ t->to_pid_to_str = linux_nat_pid_to_str;
+ t->to_has_thread_control = tc_schedlock;
+
+ /* We don't change the stratum; this target will sit at
+ process_stratum and thread_db will set at thread_stratum. This
+ is a little strange, since this is a multi-threaded-capable
+ target, but we want to be on the stack below thread_db, and we
+ also want to be used for single-threaded processes. */
+
+ add_target (t);
+
+ /* TODO: Eliminate this and have libthread_db use
+ find_target_beneath. */
+ thread_db_init (t);
+}
+
void
_initialize_linux_nat (void)
{
struct sigaction action;
- extern void thread_db_init (struct target_ops *);
add_info ("proc", linux_nat_info_proc_cmd, _("\
Show /proc process information about any running process.\n\
@@ -3349,10 +3264,6 @@ Specify any of the following keywords for detailed info:\n\
status -- list a different bunch of random process info.\n\
all -- list all available /proc info."));
- init_linux_nat_ops ();
- add_target (&linux_nat_ops);
- thread_db_init (&linux_nat_ops);
-
/* Save the original signal mask. */
sigprocmask (SIG_SETMASK, NULL, &normal_mask);
@@ -3413,12 +3324,18 @@ lin_thread_get_thread_signals (sigset_t *set)
sigemptyset (set);
restart = get_signo ("__pthread_sig_restart");
+ cancel = get_signo ("__pthread_sig_cancel");
+
+ /* LinuxThreads normally uses the first two RT signals, but in some legacy
+ cases may use SIGUSR1/SIGUSR2. NPTL always uses RT signals, but does
+ not provide any way for the debugger to query the signal numbers -
+ fortunately they don't change! */
+
if (restart == 0)
- return;
+ restart = __SIGRTMIN;
- cancel = get_signo ("__pthread_sig_cancel");
if (cancel == 0)
- return;
+ cancel = __SIGRTMIN + 1;
sigaddset (set, restart);
sigaddset (set, cancel);