4467 lines
126 KiB
C
4467 lines
126 KiB
C
/* GNU/Linux native-dependent code common to multiple platforms.
|
||
|
||
Copyright (C) 2001-2022 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 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
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, see <http://www.gnu.org/licenses/>. */
|
||
|
||
#include "defs.h"
|
||
#include "inferior.h"
|
||
#include "infrun.h"
|
||
#include "target.h"
|
||
#include "nat/linux-nat.h"
|
||
#include "nat/linux-waitpid.h"
|
||
#include "gdbsupport/gdb_wait.h"
|
||
#include <unistd.h>
|
||
#include <sys/syscall.h>
|
||
#include "nat/gdb_ptrace.h"
|
||
#include "linux-nat.h"
|
||
#include "nat/linux-ptrace.h"
|
||
#include "nat/linux-procfs.h"
|
||
#include "nat/linux-personality.h"
|
||
#include "linux-fork.h"
|
||
#include "gdbthread.h"
|
||
#include "gdbcmd.h"
|
||
#include "regcache.h"
|
||
#include "regset.h"
|
||
#include "inf-child.h"
|
||
#include "inf-ptrace.h"
|
||
#include "auxv.h"
|
||
#include <sys/procfs.h> /* for elf_gregset etc. */
|
||
#include "elf-bfd.h" /* for elfcore_write_* */
|
||
#include "gregset.h" /* for gregset */
|
||
#include "gdbcore.h" /* for get_exec_file */
|
||
#include <ctype.h> /* for isdigit */
|
||
#include <sys/stat.h> /* for struct stat */
|
||
#include <fcntl.h> /* for O_RDONLY */
|
||
#include "inf-loop.h"
|
||
#include "gdbsupport/event-loop.h"
|
||
#include "event-top.h"
|
||
#include <pwd.h>
|
||
#include <sys/types.h>
|
||
#include <dirent.h>
|
||
#include "xml-support.h"
|
||
#include <sys/vfs.h>
|
||
#include "solib.h"
|
||
#include "nat/linux-osdata.h"
|
||
#include "linux-tdep.h"
|
||
#include "symfile.h"
|
||
#include "gdbsupport/agent.h"
|
||
#include "tracepoint.h"
|
||
#include "gdbsupport/buffer.h"
|
||
#include "target-descriptions.h"
|
||
#include "gdbsupport/filestuff.h"
|
||
#include "objfiles.h"
|
||
#include "nat/linux-namespaces.h"
|
||
#include "gdbsupport/block-signals.h"
|
||
#include "gdbsupport/fileio.h"
|
||
#include "gdbsupport/scope-exit.h"
|
||
#include "gdbsupport/gdb-sigmask.h"
|
||
#include "gdbsupport/common-debug.h"
|
||
#include <unordered_map>
|
||
|
||
/* This comment documents high-level logic of this file.
|
||
|
||
Waiting for events in sync mode
|
||
===============================
|
||
|
||
When waiting for an event in a specific thread, we just use waitpid,
|
||
passing the specific pid, and not passing WNOHANG.
|
||
|
||
When waiting for an event in all threads, waitpid is not quite good:
|
||
|
||
- If the thread group leader exits while other threads in the thread
|
||
group still exist, waitpid(TGID, ...) hangs. That waitpid won't
|
||
return an exit status until the other threads in the group are
|
||
reaped.
|
||
|
||
- When a non-leader thread execs, that thread just vanishes without
|
||
reporting an exit (so we'd hang if we waited for it explicitly in
|
||
that case). The exec event is instead reported to the TGID pid.
|
||
|
||
The solution is to always use -1 and WNOHANG, together with
|
||
sigsuspend.
|
||
|
||
First, we use non-blocking waitpid to check for events. If nothing is
|
||
found, we use sigsuspend to wait for SIGCHLD. When SIGCHLD arrives,
|
||
it means something happened to a child process. As soon as we know
|
||
there's an event, we get back to calling nonblocking waitpid.
|
||
|
||
Note that SIGCHLD should be blocked between waitpid and sigsuspend
|
||
calls, so that we don't miss a signal. If SIGCHLD arrives in between,
|
||
when it's blocked, the signal becomes pending and sigsuspend
|
||
immediately notices it and returns.
|
||
|
||
Waiting for events in async mode (TARGET_WNOHANG)
|
||
=================================================
|
||
|
||
In async mode, GDB should always be ready to handle both user input
|
||
and target events, so neither blocking waitpid nor sigsuspend are
|
||
viable options. Instead, we should asynchronously notify the GDB main
|
||
event loop whenever there's an unprocessed event from the target. We
|
||
detect asynchronous target events by handling SIGCHLD signals. To
|
||
notify the event loop about target events, an event pipe is used
|
||
--- the pipe is registered as waitable event source in the event loop,
|
||
the event loop select/poll's on the read end of this pipe (as well on
|
||
other event sources, e.g., stdin), and the SIGCHLD handler marks the
|
||
event pipe to raise an event. This is more portable than relying on
|
||
pselect/ppoll, since on kernels that lack those syscalls, libc
|
||
emulates them with select/poll+sigprocmask, and that is racy
|
||
(a.k.a. plain broken).
|
||
|
||
Obviously, if we fail to notify the event loop if there's a target
|
||
event, it's bad. OTOH, if we notify the event loop when there's no
|
||
event from the target, linux_nat_wait will detect that there's no real
|
||
event to report, and return event of type TARGET_WAITKIND_IGNORE.
|
||
This is mostly harmless, but it will waste time and is better avoided.
|
||
|
||
The main design point is that every time GDB is outside linux-nat.c,
|
||
we have a SIGCHLD handler installed that is called when something
|
||
happens to the target and notifies the GDB event loop. Whenever GDB
|
||
core decides to handle the event, and calls into linux-nat.c, we
|
||
process things as in sync mode, except that the we never block in
|
||
sigsuspend.
|
||
|
||
While processing an event, we may end up momentarily blocked in
|
||
waitpid calls. Those waitpid calls, while blocking, are guarantied to
|
||
return quickly. E.g., in all-stop mode, before reporting to the core
|
||
that an LWP hit a breakpoint, all LWPs are stopped by sending them
|
||
SIGSTOP, and synchronously waiting for the SIGSTOP to be reported.
|
||
Note that this is different from blocking indefinitely waiting for the
|
||
next event --- here, we're already handling an event.
|
||
|
||
Use of signals
|
||
==============
|
||
|
||
We stop threads by sending a SIGSTOP. The use of SIGSTOP instead of another
|
||
signal is not entirely significant; we just need for a signal to be delivered,
|
||
so that we can intercept it. SIGSTOP's advantage is that it can not be
|
||
blocked. A disadvantage is that it is not a real-time signal, so it can only
|
||
be queued once; we do not keep track of other sources of SIGSTOP.
|
||
|
||
Two other signals that can't be blocked are SIGCONT and SIGKILL. But we can't
|
||
use them, because they have special behavior when the signal is generated -
|
||
not when it is delivered. SIGCONT resumes the entire thread group and SIGKILL
|
||
kills the entire thread group.
|
||
|
||
A delivered SIGSTOP would stop the entire thread group, not just the thread we
|
||
tkill'd. But we never let the SIGSTOP be delivered; we always intercept and
|
||
cancel it (by PTRACE_CONT without passing SIGSTOP).
|
||
|
||
We could use a real-time signal instead. This would solve those problems; we
|
||
could use PTRACE_GETSIGINFO to locate the specific stop signals sent by GDB.
|
||
But we would still have to have some support for SIGSTOP, since PTRACE_ATTACH
|
||
generates it, and there are races with trying to find a signal that is not
|
||
blocked.
|
||
|
||
Exec events
|
||
===========
|
||
|
||
The case of a thread group (process) with 3 or more threads, and a
|
||
thread other than the leader execs is worth detailing:
|
||
|
||
On an exec, the Linux kernel destroys all threads except the execing
|
||
one in the thread group, and resets the execing thread's tid to the
|
||
tgid. No exit notification is sent for the execing thread -- from the
|
||
ptracer's perspective, it appears as though the execing thread just
|
||
vanishes. Until we reap all other threads except the leader and the
|
||
execing thread, the leader will be zombie, and the execing thread will
|
||
be in `D (disc sleep)' state. As soon as all other threads are
|
||
reaped, the execing thread changes its tid to the tgid, and the
|
||
previous (zombie) leader vanishes, giving place to the "new"
|
||
leader. */
|
||
|
||
#ifndef O_LARGEFILE
|
||
#define O_LARGEFILE 0
|
||
#endif
|
||
|
||
struct linux_nat_target *linux_target;
|
||
|
||
/* Does the current host support PTRACE_GETREGSET? */
|
||
enum tribool have_ptrace_getregset = TRIBOOL_UNKNOWN;
|
||
|
||
/* When true, print debug messages relating to the linux native target. */
|
||
|
||
static bool debug_linux_nat;
|
||
|
||
/* Implement 'show debug linux-nat'. */
|
||
|
||
static void
|
||
show_debug_linux_nat (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
gdb_printf (file, _("Debugging of GNU/Linux native targets is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
/* Print a linux-nat debug statement. */
|
||
|
||
#define linux_nat_debug_printf(fmt, ...) \
|
||
debug_prefixed_printf_cond (debug_linux_nat, "linux-nat", fmt, ##__VA_ARGS__)
|
||
|
||
/* Print "linux-nat" enter/exit debug statements. */
|
||
|
||
#define LINUX_NAT_SCOPED_DEBUG_ENTER_EXIT \
|
||
scoped_debug_enter_exit (debug_linux_nat, "linux-nat")
|
||
|
||
struct simple_pid_list
|
||
{
|
||
int pid;
|
||
int status;
|
||
struct simple_pid_list *next;
|
||
};
|
||
static struct simple_pid_list *stopped_pids;
|
||
|
||
/* Whether target_thread_events is in effect. */
|
||
static int report_thread_events;
|
||
|
||
static int kill_lwp (int lwpid, int signo);
|
||
|
||
static int stop_callback (struct lwp_info *lp);
|
||
|
||
static void block_child_signals (sigset_t *prev_mask);
|
||
static void restore_child_signals_mask (sigset_t *prev_mask);
|
||
|
||
struct lwp_info;
|
||
static struct lwp_info *add_lwp (ptid_t ptid);
|
||
static void purge_lwp_list (int pid);
|
||
static void delete_lwp (ptid_t ptid);
|
||
static struct lwp_info *find_lwp_pid (ptid_t ptid);
|
||
|
||
static int lwp_status_pending_p (struct lwp_info *lp);
|
||
|
||
static void save_stop_reason (struct lwp_info *lp);
|
||
|
||
static void close_proc_mem_file (pid_t pid);
|
||
static void open_proc_mem_file (ptid_t ptid);
|
||
|
||
/* Return TRUE if LWP is the leader thread of the process. */
|
||
|
||
static bool
|
||
is_leader (lwp_info *lp)
|
||
{
|
||
return lp->ptid.pid () == lp->ptid.lwp ();
|
||
}
|
||
|
||
|
||
/* LWP accessors. */
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
ptid_t
|
||
ptid_of_lwp (struct lwp_info *lwp)
|
||
{
|
||
return lwp->ptid;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
void
|
||
lwp_set_arch_private_info (struct lwp_info *lwp,
|
||
struct arch_lwp_info *info)
|
||
{
|
||
lwp->arch_private = info;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
struct arch_lwp_info *
|
||
lwp_arch_private_info (struct lwp_info *lwp)
|
||
{
|
||
return lwp->arch_private;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
int
|
||
lwp_is_stopped (struct lwp_info *lwp)
|
||
{
|
||
return lwp->stopped;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
enum target_stop_reason
|
||
lwp_stop_reason (struct lwp_info *lwp)
|
||
{
|
||
return lwp->stop_reason;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
int
|
||
lwp_is_stepping (struct lwp_info *lwp)
|
||
{
|
||
return lwp->step;
|
||
}
|
||
|
||
|
||
/* 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, int status)
|
||
{
|
||
struct simple_pid_list *new_pid = XNEW (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, int *statusp)
|
||
{
|
||
struct simple_pid_list **p;
|
||
|
||
for (p = listp; *p != NULL; p = &(*p)->next)
|
||
if ((*p)->pid == pid)
|
||
{
|
||
struct simple_pid_list *next = (*p)->next;
|
||
|
||
*statusp = (*p)->status;
|
||
xfree (*p);
|
||
*p = next;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Return the ptrace options that we want to try to enable. */
|
||
|
||
static int
|
||
linux_nat_ptrace_options (int attached)
|
||
{
|
||
int options = 0;
|
||
|
||
if (!attached)
|
||
options |= PTRACE_O_EXITKILL;
|
||
|
||
options |= (PTRACE_O_TRACESYSGOOD
|
||
| PTRACE_O_TRACEVFORKDONE
|
||
| PTRACE_O_TRACEVFORK
|
||
| PTRACE_O_TRACEFORK
|
||
| PTRACE_O_TRACEEXEC);
|
||
|
||
return options;
|
||
}
|
||
|
||
/* Initialize ptrace and procfs warnings and check for supported
|
||
ptrace features given PID.
|
||
|
||
ATTACHED should be nonzero iff we attached to the inferior. */
|
||
|
||
static void
|
||
linux_init_ptrace_procfs (pid_t pid, int attached)
|
||
{
|
||
int options = linux_nat_ptrace_options (attached);
|
||
|
||
linux_enable_event_reporting (pid, options);
|
||
linux_ptrace_init_warnings ();
|
||
linux_proc_init_warnings ();
|
||
}
|
||
|
||
linux_nat_target::~linux_nat_target ()
|
||
{}
|
||
|
||
void
|
||
linux_nat_target::post_attach (int pid)
|
||
{
|
||
linux_init_ptrace_procfs (pid, 1);
|
||
}
|
||
|
||
/* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
|
||
|
||
void
|
||
linux_nat_target::post_startup_inferior (ptid_t ptid)
|
||
{
|
||
linux_init_ptrace_procfs (ptid.pid (), 0);
|
||
}
|
||
|
||
/* Return the number of known LWPs in the tgid given by PID. */
|
||
|
||
static int
|
||
num_lwps (int pid)
|
||
{
|
||
int count = 0;
|
||
|
||
for (const lwp_info *lp ATTRIBUTE_UNUSED : all_lwps ())
|
||
if (lp->ptid.pid () == pid)
|
||
count++;
|
||
|
||
return count;
|
||
}
|
||
|
||
/* Deleter for lwp_info unique_ptr specialisation. */
|
||
|
||
struct lwp_deleter
|
||
{
|
||
void operator() (struct lwp_info *lwp) const
|
||
{
|
||
delete_lwp (lwp->ptid);
|
||
}
|
||
};
|
||
|
||
/* A unique_ptr specialisation for lwp_info. */
|
||
|
||
typedef std::unique_ptr<struct lwp_info, lwp_deleter> lwp_info_up;
|
||
|
||
/* Target hook for follow_fork. */
|
||
|
||
void
|
||
linux_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
|
||
target_waitkind fork_kind, bool follow_child,
|
||
bool detach_fork)
|
||
{
|
||
inf_ptrace_target::follow_fork (child_inf, child_ptid, fork_kind,
|
||
follow_child, detach_fork);
|
||
|
||
if (!follow_child)
|
||
{
|
||
bool has_vforked = fork_kind == TARGET_WAITKIND_VFORKED;
|
||
ptid_t parent_ptid = inferior_ptid;
|
||
int parent_pid = parent_ptid.lwp ();
|
||
int child_pid = child_ptid.lwp ();
|
||
|
||
/* We're already attached to the parent, by default. */
|
||
lwp_info *child_lp = add_lwp (child_ptid);
|
||
child_lp->stopped = 1;
|
||
child_lp->last_resume_kind = resume_stop;
|
||
|
||
/* Detach new forked process? */
|
||
if (detach_fork)
|
||
{
|
||
int child_stop_signal = 0;
|
||
bool detach_child = true;
|
||
|
||
/* Move CHILD_LP into a unique_ptr and clear the source pointer
|
||
to prevent us doing anything stupid with it. */
|
||
lwp_info_up child_lp_ptr (child_lp);
|
||
child_lp = nullptr;
|
||
|
||
linux_target->low_prepare_to_resume (child_lp_ptr.get ());
|
||
|
||
/* When debugging an inferior in an architecture that supports
|
||
hardware single stepping on a kernel without commit
|
||
6580807da14c423f0d0a708108e6df6ebc8bc83d, the vfork child
|
||
process starts with the TIF_SINGLESTEP/X86_EFLAGS_TF bits
|
||
set if the parent process had them set.
|
||
To work around this, single step the child process
|
||
once before detaching to clear the flags. */
|
||
|
||
/* Note that we consult the parent's architecture instead of
|
||
the child's because there's no inferior for the child at
|
||
this point. */
|
||
if (!gdbarch_software_single_step_p (target_thread_architecture
|
||
(parent_ptid)))
|
||
{
|
||
int status;
|
||
|
||
linux_disable_event_reporting (child_pid);
|
||
if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
|
||
perror_with_name (_("Couldn't do single step"));
|
||
if (my_waitpid (child_pid, &status, 0) < 0)
|
||
perror_with_name (_("Couldn't wait vfork process"));
|
||
else
|
||
{
|
||
detach_child = WIFSTOPPED (status);
|
||
child_stop_signal = WSTOPSIG (status);
|
||
}
|
||
}
|
||
|
||
if (detach_child)
|
||
{
|
||
int signo = child_stop_signal;
|
||
|
||
if (signo != 0
|
||
&& !signal_pass_state (gdb_signal_from_host (signo)))
|
||
signo = 0;
|
||
ptrace (PTRACE_DETACH, child_pid, 0, signo);
|
||
|
||
close_proc_mem_file (child_pid);
|
||
}
|
||
}
|
||
|
||
if (has_vforked)
|
||
{
|
||
lwp_info *parent_lp = find_lwp_pid (parent_ptid);
|
||
linux_nat_debug_printf ("waiting for VFORK_DONE on %d", parent_pid);
|
||
parent_lp->stopped = 1;
|
||
|
||
/* We'll handle the VFORK_DONE event like any other
|
||
event, in target_wait. */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
struct lwp_info *child_lp;
|
||
|
||
child_lp = add_lwp (child_ptid);
|
||
child_lp->stopped = 1;
|
||
child_lp->last_resume_kind = resume_stop;
|
||
}
|
||
}
|
||
|
||
|
||
int
|
||
linux_nat_target::insert_fork_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::remove_fork_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::insert_vfork_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::remove_vfork_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::insert_exec_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::remove_exec_catchpoint (int pid)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
linux_nat_target::set_syscall_catchpoint (int pid, bool needed, int any_count,
|
||
gdb::array_view<const int> syscall_counts)
|
||
{
|
||
/* On GNU/Linux, we ignore the arguments. It means that we only
|
||
enable the syscall catchpoints, but do not disable them.
|
||
|
||
Also, we do not use the `syscall_counts' information because we do not
|
||
filter system calls here. We let GDB do the logic for us. */
|
||
return 0;
|
||
}
|
||
|
||
/* List of known LWPs, keyed by LWP PID. This speeds up the common
|
||
case of mapping a PID returned from the kernel to our corresponding
|
||
lwp_info data structure. */
|
||
static htab_t lwp_lwpid_htab;
|
||
|
||
/* Calculate a hash from a lwp_info's LWP PID. */
|
||
|
||
static hashval_t
|
||
lwp_info_hash (const void *ap)
|
||
{
|
||
const struct lwp_info *lp = (struct lwp_info *) ap;
|
||
pid_t pid = lp->ptid.lwp ();
|
||
|
||
return iterative_hash_object (pid, 0);
|
||
}
|
||
|
||
/* Equality function for the lwp_info hash table. Compares the LWP's
|
||
PID. */
|
||
|
||
static int
|
||
lwp_lwpid_htab_eq (const void *a, const void *b)
|
||
{
|
||
const struct lwp_info *entry = (const struct lwp_info *) a;
|
||
const struct lwp_info *element = (const struct lwp_info *) b;
|
||
|
||
return entry->ptid.lwp () == element->ptid.lwp ();
|
||
}
|
||
|
||
/* Create the lwp_lwpid_htab hash table. */
|
||
|
||
static void
|
||
lwp_lwpid_htab_create (void)
|
||
{
|
||
lwp_lwpid_htab = htab_create (100, lwp_info_hash, lwp_lwpid_htab_eq, NULL);
|
||
}
|
||
|
||
/* Add LP to the hash table. */
|
||
|
||
static void
|
||
lwp_lwpid_htab_add_lwp (struct lwp_info *lp)
|
||
{
|
||
void **slot;
|
||
|
||
slot = htab_find_slot (lwp_lwpid_htab, lp, INSERT);
|
||
gdb_assert (slot != NULL && *slot == NULL);
|
||
*slot = lp;
|
||
}
|
||
|
||
/* Head of doubly-linked list of known LWPs. Sorted by reverse
|
||
creation order. This order is assumed in some cases. E.g.,
|
||
reaping status after killing alls lwps of a process: the leader LWP
|
||
must be reaped last. */
|
||
|
||
static intrusive_list<lwp_info> lwp_list;
|
||
|
||
/* See linux-nat.h. */
|
||
|
||
lwp_info_range
|
||
all_lwps ()
|
||
{
|
||
return lwp_info_range (lwp_list.begin ());
|
||
}
|
||
|
||
/* See linux-nat.h. */
|
||
|
||
lwp_info_safe_range
|
||
all_lwps_safe ()
|
||
{
|
||
return lwp_info_safe_range (lwp_list.begin ());
|
||
}
|
||
|
||
/* Add LP to sorted-by-reverse-creation-order doubly-linked list. */
|
||
|
||
static void
|
||
lwp_list_add (struct lwp_info *lp)
|
||
{
|
||
lwp_list.push_front (*lp);
|
||
}
|
||
|
||
/* Remove LP from sorted-by-reverse-creation-order doubly-linked
|
||
list. */
|
||
|
||
static void
|
||
lwp_list_remove (struct lwp_info *lp)
|
||
{
|
||
/* Remove from sorted-by-creation-order list. */
|
||
lwp_list.erase (lwp_list.iterator_to (*lp));
|
||
}
|
||
|
||
|
||
|
||
/* Signal mask for use with sigsuspend in linux_nat_wait, initialized in
|
||
_initialize_linux_nat. */
|
||
static sigset_t suspend_mask;
|
||
|
||
/* Signals to block to make that sigsuspend work. */
|
||
static sigset_t blocked_mask;
|
||
|
||
/* SIGCHLD action. */
|
||
static struct sigaction sigchld_action;
|
||
|
||
/* Block child signals (SIGCHLD and linux threads signals), and store
|
||
the previous mask in PREV_MASK. */
|
||
|
||
static void
|
||
block_child_signals (sigset_t *prev_mask)
|
||
{
|
||
/* Make sure SIGCHLD is blocked. */
|
||
if (!sigismember (&blocked_mask, SIGCHLD))
|
||
sigaddset (&blocked_mask, SIGCHLD);
|
||
|
||
gdb_sigmask (SIG_BLOCK, &blocked_mask, prev_mask);
|
||
}
|
||
|
||
/* Restore child signals mask, previously returned by
|
||
block_child_signals. */
|
||
|
||
static void
|
||
restore_child_signals_mask (sigset_t *prev_mask)
|
||
{
|
||
gdb_sigmask (SIG_SETMASK, prev_mask, NULL);
|
||
}
|
||
|
||
/* Mask of signals to pass directly to the inferior. */
|
||
static sigset_t pass_mask;
|
||
|
||
/* Update signals to pass to the inferior. */
|
||
void
|
||
linux_nat_target::pass_signals
|
||
(gdb::array_view<const unsigned char> pass_signals)
|
||
{
|
||
int signo;
|
||
|
||
sigemptyset (&pass_mask);
|
||
|
||
for (signo = 1; signo < NSIG; signo++)
|
||
{
|
||
int target_signo = gdb_signal_from_host (signo);
|
||
if (target_signo < pass_signals.size () && pass_signals[target_signo])
|
||
sigaddset (&pass_mask, signo);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* Prototypes for local functions. */
|
||
static int stop_wait_callback (struct lwp_info *lp);
|
||
static int resume_stopped_resumed_lwps (struct lwp_info *lp, const ptid_t wait_ptid);
|
||
static int check_ptrace_stopped_lwp_gone (struct lwp_info *lp);
|
||
|
||
|
||
|
||
/* Destroy and free LP. */
|
||
|
||
lwp_info::~lwp_info ()
|
||
{
|
||
/* Let the arch specific bits release arch_lwp_info. */
|
||
linux_target->low_delete_thread (this->arch_private);
|
||
}
|
||
|
||
/* Traversal function for purge_lwp_list. */
|
||
|
||
static int
|
||
lwp_lwpid_htab_remove_pid (void **slot, void *info)
|
||
{
|
||
struct lwp_info *lp = (struct lwp_info *) *slot;
|
||
int pid = *(int *) info;
|
||
|
||
if (lp->ptid.pid () == pid)
|
||
{
|
||
htab_clear_slot (lwp_lwpid_htab, slot);
|
||
lwp_list_remove (lp);
|
||
delete lp;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* Remove all LWPs belong to PID from the lwp list. */
|
||
|
||
static void
|
||
purge_lwp_list (int pid)
|
||
{
|
||
htab_traverse_noresize (lwp_lwpid_htab, lwp_lwpid_htab_remove_pid, &pid);
|
||
}
|
||
|
||
/* Add the LWP specified by PTID to the list. PTID is the first LWP
|
||
in the process. Return a pointer to the structure describing the
|
||
new LWP.
|
||
|
||
This differs from add_lwp in that we don't let the arch specific
|
||
bits know about this new thread. Current clients of this callback
|
||
take the opportunity to install watchpoints in the new thread, and
|
||
we shouldn't do that for the first thread. If we're spawning a
|
||
child ("run"), the thread executes the shell wrapper first, and we
|
||
shouldn't touch it until it execs the program we want to debug.
|
||
For "attach", it'd be okay to call the callback, but it's not
|
||
necessary, because watchpoints can't yet have been inserted into
|
||
the inferior. */
|
||
|
||
static struct lwp_info *
|
||
add_initial_lwp (ptid_t ptid)
|
||
{
|
||
gdb_assert (ptid.lwp_p ());
|
||
|
||
lwp_info *lp = new lwp_info (ptid);
|
||
|
||
|
||
/* Add to sorted-by-reverse-creation-order list. */
|
||
lwp_list_add (lp);
|
||
|
||
/* Add to keyed-by-pid htab. */
|
||
lwp_lwpid_htab_add_lwp (lp);
|
||
|
||
return lp;
|
||
}
|
||
|
||
/* Add the LWP specified by PID to the list. Return a pointer to the
|
||
structure describing the new LWP. The LWP should already be
|
||
stopped. */
|
||
|
||
static struct lwp_info *
|
||
add_lwp (ptid_t ptid)
|
||
{
|
||
struct lwp_info *lp;
|
||
|
||
lp = add_initial_lwp (ptid);
|
||
|
||
/* Let the arch specific bits know about this new thread. Current
|
||
clients of this callback take the opportunity to install
|
||
watchpoints in the new thread. We don't do this for the first
|
||
thread though. See add_initial_lwp. */
|
||
linux_target->low_new_thread (lp);
|
||
|
||
return lp;
|
||
}
|
||
|
||
/* Remove the LWP specified by PID from the list. */
|
||
|
||
static void
|
||
delete_lwp (ptid_t ptid)
|
||
{
|
||
lwp_info dummy (ptid);
|
||
|
||
void **slot = htab_find_slot (lwp_lwpid_htab, &dummy, NO_INSERT);
|
||
if (slot == NULL)
|
||
return;
|
||
|
||
lwp_info *lp = *(struct lwp_info **) slot;
|
||
gdb_assert (lp != NULL);
|
||
|
||
htab_clear_slot (lwp_lwpid_htab, slot);
|
||
|
||
/* Remove from sorted-by-creation-order list. */
|
||
lwp_list_remove (lp);
|
||
|
||
/* Release. */
|
||
delete lp;
|
||
}
|
||
|
||
/* Return a pointer to the structure describing the LWP corresponding
|
||
to PID. If no corresponding LWP could be found, return NULL. */
|
||
|
||
static struct lwp_info *
|
||
find_lwp_pid (ptid_t ptid)
|
||
{
|
||
int lwp;
|
||
|
||
if (ptid.lwp_p ())
|
||
lwp = ptid.lwp ();
|
||
else
|
||
lwp = ptid.pid ();
|
||
|
||
lwp_info dummy (ptid_t (0, lwp));
|
||
return (struct lwp_info *) htab_find (lwp_lwpid_htab, &dummy);
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
struct lwp_info *
|
||
iterate_over_lwps (ptid_t filter,
|
||
gdb::function_view<iterate_over_lwps_ftype> callback)
|
||
{
|
||
for (lwp_info *lp : all_lwps_safe ())
|
||
{
|
||
if (lp->ptid.matches (filter))
|
||
{
|
||
if (callback (lp) != 0)
|
||
return lp;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/* Update our internal state when changing from one checkpoint 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;
|
||
|
||
purge_lwp_list (inferior_ptid.pid ());
|
||
|
||
lp = add_lwp (new_ptid);
|
||
lp->stopped = 1;
|
||
|
||
/* This changes the thread's ptid while preserving the gdb thread
|
||
num. Also changes the inferior pid, while preserving the
|
||
inferior num. */
|
||
thread_change_ptid (linux_target, inferior_ptid, new_ptid);
|
||
|
||
/* We've just told GDB core that the thread changed target id, but,
|
||
in fact, it really is a different thread, with different register
|
||
contents. */
|
||
registers_changed ();
|
||
}
|
||
|
||
/* Handle the exit of a single thread LP. */
|
||
|
||
static void
|
||
exit_lwp (struct lwp_info *lp)
|
||
{
|
||
struct thread_info *th = find_thread_ptid (linux_target, lp->ptid);
|
||
|
||
if (th)
|
||
{
|
||
if (print_thread_events)
|
||
gdb_printf (_("[%s exited]\n"),
|
||
target_pid_to_str (lp->ptid).c_str ());
|
||
|
||
delete_thread (th);
|
||
}
|
||
|
||
delete_lwp (lp->ptid);
|
||
}
|
||
|
||
/* Wait for the LWP specified by LP, which we have just attached to.
|
||
Returns a wait status for that LWP, to cache. */
|
||
|
||
static int
|
||
linux_nat_post_attach_wait (ptid_t ptid, int *signalled)
|
||
{
|
||
pid_t new_pid, pid = ptid.lwp ();
|
||
int status;
|
||
|
||
if (linux_proc_pid_is_stopped (pid))
|
||
{
|
||
linux_nat_debug_printf ("Attaching to a stopped process");
|
||
|
||
/* The process is definitely stopped. It is in a job control
|
||
stop, unless the kernel predates the TASK_STOPPED /
|
||
TASK_TRACED distinction, in which case it might be in a
|
||
ptrace stop. Make sure it is in a ptrace stop; from there we
|
||
can kill it, signal it, et cetera.
|
||
|
||
First make sure there is a pending SIGSTOP. Since we are
|
||
already attached, the process can not transition from stopped
|
||
to running without a PTRACE_CONT; so we know this signal will
|
||
go into the queue. The SIGSTOP generated by PTRACE_ATTACH is
|
||
probably already in the queue (unless this kernel is old
|
||
enough to use TASK_STOPPED for ptrace stops); but since SIGSTOP
|
||
is not an RT signal, it can only be queued once. */
|
||
kill_lwp (pid, SIGSTOP);
|
||
|
||
/* Finally, resume the stopped process. This will deliver the SIGSTOP
|
||
(or a higher priority signal, just like normal PTRACE_ATTACH). */
|
||
ptrace (PTRACE_CONT, pid, 0, 0);
|
||
}
|
||
|
||
/* 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. */
|
||
new_pid = my_waitpid (pid, &status, __WALL);
|
||
gdb_assert (pid == new_pid);
|
||
|
||
if (!WIFSTOPPED (status))
|
||
{
|
||
/* The pid we tried to attach has apparently just exited. */
|
||
linux_nat_debug_printf ("Failed to stop %d: %s", pid,
|
||
status_to_str (status).c_str ());
|
||
return status;
|
||
}
|
||
|
||
if (WSTOPSIG (status) != SIGSTOP)
|
||
{
|
||
*signalled = 1;
|
||
linux_nat_debug_printf ("Received %s after attaching",
|
||
status_to_str (status).c_str ());
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
void
|
||
linux_nat_target::create_inferior (const char *exec_file,
|
||
const std::string &allargs,
|
||
char **env, int from_tty)
|
||
{
|
||
maybe_disable_address_space_randomization restore_personality
|
||
(disable_randomization);
|
||
|
||
/* The fork_child mechanism is synchronous and calls target_wait, so
|
||
we have to mask the async mode. */
|
||
|
||
/* Make sure we report all signals during startup. */
|
||
pass_signals ({});
|
||
|
||
inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty);
|
||
|
||
open_proc_mem_file (inferior_ptid);
|
||
}
|
||
|
||
/* Callback for linux_proc_attach_tgid_threads. Attach to PTID if not
|
||
already attached. Returns true if a new LWP is found, false
|
||
otherwise. */
|
||
|
||
static int
|
||
attach_proc_task_lwp_callback (ptid_t ptid)
|
||
{
|
||
struct lwp_info *lp;
|
||
|
||
/* Ignore LWPs we're already attached to. */
|
||
lp = find_lwp_pid (ptid);
|
||
if (lp == NULL)
|
||
{
|
||
int lwpid = ptid.lwp ();
|
||
|
||
if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
|
||
{
|
||
int err = errno;
|
||
|
||
/* Be quiet if we simply raced with the thread exiting.
|
||
EPERM is returned if the thread's task still exists, and
|
||
is marked as exited or zombie, as well as other
|
||
conditions, so in that case, confirm the status in
|
||
/proc/PID/status. */
|
||
if (err == ESRCH
|
||
|| (err == EPERM && linux_proc_pid_is_gone (lwpid)))
|
||
{
|
||
linux_nat_debug_printf
|
||
("Cannot attach to lwp %d: thread is gone (%d: %s)",
|
||
lwpid, err, safe_strerror (err));
|
||
|
||
}
|
||
else
|
||
{
|
||
std::string reason
|
||
= linux_ptrace_attach_fail_reason_string (ptid, err);
|
||
|
||
warning (_("Cannot attach to lwp %d: %s"),
|
||
lwpid, reason.c_str ());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
linux_nat_debug_printf ("PTRACE_ATTACH %s, 0, 0 (OK)",
|
||
ptid.to_string ().c_str ());
|
||
|
||
lp = add_lwp (ptid);
|
||
|
||
/* The next time we wait for this LWP we'll see a SIGSTOP as
|
||
PTRACE_ATTACH brings it to a halt. */
|
||
lp->signalled = 1;
|
||
|
||
/* We need to wait for a stop before being able to make the
|
||
next ptrace call on this LWP. */
|
||
lp->must_set_ptrace_flags = 1;
|
||
|
||
/* So that wait collects the SIGSTOP. */
|
||
lp->resumed = 1;
|
||
|
||
/* Also add the LWP to gdb's thread list, in case a
|
||
matching libthread_db is not found (or the process uses
|
||
raw clone). */
|
||
add_thread (linux_target, lp->ptid);
|
||
set_running (linux_target, lp->ptid, true);
|
||
set_executing (linux_target, lp->ptid, true);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
linux_nat_target::attach (const char *args, int from_tty)
|
||
{
|
||
struct lwp_info *lp;
|
||
int status;
|
||
ptid_t ptid;
|
||
|
||
/* Make sure we report all signals during attach. */
|
||
pass_signals ({});
|
||
|
||
try
|
||
{
|
||
inf_ptrace_target::attach (args, from_tty);
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
pid_t pid = parse_pid_to_attach (args);
|
||
std::string reason = linux_ptrace_attach_fail_reason (pid);
|
||
|
||
if (!reason.empty ())
|
||
throw_error (ex.error, "warning: %s\n%s", reason.c_str (),
|
||
ex.what ());
|
||
else
|
||
throw_error (ex.error, "%s", ex.what ());
|
||
}
|
||
|
||
/* The ptrace base target adds the main thread with (pid,0,0)
|
||
format. Decorate it with lwp info. */
|
||
ptid = ptid_t (inferior_ptid.pid (),
|
||
inferior_ptid.pid ());
|
||
thread_change_ptid (linux_target, inferior_ptid, ptid);
|
||
|
||
/* Add the initial process as the first LWP to the list. */
|
||
lp = add_initial_lwp (ptid);
|
||
|
||
status = linux_nat_post_attach_wait (lp->ptid, &lp->signalled);
|
||
if (!WIFSTOPPED (status))
|
||
{
|
||
if (WIFEXITED (status))
|
||
{
|
||
int exit_code = WEXITSTATUS (status);
|
||
|
||
target_terminal::ours ();
|
||
target_mourn_inferior (inferior_ptid);
|
||
if (exit_code == 0)
|
||
error (_("Unable to attach: program exited normally."));
|
||
else
|
||
error (_("Unable to attach: program exited with code %d."),
|
||
exit_code);
|
||
}
|
||
else if (WIFSIGNALED (status))
|
||
{
|
||
enum gdb_signal signo;
|
||
|
||
target_terminal::ours ();
|
||
target_mourn_inferior (inferior_ptid);
|
||
|
||
signo = gdb_signal_from_host (WTERMSIG (status));
|
||
error (_("Unable to attach: program terminated with signal "
|
||
"%s, %s."),
|
||
gdb_signal_to_name (signo),
|
||
gdb_signal_to_string (signo));
|
||
}
|
||
|
||
internal_error (__FILE__, __LINE__,
|
||
_("unexpected status %d for PID %ld"),
|
||
status, (long) ptid.lwp ());
|
||
}
|
||
|
||
lp->stopped = 1;
|
||
|
||
open_proc_mem_file (lp->ptid);
|
||
|
||
/* Save the wait status to report later. */
|
||
lp->resumed = 1;
|
||
linux_nat_debug_printf ("waitpid %ld, saving status %s",
|
||
(long) lp->ptid.pid (),
|
||
status_to_str (status).c_str ());
|
||
|
||
lp->status = status;
|
||
|
||
/* We must attach to every LWP. If /proc is mounted, use that to
|
||
find them now. The inferior may be using raw clone instead of
|
||
using pthreads. But even if it is using pthreads, thread_db
|
||
walks structures in the inferior's address space to find the list
|
||
of threads/LWPs, and those structures may well be corrupted.
|
||
Note that once thread_db is loaded, we'll still use it to list
|
||
threads and associate pthread info with each LWP. */
|
||
linux_proc_attach_tgid_threads (lp->ptid.pid (),
|
||
attach_proc_task_lwp_callback);
|
||
}
|
||
|
||
/* Ptrace-detach the thread with pid PID. */
|
||
|
||
static void
|
||
detach_one_pid (int pid, int signo)
|
||
{
|
||
if (ptrace (PTRACE_DETACH, pid, 0, signo) < 0)
|
||
{
|
||
int save_errno = errno;
|
||
|
||
/* We know the thread exists, so ESRCH must mean the lwp is
|
||
zombie. This can happen if one of the already-detached
|
||
threads exits the whole thread group. In that case we're
|
||
still attached, and must reap the lwp. */
|
||
if (save_errno == ESRCH)
|
||
{
|
||
int ret, status;
|
||
|
||
ret = my_waitpid (pid, &status, __WALL);
|
||
if (ret == -1)
|
||
{
|
||
warning (_("Couldn't reap LWP %d while detaching: %s"),
|
||
pid, safe_strerror (errno));
|
||
}
|
||
else if (!WIFEXITED (status) && !WIFSIGNALED (status))
|
||
{
|
||
warning (_("Reaping LWP %d while detaching "
|
||
"returned unexpected status 0x%x"),
|
||
pid, status);
|
||
}
|
||
}
|
||
else
|
||
error (_("Can't detach %d: %s"),
|
||
pid, safe_strerror (save_errno));
|
||
}
|
||
else
|
||
linux_nat_debug_printf ("PTRACE_DETACH (%d, %s, 0) (OK)",
|
||
pid, strsignal (signo));
|
||
}
|
||
|
||
/* Get pending signal of THREAD as a host signal number, for detaching
|
||
purposes. This is the signal the thread last stopped for, which we
|
||
need to deliver to the thread when detaching, otherwise, it'd be
|
||
suppressed/lost. */
|
||
|
||
static int
|
||
get_detach_signal (struct lwp_info *lp)
|
||
{
|
||
enum gdb_signal signo = GDB_SIGNAL_0;
|
||
|
||
/* If we paused threads momentarily, we may have stored pending
|
||
events in lp->status or lp->waitstatus (see stop_wait_callback),
|
||
and GDB core hasn't seen any signal for those threads.
|
||
Otherwise, the last signal reported to the core is found in the
|
||
thread object's stop_signal.
|
||
|
||
There's a corner case that isn't handled here at present. Only
|
||
if the thread stopped with a TARGET_WAITKIND_STOPPED does
|
||
stop_signal make sense as a real signal to pass to the inferior.
|
||
Some catchpoint related events, like
|
||
TARGET_WAITKIND_(V)FORK|EXEC|SYSCALL, have their stop_signal set
|
||
to GDB_SIGNAL_SIGTRAP when the catchpoint triggers. But,
|
||
those traps are debug API (ptrace in our case) related and
|
||
induced; the inferior wouldn't see them if it wasn't being
|
||
traced. Hence, we should never pass them to the inferior, even
|
||
when set to pass state. Since this corner case isn't handled by
|
||
infrun.c when proceeding with a signal, for consistency, neither
|
||
do we handle it here (or elsewhere in the file we check for
|
||
signal pass state). Normally SIGTRAP isn't set to pass state, so
|
||
this is really a corner case. */
|
||
|
||
if (lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
|
||
signo = GDB_SIGNAL_0; /* a pending ptrace event, not a real signal. */
|
||
else if (lp->status)
|
||
signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
||
else
|
||
{
|
||
struct thread_info *tp = find_thread_ptid (linux_target, lp->ptid);
|
||
|
||
if (target_is_non_stop_p () && !tp->executing ())
|
||
{
|
||
if (tp->has_pending_waitstatus ())
|
||
{
|
||
/* If the thread has a pending event, and it was stopped with a
|
||
signal, use that signal to resume it. If it has a pending
|
||
event of another kind, it was not stopped with a signal, so
|
||
resume it without a signal. */
|
||
if (tp->pending_waitstatus ().kind () == TARGET_WAITKIND_STOPPED)
|
||
signo = tp->pending_waitstatus ().sig ();
|
||
else
|
||
signo = GDB_SIGNAL_0;
|
||
}
|
||
else
|
||
signo = tp->stop_signal ();
|
||
}
|
||
else if (!target_is_non_stop_p ())
|
||
{
|
||
ptid_t last_ptid;
|
||
process_stratum_target *last_target;
|
||
|
||
get_last_target_status (&last_target, &last_ptid, nullptr);
|
||
|
||
if (last_target == linux_target
|
||
&& lp->ptid.lwp () == last_ptid.lwp ())
|
||
signo = tp->stop_signal ();
|
||
}
|
||
}
|
||
|
||
if (signo == GDB_SIGNAL_0)
|
||
{
|
||
linux_nat_debug_printf ("lwp %s has no pending signal",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else if (!signal_pass_state (signo))
|
||
{
|
||
linux_nat_debug_printf
|
||
("lwp %s had signal %s but it is in no pass state",
|
||
lp->ptid.to_string ().c_str (), gdb_signal_to_string (signo));
|
||
}
|
||
else
|
||
{
|
||
linux_nat_debug_printf ("lwp %s has pending signal %s",
|
||
lp->ptid.to_string ().c_str (),
|
||
gdb_signal_to_string (signo));
|
||
|
||
return gdb_signal_to_host (signo);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Detach from LP. If SIGNO_P is non-NULL, then it points to the
|
||
signal number that should be passed to the LWP when detaching.
|
||
Otherwise pass any pending signal the LWP may have, if any. */
|
||
|
||
static void
|
||
detach_one_lwp (struct lwp_info *lp, int *signo_p)
|
||
{
|
||
int lwpid = lp->ptid.lwp ();
|
||
int signo;
|
||
|
||
gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
|
||
|
||
/* If the lwp/thread we are about to detach has a pending fork event,
|
||
there is a process GDB is attached to that the core of GDB doesn't know
|
||
about. Detach from it. */
|
||
|
||
/* Check in lwp_info::status. */
|
||
if (WIFSTOPPED (lp->status) && linux_is_extended_waitstatus (lp->status))
|
||
{
|
||
int event = linux_ptrace_get_extended_event (lp->status);
|
||
|
||
if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
|
||
{
|
||
unsigned long child_pid;
|
||
int ret = ptrace (PTRACE_GETEVENTMSG, lp->ptid.lwp (), 0, &child_pid);
|
||
if (ret == 0)
|
||
detach_one_pid (child_pid, 0);
|
||
else
|
||
perror_warning_with_name (_("Failed to detach fork child"));
|
||
}
|
||
}
|
||
|
||
/* Check in lwp_info::waitstatus. */
|
||
if (lp->waitstatus.kind () == TARGET_WAITKIND_VFORKED
|
||
|| lp->waitstatus.kind () == TARGET_WAITKIND_FORKED)
|
||
detach_one_pid (lp->waitstatus.child_ptid ().pid (), 0);
|
||
|
||
|
||
/* Check in thread_info::pending_waitstatus. */
|
||
thread_info *tp = find_thread_ptid (linux_target, lp->ptid);
|
||
if (tp->has_pending_waitstatus ())
|
||
{
|
||
const target_waitstatus &ws = tp->pending_waitstatus ();
|
||
|
||
if (ws.kind () == TARGET_WAITKIND_VFORKED
|
||
|| ws.kind () == TARGET_WAITKIND_FORKED)
|
||
detach_one_pid (ws.child_ptid ().pid (), 0);
|
||
}
|
||
|
||
/* Check in thread_info::pending_follow. */
|
||
if (tp->pending_follow.kind () == TARGET_WAITKIND_VFORKED
|
||
|| tp->pending_follow.kind () == TARGET_WAITKIND_FORKED)
|
||
detach_one_pid (tp->pending_follow.child_ptid ().pid (), 0);
|
||
|
||
if (lp->status != 0)
|
||
linux_nat_debug_printf ("Pending %s for %s on detach.",
|
||
strsignal (WSTOPSIG (lp->status)),
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* If there is a pending SIGSTOP, get rid of it. */
|
||
if (lp->signalled)
|
||
{
|
||
linux_nat_debug_printf ("Sending SIGCONT to %s",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
kill_lwp (lwpid, SIGCONT);
|
||
lp->signalled = 0;
|
||
}
|
||
|
||
if (signo_p == NULL)
|
||
{
|
||
/* Pass on any pending signal for this LWP. */
|
||
signo = get_detach_signal (lp);
|
||
}
|
||
else
|
||
signo = *signo_p;
|
||
|
||
/* Preparing to resume may try to write registers, and fail if the
|
||
lwp is zombie. If that happens, ignore the error. We'll handle
|
||
it below, when detach fails with ESRCH. */
|
||
try
|
||
{
|
||
linux_target->low_prepare_to_resume (lp);
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
if (!check_ptrace_stopped_lwp_gone (lp))
|
||
throw;
|
||
}
|
||
|
||
detach_one_pid (lwpid, signo);
|
||
|
||
delete_lwp (lp->ptid);
|
||
}
|
||
|
||
static int
|
||
detach_callback (struct lwp_info *lp)
|
||
{
|
||
/* We don't actually detach from the thread group leader just yet.
|
||
If the thread group exits, we must reap the zombie clone lwps
|
||
before we're able to reap the leader. */
|
||
if (lp->ptid.lwp () != lp->ptid.pid ())
|
||
detach_one_lwp (lp, NULL);
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
linux_nat_target::detach (inferior *inf, int from_tty)
|
||
{
|
||
struct lwp_info *main_lwp;
|
||
int pid = inf->pid;
|
||
|
||
/* Don't unregister from the event loop, as there may be other
|
||
inferiors running. */
|
||
|
||
/* Stop all threads before detaching. ptrace requires that the
|
||
thread is stopped to successfully detach. */
|
||
iterate_over_lwps (ptid_t (pid), stop_callback);
|
||
/* ... and wait until all of them have reported back that
|
||
they're no longer running. */
|
||
iterate_over_lwps (ptid_t (pid), stop_wait_callback);
|
||
|
||
/* We can now safely remove breakpoints. We don't this in earlier
|
||
in common code because this target doesn't currently support
|
||
writing memory while the inferior is running. */
|
||
remove_breakpoints_inf (current_inferior ());
|
||
|
||
iterate_over_lwps (ptid_t (pid), detach_callback);
|
||
|
||
/* Only the initial process should be left right now. */
|
||
gdb_assert (num_lwps (pid) == 1);
|
||
|
||
main_lwp = find_lwp_pid (ptid_t (pid));
|
||
|
||
if (forks_exist_p ())
|
||
{
|
||
/* Multi-fork case. The current inferior_ptid is being detached
|
||
from, but there are other viable forks to debug. Detach from
|
||
the current fork, and context-switch to the first
|
||
available. */
|
||
linux_fork_detach (from_tty);
|
||
}
|
||
else
|
||
{
|
||
target_announce_detach (from_tty);
|
||
|
||
/* Pass on any pending signal for the last LWP. */
|
||
int signo = get_detach_signal (main_lwp);
|
||
|
||
detach_one_lwp (main_lwp, &signo);
|
||
|
||
detach_success (inf);
|
||
}
|
||
|
||
close_proc_mem_file (pid);
|
||
}
|
||
|
||
/* Resume execution of the inferior process. If STEP is nonzero,
|
||
single-step it. If SIGNAL is nonzero, give it that signal. */
|
||
|
||
static void
|
||
linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
|
||
enum gdb_signal signo)
|
||
{
|
||
lp->step = step;
|
||
|
||
/* stop_pc doubles as the PC the LWP had when it was last resumed.
|
||
We only presently need that if the LWP is stepped though (to
|
||
handle the case of stepping a breakpoint instruction). */
|
||
if (step)
|
||
{
|
||
struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
|
||
|
||
lp->stop_pc = regcache_read_pc (regcache);
|
||
}
|
||
else
|
||
lp->stop_pc = 0;
|
||
|
||
linux_target->low_prepare_to_resume (lp);
|
||
linux_target->low_resume (lp->ptid, step, signo);
|
||
|
||
/* Successfully resumed. Clear state that no longer makes sense,
|
||
and mark the LWP as running. Must not do this before resuming
|
||
otherwise if that fails other code will be confused. E.g., we'd
|
||
later try to stop the LWP and hang forever waiting for a stop
|
||
status. Note that we must not throw after this is cleared,
|
||
otherwise handle_zombie_lwp_error would get confused. */
|
||
lp->stopped = 0;
|
||
lp->core = -1;
|
||
lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
|
||
registers_changed_ptid (linux_target, lp->ptid);
|
||
}
|
||
|
||
/* Called when we try to resume a stopped LWP and that errors out. If
|
||
the LWP is no longer in ptrace-stopped state (meaning it's zombie,
|
||
or about to become), discard the error, clear any pending status
|
||
the LWP may have, and return true (we'll collect the exit status
|
||
soon enough). Otherwise, return false. */
|
||
|
||
static int
|
||
check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
|
||
{
|
||
/* If we get an error after resuming the LWP successfully, we'd
|
||
confuse !T state for the LWP being gone. */
|
||
gdb_assert (lp->stopped);
|
||
|
||
/* We can't just check whether the LWP is in 'Z (Zombie)' state,
|
||
because even if ptrace failed with ESRCH, the tracee may be "not
|
||
yet fully dead", but already refusing ptrace requests. In that
|
||
case the tracee has 'R (Running)' state for a little bit
|
||
(observed in Linux 3.18). See also the note on ESRCH in the
|
||
ptrace(2) man page. Instead, check whether the LWP has any state
|
||
other than ptrace-stopped. */
|
||
|
||
/* Don't assume anything if /proc/PID/status can't be read. */
|
||
if (linux_proc_pid_is_trace_stopped_nowarn (lp->ptid.lwp ()) == 0)
|
||
{
|
||
lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
|
||
lp->status = 0;
|
||
lp->waitstatus.set_ignore ();
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
|
||
disappears while we try to resume it. */
|
||
|
||
static void
|
||
linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
|
||
{
|
||
try
|
||
{
|
||
linux_resume_one_lwp_throw (lp, step, signo);
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
if (!check_ptrace_stopped_lwp_gone (lp))
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/* Resume LP. */
|
||
|
||
static void
|
||
resume_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
|
||
{
|
||
if (lp->stopped)
|
||
{
|
||
struct inferior *inf = find_inferior_ptid (linux_target, lp->ptid);
|
||
|
||
if (inf->vfork_child != NULL)
|
||
{
|
||
linux_nat_debug_printf ("Not resuming %s (vfork parent)",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else if (!lwp_status_pending_p (lp))
|
||
{
|
||
linux_nat_debug_printf ("Resuming sibling %s, %s, %s",
|
||
lp->ptid.to_string ().c_str (),
|
||
(signo != GDB_SIGNAL_0
|
||
? strsignal (gdb_signal_to_host (signo))
|
||
: "0"),
|
||
step ? "step" : "resume");
|
||
|
||
linux_resume_one_lwp (lp, step, signo);
|
||
}
|
||
else
|
||
{
|
||
linux_nat_debug_printf ("Not resuming sibling %s (has pending)",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
}
|
||
else
|
||
linux_nat_debug_printf ("Not resuming sibling %s (not stopped)",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
|
||
/* Callback for iterate_over_lwps. If LWP is EXCEPT, do nothing.
|
||
Resume LWP with the last stop signal, if it is in pass state. */
|
||
|
||
static int
|
||
linux_nat_resume_callback (struct lwp_info *lp, struct lwp_info *except)
|
||
{
|
||
enum gdb_signal signo = GDB_SIGNAL_0;
|
||
|
||
if (lp == except)
|
||
return 0;
|
||
|
||
if (lp->stopped)
|
||
{
|
||
struct thread_info *thread;
|
||
|
||
thread = find_thread_ptid (linux_target, lp->ptid);
|
||
if (thread != NULL)
|
||
{
|
||
signo = thread->stop_signal ();
|
||
thread->set_stop_signal (GDB_SIGNAL_0);
|
||
}
|
||
}
|
||
|
||
resume_lwp (lp, 0, signo);
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
resume_clear_callback (struct lwp_info *lp)
|
||
{
|
||
lp->resumed = 0;
|
||
lp->last_resume_kind = resume_stop;
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
resume_set_callback (struct lwp_info *lp)
|
||
{
|
||
lp->resumed = 1;
|
||
lp->last_resume_kind = resume_continue;
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
linux_nat_target::resume (ptid_t scope_ptid, int step, enum gdb_signal signo)
|
||
{
|
||
struct lwp_info *lp;
|
||
|
||
linux_nat_debug_printf ("Preparing to %s %s, %s, inferior_ptid %s",
|
||
step ? "step" : "resume",
|
||
scope_ptid.to_string ().c_str (),
|
||
(signo != GDB_SIGNAL_0
|
||
? strsignal (gdb_signal_to_host (signo)) : "0"),
|
||
inferior_ptid.to_string ().c_str ());
|
||
|
||
/* Mark the lwps we're resuming as resumed and update their
|
||
last_resume_kind to resume_continue. */
|
||
iterate_over_lwps (scope_ptid, resume_set_callback);
|
||
|
||
lp = find_lwp_pid (inferior_ptid);
|
||
gdb_assert (lp != NULL);
|
||
|
||
/* Remember if we're stepping. */
|
||
lp->last_resume_kind = step ? resume_step : resume_continue;
|
||
|
||
/* 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 (lp->status && WIFSTOPPED (lp->status))
|
||
{
|
||
if (!lp->step
|
||
&& WSTOPSIG (lp->status)
|
||
&& sigismember (&pass_mask, WSTOPSIG (lp->status)))
|
||
{
|
||
linux_nat_debug_printf
|
||
("Not short circuiting for ignored status 0x%x", lp->status);
|
||
|
||
/* FIXME: What should we do if we are supposed to continue
|
||
this thread with a signal? */
|
||
gdb_assert (signo == GDB_SIGNAL_0);
|
||
signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
||
lp->status = 0;
|
||
}
|
||
}
|
||
|
||
if (lwp_status_pending_p (lp))
|
||
{
|
||
/* FIXME: What should we do if we are supposed to continue
|
||
this thread with a signal? */
|
||
gdb_assert (signo == GDB_SIGNAL_0);
|
||
|
||
linux_nat_debug_printf ("Short circuiting for status 0x%x",
|
||
lp->status);
|
||
|
||
if (target_can_async_p ())
|
||
{
|
||
target_async (1);
|
||
/* Tell the event loop we have something to process. */
|
||
async_file_mark ();
|
||
}
|
||
return;
|
||
}
|
||
|
||
/* No use iterating unless we're resuming other threads. */
|
||
if (scope_ptid != lp->ptid)
|
||
iterate_over_lwps (scope_ptid, [=] (struct lwp_info *info)
|
||
{
|
||
return linux_nat_resume_callback (info, lp);
|
||
});
|
||
|
||
linux_nat_debug_printf ("%s %s, %s (resume event thread)",
|
||
step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
||
lp->ptid.to_string ().c_str (),
|
||
(signo != GDB_SIGNAL_0
|
||
? strsignal (gdb_signal_to_host (signo)) : "0"));
|
||
|
||
linux_resume_one_lwp (lp, step, signo);
|
||
}
|
||
|
||
/* Send a signal to an LWP. */
|
||
|
||
static int
|
||
kill_lwp (int lwpid, int signo)
|
||
{
|
||
int ret;
|
||
|
||
errno = 0;
|
||
ret = syscall (__NR_tkill, lwpid, signo);
|
||
if (errno == ENOSYS)
|
||
{
|
||
/* If tkill fails, then we are not using nptl threads, a
|
||
configuration we no longer support. */
|
||
perror_with_name (("tkill"));
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/* Handle a GNU/Linux syscall trap wait response. If we see a syscall
|
||
event, check if the core is interested in it: if not, ignore the
|
||
event, and keep waiting; otherwise, we need to toggle the LWP's
|
||
syscall entry/exit status, since the ptrace event itself doesn't
|
||
indicate it, and report the trap to higher layers. */
|
||
|
||
static int
|
||
linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
|
||
{
|
||
struct target_waitstatus *ourstatus = &lp->waitstatus;
|
||
struct gdbarch *gdbarch = target_thread_architecture (lp->ptid);
|
||
thread_info *thread = find_thread_ptid (linux_target, lp->ptid);
|
||
int syscall_number = (int) gdbarch_get_syscall_number (gdbarch, thread);
|
||
|
||
if (stopping)
|
||
{
|
||
/* If we're stopping threads, there's a SIGSTOP pending, which
|
||
makes it so that the LWP reports an immediate syscall return,
|
||
followed by the SIGSTOP. Skip seeing that "return" using
|
||
PTRACE_CONT directly, and let stop_wait_callback collect the
|
||
SIGSTOP. Later when the thread is resumed, a new syscall
|
||
entry event. If we didn't do this (and returned 0), we'd
|
||
leave a syscall entry pending, and our caller, by using
|
||
PTRACE_CONT to collect the SIGSTOP, skips the syscall return
|
||
itself. Later, when the user re-resumes this LWP, we'd see
|
||
another syscall entry event and we'd mistake it for a return.
|
||
|
||
If stop_wait_callback didn't force the SIGSTOP out of the LWP
|
||
(leaving immediately with LWP->signalled set, without issuing
|
||
a PTRACE_CONT), it would still be problematic to leave this
|
||
syscall enter pending, as later when the thread is resumed,
|
||
it would then see the same syscall exit mentioned above,
|
||
followed by the delayed SIGSTOP, while the syscall didn't
|
||
actually get to execute. It seems it would be even more
|
||
confusing to the user. */
|
||
|
||
linux_nat_debug_printf
|
||
("ignoring syscall %d for LWP %ld (stopping threads), resuming with "
|
||
"PTRACE_CONT for SIGSTOP", syscall_number, lp->ptid.lwp ());
|
||
|
||
lp->syscall_state = TARGET_WAITKIND_IGNORE;
|
||
ptrace (PTRACE_CONT, lp->ptid.lwp (), 0, 0);
|
||
lp->stopped = 0;
|
||
return 1;
|
||
}
|
||
|
||
/* Always update the entry/return state, even if this particular
|
||
syscall isn't interesting to the core now. In async mode,
|
||
the user could install a new catchpoint for this syscall
|
||
between syscall enter/return, and we'll need to know to
|
||
report a syscall return if that happens. */
|
||
lp->syscall_state = (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY
|
||
? TARGET_WAITKIND_SYSCALL_RETURN
|
||
: TARGET_WAITKIND_SYSCALL_ENTRY);
|
||
|
||
if (catch_syscall_enabled ())
|
||
{
|
||
if (catching_syscall_number (syscall_number))
|
||
{
|
||
/* Alright, an event to report. */
|
||
if (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
|
||
ourstatus->set_syscall_entry (syscall_number);
|
||
else if (lp->syscall_state == TARGET_WAITKIND_SYSCALL_RETURN)
|
||
ourstatus->set_syscall_return (syscall_number);
|
||
else
|
||
gdb_assert_not_reached ("unexpected syscall state");
|
||
|
||
linux_nat_debug_printf
|
||
("stopping for %s of syscall %d for LWP %ld",
|
||
(lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY
|
||
? "entry" : "return"), syscall_number, lp->ptid.lwp ());
|
||
|
||
return 0;
|
||
}
|
||
|
||
linux_nat_debug_printf
|
||
("ignoring %s of syscall %d for LWP %ld",
|
||
(lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY
|
||
? "entry" : "return"), syscall_number, lp->ptid.lwp ());
|
||
}
|
||
else
|
||
{
|
||
/* If we had been syscall tracing, and hence used PT_SYSCALL
|
||
before on this LWP, it could happen that the user removes all
|
||
syscall catchpoints before we get to process this event.
|
||
There are two noteworthy issues here:
|
||
|
||
- When stopped at a syscall entry event, resuming with
|
||
PT_STEP still resumes executing the syscall and reports a
|
||
syscall return.
|
||
|
||
- Only PT_SYSCALL catches syscall enters. If we last
|
||
single-stepped this thread, then this event can't be a
|
||
syscall enter. If we last single-stepped this thread, this
|
||
has to be a syscall exit.
|
||
|
||
The points above mean that the next resume, be it PT_STEP or
|
||
PT_CONTINUE, can not trigger a syscall trace event. */
|
||
linux_nat_debug_printf
|
||
("caught syscall event with no syscall catchpoints. %d for LWP %ld, "
|
||
"ignoring", syscall_number, lp->ptid.lwp ());
|
||
lp->syscall_state = TARGET_WAITKIND_IGNORE;
|
||
}
|
||
|
||
/* The core isn't interested in this event. For efficiency, avoid
|
||
stopping all threads only to have the core resume them all again.
|
||
Since we're not stopping threads, if we're still syscall tracing
|
||
and not stepping, we can't use PTRACE_CONT here, as we'd miss any
|
||
subsequent syscall. Simply resume using the inf-ptrace layer,
|
||
which knows when to use PT_SYSCALL or PT_CONTINUE. */
|
||
|
||
linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
||
return 1;
|
||
}
|
||
|
||
/* 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_handle_extended_wait (struct lwp_info *lp, int status)
|
||
{
|
||
int pid = lp->ptid.lwp ();
|
||
struct target_waitstatus *ourstatus = &lp->waitstatus;
|
||
int event = linux_ptrace_get_extended_event (status);
|
||
|
||
/* All extended events we currently use are mid-syscall. Only
|
||
PTRACE_EVENT_STOP is delivered more like a signal-stop, but
|
||
you have to be using PTRACE_SEIZE to get that. */
|
||
lp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY;
|
||
|
||
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, &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, __WALL);
|
||
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);
|
||
}
|
||
|
||
ptid_t child_ptid (new_pid, new_pid);
|
||
|
||
if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
|
||
{
|
||
open_proc_mem_file (child_ptid);
|
||
|
||
/* The arch-specific native code may need to know about new
|
||
forks even if those end up never mapped to an
|
||
inferior. */
|
||
linux_target->low_new_fork (lp, new_pid);
|
||
}
|
||
else if (event == PTRACE_EVENT_CLONE)
|
||
{
|
||
linux_target->low_new_clone (lp, new_pid);
|
||
}
|
||
|
||
if (event == PTRACE_EVENT_FORK
|
||
&& linux_fork_checkpointing_p (lp->ptid.pid ()))
|
||
{
|
||
/* Handle checkpointing by linux-fork.c here as a special
|
||
case. We don't want the follow-fork-mode or 'catch fork'
|
||
to interfere with this. */
|
||
|
||
/* This won't actually modify the breakpoint list, but will
|
||
physically remove the breakpoints from the child. */
|
||
detach_breakpoints (ptid_t (new_pid, new_pid));
|
||
|
||
/* Retain child fork in ptrace (stopped) state. */
|
||
if (!find_fork_pid (new_pid))
|
||
add_fork (new_pid);
|
||
|
||
/* Report as spurious, so that infrun doesn't want to follow
|
||
this fork. We're actually doing an infcall in
|
||
linux-fork.c. */
|
||
ourstatus->set_spurious ();
|
||
|
||
/* Report the stop to the core. */
|
||
return 0;
|
||
}
|
||
|
||
if (event == PTRACE_EVENT_FORK)
|
||
ourstatus->set_forked (child_ptid);
|
||
else if (event == PTRACE_EVENT_VFORK)
|
||
ourstatus->set_vforked (child_ptid);
|
||
else if (event == PTRACE_EVENT_CLONE)
|
||
{
|
||
struct lwp_info *new_lp;
|
||
|
||
ourstatus->set_ignore ();
|
||
|
||
linux_nat_debug_printf
|
||
("Got clone event from LWP %d, new child is LWP %ld", pid, new_pid);
|
||
|
||
new_lp = add_lwp (ptid_t (lp->ptid.pid (), new_pid));
|
||
new_lp->stopped = 1;
|
||
new_lp->resumed = 1;
|
||
|
||
/* If the thread_db layer is active, let it record the user
|
||
level thread id and status, and add the thread to GDB's
|
||
list. */
|
||
if (!thread_db_notice_clone (lp->ptid, new_lp->ptid))
|
||
{
|
||
/* The process is not using thread_db. Add the LWP to
|
||
GDB's list. */
|
||
target_post_attach (new_lp->ptid.lwp ());
|
||
add_thread (linux_target, new_lp->ptid);
|
||
}
|
||
|
||
/* Even if we're stopping the thread for some reason
|
||
internal to this module, from the perspective of infrun
|
||
and the user/frontend, this new thread is running until
|
||
it next reports a stop. */
|
||
set_running (linux_target, new_lp->ptid, true);
|
||
set_executing (linux_target, new_lp->ptid, true);
|
||
|
||
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. */
|
||
|
||
new_lp->signalled = 1;
|
||
|
||
/* We created NEW_LP so it cannot yet contain STATUS. */
|
||
gdb_assert (new_lp->status == 0);
|
||
|
||
/* Save the wait status to report later. */
|
||
linux_nat_debug_printf
|
||
("waitpid of new LWP %ld, saving status %s",
|
||
(long) new_lp->ptid.lwp (), status_to_str (status).c_str ());
|
||
new_lp->status = status;
|
||
}
|
||
else if (report_thread_events)
|
||
{
|
||
new_lp->waitstatus.set_thread_created ();
|
||
new_lp->status = status;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
if (event == PTRACE_EVENT_EXEC)
|
||
{
|
||
linux_nat_debug_printf ("Got exec event from LWP %ld", lp->ptid.lwp ());
|
||
|
||
/* Close the previous /proc/PID/mem file for this inferior,
|
||
which was using the address space which is now gone.
|
||
Reading/writing from this file would return 0/EOF. */
|
||
close_proc_mem_file (lp->ptid.pid ());
|
||
|
||
/* Open a new file for the new address space. */
|
||
open_proc_mem_file (lp->ptid);
|
||
|
||
ourstatus->set_execd
|
||
(make_unique_xstrdup (linux_proc_pid_to_exec_file (pid)));
|
||
|
||
/* The thread that execed must have been resumed, but, when a
|
||
thread execs, it changes its tid to the tgid, and the old
|
||
tgid thread might have not been resumed. */
|
||
lp->resumed = 1;
|
||
return 0;
|
||
}
|
||
|
||
if (event == PTRACE_EVENT_VFORK_DONE)
|
||
{
|
||
linux_nat_debug_printf
|
||
("Got PTRACE_EVENT_VFORK_DONE from LWP %ld",
|
||
lp->ptid.lwp ());
|
||
ourstatus->set_vfork_done ();
|
||
return 0;
|
||
}
|
||
|
||
internal_error (__FILE__, __LINE__,
|
||
_("unknown ptrace event %d"), event);
|
||
}
|
||
|
||
/* Suspend waiting for a signal. We're mostly interested in
|
||
SIGCHLD/SIGINT. */
|
||
|
||
static void
|
||
wait_for_signal ()
|
||
{
|
||
linux_nat_debug_printf ("about to sigsuspend");
|
||
sigsuspend (&suspend_mask);
|
||
|
||
/* If the quit flag is set, it means that the user pressed Ctrl-C
|
||
and we're debugging a process that is running on a separate
|
||
terminal, so we must forward the Ctrl-C to the inferior. (If the
|
||
inferior is sharing GDB's terminal, then the Ctrl-C reaches the
|
||
inferior directly.) We must do this here because functions that
|
||
need to block waiting for a signal loop forever until there's an
|
||
event to report before returning back to the event loop. */
|
||
if (!target_terminal::is_ours ())
|
||
{
|
||
if (check_quit_flag ())
|
||
target_pass_ctrlc ();
|
||
}
|
||
}
|
||
|
||
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
|
||
exited. */
|
||
|
||
static int
|
||
wait_lwp (struct lwp_info *lp)
|
||
{
|
||
pid_t pid;
|
||
int status = 0;
|
||
int thread_dead = 0;
|
||
sigset_t prev_mask;
|
||
|
||
gdb_assert (!lp->stopped);
|
||
gdb_assert (lp->status == 0);
|
||
|
||
/* Make sure SIGCHLD is blocked for sigsuspend avoiding a race below. */
|
||
block_child_signals (&prev_mask);
|
||
|
||
for (;;)
|
||
{
|
||
pid = my_waitpid (lp->ptid.lwp (), &status, __WALL | WNOHANG);
|
||
if (pid == -1 && errno == ECHILD)
|
||
{
|
||
/* The thread has previously exited. We need to delete it
|
||
now because if this was a non-leader thread execing, we
|
||
won't get an exit event. See comments on exec events at
|
||
the top of the file. */
|
||
thread_dead = 1;
|
||
linux_nat_debug_printf ("%s vanished.",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
if (pid != 0)
|
||
break;
|
||
|
||
/* Bugs 10970, 12702.
|
||
Thread group leader may have exited in which case we'll lock up in
|
||
waitpid if there are other threads, even if they are all zombies too.
|
||
Basically, we're not supposed to use waitpid this way.
|
||
tkill(pid,0) cannot be used here as it gets ESRCH for both
|
||
for zombie and running processes.
|
||
|
||
As a workaround, check if we're waiting for the thread group leader and
|
||
if it's a zombie, and avoid calling waitpid if it is.
|
||
|
||
This is racy, what if the tgl becomes a zombie right after we check?
|
||
Therefore always use WNOHANG with sigsuspend - it is equivalent to
|
||
waiting waitpid but linux_proc_pid_is_zombie is safe this way. */
|
||
|
||
if (lp->ptid.pid () == lp->ptid.lwp ()
|
||
&& linux_proc_pid_is_zombie (lp->ptid.lwp ()))
|
||
{
|
||
thread_dead = 1;
|
||
linux_nat_debug_printf ("Thread group leader %s vanished.",
|
||
lp->ptid.to_string ().c_str ());
|
||
break;
|
||
}
|
||
|
||
/* Wait for next SIGCHLD and try again. This may let SIGCHLD handlers
|
||
get invoked despite our caller had them intentionally blocked by
|
||
block_child_signals. This is sensitive only to the loop of
|
||
linux_nat_wait_1 and there if we get called my_waitpid gets called
|
||
again before it gets to sigsuspend so we can safely let the handlers
|
||
get executed here. */
|
||
wait_for_signal ();
|
||
}
|
||
|
||
restore_child_signals_mask (&prev_mask);
|
||
|
||
if (!thread_dead)
|
||
{
|
||
gdb_assert (pid == lp->ptid.lwp ());
|
||
|
||
linux_nat_debug_printf ("waitpid %s received %s",
|
||
lp->ptid.to_string ().c_str (),
|
||
status_to_str (status).c_str ());
|
||
|
||
/* Check if the thread has exited. */
|
||
if (WIFEXITED (status) || WIFSIGNALED (status))
|
||
{
|
||
if (report_thread_events
|
||
|| lp->ptid.pid () == lp->ptid.lwp ())
|
||
{
|
||
linux_nat_debug_printf ("LWP %d exited.", lp->ptid.pid ());
|
||
|
||
/* If this is the leader exiting, it means the whole
|
||
process is gone. Store the status to report to the
|
||
core. Store it in lp->waitstatus, because lp->status
|
||
would be ambiguous (W_EXITCODE(0,0) == 0). */
|
||
lp->waitstatus = host_status_to_waitstatus (status);
|
||
return 0;
|
||
}
|
||
|
||
thread_dead = 1;
|
||
linux_nat_debug_printf ("%s exited.",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
}
|
||
|
||
if (thread_dead)
|
||
{
|
||
exit_lwp (lp);
|
||
return 0;
|
||
}
|
||
|
||
gdb_assert (WIFSTOPPED (status));
|
||
lp->stopped = 1;
|
||
|
||
if (lp->must_set_ptrace_flags)
|
||
{
|
||
inferior *inf = find_inferior_pid (linux_target, lp->ptid.pid ());
|
||
int options = linux_nat_ptrace_options (inf->attach_flag);
|
||
|
||
linux_enable_event_reporting (lp->ptid.lwp (), options);
|
||
lp->must_set_ptrace_flags = 0;
|
||
}
|
||
|
||
/* Handle GNU/Linux's syscall SIGTRAPs. */
|
||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
|
||
{
|
||
/* No longer need the sysgood bit. The ptrace event ends up
|
||
recorded in lp->waitstatus if we care for it. We can carry
|
||
on handling the event like a regular SIGTRAP from here
|
||
on. */
|
||
status = W_STOPCODE (SIGTRAP);
|
||
if (linux_handle_syscall_trap (lp, 1))
|
||
return wait_lwp (lp);
|
||
}
|
||
else
|
||
{
|
||
/* Almost all other ptrace-stops are known to be outside of system
|
||
calls, with further exceptions in linux_handle_extended_wait. */
|
||
lp->syscall_state = TARGET_WAITKIND_IGNORE;
|
||
}
|
||
|
||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
|
||
&& linux_is_extended_waitstatus (status))
|
||
{
|
||
linux_nat_debug_printf ("Handling extended status 0x%06x", status);
|
||
linux_handle_extended_wait (lp, status);
|
||
return 0;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
/* Send a SIGSTOP to LP. */
|
||
|
||
static int
|
||
stop_callback (struct lwp_info *lp)
|
||
{
|
||
if (!lp->stopped && !lp->signalled)
|
||
{
|
||
int ret;
|
||
|
||
linux_nat_debug_printf ("kill %s **<SIGSTOP>**",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
errno = 0;
|
||
ret = kill_lwp (lp->ptid.lwp (), SIGSTOP);
|
||
linux_nat_debug_printf ("lwp kill %d %s", ret,
|
||
errno ? safe_strerror (errno) : "ERRNO-OK");
|
||
|
||
lp->signalled = 1;
|
||
gdb_assert (lp->status == 0);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Request a stop on LWP. */
|
||
|
||
void
|
||
linux_stop_lwp (struct lwp_info *lwp)
|
||
{
|
||
stop_callback (lwp);
|
||
}
|
||
|
||
/* See linux-nat.h */
|
||
|
||
void
|
||
linux_stop_and_wait_all_lwps (void)
|
||
{
|
||
/* Stop all LWP's ... */
|
||
iterate_over_lwps (minus_one_ptid, stop_callback);
|
||
|
||
/* ... and wait until all of them have reported back that
|
||
they're no longer running. */
|
||
iterate_over_lwps (minus_one_ptid, stop_wait_callback);
|
||
}
|
||
|
||
/* See linux-nat.h */
|
||
|
||
void
|
||
linux_unstop_all_lwps (void)
|
||
{
|
||
iterate_over_lwps (minus_one_ptid,
|
||
[] (struct lwp_info *info)
|
||
{
|
||
return resume_stopped_resumed_lwps (info, minus_one_ptid);
|
||
});
|
||
}
|
||
|
||
/* Return non-zero if LWP PID has a pending SIGINT. */
|
||
|
||
static int
|
||
linux_nat_has_pending_sigint (int pid)
|
||
{
|
||
sigset_t pending, blocked, ignored;
|
||
|
||
linux_proc_pending_signals (pid, &pending, &blocked, &ignored);
|
||
|
||
if (sigismember (&pending, SIGINT)
|
||
&& !sigismember (&ignored, SIGINT))
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Set a flag in LP indicating that we should ignore its next SIGINT. */
|
||
|
||
static int
|
||
set_ignore_sigint (struct lwp_info *lp)
|
||
{
|
||
/* If a thread has a pending SIGINT, consume it; otherwise, set a
|
||
flag to consume the next one. */
|
||
if (lp->stopped && lp->status != 0 && WIFSTOPPED (lp->status)
|
||
&& WSTOPSIG (lp->status) == SIGINT)
|
||
lp->status = 0;
|
||
else
|
||
lp->ignore_sigint = 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* If LP does not have a SIGINT pending, then clear the ignore_sigint flag.
|
||
This function is called after we know the LWP has stopped; if the LWP
|
||
stopped before the expected SIGINT was delivered, then it will never have
|
||
arrived. Also, if the signal was delivered to a shared queue and consumed
|
||
by a different thread, it will never be delivered to this LWP. */
|
||
|
||
static void
|
||
maybe_clear_ignore_sigint (struct lwp_info *lp)
|
||
{
|
||
if (!lp->ignore_sigint)
|
||
return;
|
||
|
||
if (!linux_nat_has_pending_sigint (lp->ptid.lwp ()))
|
||
{
|
||
linux_nat_debug_printf ("Clearing bogus flag for %s",
|
||
lp->ptid.to_string ().c_str ());
|
||
lp->ignore_sigint = 0;
|
||
}
|
||
}
|
||
|
||
/* Fetch the possible triggered data watchpoint info and store it in
|
||
LP.
|
||
|
||
On some archs, like x86, that use debug registers to set
|
||
watchpoints, it's possible that the way to know which watched
|
||
address trapped, is to check the register that is used to select
|
||
which address to watch. Problem is, between setting the watchpoint
|
||
and reading back which data address trapped, the user may change
|
||
the set of watchpoints, and, as a consequence, GDB changes the
|
||
debug registers in the inferior. To avoid reading back a stale
|
||
stopped-data-address when that happens, we cache in LP the fact
|
||
that a watchpoint trapped, and the corresponding data address, as
|
||
soon as we see LP stop with a SIGTRAP. If GDB changes the debug
|
||
registers meanwhile, we have the cached data we can rely on. */
|
||
|
||
static int
|
||
check_stopped_by_watchpoint (struct lwp_info *lp)
|
||
{
|
||
scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
|
||
inferior_ptid = lp->ptid;
|
||
|
||
if (linux_target->low_stopped_by_watchpoint ())
|
||
{
|
||
lp->stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
|
||
lp->stopped_data_address_p
|
||
= linux_target->low_stopped_data_address (&lp->stopped_data_address);
|
||
}
|
||
|
||
return lp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
|
||
}
|
||
|
||
/* Returns true if the LWP had stopped for a watchpoint. */
|
||
|
||
bool
|
||
linux_nat_target::stopped_by_watchpoint ()
|
||
{
|
||
struct lwp_info *lp = find_lwp_pid (inferior_ptid);
|
||
|
||
gdb_assert (lp != NULL);
|
||
|
||
return lp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
|
||
}
|
||
|
||
bool
|
||
linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
|
||
{
|
||
struct lwp_info *lp = find_lwp_pid (inferior_ptid);
|
||
|
||
gdb_assert (lp != NULL);
|
||
|
||
*addr_p = lp->stopped_data_address;
|
||
|
||
return lp->stopped_data_address_p;
|
||
}
|
||
|
||
/* Commonly any breakpoint / watchpoint generate only SIGTRAP. */
|
||
|
||
bool
|
||
linux_nat_target::low_status_is_event (int status)
|
||
{
|
||
return WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP;
|
||
}
|
||
|
||
/* Wait until LP is stopped. */
|
||
|
||
static int
|
||
stop_wait_callback (struct lwp_info *lp)
|
||
{
|
||
inferior *inf = find_inferior_ptid (linux_target, lp->ptid);
|
||
|
||
/* If this is a vfork parent, bail out, it is not going to report
|
||
any SIGSTOP until the vfork is done with. */
|
||
if (inf->vfork_child != NULL)
|
||
return 0;
|
||
|
||
if (!lp->stopped)
|
||
{
|
||
int status;
|
||
|
||
status = wait_lwp (lp);
|
||
if (status == 0)
|
||
return 0;
|
||
|
||
if (lp->ignore_sigint && WIFSTOPPED (status)
|
||
&& WSTOPSIG (status) == SIGINT)
|
||
{
|
||
lp->ignore_sigint = 0;
|
||
|
||
errno = 0;
|
||
ptrace (PTRACE_CONT, lp->ptid.lwp (), 0, 0);
|
||
lp->stopped = 0;
|
||
linux_nat_debug_printf
|
||
("PTRACE_CONT %s, 0, 0 (%s) (discarding SIGINT)",
|
||
lp->ptid.to_string ().c_str (),
|
||
errno ? safe_strerror (errno) : "OK");
|
||
|
||
return stop_wait_callback (lp);
|
||
}
|
||
|
||
maybe_clear_ignore_sigint (lp);
|
||
|
||
if (WSTOPSIG (status) != SIGSTOP)
|
||
{
|
||
/* The thread was stopped with a signal other than SIGSTOP. */
|
||
|
||
linux_nat_debug_printf ("Pending event %s in %s",
|
||
status_to_str ((int) status).c_str (),
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* Save the sigtrap event. */
|
||
lp->status = status;
|
||
gdb_assert (lp->signalled);
|
||
save_stop_reason (lp);
|
||
}
|
||
else
|
||
{
|
||
/* We caught the SIGSTOP that we intended to catch. */
|
||
|
||
linux_nat_debug_printf ("Expected SIGSTOP caught for %s.",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
lp->signalled = 0;
|
||
|
||
/* If we are waiting for this stop so we can report the thread
|
||
stopped then we need to record this status. Otherwise, we can
|
||
now discard this stop event. */
|
||
if (lp->last_resume_kind == resume_stop)
|
||
{
|
||
lp->status = status;
|
||
save_stop_reason (lp);
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Return non-zero if LP has a wait status pending. Discard the
|
||
pending event and resume the LWP if the event that originally
|
||
caused the stop became uninteresting. */
|
||
|
||
static int
|
||
status_callback (struct lwp_info *lp)
|
||
{
|
||
/* Only report a pending wait status if we pretend that this has
|
||
indeed been resumed. */
|
||
if (!lp->resumed)
|
||
return 0;
|
||
|
||
if (!lwp_status_pending_p (lp))
|
||
return 0;
|
||
|
||
if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
|
||
|| lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
|
||
{
|
||
struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
|
||
CORE_ADDR pc;
|
||
int discard = 0;
|
||
|
||
pc = regcache_read_pc (regcache);
|
||
|
||
if (pc != lp->stop_pc)
|
||
{
|
||
linux_nat_debug_printf ("PC of %s changed. was=%s, now=%s",
|
||
lp->ptid.to_string ().c_str (),
|
||
paddress (target_gdbarch (), lp->stop_pc),
|
||
paddress (target_gdbarch (), pc));
|
||
discard = 1;
|
||
}
|
||
|
||
#if !USE_SIGTRAP_SIGINFO
|
||
else if (!breakpoint_inserted_here_p (regcache->aspace (), pc))
|
||
{
|
||
linux_nat_debug_printf ("previous breakpoint of %s, at %s gone",
|
||
lp->ptid.to_string ().c_str (),
|
||
paddress (target_gdbarch (), lp->stop_pc));
|
||
|
||
discard = 1;
|
||
}
|
||
#endif
|
||
|
||
if (discard)
|
||
{
|
||
linux_nat_debug_printf ("pending event of %s cancelled.",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
lp->status = 0;
|
||
linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* Count the LWP's that have had events. */
|
||
|
||
static int
|
||
count_events_callback (struct lwp_info *lp, int *count)
|
||
{
|
||
gdb_assert (count != NULL);
|
||
|
||
/* Select only resumed LWPs that have an event pending. */
|
||
if (lp->resumed && lwp_status_pending_p (lp))
|
||
(*count)++;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Select the LWP (if any) that is currently being single-stepped. */
|
||
|
||
static int
|
||
select_singlestep_lwp_callback (struct lwp_info *lp)
|
||
{
|
||
if (lp->last_resume_kind == resume_step
|
||
&& lp->status != 0)
|
||
return 1;
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
/* Returns true if LP has a status pending. */
|
||
|
||
static int
|
||
lwp_status_pending_p (struct lwp_info *lp)
|
||
{
|
||
/* We check for lp->waitstatus in addition to lp->status, because we
|
||
can have pending process exits recorded in lp->status and
|
||
W_EXITCODE(0,0) happens to be 0. */
|
||
return lp->status != 0 || lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE;
|
||
}
|
||
|
||
/* Select the Nth LWP that has had an event. */
|
||
|
||
static int
|
||
select_event_lwp_callback (struct lwp_info *lp, int *selector)
|
||
{
|
||
gdb_assert (selector != NULL);
|
||
|
||
/* Select only resumed LWPs that have an event pending. */
|
||
if (lp->resumed && lwp_status_pending_p (lp))
|
||
if ((*selector)-- == 0)
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Called when the LWP stopped for a signal/trap. If it stopped for a
|
||
trap check what caused it (breakpoint, watchpoint, trace, etc.),
|
||
and save the result in the LWP's stop_reason field. If it stopped
|
||
for a breakpoint, decrement the PC if necessary on the lwp's
|
||
architecture. */
|
||
|
||
static void
|
||
save_stop_reason (struct lwp_info *lp)
|
||
{
|
||
struct regcache *regcache;
|
||
struct gdbarch *gdbarch;
|
||
CORE_ADDR pc;
|
||
CORE_ADDR sw_bp_pc;
|
||
#if USE_SIGTRAP_SIGINFO
|
||
siginfo_t siginfo;
|
||
#endif
|
||
|
||
gdb_assert (lp->stop_reason == TARGET_STOPPED_BY_NO_REASON);
|
||
gdb_assert (lp->status != 0);
|
||
|
||
if (!linux_target->low_status_is_event (lp->status))
|
||
return;
|
||
|
||
inferior *inf = find_inferior_ptid (linux_target, lp->ptid);
|
||
if (inf->starting_up)
|
||
return;
|
||
|
||
regcache = get_thread_regcache (linux_target, lp->ptid);
|
||
gdbarch = regcache->arch ();
|
||
|
||
pc = regcache_read_pc (regcache);
|
||
sw_bp_pc = pc - gdbarch_decr_pc_after_break (gdbarch);
|
||
|
||
#if USE_SIGTRAP_SIGINFO
|
||
if (linux_nat_get_siginfo (lp->ptid, &siginfo))
|
||
{
|
||
if (siginfo.si_signo == SIGTRAP)
|
||
{
|
||
if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code)
|
||
&& GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code))
|
||
{
|
||
/* The si_code is ambiguous on this arch -- check debug
|
||
registers. */
|
||
if (!check_stopped_by_watchpoint (lp))
|
||
lp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
|
||
}
|
||
else if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code))
|
||
{
|
||
/* If we determine the LWP stopped for a SW breakpoint,
|
||
trust it. Particularly don't check watchpoint
|
||
registers, because, at least on s390, we'd find
|
||
stopped-by-watchpoint as long as there's a watchpoint
|
||
set. */
|
||
lp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
|
||
}
|
||
else if (GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code))
|
||
{
|
||
/* This can indicate either a hardware breakpoint or
|
||
hardware watchpoint. Check debug registers. */
|
||
if (!check_stopped_by_watchpoint (lp))
|
||
lp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
|
||
}
|
||
else if (siginfo.si_code == TRAP_TRACE)
|
||
{
|
||
linux_nat_debug_printf ("%s stopped by trace",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* We may have single stepped an instruction that
|
||
triggered a watchpoint. In that case, on some
|
||
architectures (such as x86), instead of TRAP_HWBKPT,
|
||
si_code indicates TRAP_TRACE, and we need to check
|
||
the debug registers separately. */
|
||
check_stopped_by_watchpoint (lp);
|
||
}
|
||
}
|
||
}
|
||
#else
|
||
if ((!lp->step || lp->stop_pc == sw_bp_pc)
|
||
&& software_breakpoint_inserted_here_p (regcache->aspace (),
|
||
sw_bp_pc))
|
||
{
|
||
/* The LWP was either continued, or stepped a software
|
||
breakpoint instruction. */
|
||
lp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
|
||
}
|
||
|
||
if (hardware_breakpoint_inserted_here_p (regcache->aspace (), pc))
|
||
lp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
|
||
|
||
if (lp->stop_reason == TARGET_STOPPED_BY_NO_REASON)
|
||
check_stopped_by_watchpoint (lp);
|
||
#endif
|
||
|
||
if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
|
||
{
|
||
linux_nat_debug_printf ("%s stopped by software breakpoint",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* Back up the PC if necessary. */
|
||
if (pc != sw_bp_pc)
|
||
regcache_write_pc (regcache, sw_bp_pc);
|
||
|
||
/* Update this so we record the correct stop PC below. */
|
||
pc = sw_bp_pc;
|
||
}
|
||
else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
|
||
{
|
||
linux_nat_debug_printf ("%s stopped by hardware breakpoint",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else if (lp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
|
||
{
|
||
linux_nat_debug_printf ("%s stopped by hardware watchpoint",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
|
||
lp->stop_pc = pc;
|
||
}
|
||
|
||
|
||
/* Returns true if the LWP had stopped for a software breakpoint. */
|
||
|
||
bool
|
||
linux_nat_target::stopped_by_sw_breakpoint ()
|
||
{
|
||
struct lwp_info *lp = find_lwp_pid (inferior_ptid);
|
||
|
||
gdb_assert (lp != NULL);
|
||
|
||
return lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
|
||
}
|
||
|
||
/* Implement the supports_stopped_by_sw_breakpoint method. */
|
||
|
||
bool
|
||
linux_nat_target::supports_stopped_by_sw_breakpoint ()
|
||
{
|
||
return USE_SIGTRAP_SIGINFO;
|
||
}
|
||
|
||
/* Returns true if the LWP had stopped for a hardware
|
||
breakpoint/watchpoint. */
|
||
|
||
bool
|
||
linux_nat_target::stopped_by_hw_breakpoint ()
|
||
{
|
||
struct lwp_info *lp = find_lwp_pid (inferior_ptid);
|
||
|
||
gdb_assert (lp != NULL);
|
||
|
||
return lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
|
||
}
|
||
|
||
/* Implement the supports_stopped_by_hw_breakpoint method. */
|
||
|
||
bool
|
||
linux_nat_target::supports_stopped_by_hw_breakpoint ()
|
||
{
|
||
return USE_SIGTRAP_SIGINFO;
|
||
}
|
||
|
||
/* Select one LWP out of those that have events pending. */
|
||
|
||
static void
|
||
select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
|
||
{
|
||
int num_events = 0;
|
||
int random_selector;
|
||
struct lwp_info *event_lp = NULL;
|
||
|
||
/* Record the wait status for the original LWP. */
|
||
(*orig_lp)->status = *status;
|
||
|
||
/* In all-stop, give preference to the LWP that is being
|
||
single-stepped. There will be at most one, and it will be the
|
||
LWP that the core is most interested in. If we didn't do this,
|
||
then we'd have to handle pending step SIGTRAPs somehow in case
|
||
the core later continues the previously-stepped thread, as
|
||
otherwise we'd report the pending SIGTRAP then, and the core, not
|
||
having stepped the thread, wouldn't understand what the trap was
|
||
for, and therefore would report it to the user as a random
|
||
signal. */
|
||
if (!target_is_non_stop_p ())
|
||
{
|
||
event_lp = iterate_over_lwps (filter, select_singlestep_lwp_callback);
|
||
if (event_lp != NULL)
|
||
{
|
||
linux_nat_debug_printf ("Select single-step %s",
|
||
event_lp->ptid.to_string ().c_str ());
|
||
}
|
||
}
|
||
|
||
if (event_lp == NULL)
|
||
{
|
||
/* Pick one at random, out of those which have had events. */
|
||
|
||
/* First see how many events we have. */
|
||
iterate_over_lwps (filter,
|
||
[&] (struct lwp_info *info)
|
||
{
|
||
return count_events_callback (info, &num_events);
|
||
});
|
||
gdb_assert (num_events > 0);
|
||
|
||
/* Now randomly pick a LWP out of those that have had
|
||
events. */
|
||
random_selector = (int)
|
||
((num_events * (double) rand ()) / (RAND_MAX + 1.0));
|
||
|
||
if (num_events > 1)
|
||
linux_nat_debug_printf ("Found %d events, selecting #%d",
|
||
num_events, random_selector);
|
||
|
||
event_lp
|
||
= (iterate_over_lwps
|
||
(filter,
|
||
[&] (struct lwp_info *info)
|
||
{
|
||
return select_event_lwp_callback (info,
|
||
&random_selector);
|
||
}));
|
||
}
|
||
|
||
if (event_lp != NULL)
|
||
{
|
||
/* Switch the event LWP. */
|
||
*orig_lp = event_lp;
|
||
*status = event_lp->status;
|
||
}
|
||
|
||
/* Flush the wait status for the event LWP. */
|
||
(*orig_lp)->status = 0;
|
||
}
|
||
|
||
/* Return non-zero if LP has been resumed. */
|
||
|
||
static int
|
||
resumed_callback (struct lwp_info *lp)
|
||
{
|
||
return lp->resumed;
|
||
}
|
||
|
||
/* Check if we should go on and pass this event to common code.
|
||
|
||
If so, save the status to the lwp_info structure associated to LWPID. */
|
||
|
||
static void
|
||
linux_nat_filter_event (int lwpid, int status)
|
||
{
|
||
struct lwp_info *lp;
|
||
int event = linux_ptrace_get_extended_event (status);
|
||
|
||
lp = find_lwp_pid (ptid_t (lwpid));
|
||
|
||
/* Check for events reported by anything not in our LWP list. */
|
||
if (lp == nullptr)
|
||
{
|
||
if (WIFSTOPPED (status))
|
||
{
|
||
if (WSTOPSIG (status) == SIGTRAP && event == PTRACE_EVENT_EXEC)
|
||
{
|
||
/* A non-leader thread exec'ed after we've seen the
|
||
leader zombie, and removed it from our lists (in
|
||
check_zombie_leaders). The non-leader thread changes
|
||
its tid to the tgid. */
|
||
linux_nat_debug_printf
|
||
("Re-adding thread group leader LWP %d after exec.",
|
||
lwpid);
|
||
|
||
lp = add_lwp (ptid_t (lwpid, lwpid));
|
||
lp->stopped = 1;
|
||
lp->resumed = 1;
|
||
add_thread (linux_target, lp->ptid);
|
||
}
|
||
else
|
||
{
|
||
/* A process we are controlling has forked and the new
|
||
child's stop was reported to us by the kernel. Save
|
||
its PID and go back to waiting for the fork event to
|
||
be reported - the stopped process might be returned
|
||
from waitpid before or after the fork event is. */
|
||
linux_nat_debug_printf
|
||
("Saving LWP %d status %s in stopped_pids list",
|
||
lwpid, status_to_str (status).c_str ());
|
||
add_to_pid_list (&stopped_pids, lwpid, status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Don't report an event for the exit of an LWP not in our
|
||
list, i.e. not part of any inferior we're debugging.
|
||
This can happen if we detach from a program we originally
|
||
forked and then it exits. However, note that we may have
|
||
earlier deleted a leader of an inferior we're debugging,
|
||
in check_zombie_leaders. Re-add it back here if so. */
|
||
for (inferior *inf : all_inferiors (linux_target))
|
||
{
|
||
if (inf->pid == lwpid)
|
||
{
|
||
linux_nat_debug_printf
|
||
("Re-adding thread group leader LWP %d after exit.",
|
||
lwpid);
|
||
|
||
lp = add_lwp (ptid_t (lwpid, lwpid));
|
||
lp->resumed = 1;
|
||
add_thread (linux_target, lp->ptid);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (lp == nullptr)
|
||
return;
|
||
}
|
||
|
||
/* This LWP is stopped now. (And if dead, this prevents it from
|
||
ever being continued.) */
|
||
lp->stopped = 1;
|
||
|
||
if (WIFSTOPPED (status) && lp->must_set_ptrace_flags)
|
||
{
|
||
inferior *inf = find_inferior_pid (linux_target, lp->ptid.pid ());
|
||
int options = linux_nat_ptrace_options (inf->attach_flag);
|
||
|
||
linux_enable_event_reporting (lp->ptid.lwp (), options);
|
||
lp->must_set_ptrace_flags = 0;
|
||
}
|
||
|
||
/* Handle GNU/Linux's syscall SIGTRAPs. */
|
||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
|
||
{
|
||
/* No longer need the sysgood bit. The ptrace event ends up
|
||
recorded in lp->waitstatus if we care for it. We can carry
|
||
on handling the event like a regular SIGTRAP from here
|
||
on. */
|
||
status = W_STOPCODE (SIGTRAP);
|
||
if (linux_handle_syscall_trap (lp, 0))
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
/* Almost all other ptrace-stops are known to be outside of system
|
||
calls, with further exceptions in linux_handle_extended_wait. */
|
||
lp->syscall_state = TARGET_WAITKIND_IGNORE;
|
||
}
|
||
|
||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
|
||
&& linux_is_extended_waitstatus (status))
|
||
{
|
||
linux_nat_debug_printf ("Handling extended status 0x%06x", status);
|
||
|
||
if (linux_handle_extended_wait (lp, status))
|
||
return;
|
||
}
|
||
|
||
/* Check if the thread has exited. */
|
||
if (WIFEXITED (status) || WIFSIGNALED (status))
|
||
{
|
||
if (!report_thread_events && !is_leader (lp))
|
||
{
|
||
linux_nat_debug_printf ("%s exited.",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* If this was not the leader exiting, then the exit signal
|
||
was not the end of the debugged application and should be
|
||
ignored. */
|
||
exit_lwp (lp);
|
||
return;
|
||
}
|
||
|
||
/* Note that even if the leader was ptrace-stopped, it can still
|
||
exit, if e.g., some other thread brings down the whole
|
||
process (calls `exit'). So don't assert that the lwp is
|
||
resumed. */
|
||
linux_nat_debug_printf ("LWP %ld exited (resumed=%d)",
|
||
lp->ptid.lwp (), lp->resumed);
|
||
|
||
/* Dead LWP's aren't expected to reported a pending sigstop. */
|
||
lp->signalled = 0;
|
||
|
||
/* Store the pending event in the waitstatus, because
|
||
W_EXITCODE(0,0) == 0. */
|
||
lp->waitstatus = host_status_to_waitstatus (status);
|
||
return;
|
||
}
|
||
|
||
/* 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)
|
||
{
|
||
lp->signalled = 0;
|
||
|
||
if (lp->last_resume_kind == resume_stop)
|
||
{
|
||
linux_nat_debug_printf ("resume_stop SIGSTOP caught for %s.",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else
|
||
{
|
||
/* This is a delayed SIGSTOP. Filter out the event. */
|
||
|
||
linux_nat_debug_printf
|
||
("%s %s, 0, 0 (discard delayed SIGSTOP)",
|
||
lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
||
gdb_assert (lp->resumed);
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Make sure we don't report a SIGINT that we have already displayed
|
||
for another thread. */
|
||
if (lp->ignore_sigint
|
||
&& WIFSTOPPED (status) && WSTOPSIG (status) == SIGINT)
|
||
{
|
||
linux_nat_debug_printf ("Delayed SIGINT caught for %s.",
|
||
lp->ptid.to_string ().c_str ());
|
||
|
||
/* This is a delayed SIGINT. */
|
||
lp->ignore_sigint = 0;
|
||
|
||
linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
||
linux_nat_debug_printf ("%s %s, 0, 0 (discard SIGINT)",
|
||
lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
||
lp->ptid.to_string ().c_str ());
|
||
gdb_assert (lp->resumed);
|
||
|
||
/* Discard the event. */
|
||
return;
|
||
}
|
||
|
||
/* Don't report signals that GDB isn't interested in, such as
|
||
signals that are neither printed nor stopped upon. Stopping all
|
||
threads can be a bit time-consuming, so if we want decent
|
||
performance with heavily multi-threaded programs, especially when
|
||
they're using a high frequency timer, we'd better avoid it if we
|
||
can. */
|
||
if (WIFSTOPPED (status))
|
||
{
|
||
enum gdb_signal signo = gdb_signal_from_host (WSTOPSIG (status));
|
||
|
||
if (!target_is_non_stop_p ())
|
||
{
|
||
/* Only do the below in all-stop, as we currently use SIGSTOP
|
||
to implement target_stop (see linux_nat_stop) in
|
||
non-stop. */
|
||
if (signo == GDB_SIGNAL_INT && signal_pass_state (signo) == 0)
|
||
{
|
||
/* If ^C/BREAK is typed at the tty/console, SIGINT gets
|
||
forwarded to the entire process group, that is, all LWPs
|
||
will receive it - unless they're using CLONE_THREAD to
|
||
share signals. Since we only want to report it once, we
|
||
mark it as ignored for all LWPs except this one. */
|
||
iterate_over_lwps (ptid_t (lp->ptid.pid ()), set_ignore_sigint);
|
||
lp->ignore_sigint = 0;
|
||
}
|
||
else
|
||
maybe_clear_ignore_sigint (lp);
|
||
}
|
||
|
||
/* When using hardware single-step, we need to report every signal.
|
||
Otherwise, signals in pass_mask may be short-circuited
|
||
except signals that might be caused by a breakpoint, or SIGSTOP
|
||
if we sent the SIGSTOP and are waiting for it to arrive. */
|
||
if (!lp->step
|
||
&& WSTOPSIG (status) && sigismember (&pass_mask, WSTOPSIG (status))
|
||
&& (WSTOPSIG (status) != SIGSTOP
|
||
|| !find_thread_ptid (linux_target, lp->ptid)->stop_requested)
|
||
&& !linux_wstatus_maybe_breakpoint (status))
|
||
{
|
||
linux_resume_one_lwp (lp, lp->step, signo);
|
||
linux_nat_debug_printf
|
||
("%s %s, %s (preempt 'handle')",
|
||
lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
||
lp->ptid.to_string ().c_str (),
|
||
(signo != GDB_SIGNAL_0
|
||
? strsignal (gdb_signal_to_host (signo)) : "0"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* An interesting event. */
|
||
gdb_assert (lp);
|
||
lp->status = status;
|
||
save_stop_reason (lp);
|
||
}
|
||
|
||
/* Detect zombie thread group leaders, and "exit" them. We can't reap
|
||
their exits until all other threads in the group have exited. */
|
||
|
||
static void
|
||
check_zombie_leaders (void)
|
||
{
|
||
for (inferior *inf : all_inferiors ())
|
||
{
|
||
struct lwp_info *leader_lp;
|
||
|
||
if (inf->pid == 0)
|
||
continue;
|
||
|
||
leader_lp = find_lwp_pid (ptid_t (inf->pid));
|
||
if (leader_lp != NULL
|
||
/* Check if there are other threads in the group, as we may
|
||
have raced with the inferior simply exiting. Note this
|
||
isn't a watertight check. If the inferior is
|
||
multi-threaded and is exiting, it may be we see the
|
||
leader as zombie before we reap all the non-leader
|
||
threads. See comments below. */
|
||
&& num_lwps (inf->pid) > 1
|
||
&& linux_proc_pid_is_zombie (inf->pid))
|
||
{
|
||
/* A zombie leader in a multi-threaded program can mean one
|
||
of three things:
|
||
|
||
#1 - Only the leader exited, not the whole program, e.g.,
|
||
with pthread_exit. Since we can't reap the leader's exit
|
||
status until all other threads are gone and reaped too,
|
||
we want to delete the zombie leader right away, as it
|
||
can't be debugged, we can't read its registers, etc.
|
||
This is the main reason we check for zombie leaders
|
||
disappearing.
|
||
|
||
#2 - The whole thread-group/process exited (a group exit,
|
||
via e.g. exit(3), and there is (or will be shortly) an
|
||
exit reported for each thread in the process, and then
|
||
finally an exit for the leader once the non-leaders are
|
||
reaped.
|
||
|
||
#3 - There are 3 or more threads in the group, and a
|
||
thread other than the leader exec'd. See comments on
|
||
exec events at the top of the file.
|
||
|
||
Ideally we would never delete the leader for case #2.
|
||
Instead, we want to collect the exit status of each
|
||
non-leader thread, and then finally collect the exit
|
||
status of the leader as normal and use its exit code as
|
||
whole-process exit code. Unfortunately, there's no
|
||
race-free way to distinguish cases #1 and #2. We can't
|
||
assume the exit events for the non-leaders threads are
|
||
already pending in the kernel, nor can we assume the
|
||
non-leader threads are in zombie state already. Between
|
||
the leader becoming zombie and the non-leaders exiting
|
||
and becoming zombie themselves, there's a small time
|
||
window, so such a check would be racy. Temporarily
|
||
pausing all threads and checking to see if all threads
|
||
exit or not before re-resuming them would work in the
|
||
case that all threads are running right now, but it
|
||
wouldn't work if some thread is currently already
|
||
ptrace-stopped, e.g., due to scheduler-locking.
|
||
|
||
So what we do is we delete the leader anyhow, and then
|
||
later on when we see its exit status, we re-add it back.
|
||
We also make sure that we only report a whole-process
|
||
exit when we see the leader exiting, as opposed to when
|
||
the last LWP in the LWP list exits, which can be a
|
||
non-leader if we deleted the leader here. */
|
||
linux_nat_debug_printf ("Thread group leader %d zombie "
|
||
"(it exited, or another thread execd), "
|
||
"deleting it.",
|
||
inf->pid);
|
||
exit_lwp (leader_lp);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Convenience function that is called when the kernel reports an exit
|
||
event. This decides whether to report the event to GDB as a
|
||
process exit event, a thread exit event, or to suppress the
|
||
event. */
|
||
|
||
static ptid_t
|
||
filter_exit_event (struct lwp_info *event_child,
|
||
struct target_waitstatus *ourstatus)
|
||
{
|
||
ptid_t ptid = event_child->ptid;
|
||
|
||
if (!is_leader (event_child))
|
||
{
|
||
if (report_thread_events)
|
||
ourstatus->set_thread_exited (0);
|
||
else
|
||
ourstatus->set_ignore ();
|
||
|
||
exit_lwp (event_child);
|
||
}
|
||
|
||
return ptid;
|
||
}
|
||
|
||
static ptid_t
|
||
linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
|
||
target_wait_flags target_options)
|
||
{
|
||
sigset_t prev_mask;
|
||
enum resume_kind last_resume_kind;
|
||
struct lwp_info *lp;
|
||
int status;
|
||
|
||
linux_nat_debug_printf ("enter");
|
||
|
||
/* 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 (ptid.is_pid () && find_lwp_pid (ptid) == nullptr)
|
||
{
|
||
ptid_t lwp_ptid (ptid.pid (), ptid.pid ());
|
||
|
||
/* Upgrade the main thread's ptid. */
|
||
thread_change_ptid (linux_target, ptid, lwp_ptid);
|
||
lp = add_initial_lwp (lwp_ptid);
|
||
lp->resumed = 1;
|
||
}
|
||
|
||
/* Make sure SIGCHLD is blocked until the sigsuspend below. */
|
||
block_child_signals (&prev_mask);
|
||
|
||
/* First check if there is a LWP with a wait status pending. */
|
||
lp = iterate_over_lwps (ptid, status_callback);
|
||
if (lp != NULL)
|
||
{
|
||
linux_nat_debug_printf ("Using pending wait status %s for %s.",
|
||
status_to_str (lp->status).c_str (),
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
|
||
/* But if we don't find a pending event, we'll have to wait. Always
|
||
pull all events out of the kernel. We'll randomly select an
|
||
event LWP out of all that have events, to prevent starvation. */
|
||
|
||
while (lp == NULL)
|
||
{
|
||
pid_t lwpid;
|
||
|
||
/* Always use -1 and WNOHANG, due to couple of a kernel/ptrace
|
||
quirks:
|
||
|
||
- If the thread group leader exits while other threads in the
|
||
thread group still exist, waitpid(TGID, ...) hangs. That
|
||
waitpid won't return an exit status until the other threads
|
||
in the group are reaped.
|
||
|
||
- When a non-leader thread execs, that thread just vanishes
|
||
without reporting an exit (so we'd hang if we waited for it
|
||
explicitly in that case). The exec event is reported to
|
||
the TGID pid. */
|
||
|
||
errno = 0;
|
||
lwpid = my_waitpid (-1, &status, __WALL | WNOHANG);
|
||
|
||
linux_nat_debug_printf ("waitpid(-1, ...) returned %d, %s",
|
||
lwpid,
|
||
errno ? safe_strerror (errno) : "ERRNO-OK");
|
||
|
||
if (lwpid > 0)
|
||
{
|
||
linux_nat_debug_printf ("waitpid %ld received %s",
|
||
(long) lwpid,
|
||
status_to_str (status).c_str ());
|
||
|
||
linux_nat_filter_event (lwpid, status);
|
||
/* Retry until nothing comes out of waitpid. A single
|
||
SIGCHLD can indicate more than one child stopped. */
|
||
continue;
|
||
}
|
||
|
||
/* Now that we've pulled all events out of the kernel, resume
|
||
LWPs that don't have an interesting event to report. */
|
||
iterate_over_lwps (minus_one_ptid,
|
||
[] (struct lwp_info *info)
|
||
{
|
||
return resume_stopped_resumed_lwps (info, minus_one_ptid);
|
||
});
|
||
|
||
/* ... and find an LWP with a status to report to the core, if
|
||
any. */
|
||
lp = iterate_over_lwps (ptid, status_callback);
|
||
if (lp != NULL)
|
||
break;
|
||
|
||
/* Check for zombie thread group leaders. Those can't be reaped
|
||
until all other threads in the thread group are. */
|
||
check_zombie_leaders ();
|
||
|
||
/* If there are no resumed children left, bail. We'd be stuck
|
||
forever in the sigsuspend call below otherwise. */
|
||
if (iterate_over_lwps (ptid, resumed_callback) == NULL)
|
||
{
|
||
linux_nat_debug_printf ("exit (no resumed LWP)");
|
||
|
||
ourstatus->set_no_resumed ();
|
||
|
||
restore_child_signals_mask (&prev_mask);
|
||
return minus_one_ptid;
|
||
}
|
||
|
||
/* No interesting event to report to the core. */
|
||
|
||
if (target_options & TARGET_WNOHANG)
|
||
{
|
||
linux_nat_debug_printf ("exit (ignore)");
|
||
|
||
ourstatus->set_ignore ();
|
||
restore_child_signals_mask (&prev_mask);
|
||
return minus_one_ptid;
|
||
}
|
||
|
||
/* We shouldn't end up here unless we want to try again. */
|
||
gdb_assert (lp == NULL);
|
||
|
||
/* Block until we get an event reported with SIGCHLD. */
|
||
wait_for_signal ();
|
||
}
|
||
|
||
gdb_assert (lp);
|
||
|
||
status = lp->status;
|
||
lp->status = 0;
|
||
|
||
if (!target_is_non_stop_p ())
|
||
{
|
||
/* Now stop all other LWP's ... */
|
||
iterate_over_lwps (minus_one_ptid, stop_callback);
|
||
|
||
/* ... and wait until all of them have reported back that
|
||
they're no longer running. */
|
||
iterate_over_lwps (minus_one_ptid, stop_wait_callback);
|
||
}
|
||
|
||
/* If we're not waiting for a specific LWP, choose an event LWP from
|
||
among those that have had events. Giving equal priority to all
|
||
LWPs that have had events helps prevent starvation. */
|
||
if (ptid == minus_one_ptid || ptid.is_pid ())
|
||
select_event_lwp (ptid, &lp, &status);
|
||
|
||
gdb_assert (lp != NULL);
|
||
|
||
/* Now that we've selected our final event LWP, un-adjust its PC if
|
||
it was a software breakpoint, and we can't reliably support the
|
||
"stopped by software breakpoint" stop reason. */
|
||
if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
|
||
&& !USE_SIGTRAP_SIGINFO)
|
||
{
|
||
struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
|
||
struct gdbarch *gdbarch = regcache->arch ();
|
||
int decr_pc = gdbarch_decr_pc_after_break (gdbarch);
|
||
|
||
if (decr_pc != 0)
|
||
{
|
||
CORE_ADDR pc;
|
||
|
||
pc = regcache_read_pc (regcache);
|
||
regcache_write_pc (regcache, pc + decr_pc);
|
||
}
|
||
}
|
||
|
||
/* We'll need this to determine whether to report a SIGSTOP as
|
||
GDB_SIGNAL_0. Need to take a copy because resume_clear_callback
|
||
clears it. */
|
||
last_resume_kind = lp->last_resume_kind;
|
||
|
||
if (!target_is_non_stop_p ())
|
||
{
|
||
/* In all-stop, from the core's perspective, all LWPs are now
|
||
stopped until a new resume action is sent over. */
|
||
iterate_over_lwps (minus_one_ptid, resume_clear_callback);
|
||
}
|
||
else
|
||
{
|
||
resume_clear_callback (lp);
|
||
}
|
||
|
||
if (linux_target->low_status_is_event (status))
|
||
{
|
||
linux_nat_debug_printf ("trap ptid is %s.",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
|
||
if (lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
|
||
{
|
||
*ourstatus = lp->waitstatus;
|
||
lp->waitstatus.set_ignore ();
|
||
}
|
||
else
|
||
*ourstatus = host_status_to_waitstatus (status);
|
||
|
||
linux_nat_debug_printf ("exit");
|
||
|
||
restore_child_signals_mask (&prev_mask);
|
||
|
||
if (last_resume_kind == resume_stop
|
||
&& ourstatus->kind () == TARGET_WAITKIND_STOPPED
|
||
&& WSTOPSIG (status) == SIGSTOP)
|
||
{
|
||
/* A thread that has been requested to stop by GDB with
|
||
target_stop, and it stopped cleanly, so report as SIG0. The
|
||
use of SIGSTOP is an implementation detail. */
|
||
ourstatus->set_stopped (GDB_SIGNAL_0);
|
||
}
|
||
|
||
if (ourstatus->kind () == TARGET_WAITKIND_EXITED
|
||
|| ourstatus->kind () == TARGET_WAITKIND_SIGNALLED)
|
||
lp->core = -1;
|
||
else
|
||
lp->core = linux_common_core_of_thread (lp->ptid);
|
||
|
||
if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
|
||
return filter_exit_event (lp, ourstatus);
|
||
|
||
return lp->ptid;
|
||
}
|
||
|
||
/* Resume LWPs that are currently stopped without any pending status
|
||
to report, but are resumed from the core's perspective. */
|
||
|
||
static int
|
||
resume_stopped_resumed_lwps (struct lwp_info *lp, const ptid_t wait_ptid)
|
||
{
|
||
if (!lp->stopped)
|
||
{
|
||
linux_nat_debug_printf ("NOT resuming LWP %s, not stopped",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else if (!lp->resumed)
|
||
{
|
||
linux_nat_debug_printf ("NOT resuming LWP %s, not resumed",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else if (lwp_status_pending_p (lp))
|
||
{
|
||
linux_nat_debug_printf ("NOT resuming LWP %s, has pending status",
|
||
lp->ptid.to_string ().c_str ());
|
||
}
|
||
else
|
||
{
|
||
struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
|
||
struct gdbarch *gdbarch = regcache->arch ();
|
||
|
||
try
|
||
{
|
||
CORE_ADDR pc = regcache_read_pc (regcache);
|
||
int leave_stopped = 0;
|
||
|
||
/* Don't bother if there's a breakpoint at PC that we'd hit
|
||
immediately, and we're not waiting for this LWP. */
|
||
if (!lp->ptid.matches (wait_ptid))
|
||
{
|
||
if (breakpoint_inserted_here_p (regcache->aspace (), pc))
|
||
leave_stopped = 1;
|
||
}
|
||
|
||
if (!leave_stopped)
|
||
{
|
||
linux_nat_debug_printf
|
||
("resuming stopped-resumed LWP %s at %s: step=%d",
|
||
lp->ptid.to_string ().c_str (), paddress (gdbarch, pc),
|
||
lp->step);
|
||
|
||
linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0);
|
||
}
|
||
}
|
||
catch (const gdb_exception_error &ex)
|
||
{
|
||
if (!check_ptrace_stopped_lwp_gone (lp))
|
||
throw;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
ptid_t
|
||
linux_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
|
||
target_wait_flags target_options)
|
||
{
|
||
ptid_t event_ptid;
|
||
|
||
linux_nat_debug_printf ("[%s], [%s]", ptid.to_string ().c_str (),
|
||
target_options_to_string (target_options).c_str ());
|
||
|
||
/* Flush the async file first. */
|
||
if (target_is_async_p ())
|
||
async_file_flush ();
|
||
|
||
/* Resume LWPs that are currently stopped without any pending status
|
||
to report, but are resumed from the core's perspective. LWPs get
|
||
in this state if we find them stopping at a time we're not
|
||
interested in reporting the event (target_wait on a
|
||
specific_process, for example, see linux_nat_wait_1), and
|
||
meanwhile the event became uninteresting. Don't bother resuming
|
||
LWPs we're not going to wait for if they'd stop immediately. */
|
||
if (target_is_non_stop_p ())
|
||
iterate_over_lwps (minus_one_ptid,
|
||
[=] (struct lwp_info *info)
|
||
{
|
||
return resume_stopped_resumed_lwps (info, ptid);
|
||
});
|
||
|
||
event_ptid = linux_nat_wait_1 (ptid, ourstatus, target_options);
|
||
|
||
/* If we requested any event, and something came out, assume there
|
||
may be more. If we requested a specific lwp or process, also
|
||
assume there may be more. */
|
||
if (target_is_async_p ()
|
||
&& ((ourstatus->kind () != TARGET_WAITKIND_IGNORE
|
||
&& ourstatus->kind () != TARGET_WAITKIND_NO_RESUMED)
|
||
|| ptid != minus_one_ptid))
|
||
async_file_mark ();
|
||
|
||
return event_ptid;
|
||
}
|
||
|
||
/* Kill one LWP. */
|
||
|
||
static void
|
||
kill_one_lwp (pid_t pid)
|
||
{
|
||
/* PTRACE_KILL may resume the inferior. Send SIGKILL first. */
|
||
|
||
errno = 0;
|
||
kill_lwp (pid, SIGKILL);
|
||
|
||
if (debug_linux_nat)
|
||
{
|
||
int save_errno = errno;
|
||
|
||
linux_nat_debug_printf
|
||
("kill (SIGKILL) %ld, 0, 0 (%s)", (long) pid,
|
||
save_errno != 0 ? safe_strerror (save_errno) : "OK");
|
||
}
|
||
|
||
/* Some kernels ignore even SIGKILL for processes under ptrace. */
|
||
|
||
errno = 0;
|
||
ptrace (PTRACE_KILL, pid, 0, 0);
|
||
if (debug_linux_nat)
|
||
{
|
||
int save_errno = errno;
|
||
|
||
linux_nat_debug_printf
|
||
("PTRACE_KILL %ld, 0, 0 (%s)", (long) pid,
|
||
save_errno ? safe_strerror (save_errno) : "OK");
|
||
}
|
||
}
|
||
|
||
/* Wait for an LWP to die. */
|
||
|
||
static void
|
||
kill_wait_one_lwp (pid_t pid)
|
||
{
|
||
pid_t res;
|
||
|
||
/* We must make sure that there are no pending events (delayed
|
||
SIGSTOPs, pending SIGTRAPs, etc.) to make sure the current
|
||
program doesn't interfere with any following debugging session. */
|
||
|
||
do
|
||
{
|
||
res = my_waitpid (pid, NULL, __WALL);
|
||
if (res != (pid_t) -1)
|
||
{
|
||
linux_nat_debug_printf ("wait %ld received unknown.", (long) pid);
|
||
|
||
/* 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_deliver
|
||
and waits again. So kill it again. */
|
||
kill_one_lwp (pid);
|
||
}
|
||
}
|
||
while (res == pid);
|
||
|
||
gdb_assert (res == -1 && errno == ECHILD);
|
||
}
|
||
|
||
/* Callback for iterate_over_lwps. */
|
||
|
||
static int
|
||
kill_callback (struct lwp_info *lp)
|
||
{
|
||
kill_one_lwp (lp->ptid.lwp ());
|
||
return 0;
|
||
}
|
||
|
||
/* Callback for iterate_over_lwps. */
|
||
|
||
static int
|
||
kill_wait_callback (struct lwp_info *lp)
|
||
{
|
||
kill_wait_one_lwp (lp->ptid.lwp ());
|
||
return 0;
|
||
}
|
||
|
||
/* Kill the fork children of any threads of inferior INF that are
|
||
stopped at a fork event. */
|
||
|
||
static void
|
||
kill_unfollowed_fork_children (struct inferior *inf)
|
||
{
|
||
for (thread_info *thread : inf->non_exited_threads ())
|
||
{
|
||
struct target_waitstatus *ws = &thread->pending_follow;
|
||
|
||
if (ws->kind () == TARGET_WAITKIND_FORKED
|
||
|| ws->kind () == TARGET_WAITKIND_VFORKED)
|
||
{
|
||
ptid_t child_ptid = ws->child_ptid ();
|
||
int child_pid = child_ptid.pid ();
|
||
int child_lwp = child_ptid.lwp ();
|
||
|
||
kill_one_lwp (child_lwp);
|
||
kill_wait_one_lwp (child_lwp);
|
||
|
||
/* Let the arch-specific native code know this process is
|
||
gone. */
|
||
linux_target->low_forget_process (child_pid);
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
linux_nat_target::kill ()
|
||
{
|
||
/* 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. */
|
||
kill_unfollowed_fork_children (current_inferior ());
|
||
|
||
if (forks_exist_p ())
|
||
linux_fork_killall ();
|
||
else
|
||
{
|
||
ptid_t ptid = ptid_t (inferior_ptid.pid ());
|
||
|
||
/* Stop all threads before killing them, since ptrace requires
|
||
that the thread is stopped to successfully PTRACE_KILL. */
|
||
iterate_over_lwps (ptid, stop_callback);
|
||
/* ... and wait until all of them have reported back that
|
||
they're no longer running. */
|
||
iterate_over_lwps (ptid, stop_wait_callback);
|
||
|
||
/* Kill all LWP's ... */
|
||
iterate_over_lwps (ptid, kill_callback);
|
||
|
||
/* ... and wait until we've flushed all events. */
|
||
iterate_over_lwps (ptid, kill_wait_callback);
|
||
}
|
||
|
||
target_mourn_inferior (inferior_ptid);
|
||
}
|
||
|
||
void
|
||
linux_nat_target::mourn_inferior ()
|
||
{
|
||
int pid = inferior_ptid.pid ();
|
||
|
||
purge_lwp_list (pid);
|
||
|
||
close_proc_mem_file (pid);
|
||
|
||
if (! forks_exist_p ())
|
||
/* Normal case, no other forks available. */
|
||
inf_ptrace_target::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 ();
|
||
|
||
/* Let the arch-specific native code know this process is gone. */
|
||
linux_target->low_forget_process (pid);
|
||
}
|
||
|
||
/* Convert a native/host siginfo object, into/from the siginfo in the
|
||
layout of the inferiors' architecture. */
|
||
|
||
static void
|
||
siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
|
||
{
|
||
/* If the low target didn't do anything, then just do a straight
|
||
memcpy. */
|
||
if (!linux_target->low_siginfo_fixup (siginfo, inf_siginfo, direction))
|
||
{
|
||
if (direction == 1)
|
||
memcpy (siginfo, inf_siginfo, sizeof (siginfo_t));
|
||
else
|
||
memcpy (inf_siginfo, siginfo, sizeof (siginfo_t));
|
||
}
|
||
}
|
||
|
||
static enum target_xfer_status
|
||
linux_xfer_siginfo (enum target_object object,
|
||
const char *annex, gdb_byte *readbuf,
|
||
const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
|
||
ULONGEST *xfered_len)
|
||
{
|
||
int pid;
|
||
siginfo_t siginfo;
|
||
gdb_byte inf_siginfo[sizeof (siginfo_t)];
|
||
|
||
gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
|
||
gdb_assert (readbuf || writebuf);
|
||
|
||
pid = inferior_ptid.lwp ();
|
||
if (pid == 0)
|
||
pid = inferior_ptid.pid ();
|
||
|
||
if (offset > sizeof (siginfo))
|
||
return TARGET_XFER_E_IO;
|
||
|
||
errno = 0;
|
||
ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
|
||
if (errno != 0)
|
||
return TARGET_XFER_E_IO;
|
||
|
||
/* When GDB is built as a 64-bit application, ptrace writes into
|
||
SIGINFO an object with 64-bit layout. Since debugging a 32-bit
|
||
inferior with a 64-bit GDB should look the same as debugging it
|
||
with a 32-bit GDB, we need to convert it. GDB core always sees
|
||
the converted layout, so any read/write will have to be done
|
||
post-conversion. */
|
||
siginfo_fixup (&siginfo, inf_siginfo, 0);
|
||
|
||
if (offset + len > sizeof (siginfo))
|
||
len = sizeof (siginfo) - offset;
|
||
|
||
if (readbuf != NULL)
|
||
memcpy (readbuf, inf_siginfo + offset, len);
|
||
else
|
||
{
|
||
memcpy (inf_siginfo + offset, writebuf, len);
|
||
|
||
/* Convert back to ptrace layout before flushing it out. */
|
||
siginfo_fixup (&siginfo, inf_siginfo, 1);
|
||
|
||
errno = 0;
|
||
ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
|
||
if (errno != 0)
|
||
return TARGET_XFER_E_IO;
|
||
}
|
||
|
||
*xfered_len = len;
|
||
return TARGET_XFER_OK;
|
||
}
|
||
|
||
static enum target_xfer_status
|
||
linux_nat_xfer_osdata (enum target_object object,
|
||
const char *annex, gdb_byte *readbuf,
|
||
const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
|
||
ULONGEST *xfered_len);
|
||
|
||
static enum target_xfer_status
|
||
linux_proc_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf,
|
||
ULONGEST offset, LONGEST len, ULONGEST *xfered_len);
|
||
|
||
enum target_xfer_status
|
||
linux_nat_target::xfer_partial (enum target_object object,
|
||
const char *annex, gdb_byte *readbuf,
|
||
const gdb_byte *writebuf,
|
||
ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
|
||
{
|
||
if (object == TARGET_OBJECT_SIGNAL_INFO)
|
||
return linux_xfer_siginfo (object, annex, readbuf, writebuf,
|
||
offset, len, xfered_len);
|
||
|
||
/* The target is connected but no live inferior is selected. Pass
|
||
this request down to a lower stratum (e.g., the executable
|
||
file). */
|
||
if (object == TARGET_OBJECT_MEMORY && inferior_ptid == null_ptid)
|
||
return TARGET_XFER_EOF;
|
||
|
||
if (object == TARGET_OBJECT_AUXV)
|
||
return memory_xfer_auxv (this, object, annex, readbuf, writebuf,
|
||
offset, len, xfered_len);
|
||
|
||
if (object == TARGET_OBJECT_OSDATA)
|
||
return linux_nat_xfer_osdata (object, annex, readbuf, writebuf,
|
||
offset, len, xfered_len);
|
||
|
||
if (object == TARGET_OBJECT_MEMORY)
|
||
{
|
||
/* GDB calculates all addresses in the largest possible address
|
||
width. The address width must be masked before its final use
|
||
by linux_proc_xfer_partial.
|
||
|
||
Compare ADDR_BIT first to avoid a compiler warning on shift overflow. */
|
||
int addr_bit = gdbarch_addr_bit (target_gdbarch ());
|
||
|
||
if (addr_bit < (sizeof (ULONGEST) * HOST_CHAR_BIT))
|
||
offset &= ((ULONGEST) 1 << addr_bit) - 1;
|
||
|
||
return linux_proc_xfer_memory_partial (readbuf, writebuf,
|
||
offset, len, xfered_len);
|
||
}
|
||
|
||
return inf_ptrace_target::xfer_partial (object, annex, readbuf, writebuf,
|
||
offset, len, xfered_len);
|
||
}
|
||
|
||
bool
|
||
linux_nat_target::thread_alive (ptid_t ptid)
|
||
{
|
||
/* As long as a PTID is in lwp list, consider it alive. */
|
||
return find_lwp_pid (ptid) != NULL;
|
||
}
|
||
|
||
/* Implement the to_update_thread_list target method for this
|
||
target. */
|
||
|
||
void
|
||
linux_nat_target::update_thread_list ()
|
||
{
|
||
/* We add/delete threads from the list as clone/exit events are
|
||
processed, so just try deleting exited threads still in the
|
||
thread list. */
|
||
delete_exited_threads ();
|
||
|
||
/* Update the processor core that each lwp/thread was last seen
|
||
running on. */
|
||
for (lwp_info *lwp : all_lwps ())
|
||
{
|
||
/* Avoid accessing /proc if the thread hasn't run since we last
|
||
time we fetched the thread's core. Accessing /proc becomes
|
||
noticeably expensive when we have thousands of LWPs. */
|
||
if (lwp->core == -1)
|
||
lwp->core = linux_common_core_of_thread (lwp->ptid);
|
||
}
|
||
}
|
||
|
||
std::string
|
||
linux_nat_target::pid_to_str (ptid_t ptid)
|
||
{
|
||
if (ptid.lwp_p ()
|
||
&& (ptid.pid () != ptid.lwp ()
|
||
|| num_lwps (ptid.pid ()) > 1))
|
||
return string_printf ("LWP %ld", ptid.lwp ());
|
||
|
||
return normal_pid_to_str (ptid);
|
||
}
|
||
|
||
const char *
|
||
linux_nat_target::thread_name (struct thread_info *thr)
|
||
{
|
||
return linux_proc_tid_get_name (thr->ptid);
|
||
}
|
||
|
||
/* Accepts an integer PID; Returns a string representing a file that
|
||
can be opened to get the symbols for the child process. */
|
||
|
||
const char *
|
||
linux_nat_target::pid_to_exec_file (int pid)
|
||
{
|
||
return linux_proc_pid_to_exec_file (pid);
|
||
}
|
||
|
||
/* Object representing an /proc/PID/mem open file. We keep one such
|
||
file open per inferior.
|
||
|
||
It might be tempting to think about only ever opening one file at
|
||
most for all inferiors, closing/reopening the file as we access
|
||
memory of different inferiors, to minimize number of file
|
||
descriptors open, which can otherwise run into resource limits.
|
||
However, that does not work correctly -- if the inferior execs and
|
||
we haven't processed the exec event yet, and, we opened a
|
||
/proc/PID/mem file, we will get a mem file accessing the post-exec
|
||
address space, thinking we're opening it for the pre-exec address
|
||
space. That is dangerous as we can poke memory (e.g. clearing
|
||
breakpoints) in the post-exec memory by mistake, corrupting the
|
||
inferior. For that reason, we open the mem file as early as
|
||
possible, right after spawning, forking or attaching to the
|
||
inferior, when the inferior is stopped and thus before it has a
|
||
chance of execing.
|
||
|
||
Note that after opening the file, even if the thread we opened it
|
||
for subsequently exits, the open file is still usable for accessing
|
||
memory. It's only when the whole process exits or execs that the
|
||
file becomes invalid, at which point reads/writes return EOF. */
|
||
|
||
class proc_mem_file
|
||
{
|
||
public:
|
||
proc_mem_file (ptid_t ptid, int fd)
|
||
: m_ptid (ptid), m_fd (fd)
|
||
{
|
||
gdb_assert (m_fd != -1);
|
||
}
|
||
|
||
~proc_mem_file ()
|
||
{
|
||
linux_nat_debug_printf ("closing fd %d for /proc/%d/task/%ld/mem",
|
||
m_fd, m_ptid.pid (), m_ptid.lwp ());
|
||
close (m_fd);
|
||
}
|
||
|
||
DISABLE_COPY_AND_ASSIGN (proc_mem_file);
|
||
|
||
int fd ()
|
||
{
|
||
return m_fd;
|
||
}
|
||
|
||
private:
|
||
/* The LWP this file was opened for. Just for debugging
|
||
purposes. */
|
||
ptid_t m_ptid;
|
||
|
||
/* The file descriptor. */
|
||
int m_fd = -1;
|
||
};
|
||
|
||
/* The map between an inferior process id, and the open /proc/PID/mem
|
||
file. This is stored in a map instead of in a per-inferior
|
||
structure because we need to be able to access memory of processes
|
||
which don't have a corresponding struct inferior object. E.g.,
|
||
with "detach-on-fork on" (the default), and "follow-fork parent"
|
||
(also default), we don't create an inferior for the fork child, but
|
||
we still need to remove breakpoints from the fork child's
|
||
memory. */
|
||
static std::unordered_map<int, proc_mem_file> proc_mem_file_map;
|
||
|
||
/* Close the /proc/PID/mem file for PID. */
|
||
|
||
static void
|
||
close_proc_mem_file (pid_t pid)
|
||
{
|
||
proc_mem_file_map.erase (pid);
|
||
}
|
||
|
||
/* Open the /proc/PID/mem file for the process (thread group) of PTID.
|
||
We actually open /proc/PID/task/LWP/mem, as that's the LWP we know
|
||
exists and is stopped right now. We prefer the
|
||
/proc/PID/task/LWP/mem form over /proc/LWP/mem to avoid tid-reuse
|
||
races, just in case this is ever called on an already-waited
|
||
LWP. */
|
||
|
||
static void
|
||
open_proc_mem_file (ptid_t ptid)
|
||
{
|
||
auto iter = proc_mem_file_map.find (ptid.pid ());
|
||
gdb_assert (iter == proc_mem_file_map.end ());
|
||
|
||
char filename[64];
|
||
xsnprintf (filename, sizeof filename,
|
||
"/proc/%d/task/%ld/mem", ptid.pid (), ptid.lwp ());
|
||
|
||
int fd = gdb_open_cloexec (filename, O_RDWR | O_LARGEFILE, 0).release ();
|
||
|
||
if (fd == -1)
|
||
{
|
||
warning (_("opening /proc/PID/mem file for lwp %d.%ld failed: %s (%d)"),
|
||
ptid.pid (), ptid.lwp (),
|
||
safe_strerror (errno), errno);
|
||
return;
|
||
}
|
||
|
||
proc_mem_file_map.emplace (std::piecewise_construct,
|
||
std::forward_as_tuple (ptid.pid ()),
|
||
std::forward_as_tuple (ptid, fd));
|
||
|
||
linux_nat_debug_printf ("opened fd %d for lwp %d.%ld",
|
||
fd, ptid.pid (), ptid.lwp ());
|
||
}
|
||
|
||
/* Implement the to_xfer_partial target method using /proc/PID/mem.
|
||
Because we can use a single read/write call, this can be much more
|
||
efficient than banging away at PTRACE_PEEKTEXT. Also, unlike
|
||
PTRACE_PEEKTEXT/PTRACE_POKETEXT, this works with running
|
||
threads. */
|
||
|
||
static enum target_xfer_status
|
||
linux_proc_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf,
|
||
ULONGEST offset, LONGEST len,
|
||
ULONGEST *xfered_len)
|
||
{
|
||
ssize_t ret;
|
||
|
||
auto iter = proc_mem_file_map.find (inferior_ptid.pid ());
|
||
if (iter == proc_mem_file_map.end ())
|
||
return TARGET_XFER_EOF;
|
||
|
||
int fd = iter->second.fd ();
|
||
|
||
gdb_assert (fd != -1);
|
||
|
||
/* Use pread64/pwrite64 if available, since they save a syscall and can
|
||
handle 64-bit offsets even on 32-bit platforms (for instance, SPARC
|
||
debugging a SPARC64 application). */
|
||
#ifdef HAVE_PREAD64
|
||
ret = (readbuf ? pread64 (fd, readbuf, len, offset)
|
||
: pwrite64 (fd, writebuf, len, offset));
|
||
#else
|
||
ret = lseek (fd, offset, SEEK_SET);
|
||
if (ret != -1)
|
||
ret = (readbuf ? read (fd, readbuf, len)
|
||
: write (fd, writebuf, len));
|
||
#endif
|
||
|
||
if (ret == -1)
|
||
{
|
||
linux_nat_debug_printf ("accessing fd %d for pid %d failed: %s (%d)",
|
||
fd, inferior_ptid.pid (),
|
||
safe_strerror (errno), errno);
|
||
return TARGET_XFER_E_IO;
|
||
}
|
||
else if (ret == 0)
|
||
{
|
||
/* EOF means the address space is gone, the whole process exited
|
||
or execed. */
|
||
linux_nat_debug_printf ("accessing fd %d for pid %d got EOF",
|
||
fd, inferior_ptid.pid ());
|
||
return TARGET_XFER_EOF;
|
||
}
|
||
else
|
||
{
|
||
*xfered_len = ret;
|
||
return TARGET_XFER_OK;
|
||
}
|
||
}
|
||
|
||
/* Parse LINE as a signal set and add its set bits to SIGS. */
|
||
|
||
static void
|
||
add_line_to_sigset (const char *line, sigset_t *sigs)
|
||
{
|
||
int len = strlen (line) - 1;
|
||
const char *p;
|
||
int signum;
|
||
|
||
if (line[len] != '\n')
|
||
error (_("Could not parse signal set: %s"), line);
|
||
|
||
p = line;
|
||
signum = len * 4;
|
||
while (len-- > 0)
|
||
{
|
||
int digit;
|
||
|
||
if (*p >= '0' && *p <= '9')
|
||
digit = *p - '0';
|
||
else if (*p >= 'a' && *p <= 'f')
|
||
digit = *p - 'a' + 10;
|
||
else
|
||
error (_("Could not parse signal set: %s"), line);
|
||
|
||
signum -= 4;
|
||
|
||
if (digit & 1)
|
||
sigaddset (sigs, signum + 1);
|
||
if (digit & 2)
|
||
sigaddset (sigs, signum + 2);
|
||
if (digit & 4)
|
||
sigaddset (sigs, signum + 3);
|
||
if (digit & 8)
|
||
sigaddset (sigs, signum + 4);
|
||
|
||
p++;
|
||
}
|
||
}
|
||
|
||
/* Find process PID's pending signals from /proc/pid/status and set
|
||
SIGS to match. */
|
||
|
||
void
|
||
linux_proc_pending_signals (int pid, sigset_t *pending,
|
||
sigset_t *blocked, sigset_t *ignored)
|
||
{
|
||
char buffer[PATH_MAX], fname[PATH_MAX];
|
||
|
||
sigemptyset (pending);
|
||
sigemptyset (blocked);
|
||
sigemptyset (ignored);
|
||
xsnprintf (fname, sizeof fname, "/proc/%d/status", pid);
|
||
gdb_file_up procfile = gdb_fopen_cloexec (fname, "r");
|
||
if (procfile == NULL)
|
||
error (_("Could not open %s"), fname);
|
||
|
||
while (fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
|
||
{
|
||
/* Normal queued signals are on the SigPnd line in the status
|
||
file. However, 2.6 kernels also have a "shared" pending
|
||
queue for delivering signals to a thread group, so check for
|
||
a ShdPnd line also.
|
||
|
||
Unfortunately some Red Hat kernels include the shared pending
|
||
queue but not the ShdPnd status field. */
|
||
|
||
if (startswith (buffer, "SigPnd:\t"))
|
||
add_line_to_sigset (buffer + 8, pending);
|
||
else if (startswith (buffer, "ShdPnd:\t"))
|
||
add_line_to_sigset (buffer + 8, pending);
|
||
else if (startswith (buffer, "SigBlk:\t"))
|
||
add_line_to_sigset (buffer + 8, blocked);
|
||
else if (startswith (buffer, "SigIgn:\t"))
|
||
add_line_to_sigset (buffer + 8, ignored);
|
||
}
|
||
}
|
||
|
||
static enum target_xfer_status
|
||
linux_nat_xfer_osdata (enum target_object object,
|
||
const char *annex, gdb_byte *readbuf,
|
||
const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
|
||
ULONGEST *xfered_len)
|
||
{
|
||
gdb_assert (object == TARGET_OBJECT_OSDATA);
|
||
|
||
*xfered_len = linux_common_xfer_osdata (annex, readbuf, offset, len);
|
||
if (*xfered_len == 0)
|
||
return TARGET_XFER_EOF;
|
||
else
|
||
return TARGET_XFER_OK;
|
||
}
|
||
|
||
std::vector<static_tracepoint_marker>
|
||
linux_nat_target::static_tracepoint_markers_by_strid (const char *strid)
|
||
{
|
||
char s[IPA_CMD_BUF_SIZE];
|
||
int pid = inferior_ptid.pid ();
|
||
std::vector<static_tracepoint_marker> markers;
|
||
const char *p = s;
|
||
ptid_t ptid = ptid_t (pid, 0);
|
||
static_tracepoint_marker marker;
|
||
|
||
/* Pause all */
|
||
target_stop (ptid);
|
||
|
||
memcpy (s, "qTfSTM", sizeof ("qTfSTM"));
|
||
s[sizeof ("qTfSTM")] = 0;
|
||
|
||
agent_run_command (pid, s, strlen (s) + 1);
|
||
|
||
/* Unpause all. */
|
||
SCOPE_EXIT { target_continue_no_signal (ptid); };
|
||
|
||
while (*p++ == 'm')
|
||
{
|
||
do
|
||
{
|
||
parse_static_tracepoint_marker_definition (p, &p, &marker);
|
||
|
||
if (strid == NULL || marker.str_id == strid)
|
||
markers.push_back (std::move (marker));
|
||
}
|
||
while (*p++ == ','); /* comma-separated list */
|
||
|
||
memcpy (s, "qTsSTM", sizeof ("qTsSTM"));
|
||
s[sizeof ("qTsSTM")] = 0;
|
||
agent_run_command (pid, s, strlen (s) + 1);
|
||
p = s;
|
||
}
|
||
|
||
return markers;
|
||
}
|
||
|
||
/* target_can_async_p implementation. */
|
||
|
||
bool
|
||
linux_nat_target::can_async_p ()
|
||
{
|
||
/* This flag should be checked in the common target.c code. */
|
||
gdb_assert (target_async_permitted);
|
||
|
||
/* Otherwise, this targets is always able to support async mode. */
|
||
return true;
|
||
}
|
||
|
||
bool
|
||
linux_nat_target::supports_non_stop ()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/* to_always_non_stop_p implementation. */
|
||
|
||
bool
|
||
linux_nat_target::always_non_stop_p ()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
bool
|
||
linux_nat_target::supports_multi_process ()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
bool
|
||
linux_nat_target::supports_disable_randomization ()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/* SIGCHLD handler that serves two purposes: In non-stop/async mode,
|
||
so we notice when any child changes state, and notify the
|
||
event-loop; it allows us to use sigsuspend in linux_nat_wait_1
|
||
above to wait for the arrival of a SIGCHLD. */
|
||
|
||
static void
|
||
sigchld_handler (int signo)
|
||
{
|
||
int old_errno = errno;
|
||
|
||
if (debug_linux_nat)
|
||
gdb_stdlog->write_async_safe ("sigchld\n", sizeof ("sigchld\n") - 1);
|
||
|
||
if (signo == SIGCHLD)
|
||
{
|
||
/* Let the event loop know that there are events to handle. */
|
||
linux_nat_target::async_file_mark_if_open ();
|
||
}
|
||
|
||
errno = old_errno;
|
||
}
|
||
|
||
/* Callback registered with the target events file descriptor. */
|
||
|
||
static void
|
||
handle_target_event (int error, gdb_client_data client_data)
|
||
{
|
||
inferior_event_handler (INF_REG_EVENT);
|
||
}
|
||
|
||
/* target_async implementation. */
|
||
|
||
void
|
||
linux_nat_target::async (int enable)
|
||
{
|
||
if ((enable != 0) == is_async_p ())
|
||
return;
|
||
|
||
/* Block child signals while we create/destroy the pipe, as their
|
||
handler writes to it. */
|
||
gdb::block_signals blocker;
|
||
|
||
if (enable)
|
||
{
|
||
if (!async_file_open ())
|
||
internal_error (__FILE__, __LINE__, "creating event pipe failed.");
|
||
|
||
add_file_handler (async_wait_fd (), handle_target_event, NULL,
|
||
"linux-nat");
|
||
|
||
/* There may be pending events to handle. Tell the event loop
|
||
to poll them. */
|
||
async_file_mark ();
|
||
}
|
||
else
|
||
{
|
||
delete_file_handler (async_wait_fd ());
|
||
async_file_close ();
|
||
}
|
||
}
|
||
|
||
/* Stop an LWP, and push a GDB_SIGNAL_0 stop status if no other
|
||
event came out. */
|
||
|
||
static int
|
||
linux_nat_stop_lwp (struct lwp_info *lwp)
|
||
{
|
||
if (!lwp->stopped)
|
||
{
|
||
linux_nat_debug_printf ("running -> suspending %s",
|
||
lwp->ptid.to_string ().c_str ());
|
||
|
||
|
||
if (lwp->last_resume_kind == resume_stop)
|
||
{
|
||
linux_nat_debug_printf ("already stopping LWP %ld at GDB's request",
|
||
lwp->ptid.lwp ());
|
||
return 0;
|
||
}
|
||
|
||
stop_callback (lwp);
|
||
lwp->last_resume_kind = resume_stop;
|
||
}
|
||
else
|
||
{
|
||
/* Already known to be stopped; do nothing. */
|
||
|
||
if (debug_linux_nat)
|
||
{
|
||
if (find_thread_ptid (linux_target, lwp->ptid)->stop_requested)
|
||
linux_nat_debug_printf ("already stopped/stop_requested %s",
|
||
lwp->ptid.to_string ().c_str ());
|
||
else
|
||
linux_nat_debug_printf ("already stopped/no stop_requested yet %s",
|
||
lwp->ptid.to_string ().c_str ());
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
linux_nat_target::stop (ptid_t ptid)
|
||
{
|
||
LINUX_NAT_SCOPED_DEBUG_ENTER_EXIT;
|
||
iterate_over_lwps (ptid, linux_nat_stop_lwp);
|
||
}
|
||
|
||
/* When requests are passed down from the linux-nat layer to the
|
||
single threaded inf-ptrace layer, ptids of (lwpid,0,0) form are
|
||
used. The address space pointer is stored in the inferior object,
|
||
but the common code that is passed such ptid can't tell whether
|
||
lwpid is a "main" process id or not (it assumes so). We reverse
|
||
look up the "main" process id from the lwp here. */
|
||
|
||
struct address_space *
|
||
linux_nat_target::thread_address_space (ptid_t ptid)
|
||
{
|
||
struct lwp_info *lwp;
|
||
struct inferior *inf;
|
||
int pid;
|
||
|
||
if (ptid.lwp () == 0)
|
||
{
|
||
/* An (lwpid,0,0) ptid. Look up the lwp object to get at the
|
||
tgid. */
|
||
lwp = find_lwp_pid (ptid);
|
||
pid = lwp->ptid.pid ();
|
||
}
|
||
else
|
||
{
|
||
/* A (pid,lwpid,0) ptid. */
|
||
pid = ptid.pid ();
|
||
}
|
||
|
||
inf = find_inferior_pid (this, pid);
|
||
gdb_assert (inf != NULL);
|
||
return inf->aspace;
|
||
}
|
||
|
||
/* Return the cached value of the processor core for thread PTID. */
|
||
|
||
int
|
||
linux_nat_target::core_of_thread (ptid_t ptid)
|
||
{
|
||
struct lwp_info *info = find_lwp_pid (ptid);
|
||
|
||
if (info)
|
||
return info->core;
|
||
return -1;
|
||
}
|
||
|
||
/* Implementation of to_filesystem_is_local. */
|
||
|
||
bool
|
||
linux_nat_target::filesystem_is_local ()
|
||
{
|
||
struct inferior *inf = current_inferior ();
|
||
|
||
if (inf->fake_pid_p || inf->pid == 0)
|
||
return true;
|
||
|
||
return linux_ns_same (inf->pid, LINUX_NS_MNT);
|
||
}
|
||
|
||
/* Convert the INF argument passed to a to_fileio_* method
|
||
to a process ID suitable for passing to its corresponding
|
||
linux_mntns_* function. If INF is non-NULL then the
|
||
caller is requesting the filesystem seen by INF. If INF
|
||
is NULL then the caller is requesting the filesystem seen
|
||
by the GDB. We fall back to GDB's filesystem in the case
|
||
that INF is non-NULL but its PID is unknown. */
|
||
|
||
static pid_t
|
||
linux_nat_fileio_pid_of (struct inferior *inf)
|
||
{
|
||
if (inf == NULL || inf->fake_pid_p || inf->pid == 0)
|
||
return getpid ();
|
||
else
|
||
return inf->pid;
|
||
}
|
||
|
||
/* Implementation of to_fileio_open. */
|
||
|
||
int
|
||
linux_nat_target::fileio_open (struct inferior *inf, const char *filename,
|
||
int flags, int mode, int warn_if_slow,
|
||
int *target_errno)
|
||
{
|
||
int nat_flags;
|
||
mode_t nat_mode;
|
||
int fd;
|
||
|
||
if (fileio_to_host_openflags (flags, &nat_flags) == -1
|
||
|| fileio_to_host_mode (mode, &nat_mode) == -1)
|
||
{
|
||
*target_errno = FILEIO_EINVAL;
|
||
return -1;
|
||
}
|
||
|
||
fd = linux_mntns_open_cloexec (linux_nat_fileio_pid_of (inf),
|
||
filename, nat_flags, nat_mode);
|
||
if (fd == -1)
|
||
*target_errno = host_to_fileio_error (errno);
|
||
|
||
return fd;
|
||
}
|
||
|
||
/* Implementation of to_fileio_readlink. */
|
||
|
||
gdb::optional<std::string>
|
||
linux_nat_target::fileio_readlink (struct inferior *inf, const char *filename,
|
||
int *target_errno)
|
||
{
|
||
char buf[PATH_MAX];
|
||
int len;
|
||
|
||
len = linux_mntns_readlink (linux_nat_fileio_pid_of (inf),
|
||
filename, buf, sizeof (buf));
|
||
if (len < 0)
|
||
{
|
||
*target_errno = host_to_fileio_error (errno);
|
||
return {};
|
||
}
|
||
|
||
return std::string (buf, len);
|
||
}
|
||
|
||
/* Implementation of to_fileio_unlink. */
|
||
|
||
int
|
||
linux_nat_target::fileio_unlink (struct inferior *inf, const char *filename,
|
||
int *target_errno)
|
||
{
|
||
int ret;
|
||
|
||
ret = linux_mntns_unlink (linux_nat_fileio_pid_of (inf),
|
||
filename);
|
||
if (ret == -1)
|
||
*target_errno = host_to_fileio_error (errno);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/* Implementation of the to_thread_events method. */
|
||
|
||
void
|
||
linux_nat_target::thread_events (int enable)
|
||
{
|
||
report_thread_events = enable;
|
||
}
|
||
|
||
linux_nat_target::linux_nat_target ()
|
||
{
|
||
/* 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. */
|
||
}
|
||
|
||
/* See linux-nat.h. */
|
||
|
||
int
|
||
linux_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo)
|
||
{
|
||
int pid;
|
||
|
||
pid = ptid.lwp ();
|
||
if (pid == 0)
|
||
pid = ptid.pid ();
|
||
|
||
errno = 0;
|
||
ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, siginfo);
|
||
if (errno != 0)
|
||
{
|
||
memset (siginfo, 0, sizeof (*siginfo));
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/* See nat/linux-nat.h. */
|
||
|
||
ptid_t
|
||
current_lwp_ptid (void)
|
||
{
|
||
gdb_assert (inferior_ptid.lwp_p ());
|
||
return inferior_ptid;
|
||
}
|
||
|
||
void _initialize_linux_nat ();
|
||
void
|
||
_initialize_linux_nat ()
|
||
{
|
||
add_setshow_boolean_cmd ("linux-nat", class_maintenance,
|
||
&debug_linux_nat, _("\
|
||
Set debugging of GNU/Linux native target."), _(" \
|
||
Show debugging of GNU/Linux native target."), _(" \
|
||
When on, print debug messages relating to the GNU/Linux native target."),
|
||
nullptr,
|
||
show_debug_linux_nat,
|
||
&setdebuglist, &showdebuglist);
|
||
|
||
add_setshow_boolean_cmd ("linux-namespaces", class_maintenance,
|
||
&debug_linux_namespaces, _("\
|
||
Set debugging of GNU/Linux namespaces module."), _("\
|
||
Show debugging of GNU/Linux namespaces module."), _("\
|
||
Enables printf debugging output."),
|
||
NULL,
|
||
NULL,
|
||
&setdebuglist, &showdebuglist);
|
||
|
||
/* Install a SIGCHLD handler. */
|
||
sigchld_action.sa_handler = sigchld_handler;
|
||
sigemptyset (&sigchld_action.sa_mask);
|
||
sigchld_action.sa_flags = SA_RESTART;
|
||
|
||
/* Make it the default. */
|
||
sigaction (SIGCHLD, &sigchld_action, NULL);
|
||
|
||
/* Make sure we don't block SIGCHLD during a sigsuspend. */
|
||
gdb_sigmask (SIG_SETMASK, NULL, &suspend_mask);
|
||
sigdelset (&suspend_mask, SIGCHLD);
|
||
|
||
sigemptyset (&blocked_mask);
|
||
|
||
lwp_lwpid_htab_create ();
|
||
}
|
||
|
||
|
||
/* FIXME: kettenis/2000-08-26: The stuff on this page is specific to
|
||
the GNU/Linux Threads library and therefore doesn't really belong
|
||
here. */
|
||
|
||
/* NPTL reserves the first two RT signals, but does not provide any
|
||
way for the debugger to query the signal numbers - fortunately
|
||
they don't change. */
|
||
static int lin_thread_signals[] = { __SIGRTMIN, __SIGRTMIN + 1 };
|
||
|
||
/* See linux-nat.h. */
|
||
|
||
unsigned int
|
||
lin_thread_get_thread_signal_num (void)
|
||
{
|
||
return sizeof (lin_thread_signals) / sizeof (lin_thread_signals[0]);
|
||
}
|
||
|
||
/* See linux-nat.h. */
|
||
|
||
int
|
||
lin_thread_get_thread_signal (unsigned int i)
|
||
{
|
||
gdb_assert (i < lin_thread_get_thread_signal_num ());
|
||
return lin_thread_signals[i];
|
||
}
|