/* Low level interface to ptrace, for the remote server for GDB.
- Copyright (C) 1995-2022 Free Software Foundation, Inc.
+ Copyright (C) 1995-2023 Free Software Foundation, Inc.
This file is part of GDB.
#include "nat/linux-osdata.h"
#include "gdbsupport/agent.h"
#include "tdesc.h"
+#include "gdbsupport/event-loop.h"
+#include "gdbsupport/event-pipe.h"
#include "gdbsupport/rsp-low.h"
#include "gdbsupport/signals-state-save-restore.h"
#include "nat/linux-nat.h"
/* Does the current host support PTRACE_GETREGSET? */
int have_ptrace_getregset = -1;
+/* Return TRUE if THREAD is the leader thread of the process. */
+
+static bool
+is_leader (thread_info *thread)
+{
+ ptid_t ptid = ptid_of (thread);
+ return ptid.pid () == ptid.lwp ();
+}
+
/* LWP accessors. */
/* See nat/linux-nat.h. */
return (pc >= lwp->step_range_start && pc < lwp->step_range_end);
}
-/* The read/write ends of the pipe registered as waitable file in the
- event loop. */
-static int linux_event_pipe[2] = { -1, -1 };
+/* The event pipe registered as a waitable file in the event loop. */
+static event_pipe linux_event_pipe;
/* True if we're currently in async mode. */
-#define target_is_async_p() (linux_event_pipe[0] != -1)
+#define target_is_async_p() (linux_event_pipe.is_open ())
static void send_sigstop (struct lwp_info *lwp);
{
struct thread_info *thr = get_lwp_thread (lwp);
- if (debug_threads)
- debug_printf ("deleting %ld\n", lwpid_of (thr));
+ threads_debug_printf ("deleting %ld", lwpid_of (thr));
remove_thread (thr);
gdb_assert (info == nullptr);
}
+/* Open the /proc/PID/mem file for PROC. */
+
+static void
+open_proc_mem_file (process_info *proc)
+{
+ gdb_assert (proc->priv->mem_fd == -1);
+
+ char filename[64];
+ xsnprintf (filename, sizeof filename, "/proc/%d/mem", proc->pid);
+
+ proc->priv->mem_fd
+ = gdb_open_cloexec (filename, O_RDWR | O_LARGEFILE, 0).release ();
+}
+
process_info *
-linux_process_target::add_linux_process (int pid, int attached)
+linux_process_target::add_linux_process_no_mem_file (int pid, int attached)
{
struct process_info *proc;
proc->priv = XCNEW (struct process_info_private);
proc->priv->arch_private = low_new_process ();
+ proc->priv->mem_fd = -1;
return proc;
}
+
+process_info *
+linux_process_target::add_linux_process (int pid, int attached)
+{
+ process_info *proc = add_linux_process_no_mem_file (pid, attached);
+ open_proc_mem_file (proc);
+ return proc;
+}
+
+void
+linux_process_target::remove_linux_process (process_info *proc)
+{
+ if (proc->priv->mem_fd >= 0)
+ close (proc->priv->mem_fd);
+
+ this->low_delete_process (proc->priv->arch_private);
+
+ xfree (proc->priv);
+ proc->priv = nullptr;
+
+ remove_process (proc);
+}
+
arch_process_info *
linux_process_target::low_new_process ()
{
ptid = ptid_t (new_pid, new_pid);
- if (debug_threads)
- {
- debug_printf ("HEW: Got fork event from LWP %ld, "
- "new child is %d\n",
- ptid_of (event_thr).lwp (),
- ptid.pid ());
- }
+ threads_debug_printf ("Got fork event from LWP %ld, "
+ "new child is %d",
+ ptid_of (event_thr).lwp (),
+ ptid.pid ());
/* Add the new process to the tables and clone the breakpoint
lists of the parent. We need to do this even if the new process
if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS
|| event_lwp->bp_reinsert != 0)
{
- if (debug_threads)
- debug_printf ("HEW: leaving child suspended\n");
+ threads_debug_printf ("leaving child suspended");
child_lwp->suspended = 1;
}
return 0;
}
- if (debug_threads)
- debug_printf ("HEW: Got clone event "
- "from LWP %ld, new child is LWP %ld\n",
- lwpid_of (event_thr), new_pid);
+ threads_debug_printf
+ ("Got clone event from LWP %ld, new child is LWP %ld",
+ lwpid_of (event_thr), new_pid);
ptid = ptid_t (pid_of (event_thr), new_pid);
new_lwp = add_lwp (ptid);
ptid_t event_ptid;
pid_t event_pid;
- if (debug_threads)
- {
- debug_printf ("HEW: Got exec event from LWP %ld\n",
- lwpid_of (event_thr));
- }
+ threads_debug_printf ("Got exec event from LWP %ld",
+ lwpid_of (event_thr));
/* Get the event ptid. */
event_ptid = ptid_of (event_thr);
return 0;
}
- internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
+ internal_error (_("unknown ptrace event %d"), event);
}
CORE_ADDR
linux_process_target::get_pc (lwp_info *lwp)
{
- struct regcache *regcache;
- CORE_ADDR pc;
+ process_info *proc = get_thread_process (get_lwp_thread (lwp));
+ gdb_assert (!proc->starting_up);
if (!low_supports_breakpoints ())
return 0;
scoped_restore_current_thread restore_thread;
switch_to_thread (get_lwp_thread (lwp));
- regcache = get_thread_regcache (current_thread, 1);
- pc = low_get_pc (regcache);
+ struct regcache *regcache = get_thread_regcache (current_thread, 1);
+ CORE_ADDR pc = low_get_pc (regcache);
- if (debug_threads)
- debug_printf ("pc is 0x%lx\n", (long) pc);
+ threads_debug_printf ("pc is 0x%lx", (long) pc);
return pc;
}
regcache = get_thread_regcache (current_thread, 1);
low_get_syscall_trapinfo (regcache, sysno);
- if (debug_threads)
- debug_printf ("get_syscall_trapinfo sysno %d\n", *sysno);
+ threads_debug_printf ("get_syscall_trapinfo sysno %d", *sysno);
}
void
if (!low_supports_breakpoints ())
return false;
+ process_info *proc = get_thread_process (get_lwp_thread (lwp));
+ if (proc->starting_up)
+ {
+ /* Claim we have the stop PC so that the caller doesn't try to
+ fetch it itself. */
+ return true;
+ }
+
pc = get_pc (lwp);
sw_breakpoint_pc = pc - low_decr_pc_after_break ();
if (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
{
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by software breakpoint\n",
- target_pid_to_str (ptid_of (thr)).c_str ());
- }
+ threads_debug_printf
+ ("%s stopped by software breakpoint",
+ target_pid_to_str (ptid_of (get_lwp_thread (lwp))).c_str ());
/* Back up the PC if necessary. */
if (pc != sw_breakpoint_pc)
pc = sw_breakpoint_pc;
}
else if (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
- {
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by hardware breakpoint\n",
- target_pid_to_str (ptid_of (thr)).c_str ());
- }
- }
+ threads_debug_printf
+ ("%s stopped by hardware breakpoint",
+ target_pid_to_str (ptid_of (get_lwp_thread (lwp))).c_str ());
else if (lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
- {
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by hardware watchpoint\n",
- target_pid_to_str (ptid_of (thr)).c_str ());
- }
- }
+ threads_debug_printf
+ ("%s stopped by hardware watchpoint",
+ target_pid_to_str (ptid_of (get_lwp_thread (lwp))).c_str ());
else if (lwp->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP)
- {
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by trace\n",
- target_pid_to_str (ptid_of (thr)).c_str ());
- }
- }
+ threads_debug_printf
+ ("%s stopped by trace",
+ target_pid_to_str (ptid_of (get_lwp_thread (lwp))).c_str ());
lwp->stop_pc = pc;
return true;
NULL, NULL, NULL, NULL);
}
- add_linux_process (pid, 0);
+ /* When spawning a new process, we can't open the mem file yet. We
+ still have to nurse the process through the shell, and that execs
+ a couple times. The address space a /proc/PID/mem file is
+ accessing is destroyed on exec. */
+ process_info *proc = add_linux_process_no_mem_file (pid, 0);
ptid = ptid_t (pid, pid);
new_lwp = add_lwp (ptid);
post_fork_inferior (pid, program);
+ /* PROC is now past the shell running the program we want, so we can
+ open the /proc/PID/mem file. */
+ open_proc_mem_file (proc);
+
return pid;
}
if (linux_proc_pid_is_stopped (lwpid))
{
- if (debug_threads)
- debug_printf ("Attached to a stopped process\n");
+ threads_debug_printf ("Attached to a stopped process");
/* The process is definitely stopped. It is in a job control
stop, unless the kernel predates the TASK_STOPPED /
int lwpid = ptid.lwp ();
int err;
- if (debug_threads)
- debug_printf ("Found new lwp %d\n", lwpid);
+ threads_debug_printf ("Found new lwp %d", lwpid);
err = the_linux_target->attach_lwp (ptid);
case, confirm the status in /proc/PID/status. */
if (err == ESRCH
|| (err == EPERM && linux_proc_pid_is_gone (lwpid)))
- {
- if (debug_threads)
- {
- debug_printf ("Cannot attach to lwp %d: "
- "thread is gone (%d: %s)\n",
- lwpid, err, safe_strerror (err));
- }
- }
+ threads_debug_printf
+ ("Cannot attach to lwp %d: thread is gone (%d: %s)",
+ lwpid, err, safe_strerror (err));
else if (err != 0)
{
std::string reason
ptid_t ptid = ptid_t (pid, pid);
int err;
- proc = add_linux_process (pid, 1);
+ /* Delay opening the /proc/PID/mem file until we've successfully
+ attached. */
+ proc = add_linux_process_no_mem_file (pid, 1);
/* Attach to PID. We will check for other threads
soon. */
err = attach_lwp (ptid);
if (err != 0)
{
- remove_process (proc);
+ this->remove_linux_process (proc);
std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err);
error ("Cannot attach to process %ld: %s", pid, reason.c_str ());
}
+ open_proc_mem_file (proc);
+
/* Don't ignore the initial SIGSTOP if we just attached to this
process. It will be collected by wait shortly. */
initial_thread = find_thread_ptid (ptid_t (pid, pid));
{
int save_errno = errno;
- debug_printf ("LKL: kill_lwp (SIGKILL) %s, 0, 0 (%s)\n",
- target_pid_to_str (ptid_of (thr)).c_str (),
- save_errno ? safe_strerror (save_errno) : "OK");
+ threads_debug_printf ("kill_lwp (SIGKILL) %s, 0, 0 (%s)",
+ target_pid_to_str (ptid_of (thr)).c_str (),
+ save_errno ? safe_strerror (save_errno) : "OK");
}
errno = 0;
{
int save_errno = errno;
- debug_printf ("LKL: PTRACE_KILL %s, 0, 0 (%s)\n",
- target_pid_to_str (ptid_of (thr)).c_str (),
- save_errno ? safe_strerror (save_errno) : "OK");
+ threads_debug_printf ("PTRACE_KILL %s, 0, 0 (%s)",
+ target_pid_to_str (ptid_of (thr)).c_str (),
+ save_errno ? safe_strerror (save_errno) : "OK");
}
}
int wstat;
int res;
- if (debug_threads)
- debug_printf ("kwl: killing lwp %d, for pid: %d\n", lwpid, pid);
+ threads_debug_printf ("killing lwp %d, for pid: %d", lwpid, pid);
do
{
if (lwpid_of (thread) == pid)
{
- if (debug_threads)
- debug_printf ("lkop: is last of process %s\n",
- target_pid_to_str (thread->id).c_str ());
+ threads_debug_printf ("is last of process %s",
+ target_pid_to_str (thread->id).c_str ());
return;
}
lwp_info *lwp = find_lwp_pid (ptid_t (pid));
if (lwp == NULL)
- {
- if (debug_threads)
- debug_printf ("lk_1: cannot find lwp for pid: %d\n",
- pid);
- }
+ threads_debug_printf ("cannot find lwp for pid: %d", pid);
else
kill_wait_lwp (lwp);
if (!WIFSTOPPED (status))
{
- if (debug_threads)
- debug_printf ("GPS: lwp %s hasn't stopped: no pending signal\n",
- target_pid_to_str (ptid_of (thread)).c_str ());
+ threads_debug_printf ("lwp %s hasn't stopped: no pending signal",
+ target_pid_to_str (ptid_of (thread)).c_str ());
return 0;
}
/* Extended wait statuses aren't real SIGTRAPs. */
if (WSTOPSIG (status) == SIGTRAP && linux_is_extended_waitstatus (status))
{
- if (debug_threads)
- debug_printf ("GPS: lwp %s had stopped with extended "
- "status: no pending signal\n",
- target_pid_to_str (ptid_of (thread)).c_str ());
+ threads_debug_printf ("lwp %s had stopped with extended "
+ "status: no pending signal",
+ target_pid_to_str (ptid_of (thread)).c_str ());
return 0;
}
if (cs.program_signals_p && !cs.program_signals[signo])
{
- if (debug_threads)
- debug_printf ("GPS: lwp %s had signal %s, but it is in nopass state\n",
- target_pid_to_str (ptid_of (thread)).c_str (),
- gdb_signal_to_string (signo));
+ threads_debug_printf ("lwp %s had signal %s, but it is in nopass state",
+ target_pid_to_str (ptid_of (thread)).c_str (),
+ gdb_signal_to_string (signo));
return 0;
}
else if (!cs.program_signals_p
SIGTRAP/SIGINT, which is GDB's default. */
&& (signo == GDB_SIGNAL_TRAP || signo == GDB_SIGNAL_INT))
{
- if (debug_threads)
- debug_printf ("GPS: lwp %s had signal %s, "
- "but we don't know if we should pass it. "
- "Default to not.\n",
- target_pid_to_str (ptid_of (thread)).c_str (),
- gdb_signal_to_string (signo));
+ threads_debug_printf ("lwp %s had signal %s, "
+ "but we don't know if we should pass it. "
+ "Default to not.",
+ target_pid_to_str (ptid_of (thread)).c_str (),
+ gdb_signal_to_string (signo));
return 0;
}
else
{
- if (debug_threads)
- debug_printf ("GPS: lwp %s has pending signal %s: delivering it.\n",
- target_pid_to_str (ptid_of (thread)).c_str (),
- gdb_signal_to_string (signo));
+ threads_debug_printf ("lwp %s has pending signal %s: delivering it",
+ target_pid_to_str (ptid_of (thread)).c_str (),
+ gdb_signal_to_string (signo));
return WSTOPSIG (status);
}
/* If there is a pending SIGSTOP, get rid of it. */
if (lwp->stop_expected)
{
- if (debug_threads)
- debug_printf ("Sending SIGCONT to %s\n",
- target_pid_to_str (ptid_of (thread)).c_str ());
+ threads_debug_printf ("Sending SIGCONT to %s",
+ target_pid_to_str (ptid_of (thread)).c_str ());
kill_lwp (lwpid_of (thread), SIGCONT);
lwp->stop_expected = 0;
safe_strerror (save_errno));
}
}
- else if (debug_threads)
- {
- debug_printf ("PTRACE_DETACH (%s, %s, 0) (OK)\n",
- target_pid_to_str (ptid_of (thread)).c_str (),
- strsignal (sig));
- }
+ else
+ threads_debug_printf ("PTRACE_DETACH (%s, %s, 0) (OK)",
+ target_pid_to_str (ptid_of (thread)).c_str (),
+ strsignal (sig));
delete_lwp (lwp);
}
void
linux_process_target::mourn (process_info *process)
{
- struct process_info_private *priv;
-
#ifdef USE_THREAD_DB
thread_db_mourn (process);
#endif
delete_lwp (get_thread_lwp (thread));
});
- /* Freeing all private data. */
- priv = process->priv;
- low_delete_process (priv->arch_private);
- free (priv);
- process->priv = NULL;
-
- remove_process (process);
+ this->remove_linux_process (process);
}
void
if (pc != lp->stop_pc)
{
- if (debug_threads)
- debug_printf ("PC of %ld changed\n",
- lwpid_of (thread));
+ threads_debug_printf ("PC of %ld changed",
+ lwpid_of (thread));
discard = 1;
}
else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
&& !low_breakpoint_at (pc))
{
- if (debug_threads)
- debug_printf ("previous SW breakpoint of %ld gone\n",
- lwpid_of (thread));
+ threads_debug_printf ("previous SW breakpoint of %ld gone",
+ lwpid_of (thread));
discard = 1;
}
else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT
&& !hardware_breakpoint_inserted_here (pc))
{
- if (debug_threads)
- debug_printf ("previous HW breakpoint of %ld gone\n",
- lwpid_of (thread));
+ threads_debug_printf ("previous HW breakpoint of %ld gone",
+ lwpid_of (thread));
discard = 1;
}
#endif
if (discard)
{
- if (debug_threads)
- debug_printf ("discarding pending breakpoint status\n");
+ threads_debug_printf ("discarding pending breakpoint status");
lp->status_pending_p = 0;
return 0;
}
struct lwp_info *
find_lwp_pid (ptid_t ptid)
{
- thread_info *thread = find_thread ([&] (thread_info *thr_arg)
+ long lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid ();
+ thread_info *thread = find_thread ([lwp] (thread_info *thr_arg)
{
- int lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid ();
return thr_arg->id.lwp () == lwp;
});
void
linux_process_target::check_zombie_leaders ()
{
- for_each_process ([this] (process_info *proc) {
- pid_t leader_pid = pid_of (proc);
- struct lwp_info *leader_lp;
-
- leader_lp = find_lwp_pid (ptid_t (leader_pid));
-
- if (debug_threads)
- debug_printf ("leader_pid=%d, leader_lp!=NULL=%d, "
- "num_lwps=%d, zombie=%d\n",
- leader_pid, leader_lp!= NULL, num_lwps (leader_pid),
- linux_proc_pid_is_zombie (leader_pid));
-
- if (leader_lp != NULL && !leader_lp->stopped
- /* Check if there are other threads in the group, as we may
- have raced with the inferior simply exiting. */
- && !last_thread_of_process_p (leader_pid)
- && linux_proc_pid_is_zombie (leader_pid))
- {
- /* A leader zombie can mean one of two things:
-
- - It exited, and there's an exit status pending
- available, or only the leader exited (not the whole
- program). In the latter case, we can't waitpid the
- leader's exit status until all other threads are gone.
-
- - There are 3 or more threads in the group, and a thread
- other than the leader exec'd. On an exec, the Linux
- kernel destroys all other 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)'. As soon as
- all other threads are reaped, the execing thread changes
- it's tid to the tgid, and the previous (zombie) leader
- vanishes, giving place to the "new" leader. We could try
- distinguishing the exit and exec cases, by waiting once
- more, and seeing if something comes out, but it doesn't
- sound useful. The previous leader _does_ go away, and
- we'll re-add the new one once we see the exec event
- (which is just the same as what would happen if the
- previous leader did exit voluntarily before some other
- thread execs). */
-
- if (debug_threads)
- debug_printf ("CZL: Thread group leader %d zombie "
- "(it exited, or another thread execd).\n",
- leader_pid);
-
- delete_lwp (leader_lp);
- }
+ for_each_process ([this] (process_info *proc)
+ {
+ pid_t leader_pid = pid_of (proc);
+ lwp_info *leader_lp = find_lwp_pid (ptid_t (leader_pid));
+
+ threads_debug_printf ("leader_pid=%d, leader_lp!=NULL=%d, "
+ "num_lwps=%d, zombie=%d",
+ leader_pid, leader_lp!= NULL, num_lwps (leader_pid),
+ linux_proc_pid_is_zombie (leader_pid));
+
+ if (leader_lp != NULL && !leader_lp->stopped
+ /* 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. */
+ && !last_thread_of_process_p (leader_pid)
+ && linux_proc_pid_is_zombie (leader_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. */
+ threads_debug_printf ("Thread group leader %d zombie "
+ "(it exited, or another thread execd), "
+ "deleting it.",
+ leader_pid);
+ delete_lwp (leader_lp);
+ }
});
}
{
lwp->suspended++;
- if (debug_threads && lwp->suspended > 4)
- {
- struct thread_info *thread = get_lwp_thread (lwp);
-
- debug_printf ("LWP %ld has a suspiciously high suspend count,"
- " suspended=%d\n", lwpid_of (thread), lwp->suspended);
- }
+ if (lwp->suspended > 4)
+ threads_debug_printf
+ ("LWP %ld has a suspiciously high suspend count, suspended=%d",
+ lwpid_of (get_lwp_thread (lwp)), lwp->suspended);
}
/* Decrement LWP's suspend count. */
{
struct thread_info *thread = get_lwp_thread (lwp);
- internal_error (__FILE__, __LINE__,
- "unsuspend LWP %ld, suspended=%d\n", lwpid_of (thread),
+ internal_error ("unsuspend LWP %ld, suspended=%d\n", lwpid_of (thread),
lwp->suspended);
}
}
if (tpoint_related_event)
{
- if (debug_threads)
- debug_printf ("got a tracepoint event\n");
+ threads_debug_printf ("got a tracepoint event");
return 1;
}
{
struct fast_tpoint_collect_status status;
- if (debug_threads)
- debug_printf ("Checking whether LWP %ld needs to move out of the "
- "jump pad.\n",
- lwpid_of (current_thread));
+ threads_debug_printf
+ ("Checking whether LWP %ld needs to move out of the jump pad.",
+ lwpid_of (current_thread));
fast_tpoint_collect_result r
= linux_fast_tracepoint_collecting (lwp, &status);
= set_breakpoint_at (status.adjusted_insn_addr, NULL);
}
- if (debug_threads)
- debug_printf ("Checking whether LWP %ld needs to move out of "
- "the jump pad...it does\n",
- lwpid_of (current_thread));
+ threads_debug_printf
+ ("Checking whether LWP %ld needs to move out of the jump pad..."
+ " it does", lwpid_of (current_thread));
return true;
}
if (lwp->exit_jump_pad_bkpt != NULL)
{
- if (debug_threads)
- debug_printf ("Cancelling fast exit-jump-pad: removing bkpt. "
- "stopping all threads momentarily.\n");
+ threads_debug_printf
+ ("Cancelling fast exit-jump-pad: removing bkpt."
+ "stopping all threads momentarily.");
stop_all_lwps (1, lwp);
}
}
- if (debug_threads)
- debug_printf ("Checking whether LWP %ld needs to move out of the "
- "jump pad...no\n",
- lwpid_of (current_thread));
+ threads_debug_printf
+ ("Checking whether LWP %ld needs to move out of the jump pad... no",
+ lwpid_of (current_thread));
return false;
}
{
struct thread_info *thread = get_lwp_thread (lwp);
- if (debug_threads)
- debug_printf ("Deferring signal %d for LWP %ld.\n",
- WSTOPSIG (*wstat), lwpid_of (thread));
+ threads_debug_printf ("Deferring signal %d for LWP %ld.",
+ WSTOPSIG (*wstat), lwpid_of (thread));
if (debug_threads)
{
for (const auto &sig : lwp->pending_signals_to_report)
- debug_printf (" Already queued %d\n",
- sig.signal);
+ threads_debug_printf (" Already queued %d", sig.signal);
- debug_printf (" (no more currently queued signals)\n");
+ threads_debug_printf (" (no more currently queued signals)");
}
/* Don't enqueue non-RT signals if they are already in the deferred
{
if (sig.signal == WSTOPSIG (*wstat))
{
- if (debug_threads)
- debug_printf ("Not requeuing already queued non-RT signal %d"
- " for LWP %ld\n",
- sig.signal,
- lwpid_of (thread));
+ threads_debug_printf
+ ("Not requeuing already queued non-RT signal %d for LWP %ld",
+ sig.signal, lwpid_of (thread));
return;
}
}
lwp->pending_signals_to_report.pop_front ();
- if (debug_threads)
- debug_printf ("Reporting deferred signal %d for LWP %ld.\n",
- WSTOPSIG (*wstat), lwpid_of (thread));
+ threads_debug_printf ("Reporting deferred signal %d for LWP %ld.",
+ WSTOPSIG (*wstat), lwpid_of (thread));
if (debug_threads)
{
for (const auto &sig : lwp->pending_signals_to_report)
- debug_printf (" Still queued %d\n",
- sig.signal);
+ threads_debug_printf (" Still queued %d", sig.signal);
- debug_printf (" (no more queued signals)\n");
+ threads_debug_printf (" (no more queued signals)");
}
return 1;
child = find_lwp_pid (ptid_t (lwpid));
- /* Check for stop events reported by a process we didn't already
- know about - anything not already in our LWP list.
-
- If we're expecting to receive stopped processes after
- fork, vfork, and clone events, then we'll just add the
- new one to our list and go back to waiting for the event
- to be reported - the stopped process might be returned
- from waitpid before or after the event is.
-
- But note the case of a non-leader thread exec'ing after the
- leader having exited, and gone from our lists (because
- check_zombie_leaders deleted it). The non-leader thread
- changes its tid to the tgid. */
-
- if (WIFSTOPPED (wstat) && child == NULL && WSTOPSIG (wstat) == SIGTRAP
- && linux_ptrace_get_extended_event (wstat) == PTRACE_EVENT_EXEC)
+ /* Check for events reported by anything not in our LWP list. */
+ if (child == nullptr)
{
- ptid_t child_ptid;
-
- /* A multi-thread exec after we had seen the leader exiting. */
- if (debug_threads)
+ if (WIFSTOPPED (wstat))
{
- debug_printf ("LLW: Re-adding thread group leader LWP %d"
- "after exec.\n", lwpid);
+ if (WSTOPSIG (wstat) == SIGTRAP
+ && linux_ptrace_get_extended_event (wstat) == 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. */
+ threads_debug_printf
+ ("Re-adding thread group leader LWP %d after exec.",
+ lwpid);
+
+ child = add_lwp (ptid_t (lwpid, lwpid));
+ child->stopped = 1;
+ switch_to_thread (child->thread);
+ }
+ 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. */
+ threads_debug_printf
+ ("Saving LWP %d status %s in stopped_pids list",
+ lwpid, status_to_str (wstat).c_str ());
+ add_to_pid_list (&stopped_pids, lwpid, wstat);
+ }
}
+ 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. */
+ find_process ([&] (process_info *proc)
+ {
+ if (proc->pid == lwpid)
+ {
+ threads_debug_printf
+ ("Re-adding thread group leader LWP %d after exit.",
+ lwpid);
- child_ptid = ptid_t (lwpid, lwpid);
- child = add_lwp (child_ptid);
- child->stopped = 1;
- switch_to_thread (child->thread);
- }
+ child = add_lwp (ptid_t (lwpid, lwpid));
+ return true;
+ }
+ return false;
+ });
+ }
- /* If we didn't find a process, one of two things presumably happened:
- - A process we started and then detached from has exited. Ignore it.
- - A process we are controlling has forked and the new child's stop
- was reported to us by the kernel. Save its PID. */
- if (child == NULL && WIFSTOPPED (wstat))
- {
- add_to_pid_list (&stopped_pids, lwpid, wstat);
- return;
+ if (child == nullptr)
+ return;
}
- else if (child == NULL)
- return;
thread = get_lwp_thread (child);
/* Check if the thread has exited. */
if ((WIFEXITED (wstat) || WIFSIGNALED (wstat)))
{
- if (debug_threads)
- debug_printf ("LLFE: %d exited.\n", lwpid);
+ threads_debug_printf ("%d exited", lwpid);
if (finish_step_over (child))
{
unsuspend_all_lwps (child);
}
- /* If there is at least one more LWP, then the exit signal was
- not the end of the debugged application and should be
- ignored, unless GDB wants to hear about thread exits. */
- if (cs.report_thread_events
- || last_thread_of_process_p (pid_of (thread)))
+ /* If this is not the leader LWP, then the exit signal was not
+ the end of the debugged application and should be ignored,
+ unless GDB wants to hear about thread exits. */
+ if (cs.report_thread_events || is_leader (thread))
{
/* Since events are serialized to GDB core, and we can't
report this one right now. Leave the status pending for
if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP
&& child->stop_expected)
{
- if (debug_threads)
- debug_printf ("Expected stop.\n");
+ threads_debug_printf ("Expected stop.");
+
child->stop_expected = 0;
if (thread->last_resume_kind == resume_stop)
{
/* We want to report the stop to the core. Treat the
SIGSTOP as a normal event. */
- if (debug_threads)
- debug_printf ("LLW: resume_stop SIGSTOP caught for %s.\n",
- target_pid_to_str (ptid_of (thread)).c_str ());
+ threads_debug_printf ("resume_stop SIGSTOP caught for %s.",
+ target_pid_to_str (ptid_of (thread)).c_str ());
}
else if (stopping_threads != NOT_STOPPING_THREADS)
{
/* Stopping threads. We don't want this SIGSTOP to end up
pending. */
- if (debug_threads)
- debug_printf ("LLW: SIGSTOP caught for %s "
- "while stopping threads.\n",
- target_pid_to_str (ptid_of (thread)).c_str ());
+ threads_debug_printf ("SIGSTOP caught for %s while stopping threads.",
+ target_pid_to_str (ptid_of (thread)).c_str ());
return;
}
else
{
/* This is a delayed SIGSTOP. Filter out the event. */
- if (debug_threads)
- debug_printf ("LLW: %s %s, 0, 0 (discard delayed SIGSTOP)\n",
+ threads_debug_printf ("%s %s, 0, 0 (discard delayed SIGSTOP)",
child->stepping ? "step" : "continue",
target_pid_to_str (ptid_of (thread)).c_str ());
int step = 0;
if (thread->last_resume_kind == resume_step)
- step = maybe_hw_step (thread);
+ {
+ if (supports_software_single_step ())
+ install_software_single_step_breakpoints (lp);
- if (debug_threads)
- debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
- target_pid_to_str (ptid_of (thread)).c_str (),
- paddress (lp->stop_pc),
- step);
+ step = maybe_hw_step (thread);
+ }
+
+ threads_debug_printf ("resuming stopped-resumed LWP %s at %s: step=%d",
+ target_pid_to_str (ptid_of (thread)).c_str (),
+ paddress (lp->stop_pc), step);
resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL);
}
});
if (event_thread != NULL)
- event_child = get_thread_lwp (event_thread);
- if (debug_threads && event_thread)
- debug_printf ("Got a pending child %ld\n", lwpid_of (event_thread));
+ {
+ event_child = get_thread_lwp (event_thread);
+ threads_debug_printf ("Got a pending child %ld", lwpid_of (event_thread));
+ }
}
else if (filter_ptid != null_ptid)
{
if (requested_child->suspended
&& requested_child->status_pending_p)
{
- internal_error (__FILE__, __LINE__,
- "requesting an event out of a"
+ internal_error ("requesting an event out of a"
" suspended child?");
}
if (event_child != NULL)
{
- if (debug_threads)
- debug_printf ("Got an event from pending child %ld (%04x)\n",
- lwpid_of (event_thread), event_child->status_pending);
+ threads_debug_printf ("Got an event from pending child %ld (%04x)",
+ lwpid_of (event_thread),
+ event_child->status_pending);
+
*wstatp = event_child->status_pending;
event_child->status_pending_p = 0;
event_child->status_pending = 0;
errno = 0;
ret = my_waitpid (-1, wstatp, options | WNOHANG);
- if (debug_threads)
- debug_printf ("LWFE: waitpid(-1, ...) returned %d, %s\n",
- ret, errno ? safe_strerror (errno) : "ERRNO-OK");
+ threads_debug_printf ("waitpid(-1, ...) returned %d, %s",
+ ret, errno ? safe_strerror (errno) : "ERRNO-OK");
if (ret > 0)
{
- if (debug_threads)
- {
- debug_printf ("LLW: waitpid %ld received %s\n",
- (long) ret, status_to_str (*wstatp).c_str ());
- }
+ threads_debug_printf ("waitpid %ld received %s",
+ (long) ret, status_to_str (*wstatp).c_str ());
/* Filter all events. IOW, leave all events pending. We'll
randomly select an event LWP out of all that have events
over 0 (below), as it is more detailed. */
if (find_thread (not_stopped) == NULL)
{
- if (debug_threads)
- debug_printf ("LLW: exit (no unwaited-for LWP)\n");
+ threads_debug_printf ("exit (no unwaited-for LWP)");
+
gdb_sigmask (SIG_SETMASK, &prev_mask, NULL);
return -1;
}
/* No interesting event to report to the caller. */
if ((options & WNOHANG))
{
- if (debug_threads)
- debug_printf ("WNOHANG set, no event found\n");
+ threads_debug_printf ("WNOHANG set, no event found");
gdb_sigmask (SIG_SETMASK, &prev_mask, NULL);
return 0;
}
/* Block until we get an event reported with SIGCHLD. */
- if (debug_threads)
- debug_printf ("sigsuspend'ing\n");
+ threads_debug_printf ("sigsuspend'ing");
sigsuspend (&prev_mask);
gdb_sigmask (SIG_SETMASK, &prev_mask, NULL);
});
if (event_thread != NULL)
- {
- if (debug_threads)
- debug_printf ("SEL: Select single-step %s\n",
- target_pid_to_str (ptid_of (event_thread)).c_str ());
- }
+ threads_debug_printf
+ ("Select single-step %s",
+ target_pid_to_str (ptid_of (event_thread)).c_str ());
}
if (event_thread == NULL)
{
if (thread_stuck != NULL)
{
- if (debug_threads)
- debug_printf ("can't stabilize, LWP %ld is stuck in jump pad\n",
- lwpid_of (thread_stuck));
+ threads_debug_printf ("can't stabilize, LWP %ld is stuck in jump pad",
+ lwpid_of (thread_stuck));
return;
}
});
if (thread_stuck != NULL)
- debug_printf ("couldn't stabilize, LWP %ld got stuck in jump pad\n",
- lwpid_of (thread_stuck));
+ threads_debug_printf
+ ("couldn't stabilize, LWP %ld got stuck in jump pad",
+ lwpid_of (thread_stuck));
}
}
struct thread_info *thread = get_lwp_thread (event_child);
ptid_t ptid = ptid_of (thread);
- if (!last_thread_of_process_p (pid_of (thread)))
+ if (!is_leader (thread))
{
if (cs.report_thread_events)
ourstatus->set_thread_exited (0);
linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
target_wait_flags target_options)
{
+ THREADS_SCOPED_DEBUG_ENTER_EXIT;
+
client_state &cs = get_client_state ();
int w;
struct lwp_info *event_child;
int in_step_range;
int any_resumed;
- if (debug_threads)
- {
- debug_enter ();
- debug_printf ("wait_1: [%s]\n", target_pid_to_str (ptid).c_str ());
- }
+ threads_debug_printf ("[%s]", target_pid_to_str (ptid).c_str ());
/* Translate generic target options into linux options. */
options = __WALL;
pid = wait_for_event (ptid, &w, options);
else
{
- if (debug_threads)
- debug_printf ("step_over_bkpt set [%s], doing a blocking wait\n",
- target_pid_to_str (step_over_bkpt).c_str ());
+ threads_debug_printf ("step_over_bkpt set [%s], doing a blocking wait",
+ target_pid_to_str (step_over_bkpt).c_str ());
pid = wait_for_event (step_over_bkpt, &w, options & ~WNOHANG);
}
{
gdb_assert (target_options & TARGET_WNOHANG);
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = null_ptid, "
- "TARGET_WAITKIND_IGNORE\n");
- debug_exit ();
- }
+ threads_debug_printf ("ret = null_ptid, TARGET_WAITKIND_IGNORE");
ourstatus->set_ignore ();
return null_ptid;
}
else if (pid == -1)
{
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = null_ptid, "
- "TARGET_WAITKIND_NO_RESUMED\n");
- debug_exit ();
- }
+ threads_debug_printf ("ret = null_ptid, TARGET_WAITKIND_NO_RESUMED");
ourstatus->set_no_resumed ();
return null_ptid;
{
ourstatus->set_exited (WEXITSTATUS (w));
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = %s, exited with "
- "retcode %d\n",
- target_pid_to_str (ptid_of (current_thread)).c_str (),
- WEXITSTATUS (w));
- debug_exit ();
- }
+ threads_debug_printf
+ ("ret = %s, exited with retcode %d",
+ target_pid_to_str (ptid_of (current_thread)).c_str (),
+ WEXITSTATUS (w));
}
else
{
ourstatus->set_signalled (gdb_signal_from_host (WTERMSIG (w)));
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = %s, terminated with "
- "signal %d\n",
- target_pid_to_str (ptid_of (current_thread)).c_str (),
- WTERMSIG (w));
- debug_exit ();
- }
+ threads_debug_printf
+ ("ret = %s, terminated with signal %d",
+ target_pid_to_str (ptid_of (current_thread)).c_str (),
+ WTERMSIG (w));
}
if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
breakpoint_kind = breakpoint_kind_from_current_state (&stop_pc);
sw_breakpoint_from_kind (breakpoint_kind, &increment_pc);
- if (debug_threads)
- {
- debug_printf ("step-over for %s executed software breakpoint\n",
- target_pid_to_str (ptid_of (current_thread)).c_str ());
- }
+ threads_debug_printf
+ ("step-over for %s executed software breakpoint",
+ target_pid_to_str (ptid_of (current_thread)).c_str ());
if (increment_pc != 0)
{
trace_event = handle_tracepoints (event_child);
if (bp_explains_trap)
- {
- if (debug_threads)
- debug_printf ("Hit a gdbserver breakpoint.\n");
- }
+ threads_debug_printf ("Hit a gdbserver breakpoint.");
}
else
{
&& supports_fast_tracepoints ()
&& agent_loaded_p ())
{
- if (debug_threads)
- debug_printf ("Got signal %d for LWP %ld. Check if we need "
- "to defer or adjust it.\n",
- WSTOPSIG (w), lwpid_of (current_thread));
+ threads_debug_printf ("Got signal %d for LWP %ld. Check if we need "
+ "to defer or adjust it.",
+ WSTOPSIG (w), lwpid_of (current_thread));
/* Allow debugging the jump pad itself. */
if (current_thread->last_resume_kind != resume_step
{
enqueue_one_deferred_signal (event_child, &w);
- if (debug_threads)
- debug_printf ("Signal %d for LWP %ld deferred (in jump pad)\n",
- WSTOPSIG (w), lwpid_of (current_thread));
+ threads_debug_printf ("Signal %d for LWP %ld deferred (in jump pad)",
+ WSTOPSIG (w), lwpid_of (current_thread));
resume_one_lwp (event_child, 0, 0, NULL);
- if (debug_threads)
- debug_exit ();
return ignore_event (ourstatus);
}
}
if (event_child->collecting_fast_tracepoint
!= fast_tpoint_collect_result::not_collecting)
{
- if (debug_threads)
- debug_printf ("LWP %ld was trying to move out of the jump pad (%d). "
- "Check if we're already there.\n",
- lwpid_of (current_thread),
- (int) event_child->collecting_fast_tracepoint);
+ threads_debug_printf
+ ("LWP %ld was trying to move out of the jump pad (%d). "
+ "Check if we're already there.",
+ lwpid_of (current_thread),
+ (int) event_child->collecting_fast_tracepoint);
trace_event = 1;
/* No longer need this breakpoint. */
if (event_child->exit_jump_pad_bkpt != NULL)
{
- if (debug_threads)
- debug_printf ("No longer need exit-jump-pad bkpt; removing it."
- "stopping all threads momentarily.\n");
+ threads_debug_printf
+ ("No longer need exit-jump-pad bkpt; removing it."
+ "stopping all threads momentarily.");
/* Other running threads could hit this breakpoint.
We don't handle moribund locations like GDB does,
if (event_child->collecting_fast_tracepoint
== fast_tpoint_collect_result::not_collecting)
{
- if (debug_threads)
- debug_printf ("fast tracepoint finished "
- "collecting successfully.\n");
+ threads_debug_printf
+ ("fast tracepoint finished collecting successfully.");
/* We may have a deferred signal to report. */
if (dequeue_one_deferred_signal (event_child, &w))
- {
- if (debug_threads)
- debug_printf ("dequeued one signal.\n");
- }
+ threads_debug_printf ("dequeued one signal.");
else
{
- if (debug_threads)
- debug_printf ("no deferred signals.\n");
+ threads_debug_printf ("no deferred signals.");
if (stabilizing_threads)
{
ourstatus->set_stopped (GDB_SIGNAL_0);
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = %s, stopped "
- "while stabilizing threads\n",
- target_pid_to_str
- (ptid_of (current_thread)).c_str ());
- debug_exit ();
- }
+ threads_debug_printf
+ ("ret = %s, stopped while stabilizing threads",
+ target_pid_to_str (ptid_of (current_thread)).c_str ());
return ptid_of (current_thread);
}
&& WSTOPSIG (w) == SYSCALL_SIGTRAP
&& !gdb_catch_this_syscall (event_child))
{
- if (debug_threads)
- {
- debug_printf ("Ignored syscall for LWP %ld.\n",
- lwpid_of (current_thread));
- }
+ threads_debug_printf ("Ignored syscall for LWP %ld.",
+ lwpid_of (current_thread));
resume_one_lwp (event_child, event_child->stepping, 0, NULL);
- if (debug_threads)
- debug_exit ();
return ignore_event (ourstatus);
}
{
siginfo_t info, *info_p;
- if (debug_threads)
- debug_printf ("Ignored signal %d for LWP %ld.\n",
- WSTOPSIG (w), lwpid_of (current_thread));
+ threads_debug_printf ("Ignored signal %d for LWP %ld.",
+ WSTOPSIG (w), lwpid_of (current_thread));
if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread),
(PTRACE_TYPE_ARG3) 0, &info) == 0)
WSTOPSIG (w), info_p);
}
- if (debug_threads)
- debug_exit ();
-
return ignore_event (ourstatus);
}
shouldn't know about. */
if (!report_to_gdb)
{
- if (debug_threads)
- {
- if (bp_explains_trap)
- debug_printf ("Hit a gdbserver breakpoint.\n");
- if (step_over_finished)
- debug_printf ("Step-over finished.\n");
- if (trace_event)
- debug_printf ("Tracepoint event.\n");
- if (lwp_in_step_range (event_child))
- debug_printf ("Range stepping pc 0x%s [0x%s, 0x%s).\n",
- paddress (event_child->stop_pc),
- paddress (event_child->step_range_start),
- paddress (event_child->step_range_end));
- }
+ if (bp_explains_trap)
+ threads_debug_printf ("Hit a gdbserver breakpoint.");
+
+ if (step_over_finished)
+ threads_debug_printf ("Step-over finished.");
+
+ if (trace_event)
+ threads_debug_printf ("Tracepoint event.");
+
+ if (lwp_in_step_range (event_child))
+ threads_debug_printf ("Range stepping pc 0x%s [0x%s, 0x%s).",
+ paddress (event_child->stop_pc),
+ paddress (event_child->step_range_start),
+ paddress (event_child->step_range_end));
/* We're not reporting this breakpoint to GDB, so apply the
decr_pc_after_break adjustment to the inferior's regcache
}
}
- if (debug_threads)
- debug_printf ("proceeding all threads.\n");
- proceed_all_lwps ();
+ threads_debug_printf ("proceeding all threads.");
- if (debug_threads)
- debug_exit ();
+ proceed_all_lwps ();
return ignore_event (ourstatus);
}
- if (debug_threads)
- {
- if (event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
- debug_printf ("LWP %ld: extended event with waitstatus %s\n",
- lwpid_of (get_lwp_thread (event_child)),
- event_child->waitstatus.to_string ().c_str ());
- if (current_thread->last_resume_kind == resume_step)
- {
- if (event_child->step_range_start == event_child->step_range_end)
- debug_printf ("GDB wanted to single-step, reporting event.\n");
- else if (!lwp_in_step_range (event_child))
- debug_printf ("Out of step range, reporting event.\n");
- }
- if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
- debug_printf ("Stopped by watchpoint.\n");
- else if (gdb_breakpoint_here (event_child->stop_pc))
- debug_printf ("Stopped by GDB breakpoint.\n");
- if (debug_threads)
- debug_printf ("Hit a non-gdbserver trap event.\n");
- }
+ if (debug_threads)
+ {
+ if (event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
+ threads_debug_printf ("LWP %ld: extended event with waitstatus %s",
+ lwpid_of (get_lwp_thread (event_child)),
+ event_child->waitstatus.to_string ().c_str ());
+
+ if (current_thread->last_resume_kind == resume_step)
+ {
+ if (event_child->step_range_start == event_child->step_range_end)
+ threads_debug_printf
+ ("GDB wanted to single-step, reporting event.");
+ else if (!lwp_in_step_range (event_child))
+ threads_debug_printf ("Out of step range, reporting event.");
+ }
+
+ if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
+ threads_debug_printf ("Stopped by watchpoint.");
+ else if (gdb_breakpoint_here (event_child->stop_pc))
+ threads_debug_printf ("Stopped by GDB breakpoint.");
+ }
+
+ threads_debug_printf ("Hit a non-gdbserver trap event.");
/* Alright, we're going to report a stop. */
unstop_all_lwps (1, event_child);
}
+ /* At this point, we haven't set OURSTATUS. This is where we do it. */
+ gdb_assert (ourstatus->kind () == TARGET_WAITKIND_IGNORE);
+
if (event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
{
/* If the reported event is an exit, fork, vfork or exec, let
}
else
{
- /* The actual stop signal is overwritten below. */
- ourstatus->set_stopped (GDB_SIGNAL_0);
+ /* The LWP stopped due to a plain signal or a syscall signal. Either way,
+ event_child->waitstatus wasn't filled in with the details, so look at
+ the wait status W. */
+ if (WSTOPSIG (w) == SYSCALL_SIGTRAP)
+ {
+ int syscall_number;
+
+ get_syscall_trapinfo (event_child, &syscall_number);
+ if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
+ ourstatus->set_syscall_entry (syscall_number);
+ else if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_RETURN)
+ ourstatus->set_syscall_return (syscall_number);
+ else
+ gdb_assert_not_reached ("unexpected syscall state");
+ }
+ else if (current_thread->last_resume_kind == resume_stop
+ && WSTOPSIG (w) == SIGSTOP)
+ {
+ /* A thread that has been requested to stop by GDB with vCont;t,
+ and it stopped cleanly, so report as SIG0. The use of
+ SIGSTOP is an implementation detail. */
+ ourstatus->set_stopped (GDB_SIGNAL_0);
+ }
+ else
+ ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
}
/* Now that we've selected our final event LWP, un-adjust its PC if
}
}
- if (WSTOPSIG (w) == SYSCALL_SIGTRAP)
- {
- int syscall_number;
-
- get_syscall_trapinfo (event_child, &syscall_number);
- if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
- ourstatus->set_syscall_entry (syscall_number);
- else if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_RETURN)
- ourstatus->set_syscall_return (syscall_number);
- else
- gdb_assert_not_reached ("unexpected syscall state");
- }
- else if (current_thread->last_resume_kind == resume_stop
- && WSTOPSIG (w) == SIGSTOP)
- {
- /* A thread that has been requested to stop by GDB with vCont;t,
- and it stopped cleanly, so report as SIG0. The use of
- SIGSTOP is an implementation detail. */
- ourstatus->set_stopped (GDB_SIGNAL_0);
- }
- else if (current_thread->last_resume_kind == resume_stop
- && WSTOPSIG (w) != SIGSTOP)
- {
- /* A thread that has been requested to stop by GDB with vCont;t,
- but, it stopped for other reasons. */
- ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
- }
- else if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
- ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
-
gdb_assert (step_over_bkpt == null_ptid);
- if (debug_threads)
- {
- debug_printf ("wait_1 ret = %s, %d, %d\n",
- target_pid_to_str (ptid_of (current_thread)).c_str (),
- ourstatus->kind (), ourstatus->sig ());
- debug_exit ();
- }
+ threads_debug_printf ("ret = %s, %s",
+ target_pid_to_str (ptid_of (current_thread)).c_str (),
+ ourstatus->to_string ().c_str ());
if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
return filter_exit_event (event_child, ourstatus);
static void
async_file_flush (void)
{
- int ret;
- char buf;
-
- do
- ret = read (linux_event_pipe[0], &buf, 1);
- while (ret >= 0 || (ret == -1 && errno == EINTR));
+ linux_event_pipe.flush ();
}
/* Put something in the pipe, so the event loop wakes up. */
static void
async_file_mark (void)
{
- int ret;
-
- async_file_flush ();
-
- do
- ret = write (linux_event_pipe[1], "+", 1);
- while (ret == 0 || (ret == -1 && errno == EINTR));
-
- /* Ignore EAGAIN. If the pipe is full, the event loop will already
- be awakened anyway. */
+ linux_event_pipe.mark ();
}
ptid_t
send another. */
if (lwp->stop_expected)
{
- if (debug_threads)
- debug_printf ("Have pending sigstop for lwp %d\n", pid);
+ threads_debug_printf ("Have pending sigstop for lwp %d", pid);
return;
}
- if (debug_threads)
- debug_printf ("Sending sigstop to lwp %d\n", pid);
+ threads_debug_printf ("Sending sigstop to lwp %d", pid);
lwp->stop_expected = 1;
kill_lwp (pid, SIGSTOP);
scoped_restore_current_thread restore_thread;
- if (debug_threads)
- debug_printf ("wait_for_sigstop: pulling events\n");
+ threads_debug_printf ("pulling events");
/* Passing NULL_PTID as filter indicates we want all events to be
left pending. Eventually this returns when there are no
return;
else
{
- if (debug_threads)
- debug_printf ("Previously current thread died.\n");
+ threads_debug_printf ("Previously current thread died.");
/* We can't change the current inferior behind GDB's back,
otherwise, a subsequent command may apply to the wrong
if (lwp->suspended != 0)
{
- internal_error (__FILE__, __LINE__,
- "LWP %ld is suspended, suspended=%d\n",
+ internal_error ("LWP %ld is suspended, suspended=%d\n",
lwpid_of (thread), lwp->suspended);
}
gdb_assert (lwp->stopped);
if (lwp->suspended != 0)
{
- internal_error (__FILE__, __LINE__,
- "LWP %ld is suspended, suspended=%d\n",
+ internal_error ("LWP %ld is suspended, suspended=%d\n",
lwpid_of (thread), lwp->suspended);
}
gdb_assert (lwp->stopped);
&& thread->last_resume_kind != resume_step
&& maybe_move_out_of_jump_pad (lwp, wstat))
{
- if (debug_threads)
- debug_printf ("LWP %ld needs stabilizing (in jump pad)\n",
- lwpid_of (thread));
+ threads_debug_printf ("LWP %ld needs stabilizing (in jump pad)",
+ lwpid_of (thread));
if (wstat)
{
lwp->status_pending_p = 0;
enqueue_one_deferred_signal (lwp, wstat);
- if (debug_threads)
- debug_printf ("Signal %d for LWP %ld deferred "
- "(in jump pad)\n",
- WSTOPSIG (*wstat), lwpid_of (thread));
+ threads_debug_printf ("Signal %d for LWP %ld deferred (in jump pad",
+ WSTOPSIG (*wstat), lwpid_of (thread));
}
resume_one_lwp (lwp, 0, 0, NULL);
/* Should not be called recursively. */
gdb_assert (stopping_threads == NOT_STOPPING_THREADS);
- if (debug_threads)
- {
- debug_enter ();
- debug_printf ("stop_all_lwps (%s, except=%s)\n",
- suspend ? "stop-and-suspend" : "stop",
- (except != NULL
- ? target_pid_to_str
- (ptid_of (get_lwp_thread (except))).c_str ()
- : "none"));
- }
+ THREADS_SCOPED_DEBUG_ENTER_EXIT;
+
+ threads_debug_printf
+ ("%s, except=%s", suspend ? "stop-and-suspend" : "stop",
+ (except != NULL
+ ? target_pid_to_str (ptid_of (get_lwp_thread (except))).c_str ()
+ : "none"));
stopping_threads = (suspend
? STOPPING_AND_SUSPENDING_THREADS
wait_for_sigstop ();
stopping_threads = NOT_STOPPING_THREADS;
- if (debug_threads)
- {
- debug_printf ("stop_all_lwps done, setting stopping_threads "
- "back to !stopping\n");
- debug_exit ();
- }
+ threads_debug_printf ("setting stopping_threads back to !stopping");
}
/* Enqueue one signal in the chain of signals which need to be
step = 0;
}
else
- {
- if (debug_threads)
- debug_printf ("stepping is not implemented on this target");
- }
+ threads_debug_printf ("stepping is not implemented on this target");
return step;
}
if (lwp->status_pending_p)
{
- if (debug_threads)
- debug_printf ("Not resuming lwp %ld (%s, stop %s);"
- " has pending status\n",
- lwpid_of (thread), step ? "step" : "continue",
- lwp->stop_expected ? "expected" : "not expected");
+ threads_debug_printf
+ ("Not resuming lwp %ld (%s, stop %s); has pending status",
+ lwpid_of (thread), step ? "step" : "continue",
+ lwp->stop_expected ? "expected" : "not expected");
return;
}
worthwhile just to solve this one, however. */
if (lwp->bp_reinsert != 0)
{
- if (debug_threads)
- debug_printf (" pending reinsert at 0x%s\n",
- paddress (lwp->bp_reinsert));
+ threads_debug_printf (" pending reinsert at 0x%s",
+ paddress (lwp->bp_reinsert));
if (supports_hardware_single_step ())
{
}
if (fast_tp_collecting == fast_tpoint_collect_result::before_insn)
- {
- if (debug_threads)
- debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad"
- " (exit-jump-pad-bkpt)\n",
- lwpid_of (thread));
- }
+ threads_debug_printf
+ ("lwp %ld wants to get out of fast tracepoint jump pad "
+ "(exit-jump-pad-bkpt)", lwpid_of (thread));
+
else if (fast_tp_collecting == fast_tpoint_collect_result::at_insn)
{
- if (debug_threads)
- debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad"
- " single-stepping\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("lwp %ld wants to get out of fast tracepoint jump pad single-stepping",
+ lwpid_of (thread));
if (supports_hardware_single_step ())
step = 1;
else
{
- internal_error (__FILE__, __LINE__,
- "moving out of jump pad single-stepping"
+ internal_error ("moving out of jump pad single-stepping"
" not implemented on this target");
}
}
enhancement. */
if (thread->while_stepping != NULL)
{
- if (debug_threads)
- debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("lwp %ld has a while-stepping action -> forcing step.",
+ lwpid_of (thread));
step = single_step (lwp);
}
lwp->stop_pc = low_get_pc (regcache);
- if (debug_threads)
- {
- debug_printf (" %s from pc 0x%lx\n", step ? "step" : "continue",
- (long) lwp->stop_pc);
- }
+ threads_debug_printf (" %s from pc 0x%lx", step ? "step" : "continue",
+ (long) lwp->stop_pc);
}
/* If we have pending signals, consume one if it can be delivered to
lwp->pending_signals.pop_front ();
}
- if (debug_threads)
- debug_printf ("Resuming lwp %ld (%s, signal %d, stop %s)\n",
- lwpid_of (thread), step ? "step" : "continue", signal,
- lwp->stop_expected ? "expected" : "not expected");
+ threads_debug_printf ("Resuming lwp %ld (%s, signal %d, stop %s)",
+ lwpid_of (thread), step ? "step" : "continue", signal,
+ lwp->stop_expected ? "expected" : "not expected");
low_prepare_to_resume (lwp);
(PTRACE_TYPE_ARG4) (uintptr_t) signal);
if (errno)
- perror_with_name ("resuming thread");
+ {
+ int saved_errno = errno;
+
+ threads_debug_printf ("ptrace errno = %d (%s)",
+ saved_errno, strerror (saved_errno));
+
+ errno = saved_errno;
+ perror_with_name ("resuming thread");
+ }
/* Successfully resumed. Clear state that no longer makes sense,
and mark the LWP as running. Must not do this before resuming
}
catch (const gdb_exception_error &ex)
{
- if (!check_ptrace_stopped_lwp_gone (lwp))
+ if (check_ptrace_stopped_lwp_gone (lwp))
+ {
+ /* This could because we tried to resume an LWP after its leader
+ exited. Mark it as resumed, so we can collect an exit event
+ from it. */
+ lwp->stopped = 0;
+ lwp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+ }
+ else
throw;
}
}
if (resume[ndx].kind == resume_stop
&& thread->last_resume_kind == resume_stop)
{
- if (debug_threads)
- debug_printf ("already %s LWP %ld at GDB's request\n",
- (thread->last_status.kind ()
- == TARGET_WAITKIND_STOPPED)
- ? "stopped"
- : "stopping",
- lwpid_of (thread));
+ threads_debug_printf
+ ("already %s LWP %ld at GDB's request",
+ (thread->last_status.kind () == TARGET_WAITKIND_STOPPED
+ ? "stopped" : "stopping"),
+ lwpid_of (thread));
continue;
}
if (resume[ndx].kind != resume_stop
&& thread->last_resume_kind != resume_stop)
{
- if (debug_threads)
- debug_printf ("already %s LWP %ld at GDB's request\n",
- (thread->last_resume_kind
- == resume_step)
- ? "stepping"
- : "continuing",
- lwpid_of (thread));
+ threads_debug_printf
+ ("already %s LWP %ld at GDB's request",
+ (thread->last_resume_kind == resume_step
+ ? "stepping" : "continuing"),
+ lwpid_of (thread));
continue;
}
&& (rel->waitstatus.kind () == TARGET_WAITKIND_FORKED
|| rel->waitstatus.kind () == TARGET_WAITKIND_VFORKED))
{
- if (debug_threads)
- debug_printf ("not resuming LWP %ld: has queued stop reply\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("not resuming LWP %ld: has queued stop reply",
+ lwpid_of (thread));
continue;
}
}
(wildcard) resume request. */
if (in_queued_stop_replies (thread->id))
{
- if (debug_threads)
- debug_printf ("not resuming LWP %ld: has queued stop reply\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("not resuming LWP %ld: has queued stop reply",
+ lwpid_of (thread));
continue;
}
{
lwp->status_pending_p = 1;
- if (debug_threads)
- debug_printf ("Dequeueing deferred signal %d for LWP %ld, "
- "leaving status pending.\n",
- WSTOPSIG (lwp->status_pending),
- lwpid_of (thread));
+ threads_debug_printf
+ ("Dequeueing deferred signal %d for LWP %ld, "
+ "leaving status pending.",
+ WSTOPSIG (lwp->status_pending),
+ lwpid_of (thread));
}
return;
if (!lwp->stopped)
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Ignoring, not stopped\n",
- lwpid_of (thread));
+ threads_debug_printf ("Need step over [LWP %ld]? Ignoring, not stopped",
+ lwpid_of (thread));
return false;
}
if (thread->last_resume_kind == resume_stop)
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Ignoring, should remain"
- " stopped\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("Need step over [LWP %ld]? Ignoring, should remain stopped",
+ lwpid_of (thread));
return false;
}
if (lwp->suspended)
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Ignoring, suspended\n",
- lwpid_of (thread));
+ threads_debug_printf ("Need step over [LWP %ld]? Ignoring, suspended",
+ lwpid_of (thread));
return false;
}
if (lwp->status_pending_p)
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Ignoring, has pending"
- " status.\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("Need step over [LWP %ld]? Ignoring, has pending status.",
+ lwpid_of (thread));
return false;
}
command, or poked thread's registers herself. */
if (pc != lwp->stop_pc)
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Cancelling, PC was changed. "
- "Old stop_pc was 0x%s, PC is now 0x%s\n",
- lwpid_of (thread),
- paddress (lwp->stop_pc), paddress (pc));
+ threads_debug_printf
+ ("Need step over [LWP %ld]? Cancelling, PC was changed. "
+ "Old stop_pc was 0x%s, PC is now 0x%s", lwpid_of (thread),
+ paddress (lwp->stop_pc), paddress (pc));
return false;
}
&& !lwp->pending_signals.empty ()
&& lwp_signal_can_be_delivered (lwp))
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? Ignoring, has pending"
- " signals.\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("Need step over [LWP %ld]? Ignoring, has pending signals.",
+ lwpid_of (thread));
return false;
}
&& gdb_condition_true_at_breakpoint (pc)
&& gdb_no_commands_at_breakpoint (pc))
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? yes, but found"
- " GDB breakpoint at 0x%s; skipping step over\n",
- lwpid_of (thread), paddress (pc));
+ threads_debug_printf ("Need step over [LWP %ld]? yes, but found"
+ " GDB breakpoint at 0x%s; skipping step over",
+ lwpid_of (thread), paddress (pc));
return false;
}
else
{
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? yes, "
- "found breakpoint at 0x%s\n",
- lwpid_of (thread), paddress (pc));
+ threads_debug_printf ("Need step over [LWP %ld]? yes, "
+ "found breakpoint at 0x%s",
+ lwpid_of (thread), paddress (pc));
/* We've found an lwp that needs stepping over --- return 1 so
that find_thread stops looking. */
}
}
- if (debug_threads)
- debug_printf ("Need step over [LWP %ld]? No, no breakpoint found"
- " at 0x%s\n",
- lwpid_of (thread), paddress (pc));
+ threads_debug_printf
+ ("Need step over [LWP %ld]? No, no breakpoint found at 0x%s",
+ lwpid_of (thread), paddress (pc));
return false;
}
struct thread_info *thread = get_lwp_thread (lwp);
CORE_ADDR pc;
- if (debug_threads)
- debug_printf ("Starting step-over on LWP %ld. Stopping all threads\n",
- lwpid_of (thread));
+ threads_debug_printf ("Starting step-over on LWP %ld. Stopping all threads",
+ lwpid_of (thread));
stop_all_lwps (1, lwp);
if (lwp->suspended != 0)
{
- internal_error (__FILE__, __LINE__,
- "LWP %ld suspended=%d\n", lwpid_of (thread),
+ internal_error ("LWP %ld suspended=%d\n", lwpid_of (thread),
lwp->suspended);
}
- if (debug_threads)
- debug_printf ("Done stopping all threads for step-over.\n");
+ threads_debug_printf ("Done stopping all threads for step-over.");
/* Note, we should always reach here with an already adjusted PC,
either by GDB (if we're resuming due to GDB's request), or by our
{
scoped_restore_current_thread restore_thread;
- if (debug_threads)
- debug_printf ("Finished step over.\n");
+ threads_debug_printf ("Finished step over.");
switch_to_thread (get_lwp_thread (lwp));
int wstat;
int ret;
- if (debug_threads)
- debug_printf ("detach: step over in progress, finish it first\n");
+ threads_debug_printf ("detach: step over in progress, finish it first");
/* Passing NULL_PTID as filter indicates we want all events to
be left pending. Eventually this returns when there are no
thread_info *thread = get_lwp_thread (lwp);
if (thread->last_resume_kind != resume_step)
{
- if (debug_threads)
- debug_printf ("detach: discard step-over SIGTRAP\n");
+ threads_debug_printf ("detach: discard step-over SIGTRAP");
lwp->status_pending_p = 0;
lwp->status_pending = 0;
resume_one_lwp (lwp, lwp->stepping, 0, NULL);
}
else
- {
- if (debug_threads)
- debug_printf ("detach: resume_step, "
- "not discarding step-over SIGTRAP\n");
- }
+ threads_debug_printf
+ ("detach: resume_step, not discarding step-over SIGTRAP");
}
}
step_over_bkpt = null_ptid;
if (lwp->resume->kind == resume_stop)
{
- if (debug_threads)
- debug_printf ("resume_stop request for LWP %ld\n", lwpid_of (thread));
+ threads_debug_printf ("resume_stop request for LWP %ld",
+ lwpid_of (thread));
if (!lwp->stopped)
{
- if (debug_threads)
- debug_printf ("stopping LWP %ld\n", lwpid_of (thread));
+ threads_debug_printf ("stopping LWP %ld", lwpid_of (thread));
/* Stop the thread, and wait for the event asynchronously,
through the event loop. */
}
else
{
- if (debug_threads)
- debug_printf ("already stopped LWP %ld\n",
- lwpid_of (thread));
+ threads_debug_printf ("already stopped LWP %ld", lwpid_of (thread));
/* The LWP may have been stopped in an internal event that
was not meant to be notified back to GDB (e.g., gdbserver
if (!leave_pending)
{
- if (debug_threads)
- debug_printf ("resuming LWP %ld\n", lwpid_of (thread));
+ threads_debug_printf ("resuming LWP %ld", lwpid_of (thread));
proceed_one_lwp (thread, NULL);
}
else
- {
- if (debug_threads)
- debug_printf ("leaving LWP %ld stopped\n", lwpid_of (thread));
- }
+ threads_debug_printf ("leaving LWP %ld stopped", lwpid_of (thread));
thread->last_status.set_ignore ();
lwp->resume = NULL;
{
struct thread_info *need_step_over = NULL;
- if (debug_threads)
- {
- debug_enter ();
- debug_printf ("linux_resume:\n");
- }
+ THREADS_SCOPED_DEBUG_ENTER_EXIT;
for_each_thread ([&] (thread_info *thread)
{
bool leave_all_stopped = (need_step_over != NULL || any_pending);
- if (debug_threads)
- {
- if (need_step_over != NULL)
- debug_printf ("Not resuming all, need step over\n");
- else if (any_pending)
- debug_printf ("Not resuming, all-stop and found "
- "an LWP with pending status\n");
- else
- debug_printf ("Resuming, no pending status or step over needed\n");
- }
+ if (need_step_over != NULL)
+ threads_debug_printf ("Not resuming all, need step over");
+ else if (any_pending)
+ threads_debug_printf ("Not resuming, all-stop and found "
+ "an LWP with pending status");
+ else
+ threads_debug_printf ("Resuming, no pending status or step over needed");
/* Even if we're leaving threads stopped, queue all signals we'd
otherwise deliver. */
if (need_step_over)
start_step_over (get_thread_lwp (need_step_over));
- if (debug_threads)
- {
- debug_printf ("linux_resume done\n");
- debug_exit ();
- }
-
/* We may have events that were pending that can/should be sent to
the client now. Trigger a linux_wait call. */
if (target_is_async_p ())
if (lwp == except)
return;
- if (debug_threads)
- debug_printf ("proceed_one_lwp: lwp %ld\n", lwpid_of (thread));
+ threads_debug_printf ("lwp %ld", lwpid_of (thread));
if (!lwp->stopped)
{
- if (debug_threads)
- debug_printf (" LWP %ld already running\n", lwpid_of (thread));
+ threads_debug_printf (" LWP %ld already running", lwpid_of (thread));
return;
}
if (thread->last_resume_kind == resume_stop
&& thread->last_status.kind () != TARGET_WAITKIND_IGNORE)
{
- if (debug_threads)
- debug_printf (" client wants LWP to remain %ld stopped\n",
- lwpid_of (thread));
+ threads_debug_printf (" client wants LWP to remain %ld stopped",
+ lwpid_of (thread));
return;
}
if (lwp->status_pending_p)
{
- if (debug_threads)
- debug_printf (" LWP %ld has pending status, leaving stopped\n",
- lwpid_of (thread));
+ threads_debug_printf (" LWP %ld has pending status, leaving stopped",
+ lwpid_of (thread));
return;
}
if (lwp->suspended)
{
- if (debug_threads)
- debug_printf (" LWP %ld is suspended\n", lwpid_of (thread));
+ threads_debug_printf (" LWP %ld is suspended", lwpid_of (thread));
return;
}
another one here. Note that if the LWP already has a SIGSTOP
pending, this is a no-op. */
- if (debug_threads)
- debug_printf ("Client wants LWP %ld to stop. "
- "Making sure it has a SIGSTOP pending\n",
- lwpid_of (thread));
+ threads_debug_printf
+ ("Client wants LWP %ld to stop. Making sure it has a SIGSTOP pending",
+ lwpid_of (thread));
send_sigstop (lwp);
}
if (thread->last_resume_kind == resume_step)
{
- if (debug_threads)
- debug_printf (" stepping LWP %ld, client wants it stepping\n",
- lwpid_of (thread));
+ threads_debug_printf (" stepping LWP %ld, client wants it stepping",
+ lwpid_of (thread));
/* If resume_step is requested by GDB, install single-step
breakpoints when the thread is about to be actually resumed if
}
else if (lwp->bp_reinsert != 0)
{
- if (debug_threads)
- debug_printf (" stepping LWP %ld, reinsert set\n",
- lwpid_of (thread));
+ threads_debug_printf (" stepping LWP %ld, reinsert set",
+ lwpid_of (thread));
step = maybe_hw_step (thread);
}
if (need_step_over != NULL)
{
- if (debug_threads)
- debug_printf ("proceed_all_lwps: found "
- "thread %ld needing a step-over\n",
- lwpid_of (need_step_over));
+ threads_debug_printf ("found thread %ld needing a step-over",
+ lwpid_of (need_step_over));
start_step_over (get_thread_lwp (need_step_over));
return;
}
}
- if (debug_threads)
- debug_printf ("Proceeding, no step-over needed\n");
+ threads_debug_printf ("Proceeding, no step-over needed");
for_each_thread ([this] (thread_info *thread)
{
void
linux_process_target::unstop_all_lwps (int unsuspend, lwp_info *except)
{
- if (debug_threads)
- {
- debug_enter ();
- if (except)
- debug_printf ("unstopping all lwps, except=(LWP %ld)\n",
- lwpid_of (get_lwp_thread (except)));
- else
- debug_printf ("unstopping all lwps\n");
- }
+ THREADS_SCOPED_DEBUG_ENTER_EXIT;
+
+ if (except)
+ threads_debug_printf ("except=(LWP %ld)",
+ lwpid_of (get_lwp_thread (except)));
+ else
+ threads_debug_printf ("except=nullptr");
if (unsuspend)
for_each_thread ([&] (thread_info *thread)
{
proceed_one_lwp (thread, except);
});
-
- if (debug_threads)
- {
- debug_printf ("unstop_all_lwps done\n");
- debug_exit ();
- }
}
return the_target->read_memory (memaddr, myaddr, len);
}
-/* Copy LEN bytes from inferior's memory starting at MEMADDR
- to debugger memory starting at MYADDR. */
-int
-linux_process_target::read_memory (CORE_ADDR memaddr,
- unsigned char *myaddr, int len)
+/* Helper for read_memory/write_memory 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.
+ One an only one of READBUF and WRITEBUF is non-null. If READBUF is
+ not null, then we're reading, otherwise we're writing. */
+
+static int
+proc_xfer_memory (CORE_ADDR memaddr, unsigned char *readbuf,
+ const gdb_byte *writebuf, int len)
{
- int pid = lwpid_of (current_thread);
- PTRACE_XFER_TYPE *buffer;
- CORE_ADDR addr;
- int count;
- char filename[64];
- int i;
- int ret;
- int fd;
+ gdb_assert ((readbuf == nullptr) != (writebuf == nullptr));
+
+ process_info *proc = current_process ();
- /* Try using /proc. Don't bother for one word. */
- if (len >= 3 * sizeof (long))
+ int fd = proc->priv->mem_fd;
+ if (fd == -1)
+ return EIO;
+
+ while (len > 0)
{
int bytes;
- /* We could keep this file open and cache it - possibly one per
- thread. That requires some juggling, but is even faster. */
- sprintf (filename, "/proc/%d/mem", pid);
- fd = open (filename, O_RDONLY | O_LARGEFILE);
- if (fd == -1)
- goto no_proc;
-
- /* If pread64 is available, use it. It's faster if the kernel
- supports it (only one syscall), and it's 64-bit safe even on
- 32-bit platforms (for instance, SPARC debugging a SPARC64
- application). */
+ /* 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). But only
+ use them if the offset isn't so high that when cast to off_t
+ it'd be negative, as seen on SPARC64. pread64/pwrite64
+ outright reject such offsets. lseek does not. */
#ifdef HAVE_PREAD64
- bytes = pread64 (fd, myaddr, len, memaddr);
-#else
- bytes = -1;
- if (lseek (fd, memaddr, SEEK_SET) != -1)
- bytes = read (fd, myaddr, len);
+ if ((off_t) memaddr >= 0)
+ bytes = (readbuf != nullptr
+ ? pread64 (fd, readbuf, len, memaddr)
+ : pwrite64 (fd, writebuf, len, memaddr));
+ else
#endif
-
- close (fd);
- if (bytes == len)
- return 0;
-
- /* Some data was read, we'll try to get the rest with ptrace. */
- if (bytes > 0)
{
- memaddr += bytes;
- myaddr += bytes;
- len -= bytes;
+ bytes = -1;
+ if (lseek (fd, memaddr, SEEK_SET) != -1)
+ bytes = (readbuf != nullptr
+ ? read (fd, readbuf, len)
+ : write (fd, writebuf, len));
}
- }
- no_proc:
- /* Round starting address down to longword boundary. */
- addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
- /* Round ending address up; get number of longwords that makes. */
- count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
- / sizeof (PTRACE_XFER_TYPE));
- /* Allocate buffer of that many longwords. */
- buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count);
+ if (bytes < 0)
+ return errno;
+ else if (bytes == 0)
+ {
+ /* EOF means the address space is gone, the whole process
+ exited or execed. */
+ return EIO;
+ }
- /* Read all the longwords */
- errno = 0;
- for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
- {
- /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning
- about coercing an 8 byte integer to a 4 byte pointer. */
- buffer[i] = ptrace (PTRACE_PEEKTEXT, pid,
- (PTRACE_TYPE_ARG3) (uintptr_t) addr,
- (PTRACE_TYPE_ARG4) 0);
- if (errno)
- break;
+ memaddr += bytes;
+ if (readbuf != nullptr)
+ readbuf += bytes;
+ else
+ writebuf += bytes;
+ len -= bytes;
}
- ret = errno;
- /* Copy appropriate bytes out of the buffer. */
- if (i > 0)
- {
- i *= sizeof (PTRACE_XFER_TYPE);
- i -= memaddr & (sizeof (PTRACE_XFER_TYPE) - 1);
- memcpy (myaddr,
- (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
- i < len ? i : len);
- }
+ return 0;
+}
- return ret;
+int
+linux_process_target::read_memory (CORE_ADDR memaddr,
+ unsigned char *myaddr, int len)
+{
+ return proc_xfer_memory (memaddr, myaddr, nullptr, len);
}
/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
linux_process_target::write_memory (CORE_ADDR memaddr,
const unsigned char *myaddr, int len)
{
- int i;
- /* Round starting address down to longword boundary. */
- CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
- /* Round ending address up; get number of longwords that makes. */
- int count
- = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
- / sizeof (PTRACE_XFER_TYPE);
-
- /* Allocate buffer of that many longwords. */
- PTRACE_XFER_TYPE *buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count);
-
- int pid = lwpid_of (current_thread);
-
- if (len == 0)
- {
- /* Zero length write always succeeds. */
- return 0;
- }
-
if (debug_threads)
{
/* Dump up to four bytes. */
char *p = str;
int dump = len < 4 ? len : 4;
- for (i = 0; i < dump; i++)
+ for (int i = 0; i < dump; i++)
{
sprintf (p, "%02x", myaddr[i]);
p += 2;
}
*p = '\0';
- debug_printf ("Writing %s to 0x%08lx in process %d\n",
- str, (long) memaddr, pid);
- }
-
- /* Fill start and end extra bytes of buffer with existing memory data. */
-
- errno = 0;
- /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning
- about coercing an 8 byte integer to a 4 byte pointer. */
- buffer[0] = ptrace (PTRACE_PEEKTEXT, pid,
- (PTRACE_TYPE_ARG3) (uintptr_t) addr,
- (PTRACE_TYPE_ARG4) 0);
- if (errno)
- return errno;
-
- if (count > 1)
- {
- errno = 0;
- buffer[count - 1]
- = ptrace (PTRACE_PEEKTEXT, pid,
- /* Coerce to a uintptr_t first to avoid potential gcc warning
- about coercing an 8 byte integer to a 4 byte pointer. */
- (PTRACE_TYPE_ARG3) (uintptr_t) (addr + (count - 1)
- * sizeof (PTRACE_XFER_TYPE)),
- (PTRACE_TYPE_ARG4) 0);
- if (errno)
- return errno;
- }
-
- /* Copy data to be written over corresponding part of buffer. */
-
- memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
- myaddr, len);
-
- /* Write the entire buffer. */
-
- for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
- {
- errno = 0;
- ptrace (PTRACE_POKETEXT, pid,
- /* Coerce to a uintptr_t first to avoid potential gcc warning
- about coercing an 8 byte integer to a 4 byte pointer. */
- (PTRACE_TYPE_ARG3) (uintptr_t) addr,
- (PTRACE_TYPE_ARG4) buffer[i]);
- if (errno)
- return errno;
+ threads_debug_printf ("Writing %s to 0x%08lx in process %d",
+ str, (long) memaddr, current_process ()->pid);
}
- return 0;
+ return proc_xfer_memory (memaddr, nullptr, myaddr, len);
}
void
{
/* Send a SIGINT to the process group. This acts just like the user
typed a ^C on the controlling terminal. */
- ::kill (-signal_pid, SIGINT);
+ int res = ::kill (-signal_pid, SIGINT);
+ if (res == -1)
+ warning (_("Sending SIGINT to process group of pid %ld failed: %s"),
+ signal_pid, safe_strerror (errno));
}
bool
to debugger memory starting at MYADDR. */
int
-linux_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
- unsigned int len)
+linux_process_target::read_auxv (int pid, CORE_ADDR offset,
+ unsigned char *myaddr, unsigned int len)
{
char filename[PATH_MAX];
int fd, n;
- int pid = lwpid_of (current_thread);
xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
pid = lwpid_of (current_thread);
- if (debug_threads)
- debug_printf ("%s siginfo for lwp %d.\n",
- readbuf != NULL ? "Reading" : "Writing",
- pid);
+ threads_debug_printf ("%s siginfo for lwp %d.",
+ readbuf != NULL ? "Reading" : "Writing",
+ pid);
if (offset >= sizeof (siginfo))
return -1;
{
bool previous = target_is_async_p ();
- if (debug_threads)
- debug_printf ("linux_async (%d), previous=%d\n",
- enable, previous);
+ threads_debug_printf ("async (%d), previous=%d",
+ enable, previous);
if (previous != enable)
{
if (enable)
{
- if (pipe (linux_event_pipe) == -1)
+ if (!linux_event_pipe.open_pipe ())
{
- linux_event_pipe[0] = -1;
- linux_event_pipe[1] = -1;
gdb_sigmask (SIG_UNBLOCK, &mask, NULL);
warning ("creating event pipe failed.");
return previous;
}
- fcntl (linux_event_pipe[0], F_SETFL, O_NONBLOCK);
- fcntl (linux_event_pipe[1], F_SETFL, O_NONBLOCK);
-
/* Register the event loop handler. */
- add_file_handler (linux_event_pipe[0],
+ add_file_handler (linux_event_pipe.event_fd (),
handle_target_event, NULL,
"linux-low");
}
else
{
- delete_file_handler (linux_event_pipe[0]);
+ delete_file_handler (linux_event_pipe.event_fd ());
- close (linux_event_pipe[0]);
- close (linux_event_pipe[1]);
- linux_event_pipe[0] = -1;
- linux_event_pipe[1] = -1;
+ linux_event_pipe.close_pipe ();
}
gdb_sigmask (SIG_UNBLOCK, &mask, NULL);
bool
linux_process_target::supports_fork_events ()
{
- return linux_supports_tracefork ();
+ return true;
}
/* Check if vfork events are supported. */
bool
linux_process_target::supports_vfork_events ()
{
- return linux_supports_tracefork ();
+ return true;
}
/* Check if exec events are supported. */
bool
linux_process_target::supports_exec_events ()
{
- return linux_supports_traceexec ();
+ return true;
}
/* Target hook for 'handle_new_gdb_connection'. Causes a reset of the
bool
linux_process_target::supports_catch_syscall ()
{
- return (low_supports_catch_syscall ()
- && linux_supports_tracesysgood ());
+ return low_supports_catch_syscall ();
}
bool
unstop_all_lwps (unfreeze, NULL);
}
-int
-linux_process_target::prepare_to_access_memory ()
-{
- /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
- running LWP. */
- if (non_stop)
- target_pause_all (true);
- return 0;
-}
-
-void
-linux_process_target::done_accessing_memory ()
-{
- /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
- running LWP. */
- if (non_stop)
- target_unpause_all (true);
-}
-
/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */
static int
/* Offset and size of r_debug.r_map. */
int r_map_offset;
+ /* Offset of r_debug_extended.r_next. */
+ int r_next_offset;
+
/* Offset to l_addr field in struct link_map. */
int l_addr_offset;
int l_prev_offset;
};
+static const link_map_offsets lmo_32bit_offsets =
+ {
+ 0, /* r_version offset. */
+ 4, /* r_debug.r_map offset. */
+ 20, /* r_debug_extended.r_next. */
+ 0, /* l_addr offset in link_map. */
+ 4, /* l_name offset in link_map. */
+ 8, /* l_ld offset in link_map. */
+ 12, /* l_next offset in link_map. */
+ 16 /* l_prev offset in link_map. */
+ };
+
+static const link_map_offsets lmo_64bit_offsets =
+ {
+ 0, /* r_version offset. */
+ 8, /* r_debug.r_map offset. */
+ 40, /* r_debug_extended.r_next. */
+ 0, /* l_addr offset in link_map. */
+ 8, /* l_name offset in link_map. */
+ 16, /* l_ld offset in link_map. */
+ 24, /* l_next offset in link_map. */
+ 32 /* l_prev offset in link_map. */
+ };
+
+/* Get the loaded shared libraries from one namespace. */
+
+static void
+read_link_map (std::string &document, CORE_ADDR lmid, CORE_ADDR lm_addr,
+ CORE_ADDR lm_prev, int ptr_size, const link_map_offsets *lmo)
+{
+ CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+
+ while (lm_addr
+ && read_one_ptr (lm_addr + lmo->l_name_offset,
+ &l_name, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_addr_offset,
+ &l_addr, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_ld_offset,
+ &l_ld, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_prev_offset,
+ &l_prev, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_next_offset,
+ &l_next, ptr_size) == 0)
+ {
+ unsigned char libname[PATH_MAX];
+
+ if (lm_prev != l_prev)
+ {
+ warning ("Corrupted shared library list: 0x%s != 0x%s",
+ paddress (lm_prev), paddress (l_prev));
+ break;
+ }
+
+ /* Not checking for error because reading may stop before we've got
+ PATH_MAX worth of characters. */
+ libname[0] = '\0';
+ linux_read_memory (l_name, libname, sizeof (libname) - 1);
+ libname[sizeof (libname) - 1] = '\0';
+ if (libname[0] != '\0')
+ {
+ string_appendf (document, "<library name=\"");
+ xml_escape_text_append (document, (char *) libname);
+ string_appendf (document, "\" lm=\"0x%s\" l_addr=\"0x%s\" "
+ "l_ld=\"0x%s\" lmid=\"0x%s\"/>",
+ paddress (lm_addr), paddress (l_addr),
+ paddress (l_ld), paddress (lmid));
+ }
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
+ }
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
int
struct process_info_private *const priv = current_process ()->priv;
char filename[PATH_MAX];
int pid, is_elf64;
-
- static const struct link_map_offsets lmo_32bit_offsets =
- {
- 0, /* r_version offset. */
- 4, /* r_debug.r_map offset. */
- 0, /* l_addr offset in link_map. */
- 4, /* l_name offset in link_map. */
- 8, /* l_ld offset in link_map. */
- 12, /* l_next offset in link_map. */
- 16 /* l_prev offset in link_map. */
- };
-
- static const struct link_map_offsets lmo_64bit_offsets =
- {
- 0, /* r_version offset. */
- 8, /* r_debug.r_map offset. */
- 0, /* l_addr offset in link_map. */
- 8, /* l_name offset in link_map. */
- 16, /* l_ld offset in link_map. */
- 24, /* l_next offset in link_map. */
- 32 /* l_prev offset in link_map. */
- };
- const struct link_map_offsets *lmo;
unsigned int machine;
- int ptr_size;
- CORE_ADDR lm_addr = 0, lm_prev = 0;
- CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
- int header_done = 0;
+ CORE_ADDR lmid = 0, lm_addr = 0, lm_prev = 0;
if (writebuf != NULL)
return -2;
pid = lwpid_of (current_thread);
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
is_elf64 = elf_64_file_p (filename, &machine);
- lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
- ptr_size = is_elf64 ? 8 : 4;
+ const link_map_offsets *lmo;
+ int ptr_size;
+ if (is_elf64)
+ {
+ lmo = &lmo_64bit_offsets;
+ ptr_size = 8;
+ }
+ else
+ {
+ lmo = &lmo_32bit_offsets;
+ ptr_size = 4;
+ }
while (annex[0] != '\0')
{
break;
name_len = sep - annex;
- if (name_len == 5 && startswith (annex, "start"))
+ if (name_len == 4 && startswith (annex, "lmid"))
+ addrp = &lmid;
+ else if (name_len == 5 && startswith (annex, "start"))
addrp = &lm_addr;
else if (name_len == 4 && startswith (annex, "prev"))
addrp = &lm_prev;
annex = decode_address_to_semicolon (addrp, sep + 1);
}
- if (lm_addr == 0)
+ std::string document = "<library-list-svr4 version=\"1.0\"";
+
+ /* When the starting LM_ADDR is passed in the annex, only traverse that
+ namespace, which is assumed to be identified by LMID.
+
+ Otherwise, start with R_DEBUG and traverse all namespaces we find. */
+ if (lm_addr != 0)
+ {
+ document += ">";
+ read_link_map (document, lmid, lm_addr, lm_prev, ptr_size, lmo);
+ }
+ else
{
- int r_version = 0;
+ if (lm_prev != 0)
+ warning ("ignoring prev=0x%s without start", paddress (lm_prev));
- if (priv->r_debug == 0)
- priv->r_debug = get_r_debug (pid, is_elf64);
+ /* We could interpret LMID as 'provide only the libraries for this
+ namespace' but GDB is currently only providing lmid, start, and
+ prev, or nothing. */
+ if (lmid != 0)
+ warning ("ignoring lmid=0x%s without start", paddress (lmid));
+
+ CORE_ADDR r_debug = priv->r_debug;
+ if (r_debug == 0)
+ r_debug = priv->r_debug = get_r_debug (pid, is_elf64);
/* We failed to find DT_DEBUG. Such situation will not change
for this inferior - do not retry it. Report it to GDB as
E01, see for the reasons at the GDB solib-svr4.c side. */
- if (priv->r_debug == (CORE_ADDR) -1)
+ if (r_debug == (CORE_ADDR) -1)
return -1;
- if (priv->r_debug != 0)
+ /* Terminate the header if we end up with an empty list. */
+ if (r_debug == 0)
+ document += ">";
+
+ while (r_debug != 0)
{
- if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+ int r_version = 0;
+ if (linux_read_memory (r_debug + lmo->r_version_offset,
(unsigned char *) &r_version,
- sizeof (r_version)) != 0
- || r_version < 1)
+ sizeof (r_version)) != 0)
{
- warning ("unexpected r_debug version %d", r_version);
+ warning ("unable to read r_version from 0x%s",
+ paddress (r_debug + lmo->r_version_offset));
+ break;
}
- else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
- &lm_addr, ptr_size) != 0)
+
+ if (r_version < 1)
{
- warning ("unable to read r_map from 0x%lx",
- (long) priv->r_debug + lmo->r_map_offset);
+ warning ("unexpected r_debug version %d", r_version);
+ break;
}
- }
- }
-
- std::string document = "<library-list-svr4 version=\"1.0\"";
- while (lm_addr
- && read_one_ptr (lm_addr + lmo->l_name_offset,
- &l_name, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_addr_offset,
- &l_addr, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_ld_offset,
- &l_ld, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_prev_offset,
- &l_prev, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_next_offset,
- &l_next, ptr_size) == 0)
- {
- unsigned char libname[PATH_MAX];
+ if (read_one_ptr (r_debug + lmo->r_map_offset, &lm_addr,
+ ptr_size) != 0)
+ {
+ warning ("unable to read r_map from 0x%s",
+ paddress (r_debug + lmo->r_map_offset));
+ break;
+ }
- if (lm_prev != l_prev)
- {
- warning ("Corrupted shared library list: 0x%lx != 0x%lx",
- (long) lm_prev, (long) l_prev);
- break;
- }
+ /* We read the entire namespace. */
+ lm_prev = 0;
- /* Ignore the first entry even if it has valid name as the first entry
- corresponds to the main executable. The first entry should not be
- skipped if the dynamic loader was loaded late by a static executable
- (see solib-svr4.c parameter ignore_first). But in such case the main
- executable does not have PT_DYNAMIC present and this function already
- exited above due to failed get_r_debug. */
- if (lm_prev == 0)
- string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
- else
- {
- /* Not checking for error because reading may stop before
- we've got PATH_MAX worth of characters. */
- libname[0] = '\0';
- linux_read_memory (l_name, libname, sizeof (libname) - 1);
- libname[sizeof (libname) - 1] = '\0';
- if (libname[0] != '\0')
+ /* The first entry corresponds to the main executable unless the
+ dynamic loader was loaded late by a static executable. But
+ in such case the main executable does not have PT_DYNAMIC
+ present and we would not have gotten here. */
+ if (r_debug == priv->r_debug)
{
- if (!header_done)
+ if (lm_addr != 0)
+ string_appendf (document, " main-lm=\"0x%s\">",
+ paddress (lm_addr));
+ else
+ document += ">";
+
+ lm_prev = lm_addr;
+ if (read_one_ptr (lm_addr + lmo->l_next_offset,
+ &lm_addr, ptr_size) != 0)
{
- /* Terminate `<library-list-svr4'. */
- document += '>';
- header_done = 1;
+ warning ("unable to read l_next from 0x%s",
+ paddress (lm_addr + lmo->l_next_offset));
+ break;
}
+ }
+
+ read_link_map (document, r_debug, lm_addr, lm_prev, ptr_size, lmo);
+
+ if (r_version < 2)
+ break;
- string_appendf (document, "<library name=\"");
- xml_escape_text_append (&document, (char *) libname);
- string_appendf (document, "\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
- (unsigned long) lm_addr, (unsigned long) l_addr,
- (unsigned long) l_ld);
+ if (read_one_ptr (r_debug + lmo->r_next_offset, &r_debug,
+ ptr_size) != 0)
+ {
+ warning ("unable to read r_next from 0x%s",
+ paddress (r_debug + lmo->r_next_offset));
+ break;
}
}
-
- lm_prev = lm_addr;
- lm_addr = l_next;
}
- if (!header_done)
- {
- /* Empty list; terminate `<library-list-svr4'. */
- document += "/>";
- }
- else
- document += "</library-list-svr4>";
+ document += "</library-list-svr4>";
int document_len = document.length ();
if (offset < document_len)
#ifdef HAVE_LINUX_BTRACE
+bool
+linux_process_target::supports_btrace ()
+{
+ return true;
+}
+
btrace_target_info *
-linux_process_target::enable_btrace (ptid_t ptid,
+linux_process_target::enable_btrace (thread_info *tp,
const btrace_config *conf)
{
- return linux_enable_btrace (ptid, conf);
+ return linux_enable_btrace (tp->id, conf);
}
/* See to_disable_btrace target method. */
/* Encode an Intel Processor Trace configuration. */
static void
-linux_low_encode_pt_config (struct buffer *buffer,
+linux_low_encode_pt_config (std::string *buffer,
const struct btrace_data_pt_config *config)
{
- buffer_grow_str (buffer, "<pt-config>\n");
+ *buffer += "<pt-config>\n";
switch (config->cpu.vendor)
{
case CV_INTEL:
- buffer_xml_printf (buffer, "<cpu vendor=\"GenuineIntel\" family=\"%u\" "
- "model=\"%u\" stepping=\"%u\"/>\n",
- config->cpu.family, config->cpu.model,
- config->cpu.stepping);
+ string_xml_appendf (*buffer, "<cpu vendor=\"GenuineIntel\" family=\"%u\" "
+ "model=\"%u\" stepping=\"%u\"/>\n",
+ config->cpu.family, config->cpu.model,
+ config->cpu.stepping);
break;
default:
break;
}
- buffer_grow_str (buffer, "</pt-config>\n");
+ *buffer += "</pt-config>\n";
}
/* Encode a raw buffer. */
static void
-linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data,
+linux_low_encode_raw (std::string *buffer, const gdb_byte *data,
unsigned int size)
{
if (size == 0)
return;
/* We use hex encoding - see gdbsupport/rsp-low.h. */
- buffer_grow_str (buffer, "<raw>\n");
+ *buffer += "<raw>\n";
while (size-- > 0)
{
elem[0] = tohex ((*data >> 4) & 0xf);
elem[1] = tohex (*data++ & 0xf);
- buffer_grow (buffer, elem, 2);
+ buffer->append (elem, 2);
}
- buffer_grow_str (buffer, "</raw>\n");
+ *buffer += "</raw>\n";
}
/* See to_read_btrace target method. */
int
linux_process_target::read_btrace (btrace_target_info *tinfo,
- buffer *buffer,
+ std::string *buffer,
enum btrace_read_type type)
{
struct btrace_data btrace;
if (err != BTRACE_ERR_NONE)
{
if (err == BTRACE_ERR_OVERFLOW)
- buffer_grow_str0 (buffer, "E.Overflow.");
+ *buffer += "E.Overflow.";
else
- buffer_grow_str0 (buffer, "E.Generic Error.");
+ *buffer += "E.Generic Error.";
return -1;
}
switch (btrace.format)
{
case BTRACE_FORMAT_NONE:
- buffer_grow_str0 (buffer, "E.No Trace.");
+ *buffer += "E.No Trace.";
return -1;
case BTRACE_FORMAT_BTS:
- buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
- buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+ *buffer += "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n";
+ *buffer += "<btrace version=\"1.0\">\n";
for (const btrace_block &block : *btrace.variant.bts.blocks)
- buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
- paddress (block.begin), paddress (block.end));
+ string_xml_appendf (*buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+ paddress (block.begin), paddress (block.end));
- buffer_grow_str0 (buffer, "</btrace>\n");
+ *buffer += "</btrace>\n";
break;
case BTRACE_FORMAT_PT:
- buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
- buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
- buffer_grow_str (buffer, "<pt>\n");
+ *buffer += "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n";
+ *buffer += "<btrace version=\"1.0\">\n";
+ *buffer += "<pt>\n";
linux_low_encode_pt_config (buffer, &btrace.variant.pt.config);
linux_low_encode_raw (buffer, btrace.variant.pt.data,
btrace.variant.pt.size);
- buffer_grow_str (buffer, "</pt>\n");
- buffer_grow_str0 (buffer, "</btrace>\n");
+ *buffer += "</pt>\n";
+ *buffer += "</btrace>\n";
break;
default:
- buffer_grow_str0 (buffer, "E.Unsupported Trace Format.");
+ *buffer += "E.Unsupported Trace Format.";
return -1;
}
int
linux_process_target::read_btrace_conf (const btrace_target_info *tinfo,
- buffer *buffer)
+ std::string *buffer)
{
const struct btrace_config *conf;
- buffer_grow_str (buffer, "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n");
- buffer_grow_str (buffer, "<btrace-conf version=\"1.0\">\n");
+ *buffer += "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n";
+ *buffer += "<btrace-conf version=\"1.0\">\n";
conf = linux_btrace_conf (tinfo);
if (conf != NULL)
break;
case BTRACE_FORMAT_BTS:
- buffer_xml_printf (buffer, "<bts");
- buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
- buffer_xml_printf (buffer, " />\n");
+ string_xml_appendf (*buffer, "<bts");
+ string_xml_appendf (*buffer, " size=\"0x%x\"", conf->bts.size);
+ string_xml_appendf (*buffer, " />\n");
break;
case BTRACE_FORMAT_PT:
- buffer_xml_printf (buffer, "<pt");
- buffer_xml_printf (buffer, " size=\"0x%x\"", conf->pt.size);
- buffer_xml_printf (buffer, "/>\n");
+ string_xml_appendf (*buffer, "<pt");
+ string_xml_appendf (*buffer, " size=\"0x%x\"", conf->pt.size);
+ string_xml_appendf (*buffer, "/>\n");
break;
}
}
- buffer_grow_str0 (buffer, "</btrace-conf>\n");
+ *buffer += "</btrace-conf>\n";
return 0;
}
#endif /* HAVE_LINUX_BTRACE */
uint32_t pc;
collect_register_by_name (regcache, "pc", &pc);
- if (debug_threads)
- debug_printf ("stop pc is 0x%" PRIx32 "\n", pc);
+ threads_debug_printf ("stop pc is 0x%" PRIx32, pc);
return pc;
}
uint64_t pc;
collect_register_by_name (regcache, "pc", &pc);
- if (debug_threads)
- debug_printf ("stop pc is 0x%" PRIx64 "\n", pc);
+ threads_debug_printf ("stop pc is 0x%" PRIx64, pc);
return pc;
}
/* See linux-low.h. */
int
-linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp)
+linux_get_auxv (int pid, int wordsize, CORE_ADDR match, CORE_ADDR *valp)
{
gdb_byte *data = (gdb_byte *) alloca (2 * wordsize);
int offset = 0;
gdb_assert (wordsize == 4 || wordsize == 8);
- while (the_target->read_auxv (offset, data, 2 * wordsize) == 2 * wordsize)
+ while (the_target->read_auxv (pid, offset, data, 2 * wordsize)
+ == 2 * wordsize)
{
if (wordsize == 4)
{
/* See linux-low.h. */
CORE_ADDR
-linux_get_hwcap (int wordsize)
+linux_get_hwcap (int pid, int wordsize)
{
CORE_ADDR hwcap = 0;
- linux_get_auxv (wordsize, AT_HWCAP, &hwcap);
+ linux_get_auxv (pid, wordsize, AT_HWCAP, &hwcap);
return hwcap;
}
/* See linux-low.h. */
CORE_ADDR
-linux_get_hwcap2 (int wordsize)
+linux_get_hwcap2 (int pid, int wordsize)
{
CORE_ADDR hwcap2 = 0;
- linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2);
+ linux_get_auxv (pid, wordsize, AT_HWCAP2, &hwcap2);
return hwcap2;
}