/* Low level interface to ptrace, for the remote server for GDB.
- Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1995-1996, 1998-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "linux-low.h"
#include "linux-osdata.h"
+#include "agent.h"
#include <sys/wait.h>
#include <stdio.h>
struct inferior_list all_lwps;
-/* A list of all unknown processes which receive stop signals. Some other
- process will presumably claim each of these as forked children
- momentarily. */
+/* A list of all unknown processes which receive stop signals. Some
+ other process will presumably claim each of these as forked
+ children momentarily. */
-struct inferior_list stopped_pids;
+struct simple_pid_list
+{
+ /* The process ID. */
+ int pid;
+
+ /* The status as reported by waitpid. */
+ int status;
+
+ /* Next in chain. */
+ struct simple_pid_list *next;
+};
+struct simple_pid_list *stopped_pids;
+
+/* 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 = xmalloc (sizeof (struct simple_pid_list));
+
+ new_pid->pid = pid;
+ new_pid->status = status;
+ new_pid->next = *listp;
+ *listp = new_pid;
+}
+
+static int
+pull_pid_from_list (struct simple_pid_list **listp, int pid, 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;
+}
/* FIXME this is a bit of a hack, and could be removed. */
int stopping_threads;
static void send_sigstop (struct lwp_info *lwp);
static void wait_for_sigstop (struct inferior_list_entry *entry);
-/* Accepts an integer PID; Returns a string representing a file that
- can be opened to get info for the child process.
- Space for the result is malloc'd, caller must free. */
-
-char *
-linux_child_pid_to_exec_file (int pid)
-{
- char *name1, *name2;
-
- name1 = xmalloc (MAXPATHLEN);
- name2 = xmalloc (MAXPATHLEN);
- memset (name2, 0, MAXPATHLEN);
-
- sprintf (name1, "/proc/%d/exe", pid);
- if (readlink (name1, name2, MAXPATHLEN) > 0)
- {
- free (name1);
- return name2;
- }
- else
- {
- free (name2);
- return name1;
- }
-}
-
/* Return non-zero if HEADER is a 64-bit ELF file. */
static int
zero if the file is not a 64-bit ELF file,
and -1 if the file is not accessible or doesn't exist. */
-int
+static int
elf_64_file_p (const char *file)
{
Elf64_Ehdr header;
return elf_64_header_p (&header);
}
+/* Accepts an integer PID; Returns true if the executable PID is
+ running is a 64-bit ELF file.. */
+
+int
+linux_pid_exe_is_elf_64_file (int pid)
+{
+ char file[MAXPATHLEN];
+
+ sprintf (file, "/proc/%d/exe", pid);
+ return elf_64_file_p (file);
+}
+
static void
delete_lwp (struct lwp_info *lwp)
{
{
ptid_t ptid;
unsigned long new_pid;
- int ret, status = W_STOPCODE (SIGSTOP);
+ int ret, status;
ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), 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))
+ 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. */
setpgid (0, 0);
+ /* If gdbserver is connected to gdb via stdio, redirect the inferior's
+ stdout to stderr so that inferior i/o doesn't corrupt the connection.
+ Also, redirect stdin to /dev/null. */
+ if (remote_connection_is_stdio ())
+ {
+ close (0);
+ open ("/dev/null", O_RDONLY);
+ dup2 (2, 1);
+ if (write (2, "stdin/stdout redirected\n",
+ sizeof ("stdin/stdout redirected\n") - 1) < 0)
+ /* Errors ignored. */;
+ }
+
execv (program, allargs);
if (errno == ENOENT)
execvp (program, allargs);
if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0)
{
+ struct buffer buffer;
+
if (!initial)
{
/* If we fail to attach to an LWP, just warn. */
fflush (stderr);
return;
}
- else
- /* If we fail to attach to a process, report an error. */
- error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
- strerror (errno), errno);
+
+ /* If we fail to attach to a process, report an error. */
+ buffer_init (&buffer);
+ linux_ptrace_attach_warnings (lwpid, &buffer);
+ buffer_grow_str0 (&buffer, "");
+ error ("%sCannot attach to lwp %ld: %s (%d)", buffer_finish (&buffer),
+ lwpid, strerror (errno), errno);
}
if (initial)
ptrace call on this LWP. */
new_lwp->must_set_ptrace_flags = 1;
+ if (linux_proc_pid_is_stopped (lwpid))
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "Attached to a stopped process\n");
+
+ /* 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 (lwpid, SIGSTOP);
+
+ /* Finally, resume the stopped process. This will deliver the
+ SIGSTOP (or a higher priority signal, just like normal
+ PTRACE_ATTACH), which we'll catch later on. */
+ ptrace (PTRACE_CONT, lwpid, 0, 0);
+ }
+
/* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
brings it to a halt.
second_thread_of_pid_p, &counter) == NULL);
}
-/* Kill the inferior lwp. */
+/* Kill LWP. */
+
+static void
+linux_kill_one_lwp (struct lwp_info *lwp)
+{
+ int pid = lwpid_of (lwp);
+
+ /* PTRACE_KILL is unreliable. After stepping into a signal handler,
+ there is no signal context, and ptrace(PTRACE_KILL) (or
+ ptrace(PTRACE_CONT, SIGKILL), pretty much the same) acts like
+ ptrace(CONT, pid, 0,0) and just resumes the tracee. A better
+ alternative is to kill with SIGKILL. We only need one SIGKILL
+ per process, not one for each thread. But since we still support
+ linuxthreads, and we also support debugging programs using raw
+ clone without CLONE_THREAD, we send one for each thread. For
+ years, we used PTRACE_KILL only, so we're being a bit paranoid
+ about some old kernels where PTRACE_KILL might work better
+ (dubious if there are any such, but that's why it's paranoia), so
+ we try SIGKILL first, PTRACE_KILL second, and so we're fine
+ everywhere. */
+
+ errno = 0;
+ kill (pid, SIGKILL);
+ if (debug_threads)
+ fprintf (stderr,
+ "LKL: kill (SIGKILL) %s, 0, 0 (%s)\n",
+ target_pid_to_str (ptid_of (lwp)),
+ errno ? strerror (errno) : "OK");
+
+ errno = 0;
+ ptrace (PTRACE_KILL, pid, 0, 0);
+ if (debug_threads)
+ fprintf (stderr,
+ "LKL: PTRACE_KILL %s, 0, 0 (%s)\n",
+ target_pid_to_str (ptid_of (lwp)),
+ errno ? strerror (errno) : "OK");
+}
+
+/* Callback for `find_inferior'. Kills an lwp of a given process,
+ except the leader. */
static int
-linux_kill_one_lwp (struct inferior_list_entry *entry, void *args)
+kill_one_lwp_callback (struct inferior_list_entry *entry, void *args)
{
struct thread_info *thread = (struct thread_info *) entry;
struct lwp_info *lwp = get_thread_lwp (thread);
do
{
- ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
+ linux_kill_one_lwp (lwp);
/* Make sure it died. The loop is most likely unnecessary. */
pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
first, as PTRACE_KILL will not work otherwise. */
stop_all_lwps (0, NULL);
- find_inferior (&all_threads, linux_kill_one_lwp, &pid);
+ find_inferior (&all_threads, kill_one_lwp_callback , &pid);
/* See the comment in linux_kill_one_lwp. We did not kill the first
thread in the list, so do so now. */
lwp = find_lwp_pid (pid_to_ptid (pid));
- if (debug_threads)
- fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n",
- lwpid_of (lwp), pid);
-
- do
+ if (lwp == NULL)
{
- ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
+ if (debug_threads)
+ fprintf (stderr, "lk_1: cannot find lwp %ld, for pid: %d\n",
+ lwpid_of (lwp), pid);
+ }
+ else
+ {
+ if (debug_threads)
+ fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n",
+ lwpid_of (lwp), pid);
- /* Make sure it died. The loop is most likely unnecessary. */
- lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
- } while (lwpid > 0 && WIFSTOPPED (wstat));
+ do
+ {
+ linux_kill_one_lwp (lwp);
+
+ /* Make sure it died. The loop is most likely unnecessary. */
+ lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
+ } while (lwpid > 0 && WIFSTOPPED (wstat));
+ }
the_target->mourn (process);
return 0;
}
+/* Get pending signal of THREAD, 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 thread_info *thread)
+{
+ enum target_signal signo = TARGET_SIGNAL_0;
+ int status;
+ struct lwp_info *lp = get_thread_lwp (thread);
+
+ if (lp->status_pending_p)
+ status = lp->status_pending;
+ else
+ {
+ /* If the thread had been suspended by gdbserver, and it stopped
+ cleanly, then it'll have stopped with SIGSTOP. But we don't
+ want to deliver that SIGSTOP. */
+ if (thread->last_status.kind != TARGET_WAITKIND_STOPPED
+ || thread->last_status.value.sig == TARGET_SIGNAL_0)
+ return 0;
+
+ /* Otherwise, we may need to deliver the signal we
+ intercepted. */
+ status = lp->last_status;
+ }
+
+ if (!WIFSTOPPED (status))
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "GPS: lwp %s hasn't stopped: no pending signal\n",
+ target_pid_to_str (ptid_of (lp)));
+ return 0;
+ }
+
+ /* Extended wait statuses aren't real SIGTRAPs. */
+ if (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "GPS: lwp %s had stopped with extended "
+ "status: no pending signal\n",
+ target_pid_to_str (ptid_of (lp)));
+ return 0;
+ }
+
+ signo = target_signal_from_host (WSTOPSIG (status));
+
+ if (program_signals_p && !program_signals[signo])
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "GPS: lwp %s had signal %s, but it is in nopass state\n",
+ target_pid_to_str (ptid_of (lp)),
+ target_signal_to_string (signo));
+ return 0;
+ }
+ else if (!program_signals_p
+ /* If we have no way to know which signals GDB does not
+ want to have passed to the program, assume
+ SIGTRAP/SIGINT, which is GDB's default. */
+ && (signo == TARGET_SIGNAL_TRAP || signo == TARGET_SIGNAL_INT))
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "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 (lp)),
+ target_signal_to_string (signo));
+ return 0;
+ }
+ else
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "GPS: lwp %s has pending signal %s: delivering it.\n",
+ target_pid_to_str (ptid_of (lp)),
+ target_signal_to_string (signo));
+
+ return WSTOPSIG (status);
+ }
+}
+
static int
linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
{
struct thread_info *thread = (struct thread_info *) entry;
struct lwp_info *lwp = get_thread_lwp (thread);
int pid = * (int *) args;
+ int sig;
if (ptid_get_pid (entry->id) != pid)
return 0;
- /* If this process is stopped but is expecting a SIGSTOP, then make
- sure we take care of that now. This isn't absolutely guaranteed
- to collect the SIGSTOP, but is fairly likely to. */
+ /* If there is a pending SIGSTOP, get rid of it. */
if (lwp->stop_expected)
{
- int wstat;
- /* Clear stop_expected, so that the SIGSTOP will be reported. */
+ if (debug_threads)
+ fprintf (stderr,
+ "Sending SIGCONT to %s\n",
+ target_pid_to_str (ptid_of (lwp)));
+
+ kill_lwp (lwpid_of (lwp), SIGCONT);
lwp->stop_expected = 0;
- linux_resume_one_lwp (lwp, 0, 0, NULL);
- linux_wait_for_event (lwp->head.id, &wstat, __WALL);
}
/* Flush any pending changes to the process's registers. */
regcache_invalidate_one ((struct inferior_list_entry *)
get_lwp_thread (lwp));
+ /* Pass on any pending signal for this thread. */
+ sig = get_detach_signal (thread);
+
/* Finally, let it resume. */
- ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
+ if (the_low_target.prepare_to_resume != NULL)
+ the_low_target.prepare_to_resume (lwp);
+ if (ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, sig) < 0)
+ error (_("Can't detach %s: %s"),
+ target_pid_to_str (ptid_of (lwp)),
+ strerror (errno));
delete_lwp (lwp);
return 0;
was reported to us by the kernel. Save its PID. */
if (child == NULL && WIFSTOPPED (*wstatp))
{
- add_pid_to_list (&stopped_pids, ret);
+ add_to_pid_list (&stopped_pids, ret, *wstatp);
goto retry;
}
else if (child == NULL)
if ((wstat == NULL
|| (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP))
&& supports_fast_tracepoints ()
- && in_process_agent_loaded ())
+ && agent_loaded_p ())
{
struct fast_tpoint_collect_status status;
int r;
the stopped child otherwise. */
static int
-linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
+linux_wait_for_event (ptid_t ptid, int *wstat, int options)
{
struct lwp_info *event_child, *requested_child;
+ ptid_t wait_ptid;
event_child = NULL;
requested_child = NULL;
/* Check for a lwp with a pending status. */
- if (ptid_equal (ptid, minus_one_ptid)
- || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid))
+ if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
{
event_child = (struct lwp_info *)
find_inferior (&all_lwps, status_pending_p_callback, &ptid);
return lwpid_of (event_child);
}
+ if (ptid_is_pid (ptid))
+ {
+ /* A request to wait for a specific tgid. This is not possible
+ with waitpid, so instead, we wait for any child, and leave
+ children we're not interested in right now with a pending
+ status to report later. */
+ wait_ptid = minus_one_ptid;
+ }
+ else
+ wait_ptid = ptid;
+
/* We only enter this loop if no process has a pending wait status. Thus
any action taken in response to a wait status inside this loop is
responding as soon as we detect the status, not after any pending
events. */
while (1)
{
- event_child = linux_wait_for_lwp (ptid, wstat, options);
+ event_child = linux_wait_for_lwp (wait_ptid, wstat, options);
if ((options & WNOHANG) && event_child == NULL)
{
if (event_child == NULL)
error ("event from unknown child");
+ if (ptid_is_pid (ptid)
+ && ptid_get_pid (ptid) != ptid_get_pid (ptid_of (event_child)))
+ {
+ if (! WIFSTOPPED (*wstat))
+ mark_lwp_dead (event_child, *wstat);
+ else
+ {
+ event_child->status_pending_p = 1;
+ event_child->status_pending = *wstat;
+ }
+ continue;
+ }
+
current_inferior = get_lwp_thread (event_child);
/* Check for thread exit. */
return 0;
}
-static int
-linux_wait_for_event (ptid_t ptid, int *wstat, int options)
-{
- ptid_t wait_ptid;
-
- if (ptid_is_pid (ptid))
- {
- /* A request to wait for a specific tgid. This is not possible
- with waitpid, so instead, we wait for any child, and leave
- children we're not interested in right now with a pending
- status to report later. */
- wait_ptid = minus_one_ptid;
- }
- else
- wait_ptid = ptid;
-
- while (1)
- {
- int event_pid;
-
- event_pid = linux_wait_for_event_1 (wait_ptid, wstat, options);
-
- if (event_pid > 0
- && ptid_is_pid (ptid) && ptid_get_pid (ptid) != event_pid)
- {
- struct lwp_info *event_child
- = find_lwp_pid (pid_to_ptid (event_pid));
-
- if (! WIFSTOPPED (*wstat))
- mark_lwp_dead (event_child, *wstat);
- else
- {
- event_child->status_pending_p = 1;
- event_child->status_pending = *wstat;
- }
- }
- else
- return event_pid;
- }
-}
-
-
/* Count the LWP's that have had events. */
static int
if (WIFSTOPPED (w)
&& WSTOPSIG (w) != SIGTRAP
&& supports_fast_tracepoints ()
- && in_process_agent_loaded ())
+ && agent_loaded_p ())
{
if (debug_threads)
fprintf (stderr,
|| event_child->stopped_by_watchpoint
|| (!step_over_finished
&& !bp_explains_trap && !trace_event)
- || gdb_breakpoint_here (event_child->stop_pc));
+ || (gdb_breakpoint_here (event_child->stop_pc)
+ && gdb_condition_true_at_breakpoint (event_child->stop_pc)));
/* We found no reason GDB would want us to stop. We either hit one
of our own breakpoints, or finished an internal step GDB
why. */
find_inferior (&all_lwps, cancel_breakpoints_callback, event_child);
+ /* If we were going a step-over, all other threads but the stepping one
+ had been paused in start_step_over, with their suspend counts
+ incremented. We don't want to do a full unstop/unpause, because we're
+ in all-stop mode (so we want threads stopped), but we still need to
+ unsuspend the other threads, to decrement their `suspended' count
+ back. */
+ if (step_over_finished)
+ unsuspend_all_lwps (event_child);
+
/* Stabilize threads (move out of jump pads). */
stabilize_threads ();
}
/* Allow debugging the jump pad, gdb_collect, etc.. */
return (supports_fast_tracepoints ()
- && in_process_agent_loaded ()
+ && agent_loaded_p ()
&& (gdb_breakpoint_here (lwp->stop_pc)
|| lwp->stopped_by_watchpoint
|| thread->last_resume_kind == resume_step)
if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc))
{
/* Don't step over a breakpoint that GDB expects to hit
- though. */
- if (gdb_breakpoint_here (pc))
+ though. If the condition is being evaluated on the target's side
+ and it evaluate to false, step over this breakpoint as well. */
+ if (gdb_breakpoint_here (pc)
+ && gdb_condition_true_at_breakpoint (pc))
{
if (debug_threads)
fprintf (stderr,
find_inferior (&all_lwps, proceed_one_lwp, except);
}
-#ifdef HAVE_LINUX_USRREGS
-
-int
-register_addr (int regnum)
-{
- int addr;
-
- if (regnum < 0 || regnum >= the_low_target.num_regs)
- error ("Invalid register number %d.", regnum);
-
- addr = the_low_target.regmap[regnum];
-
- return addr;
-}
-
-/* Fetch one register. */
-static void
-fetch_register (struct regcache *regcache, int regno)
-{
- CORE_ADDR regaddr;
- int i, size;
- char *buf;
- int pid;
-
- if (regno >= the_low_target.num_regs)
- return;
- if ((*the_low_target.cannot_fetch_register) (regno))
- return;
-
- regaddr = register_addr (regno);
- if (regaddr == -1)
- return;
-
- pid = lwpid_of (get_thread_lwp (current_inferior));
- size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
- & - sizeof (PTRACE_XFER_TYPE));
- buf = alloca (size);
- for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
- {
- errno = 0;
- *(PTRACE_XFER_TYPE *) (buf + i) =
- ptrace (PTRACE_PEEKUSER, pid,
- /* Coerce to a uintptr_t first to avoid potential gcc warning
- of coercing an 8 byte integer to a 4 byte pointer. */
- (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0);
- regaddr += sizeof (PTRACE_XFER_TYPE);
- if (errno != 0)
- error ("reading register %d: %s", regno, strerror (errno));
- }
-
- if (the_low_target.supply_ptrace_register)
- the_low_target.supply_ptrace_register (regcache, regno, buf);
- else
- supply_register (regcache, regno, buf);
-}
-
-/* Fetch all registers, or just one, from the child process. */
-static void
-usr_fetch_inferior_registers (struct regcache *regcache, int regno)
-{
- if (regno == -1)
- for (regno = 0; regno < the_low_target.num_regs; regno++)
- fetch_register (regcache, regno);
- else
- fetch_register (regcache, regno);
-}
-
-/* Store our register values back into the inferior.
- If REGNO is -1, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
-static void
-usr_store_inferior_registers (struct regcache *regcache, int regno)
-{
- CORE_ADDR regaddr;
- int i, size;
- char *buf;
- int pid;
-
- if (regno >= 0)
- {
- if (regno >= the_low_target.num_regs)
- return;
-
- if ((*the_low_target.cannot_store_register) (regno) == 1)
- return;
-
- regaddr = register_addr (regno);
- if (regaddr == -1)
- return;
- errno = 0;
- size = (register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
- & - sizeof (PTRACE_XFER_TYPE);
- buf = alloca (size);
- memset (buf, 0, size);
-
- if (the_low_target.collect_ptrace_register)
- the_low_target.collect_ptrace_register (regcache, regno, buf);
- else
- collect_register (regcache, regno, buf);
-
- pid = lwpid_of (get_thread_lwp (current_inferior));
- for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
- {
- errno = 0;
- ptrace (PTRACE_POKEUSER, pid,
- /* Coerce to a uintptr_t first to avoid potential gcc warning
- about coercing an 8 byte integer to a 4 byte pointer. */
- (PTRACE_ARG3_TYPE) (uintptr_t) regaddr,
- (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i));
- if (errno != 0)
- {
- /* At this point, ESRCH should mean the process is
- already gone, in which case we simply ignore attempts
- to change its registers. See also the related
- comment in linux_resume_one_lwp. */
- if (errno == ESRCH)
- return;
-
- if ((*the_low_target.cannot_store_register) (regno) == 0)
- error ("writing register %d: %s", regno, strerror (errno));
- }
- regaddr += sizeof (PTRACE_XFER_TYPE);
- }
- }
- else
- for (regno = 0; regno < the_low_target.num_regs; regno++)
- usr_store_inferior_registers (regcache, regno);
-}
-#endif /* HAVE_LINUX_USRREGS */
-
-
#ifdef HAVE_LINUX_REGSETS
+#define use_linux_regsets 1
+
static int
regsets_fetch_inferior_registers (struct regcache *regcache)
{
return 0;
else
return 1;
- return 0;
}
-#endif /* HAVE_LINUX_REGSETS */
+#else /* !HAVE_LINUX_REGSETS */
+#define use_linux_regsets 0
+#define regsets_fetch_inferior_registers(regcache) 1
+#define regsets_store_inferior_registers(regcache) 1
-void
-linux_fetch_registers (struct regcache *regcache, int regno)
-{
-#ifdef HAVE_LINUX_REGSETS
- if (regsets_fetch_inferior_registers (regcache) == 0)
- return;
#endif
+
+/* Return 1 if register REGNO is supported by one of the regset ptrace
+ calls or 0 if it has to be transferred individually. */
+
+static int
+linux_register_in_regsets (int regno)
+{
+ unsigned char mask = 1 << (regno % 8);
+ size_t index = regno / 8;
+
+ return (use_linux_regsets
+ && (the_low_target.regset_bitmap == NULL
+ || (the_low_target.regset_bitmap[index] & mask) != 0));
+}
+
#ifdef HAVE_LINUX_USRREGS
- usr_fetch_inferior_registers (regcache, regno);
+
+int
+register_addr (int regnum)
+{
+ int addr;
+
+ if (regnum < 0 || regnum >= the_low_target.num_regs)
+ error ("Invalid register number %d.", regnum);
+
+ addr = the_low_target.regmap[regnum];
+
+ return addr;
+}
+
+/* Fetch one register. */
+static void
+fetch_register (struct regcache *regcache, int regno)
+{
+ CORE_ADDR regaddr;
+ int i, size;
+ char *buf;
+ int pid;
+
+ if (regno >= the_low_target.num_regs)
+ return;
+ if ((*the_low_target.cannot_fetch_register) (regno))
+ return;
+
+ regaddr = register_addr (regno);
+ if (regaddr == -1)
+ return;
+
+ size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+ & -sizeof (PTRACE_XFER_TYPE));
+ buf = alloca (size);
+
+ pid = lwpid_of (get_thread_lwp (current_inferior));
+ for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ *(PTRACE_XFER_TYPE *) (buf + i) =
+ ptrace (PTRACE_PEEKUSER, pid,
+ /* Coerce to a uintptr_t first to avoid potential gcc warning
+ of coercing an 8 byte integer to a 4 byte pointer. */
+ (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0);
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
+ error ("reading register %d: %s", regno, strerror (errno));
+ }
+
+ if (the_low_target.supply_ptrace_register)
+ the_low_target.supply_ptrace_register (regcache, regno, buf);
+ else
+ supply_register (regcache, regno, buf);
+}
+
+/* Store one register. */
+static void
+store_register (struct regcache *regcache, int regno)
+{
+ CORE_ADDR regaddr;
+ int i, size;
+ char *buf;
+ int pid;
+
+ if (regno >= the_low_target.num_regs)
+ return;
+ if ((*the_low_target.cannot_store_register) (regno))
+ return;
+
+ regaddr = register_addr (regno);
+ if (regaddr == -1)
+ return;
+
+ size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+ & -sizeof (PTRACE_XFER_TYPE));
+ buf = alloca (size);
+ memset (buf, 0, size);
+
+ if (the_low_target.collect_ptrace_register)
+ the_low_target.collect_ptrace_register (regcache, regno, buf);
+ else
+ collect_register (regcache, regno, buf);
+
+ pid = lwpid_of (get_thread_lwp (current_inferior));
+ for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ ptrace (PTRACE_POKEUSER, pid,
+ /* Coerce to a uintptr_t first to avoid potential gcc warning
+ about coercing an 8 byte integer to a 4 byte pointer. */
+ (PTRACE_ARG3_TYPE) (uintptr_t) regaddr,
+ (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i));
+ if (errno != 0)
+ {
+ /* At this point, ESRCH should mean the process is
+ already gone, in which case we simply ignore attempts
+ to change its registers. See also the related
+ comment in linux_resume_one_lwp. */
+ if (errno == ESRCH)
+ return;
+
+ if ((*the_low_target.cannot_store_register) (regno) == 0)
+ error ("writing register %d: %s", regno, strerror (errno));
+ }
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ }
+}
+
+/* Fetch all registers, or just one, from the child process.
+ If REGNO is -1, do this for all registers, skipping any that are
+ assumed to have been retrieved by regsets_fetch_inferior_registers,
+ unless ALL is non-zero.
+ Otherwise, REGNO specifies which register (so we can save time). */
+static void
+usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < the_low_target.num_regs; regno++)
+ if (all || !linux_register_in_regsets (regno))
+ fetch_register (regcache, regno);
+ }
+ else
+ fetch_register (regcache, regno);
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers, skipping any that are
+ assumed to have been saved by regsets_store_inferior_registers,
+ unless ALL is non-zero.
+ Otherwise, REGNO specifies which register (so we can save time). */
+static void
+usr_store_inferior_registers (struct regcache *regcache, int regno, int all)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < the_low_target.num_regs; regno++)
+ if (all || !linux_register_in_regsets (regno))
+ store_register (regcache, regno);
+ }
+ else
+ store_register (regcache, regno);
+}
+
+#else /* !HAVE_LINUX_USRREGS */
+
+#define usr_fetch_inferior_registers(regcache, regno, all) do {} while (0)
+#define usr_store_inferior_registers(regcache, regno, all) do {} while (0)
+
#endif
+
+
+void
+linux_fetch_registers (struct regcache *regcache, int regno)
+{
+ int use_regsets;
+ int all = 0;
+
+ if (regno == -1)
+ {
+ all = regsets_fetch_inferior_registers (regcache);
+ usr_fetch_inferior_registers (regcache, regno, all);
+ }
+ else
+ {
+ use_regsets = linux_register_in_regsets (regno);
+ if (use_regsets)
+ all = regsets_fetch_inferior_registers (regcache);
+ if (!use_regsets || all)
+ usr_fetch_inferior_registers (regcache, regno, 1);
+ }
}
void
linux_store_registers (struct regcache *regcache, int regno)
{
-#ifdef HAVE_LINUX_REGSETS
- if (regsets_store_inferior_registers (regcache) == 0)
- return;
-#endif
-#ifdef HAVE_LINUX_USRREGS
- usr_store_inferior_registers (regcache, regno);
-#endif
+ int use_regsets;
+ int all = 0;
+
+ if (regno == -1)
+ {
+ all = regsets_store_inferior_registers (regcache);
+ usr_store_inferior_registers (regcache, regno, all);
+ }
+ else
+ {
+ use_regsets = linux_register_in_regsets (regno);
+ if (use_regsets)
+ all = regsets_store_inferior_registers (regcache);
+ if (!use_regsets || all)
+ usr_store_inferior_registers (regcache, regno, 1);
+ }
}
layout of the inferiors' architecture. */
static void
-siginfo_fixup (struct siginfo *siginfo, void *inf_siginfo, int direction)
+siginfo_fixup (siginfo_t *siginfo, void *inf_siginfo, int direction)
{
int done = 0;
if (!done)
{
if (direction == 1)
- memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+ memcpy (siginfo, inf_siginfo, sizeof (siginfo_t));
else
- memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+ memcpy (inf_siginfo, siginfo, sizeof (siginfo_t));
}
}
unsigned const char *writebuf, CORE_ADDR offset, int len)
{
int pid;
- struct siginfo siginfo;
- char inf_siginfo[sizeof (struct siginfo)];
+ siginfo_t siginfo;
+ char inf_siginfo[sizeof (siginfo_t)];
if (current_inferior == NULL)
return -1;
#endif
}
+static int
+linux_supports_agent (void)
+{
+ return 1;
+}
+
/* Enumerate spufs IDs for process PID. */
static int
spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
if (relocation == -1)
{
- warning ("Unexpected missing PT_PHDR");
+ /* PT_PHDR is optional, but necessary for PIE in general. Fortunately
+ any real world executables, including PIE executables, have always
+ PT_PHDR present. PT_PHDR is not present in some shared libraries or
+ in fpc (Free Pascal 2.4) binaries but neither of those have a need for
+ or present DT_DEBUG anyway (fpc binaries are statically linked).
+
+ Therefore if there exists DT_DEBUG there is always also PT_PHDR.
+
+ GDB could find RELOCATION also from AT_ENTRY - e_entry. */
+
return 0;
}
linux_supports_disable_randomization,
linux_get_min_fast_tracepoint_insn_len,
linux_qxfer_libraries_svr4,
+ linux_supports_agent,
};
static void