* linux-nat.c (linux_ops_saved): New.
(super_mourn_inferior, kill_inferior, threaded, linux_nat_ops) (child_mourn_inferior, child_wait, linux_nat_create_inferior) (linux_nat_fetch_registers, linux_nat_store_registers) (linux_nat_child_post_startup_inferior, init_linux_nat_ops): Delete. (init_lwp_list): Don't set threaded. (add_lwp): Don't modify threaded. (delete_lwp): Don't mention non-threaded mode. (linux_nat_switch_fork): New. (linux_nat_attach): Update inferior_ptid. (linux_nat_wait): Handle num_lwps == 0 at entry. Don't check threaded flag. (linux_nat_kill): Handle pending forks and saved forks. (linux_nat_mourn_inferior): Handle saved forks. (linux_nat_pid_to_str): Don't use the LWP form when there is only one thread. (linux_target): Don't set to_wait, to_kill, or to_mourn_inferior. (linux_nat_add_target): New. (_initialize_linux_nat): Don't initialize the linux native target here. * linux-nat.h (linux_nat_add_target, linux_nat_switch_fork): New prototypes. * linux-fork.c: Include "linux-nat.h". (add_fork): Update initial PID. (fork_load_infrun_state): Call linux_nat_switch_fork. * Makefile.in (linux-fork.o): Update. * alpha-linux-nat.c (_initialize_alpha_linux_nat): Use linux_nat_add_target instead of add_target. * amd64-linux-nat.c (_initialize_amd64_linux_nat): Likewise. * arm-linux-nat.c (_initialize_arm_linux_nat): Likewise. * hppa-linux-nat.c (_initialize_hppa_linux_nat): Likewise. * ia64-linux-nat.c (_initialize_ia64_linux_nat): Likewise. * i386-linux-nat.c (_initialize_i386_linux_nat): Likewise. * m32r-linux-nat.c (_initialize_m32r_linux_nat): Likewise. * m68klinux-nat.c (_initialize_m68k_linux_nat): Likewise. * mips-linux-nat.c (_initialize_mips_linux_nat): Likewise. * ppc-linux-nat.c (_initialize_ppc_linux_nat): Likewise. * s390-nat.c (_initialize_s390_nat): Likewise. * sparc-linux-nat.c (_initialize_sparc_linux_nat): Likewise. * sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Likewise.
This commit is contained in:
parent
57b126a363
commit
f973ed9c9f
@ -1,3 +1,47 @@
|
||||
2006-03-24 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* linux-nat.c (linux_ops_saved): New.
|
||||
(super_mourn_inferior, kill_inferior, threaded, linux_nat_ops)
|
||||
(child_mourn_inferior, child_wait, linux_nat_create_inferior)
|
||||
(linux_nat_fetch_registers, linux_nat_store_registers)
|
||||
(linux_nat_child_post_startup_inferior, init_linux_nat_ops): Delete.
|
||||
(init_lwp_list): Don't set threaded.
|
||||
(add_lwp): Don't modify threaded.
|
||||
(delete_lwp): Don't mention non-threaded mode.
|
||||
(linux_nat_switch_fork): New.
|
||||
(linux_nat_attach): Update inferior_ptid.
|
||||
(linux_nat_wait): Handle num_lwps == 0 at entry. Don't check
|
||||
threaded flag.
|
||||
(linux_nat_kill): Handle pending forks and saved forks.
|
||||
(linux_nat_mourn_inferior): Handle saved forks.
|
||||
(linux_nat_pid_to_str): Don't use the LWP form when there is
|
||||
only one thread.
|
||||
(linux_target): Don't set to_wait, to_kill, or to_mourn_inferior.
|
||||
(linux_nat_add_target): New.
|
||||
(_initialize_linux_nat): Don't initialize the linux native target
|
||||
here.
|
||||
* linux-nat.h (linux_nat_add_target, linux_nat_switch_fork): New
|
||||
prototypes.
|
||||
* linux-fork.c: Include "linux-nat.h".
|
||||
(add_fork): Update initial PID.
|
||||
(fork_load_infrun_state): Call linux_nat_switch_fork.
|
||||
* Makefile.in (linux-fork.o): Update.
|
||||
|
||||
* alpha-linux-nat.c (_initialize_alpha_linux_nat): Use
|
||||
linux_nat_add_target instead of add_target.
|
||||
* amd64-linux-nat.c (_initialize_amd64_linux_nat): Likewise.
|
||||
* arm-linux-nat.c (_initialize_arm_linux_nat): Likewise.
|
||||
* hppa-linux-nat.c (_initialize_hppa_linux_nat): Likewise.
|
||||
* ia64-linux-nat.c (_initialize_ia64_linux_nat): Likewise.
|
||||
* i386-linux-nat.c (_initialize_i386_linux_nat): Likewise.
|
||||
* m32r-linux-nat.c (_initialize_m32r_linux_nat): Likewise.
|
||||
* m68klinux-nat.c (_initialize_m68k_linux_nat): Likewise.
|
||||
* mips-linux-nat.c (_initialize_mips_linux_nat): Likewise.
|
||||
* ppc-linux-nat.c (_initialize_ppc_linux_nat): Likewise.
|
||||
* s390-nat.c (_initialize_s390_nat): Likewise.
|
||||
* sparc-linux-nat.c (_initialize_sparc_linux_nat): Likewise.
|
||||
* sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Likewise.
|
||||
|
||||
2006-03-24 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* linux-fork.c: Include "gdb_assert.h".
|
||||
|
@ -2190,7 +2190,8 @@ linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
|
||||
$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
|
||||
$(objc_lang_h) $(linespec_h) $(exceptions_h)
|
||||
linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
|
||||
$(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h)
|
||||
$(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
|
||||
$(linux_nat_h)
|
||||
linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
|
||||
$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
|
||||
$(gdbcmd_h) $(regcache_h) $(inf_ptrace.h) $(auxv.h) $(elf_bfd_h) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Low level Alpha GNU/Linux interface, for GDB when running native.
|
||||
Copyright (C) 2005
|
||||
Copyright (C) 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -28,5 +28,5 @@ void _initialialize_alpha_linux_nat (void);
|
||||
void
|
||||
_initialize_alpha_linux_nat (void)
|
||||
{
|
||||
add_target (linux_target ());
|
||||
linux_nat_add_target (linux_target ());
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* Native-dependent code for GNU/Linux x86-64.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by Jiri Smid, SuSE Labs.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -399,5 +400,5 @@ _initialize_amd64_linux_nat (void)
|
||||
t->to_store_registers = amd64_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* GNU/Linux on ARM native support.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -736,5 +736,5 @@ _initialize_arm_linux_nat (void)
|
||||
t->to_store_registers = arm_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Functions specific to running GDB native on HPPA running GNU/Linux.
|
||||
|
||||
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -392,5 +392,5 @@ _initialize_hppa_linux_nat (void)
|
||||
t->to_store_registers = hppa_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Native-dependent code for GNU/Linux i386.
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -844,5 +844,5 @@ _initialize_i386_linux_nat (void)
|
||||
t->to_store_registers = i386_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Functions specific to running gdb native on IA-64 running
|
||||
GNU/Linux.
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -700,5 +700,5 @@ _initialize_ia64_linux_nat (void)
|
||||
t->to_xfer_partial = ia64_linux_xfer_partial;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
#include "linux-fork.h"
|
||||
#include "linux-nat.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
@ -84,7 +85,7 @@ add_fork (pid_t pid)
|
||||
}
|
||||
|
||||
fp = XZALLOC (struct fork_info);
|
||||
fp->ptid = pid_to_ptid (pid);
|
||||
fp->ptid = ptid_build (pid, pid, 0);
|
||||
fp->num = ++highest_fork_num;
|
||||
fp->next = fork_list;
|
||||
fork_list = fp;
|
||||
@ -241,6 +242,8 @@ fork_load_infrun_state (struct fork_info *fp)
|
||||
|
||||
inferior_ptid = fp->ptid;
|
||||
|
||||
linux_nat_switch_fork (inferior_ptid);
|
||||
|
||||
if (fp->savedregs && fp->clobber_regs)
|
||||
regcache_cpy (current_regcache, fp->savedregs);
|
||||
|
||||
|
417
gdb/linux-nat.c
417
gdb/linux-nat.c
@ -88,6 +88,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 +98,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,
|
||||
@ -600,54 +597,6 @@ child_insert_exec_catchpoint (int 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 ();
|
||||
}
|
||||
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
|
||||
@ -686,9 +635,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)
|
||||
@ -701,9 +647,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
|
||||
@ -768,12 +711,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)
|
||||
@ -792,8 +733,7 @@ add_lwp (ptid_t ptid)
|
||||
|
||||
lp->next = lwp_list;
|
||||
lwp_list = lp;
|
||||
if (++num_lwps > 1)
|
||||
threaded = 1;
|
||||
++num_lwps;
|
||||
|
||||
return lp;
|
||||
}
|
||||
@ -814,8 +754,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)
|
||||
@ -867,6 +805,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
|
||||
@ -1046,7 +999,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
|
||||
@ -1848,134 +1802,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
|
||||
@ -2007,6 +1833,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. */
|
||||
@ -2018,9 +1857,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)
|
||||
@ -2159,23 +1997,20 @@ retry:
|
||||
if (options & __WCLONE)
|
||||
lp->cloned = 1;
|
||||
|
||||
if (threaded)
|
||||
gdb_assert (WIFSTOPPED (status)
|
||||
&& WSTOPSIG (status) == SIGSTOP);
|
||||
lp->signalled = 1;
|
||||
|
||||
if (!in_thread_list (inferior_ptid))
|
||||
{
|
||||
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));
|
||||
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. */
|
||||
@ -2377,12 +2212,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",
|
||||
@ -2399,7 +2231,7 @@ retry:
|
||||
else
|
||||
store_waitstatus (ourstatus, status);
|
||||
|
||||
return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
|
||||
return lp->ptid;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2464,22 +2296,37 @@ 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. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_nat_mourn_inferior (void)
|
||||
{
|
||||
@ -2492,7 +2339,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
|
||||
@ -2537,7 +2391,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;
|
||||
@ -2546,59 +2400,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)
|
||||
{
|
||||
@ -3310,8 +3111,6 @@ linux_target (void)
|
||||
#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;
|
||||
@ -3325,18 +3124,50 @@ linux_target (void)
|
||||
super_xfer_partial = t->to_xfer_partial;
|
||||
t->to_xfer_partial = linux_xfer_partial;
|
||||
|
||||
super_mourn_inferior = t->to_mourn_inferior;
|
||||
t->to_mourn_inferior = child_mourn_inferior;
|
||||
|
||||
linux_ops = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
linux_nat_add_target (struct target_ops *t)
|
||||
{
|
||||
extern void thread_db_init (struct target_ops *);
|
||||
|
||||
/* 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\
|
||||
@ -3347,10 +3178,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);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Native debugging support for GNU/Linux (LWP layer).
|
||||
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -83,3 +83,11 @@ struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *,
|
||||
/* Create a prototype generic Linux target. The client can override
|
||||
it with local methods. */
|
||||
struct target_ops * linux_target (void);
|
||||
|
||||
/* Register the customized Linux target. This should be used
|
||||
instead of calling add_target directly. */
|
||||
void linux_nat_add_target (struct target_ops *);
|
||||
|
||||
/* Update linux-nat internal state when changing from one fork
|
||||
to another. */
|
||||
void linux_nat_switch_fork (ptid_t new_ptid);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Native-dependent code for GNU/Linux m32r.
|
||||
|
||||
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -250,5 +250,5 @@ _initialize_m32r_linux_nat (void)
|
||||
t->to_store_registers = m32r_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Motorola m68k native support for GNU/Linux.
|
||||
|
||||
Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -633,7 +633,7 @@ _initialize_m68k_linux_nat (void)
|
||||
t->to_store_registers = m68k_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
|
||||
deprecated_add_core_fns (&linux_elf_core_fns);
|
||||
}
|
||||
|
@ -259,5 +259,5 @@ _initialize_mips_linux_nat (void)
|
||||
t->to_fetch_registers = mips64_linux_fetch_registers;
|
||||
t->to_store_registers = mips64_linux_store_registers;
|
||||
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1037,5 +1037,5 @@ _initialize_ppc_linux_nat (void)
|
||||
t->to_stopped_data_address = ppc_linux_stopped_data_address;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -388,5 +388,5 @@ _initialize_s390_nat (void)
|
||||
t->to_remove_watchpoint = s390_remove_watchpoint;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Native-dependent code for GNU/Linux SPARC.
|
||||
Copyright (C) 2005
|
||||
Copyright (C) 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -39,5 +39,5 @@ _initialize_sparc_linux_nat (void)
|
||||
t->to_store_registers = store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Native-dependent code for GNU/Linux UltraSPARC.
|
||||
|
||||
Copyright (C) 2003, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -57,7 +57,7 @@ _initialize_sparc64_linux_nat (void)
|
||||
t->to_store_registers = store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
linux_nat_add_target (t);
|
||||
|
||||
sparc_gregset = &sparc64_linux_ptrace_gregset;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user