Index: gdb/gdbserver/linux-low.c |
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c |
index 1a1b39a2111237f0ec15361ad5d5e25e6535b23b..a476031faf48be31b9dc5911771caf525d23cbbc 100644 |
--- a/gdb/gdbserver/linux-low.c |
+++ b/gdb/gdbserver/linux-low.c |
@@ -19,6 +19,7 @@ |
#include "server.h" |
#include "linux-low.h" |
#include "linux-osdata.h" |
+#include "agent.h" |
#include <sys/wait.h> |
#include <stdio.h> |
@@ -77,10 +78,42 @@ |
#ifdef __UCLIBC__ |
#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__)) |
+/* PTRACE_TEXT_ADDR and friends. */ |
+#include <asm/ptrace.h> |
#define HAS_NOMMU |
#endif |
#endif |
+#ifndef HAVE_ELF32_AUXV_T |
+/* Copied from glibc's elf.h. */ |
+typedef struct |
+{ |
+ uint32_t a_type; /* Entry type */ |
+ union |
+ { |
+ uint32_t a_val; /* Integer value */ |
+ /* We use to have pointer elements added here. We cannot do that, |
+ though, since it does not work when using 32-bit definitions |
+ on 64-bit platforms and vice versa. */ |
+ } a_un; |
+} Elf32_auxv_t; |
+#endif |
+ |
+#ifndef HAVE_ELF64_AUXV_T |
+/* Copied from glibc's elf.h. */ |
+typedef struct |
+{ |
+ uint64_t a_type; /* Entry type */ |
+ union |
+ { |
+ uint64_t a_val; /* Integer value */ |
+ /* We use to have pointer elements added here. We cannot do that, |
+ though, since it does not work when using 32-bit definitions |
+ on 64-bit platforms and vice versa. */ |
+ } a_un; |
+} Elf64_auxv_t; |
+#endif |
+ |
/* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol |
representation of the thread ID. |
@@ -92,14 +125,69 @@ |
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 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; |
+} |
+ |
+enum stopping_threads_kind |
+ { |
+ /* Not stopping threads presently. */ |
+ NOT_STOPPING_THREADS, |
+ |
+ /* Stopping threads. */ |
+ STOPPING_THREADS, |
-struct inferior_list stopped_pids; |
+ /* Stopping and suspending threads. */ |
+ STOPPING_AND_SUSPENDING_THREADS |
+ }; |
-/* FIXME this is a bit of a hack, and could be removed. */ |
-int stopping_threads; |
+/* This is set while stop_all_lwps is in effect. */ |
+enum stopping_threads_kind stopping_threads = NOT_STOPPING_THREADS; |
/* FIXME make into a target method? */ |
int using_threads = 1; |
@@ -167,10 +255,6 @@ struct pending_signals |
struct pending_signals *prev; |
}; |
-#define PTRACE_ARG3_TYPE void * |
-#define PTRACE_ARG4_TYPE void * |
-#define PTRACE_XFER_TYPE long |
- |
#ifdef HAVE_LINUX_REGSETS |
static char *disabled_regsets; |
static int num_regsets; |
@@ -186,50 +270,30 @@ static int linux_event_pipe[2] = { -1, -1 }; |
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 |
-elf_64_header_p (const Elf64_Ehdr *header) |
+elf_64_header_p (const Elf64_Ehdr *header, unsigned int *machine) |
{ |
- return (header->e_ident[EI_MAG0] == ELFMAG0 |
- && header->e_ident[EI_MAG1] == ELFMAG1 |
- && header->e_ident[EI_MAG2] == ELFMAG2 |
- && header->e_ident[EI_MAG3] == ELFMAG3 |
- && header->e_ident[EI_CLASS] == ELFCLASS64); |
+ if (header->e_ident[EI_MAG0] == ELFMAG0 |
+ && header->e_ident[EI_MAG1] == ELFMAG1 |
+ && header->e_ident[EI_MAG2] == ELFMAG2 |
+ && header->e_ident[EI_MAG3] == ELFMAG3) |
+ { |
+ *machine = header->e_machine; |
+ return header->e_ident[EI_CLASS] == ELFCLASS64; |
+ |
+ } |
+ *machine = EM_NONE; |
+ return -1; |
} |
/* Return non-zero if FILE is a 64-bit ELF file, |
zero if the file is not a 64-bit ELF file, |
and -1 if the file is not accessible or doesn't exist. */ |
-int |
-elf_64_file_p (const char *file) |
+static int |
+elf_64_file_p (const char *file, unsigned int *machine) |
{ |
Elf64_Ehdr header; |
int fd; |
@@ -245,7 +309,19 @@ elf_64_file_p (const char *file) |
} |
close (fd); |
- return elf_64_header_p (&header); |
+ return elf_64_header_p (&header, machine); |
+} |
+ |
+/* 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, unsigned int *machine) |
+{ |
+ char file[MAXPATHLEN]; |
+ |
+ sprintf (file, "/proc/%d/exe", pid); |
+ return elf_64_file_p (file, machine); |
} |
static void |
@@ -367,12 +443,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) |
{ |
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. */ |
@@ -399,12 +475,17 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) |
before calling linux_resume_one_lwp. */ |
new_lwp->stopped = 1; |
+ /* If we're suspending all threads, leave this one suspended |
+ too. */ |
+ if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS) |
+ new_lwp->suspended = 1; |
+ |
/* Normally we will get the pending SIGSTOP. But in some cases |
we might get another signal delivered to the group first. |
If we do get another signal, be sure not to lose it. */ |
if (WSTOPSIG (status) == SIGSTOP) |
{ |
- if (stopping_threads) |
+ if (stopping_threads != NOT_STOPPING_THREADS) |
new_lwp->stop_pc = get_stop_pc (new_lwp); |
else |
linux_resume_one_lwp (new_lwp, 0, 0, NULL); |
@@ -413,7 +494,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) |
{ |
new_lwp->stop_expected = 1; |
- if (stopping_threads) |
+ if (stopping_threads != NOT_STOPPING_THREADS) |
{ |
new_lwp->stop_pc = get_stop_pc (new_lwp); |
new_lwp->status_pending_p = 1; |
@@ -568,6 +649,19 @@ linux_create_inferior (char *program, char **allargs) |
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); |
@@ -609,6 +703,8 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) |
if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0) |
{ |
+ struct buffer buffer; |
+ |
if (!initial) |
{ |
/* If we fail to attach to an LWP, just warn. */ |
@@ -617,10 +713,13 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) |
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) |
@@ -644,6 +743,33 @@ linux_attach_lwp_1 (unsigned long lwpid, int 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. |
@@ -691,7 +817,7 @@ linux_attach_lwp (unsigned long lwpid) |
/* Attach to PID. If PID is the tgid, attach to it and all |
of its threads. */ |
-int |
+static int |
linux_attach (unsigned long pid) |
{ |
/* Attach to PID. We will check for other threads |
@@ -802,10 +928,49 @@ last_thread_of_process_p (struct thread_info *thread) |
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); |
@@ -830,7 +995,7 @@ linux_kill_one_lwp (struct inferior_list_entry *entry, void *args) |
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); |
@@ -855,7 +1020,7 @@ linux_kill (int pid) |
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. */ |
@@ -875,7 +1040,7 @@ linux_kill (int pid) |
do |
{ |
- ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); |
+ 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); |
@@ -890,34 +1055,128 @@ linux_kill (int pid) |
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 gdb_signal signo = GDB_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 == GDB_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 = gdb_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)), |
+ gdb_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 == GDB_SIGNAL_TRAP || signo == GDB_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)), |
+ gdb_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)), |
+ gdb_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, |
+ (PTRACE_ARG4_TYPE) (long) sig) < 0) |
+ error (_("Can't detach %s: %s"), |
+ target_pid_to_str (ptid_of (lwp)), |
+ strerror (errno)); |
delete_lwp (lwp); |
return 0; |
@@ -1103,7 +1362,7 @@ retry: |
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) |
@@ -1280,7 +1539,7 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) |
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; |
@@ -1554,17 +1813,17 @@ ptid_t step_over_bkpt; |
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); |
@@ -1575,7 +1834,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) |
{ |
requested_child = find_lwp_pid (ptid); |
- if (!stopping_threads |
+ if (stopping_threads == NOT_STOPPING_THREADS |
&& requested_child->status_pending_p |
&& requested_child->collecting_fast_tracepoint) |
{ |
@@ -1606,13 +1865,24 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) |
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) |
{ |
@@ -1624,6 +1894,19 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) |
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. */ |
@@ -1699,7 +1982,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) |
event_child->stop_expected = 0; |
should_stop = (current_inferior->last_resume_kind == resume_stop |
- || stopping_threads); |
+ || stopping_threads != NOT_STOPPING_THREADS); |
if (!should_stop) |
{ |
@@ -1716,48 +1999,6 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) |
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 |
@@ -2021,10 +2262,10 @@ linux_stabilize_threads (void) |
/* Lock it. */ |
lwp->suspended++; |
- if (ourstatus.value.sig != TARGET_SIGNAL_0 |
+ if (ourstatus.value.sig != GDB_SIGNAL_0 |
|| current_inferior->last_resume_kind == resume_stop) |
{ |
- wstat = W_STOPCODE (target_signal_to_host (ourstatus.value.sig)); |
+ wstat = W_STOPCODE (gdb_signal_to_host (ourstatus.value.sig)); |
enqueue_one_deferred_signal (lwp, &wstat); |
} |
} |
@@ -2145,7 +2386,7 @@ retry: |
else |
{ |
ourstatus->kind = TARGET_WAITKIND_SIGNALLED; |
- ourstatus->value.sig = target_signal_from_host (WTERMSIG (w)); |
+ ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (w)); |
if (debug_threads) |
fprintf (stderr, |
@@ -2229,7 +2470,7 @@ retry: |
if (WIFSTOPPED (w) |
&& WSTOPSIG (w) != SIGTRAP |
&& supports_fast_tracepoints () |
- && in_process_agent_loaded ()) |
+ && agent_loaded_p ()) |
{ |
if (debug_threads) |
fprintf (stderr, |
@@ -2317,7 +2558,7 @@ Check if we're already there.\n", |
if (stabilizing_threads) |
{ |
ourstatus->kind = TARGET_WAITKIND_STOPPED; |
- ourstatus->value.sig = TARGET_SIGNAL_0; |
+ ourstatus->value.sig = GDB_SIGNAL_0; |
return ptid_of (event_child); |
} |
} |
@@ -2344,7 +2585,7 @@ Check if we're already there.\n", |
|| WSTOPSIG (w) == __SIGRTMIN + 1)) |
|| |
#endif |
- (pass_signals[target_signal_from_host (WSTOPSIG (w))] |
+ (pass_signals[gdb_signal_from_host (WSTOPSIG (w))] |
&& !(WSTOPSIG (w) == SIGSTOP |
&& current_inferior->last_resume_kind == resume_stop)))) |
{ |
@@ -2376,7 +2617,11 @@ Check if we're already there.\n", |
|| 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) |
+ && gdb_no_commands_at_breakpoint (event_child->stop_pc))); |
+ |
+ run_breakpoint_commands (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 |
@@ -2459,6 +2704,15 @@ Check if we're already there.\n", |
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 (); |
} |
@@ -2480,18 +2734,18 @@ Check if we're already there.\n", |
/* 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->value.sig = TARGET_SIGNAL_0; |
+ ourstatus->value.sig = GDB_SIGNAL_0; |
} |
else if (current_inferior->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->value.sig = target_signal_from_host (WSTOPSIG (w)); |
+ ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); |
} |
else |
{ |
- ourstatus->value.sig = target_signal_from_host (WSTOPSIG (w)); |
+ ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); |
} |
gdb_assert (ptid_equal (step_over_bkpt, null_ptid)); |
@@ -2773,7 +3027,7 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data) |
/* 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) |
@@ -2840,14 +3094,19 @@ lwp_running (struct inferior_list_entry *entry, void *data) |
static void |
stop_all_lwps (int suspend, struct lwp_info *except) |
{ |
- stopping_threads = 1; |
+ /* Should not be called recursively. */ |
+ gdb_assert (stopping_threads == NOT_STOPPING_THREADS); |
+ |
+ stopping_threads = (suspend |
+ ? STOPPING_AND_SUSPENDING_THREADS |
+ : STOPPING_THREADS); |
if (suspend) |
find_inferior (&all_lwps, suspend_and_send_sigstop_callback, except); |
else |
find_inferior (&all_lwps, send_sigstop_callback, except); |
for_each_inferior (&all_lwps, wait_for_sigstop); |
- stopping_threads = 0; |
+ stopping_threads = NOT_STOPPING_THREADS; |
} |
/* Resume execution of the inferior process. |
@@ -3083,10 +3342,11 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg) |
ptid_t ptid = r->resume[ndx].thread; |
if (ptid_equal (ptid, minus_one_ptid) |
|| ptid_equal (ptid, entry->id) |
- || (ptid_is_pid (ptid) |
- && (ptid_get_pid (ptid) == pid_of (lwp))) |
- || (ptid_get_lwp (ptid) == -1 |
- && (ptid_get_pid (ptid) == pid_of (lwp)))) |
+ /* Handle both 'pPID' and 'pPID.-1' as meaning 'all threads |
+ of PID'. */ |
+ || (ptid_get_pid (ptid) == pid_of (lwp) |
+ && (ptid_is_pid (ptid) |
+ || ptid_get_lwp (ptid) == -1))) |
{ |
if (r->resume[ndx].kind == resume_stop |
&& thread->last_resume_kind == resume_stop) |
@@ -3239,8 +3499,11 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy) |
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) |
+ && gdb_no_commands_at_breakpoint (pc)) |
{ |
if (debug_threads) |
fprintf (stderr, |
@@ -3720,166 +3983,32 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except) |
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]; |
+#ifdef HAVE_LINUX_REGSETS |
- return addr; |
-} |
+#define use_linux_regsets 1 |
-/* Fetch one register. */ |
-static void |
-fetch_register (struct regcache *regcache, int regno) |
+static int |
+regsets_fetch_inferior_registers (struct regcache *regcache) |
{ |
- CORE_ADDR regaddr; |
- int i, size; |
- char *buf; |
+ struct regset_info *regset; |
+ int saw_general_regs = 0; |
int pid; |
+ struct iovec iov; |
- 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); |
+ regset = target_regsets; |
pid = lwpid_of (get_thread_lwp (current_inferior)); |
- for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) |
+ while (regset->size >= 0) |
{ |
- 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)); |
- } |
+ void *buf, *data; |
+ int nt_type, res; |
- 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. */ |
-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) |
-{ |
- if (regno == -1) |
- for (regno = 0; regno < the_low_target.num_regs; regno++) |
- store_register (regcache, regno); |
- else |
- store_register (regcache, regno); |
-} |
-#endif /* HAVE_LINUX_USRREGS */ |
- |
- |
- |
-#ifdef HAVE_LINUX_REGSETS |
- |
-static int |
-regsets_fetch_inferior_registers (struct regcache *regcache) |
-{ |
- struct regset_info *regset; |
- int saw_general_regs = 0; |
- int pid; |
- struct iovec iov; |
- |
- regset = target_regsets; |
- |
- pid = lwpid_of (get_thread_lwp (current_inferior)); |
- while (regset->size >= 0) |
- { |
- void *buf, *data; |
- int nt_type, res; |
- |
- if (regset->size == 0 || disabled_regsets[regset - target_regsets]) |
- { |
- regset ++; |
- continue; |
- } |
+ if (regset->size == 0 || disabled_regsets[regset - target_regsets]) |
+ { |
+ regset ++; |
+ continue; |
+ } |
buf = xmalloc (regset->size); |
@@ -3894,7 +4023,8 @@ regsets_fetch_inferior_registers (struct regcache *regcache) |
data = buf; |
#ifndef __sparc__ |
- res = ptrace (regset->get_request, pid, nt_type, data); |
+ res = ptrace (regset->get_request, pid, |
+ (PTRACE_ARG3_TYPE) (long) nt_type, data); |
#else |
res = ptrace (regset->get_request, pid, data, nt_type); |
#endif |
@@ -3967,9 +4097,10 @@ regsets_store_inferior_registers (struct regcache *regcache) |
data = buf; |
#ifndef __sparc__ |
- res = ptrace (regset->get_request, pid, nt_type, data); |
+ res = ptrace (regset->get_request, pid, |
+ (PTRACE_ARG3_TYPE) (long) nt_type, data); |
#else |
- res = ptrace (regset->get_request, pid, &iov, data); |
+ res = ptrace (regset->get_request, pid, data, nt_type); |
#endif |
if (res == 0) |
@@ -3979,7 +4110,8 @@ regsets_store_inferior_registers (struct regcache *regcache) |
/* Only now do we write the register set. */ |
#ifndef __sparc__ |
- res = ptrace (regset->set_request, pid, nt_type, data); |
+ res = ptrace (regset->set_request, pid, |
+ (PTRACE_ARG3_TYPE) (long) nt_type, data); |
#else |
res = ptrace (regset->set_request, pid, data, nt_type); |
#endif |
@@ -4018,34 +4150,232 @@ regsets_store_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) |
+ { |
+ if (the_low_target.fetch_register != NULL) |
+ for (regno = 0; regno < the_low_target.num_regs; regno++) |
+ (*the_low_target.fetch_register) (regcache, regno); |
+ |
+ all = regsets_fetch_inferior_registers (regcache); |
+ usr_fetch_inferior_registers (regcache, -1, all); |
+ } |
+ else |
+ { |
+ if (the_low_target.fetch_register != NULL |
+ && (*the_low_target.fetch_register) (regcache, regno)) |
+ return; |
+ |
+ 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); |
+ } |
} |
@@ -4055,23 +4385,20 @@ linux_store_registers (struct regcache *regcache, int regno) |
static int |
linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) |
{ |
+ int pid = lwpid_of (get_thread_lwp (current_inferior)); |
+ register PTRACE_XFER_TYPE *buffer; |
+ register CORE_ADDR addr; |
+ register int count; |
+ char filename[64]; |
register int i; |
- /* Round starting address down to longword boundary. */ |
- register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); |
- /* Round ending address up; get number of longwords that makes. */ |
- register int count |
- = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) |
- / sizeof (PTRACE_XFER_TYPE); |
- /* Allocate buffer of that many longwords. */ |
- register PTRACE_XFER_TYPE *buffer |
- = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); |
+ int ret; |
int fd; |
- char filename[64]; |
- int pid = lwpid_of (get_thread_lwp (current_inferior)); |
/* Try using /proc. Don't bother for one word. */ |
if (len >= 3 * sizeof (long)) |
{ |
+ 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); |
@@ -4084,38 +4411,59 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) |
32-bit platforms (for instance, SPARC debugging a SPARC64 |
application). */ |
#ifdef HAVE_PREAD64 |
- if (pread64 (fd, myaddr, len, memaddr) != len) |
+ bytes = pread64 (fd, myaddr, len, memaddr); |
#else |
- if (lseek (fd, memaddr, SEEK_SET) == -1 || read (fd, myaddr, len) != len) |
+ bytes = -1; |
+ if (lseek (fd, memaddr, SEEK_SET) != -1) |
+ bytes = read (fd, myaddr, len); |
#endif |
- { |
- close (fd); |
- goto no_proc; |
- } |
close (fd); |
- return 0; |
+ 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; |
+ } |
} |
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 = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); |
+ |
/* Read all the longwords */ |
+ errno = 0; |
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) |
{ |
- 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[i] = ptrace (PTRACE_PEEKTEXT, pid, |
(PTRACE_ARG3_TYPE) (uintptr_t) addr, 0); |
if (errno) |
- return errno; |
+ break; |
} |
+ ret = errno; |
/* Copy appropriate bytes out of the buffer. */ |
- memcpy (myaddr, |
- (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), |
- len); |
+ 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; |
} |
/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's |
@@ -4458,6 +4806,9 @@ linux_stopped_data_address (void) |
} |
#if defined(__UCLIBC__) && defined(HAS_NOMMU) |
+#if ! (defined(PT_TEXT_ADDR) \ |
+ || defined(PT_DATA_ADDR) \ |
+ || defined(PT_TEXT_END_ADDR)) |
#if defined(__mcoldfire__) |
/* These should really be defined in the kernel's ptrace.h header. */ |
#define PT_TEXT_ADDR 49*4 |
@@ -4472,6 +4823,7 @@ linux_stopped_data_address (void) |
#define PT_DATA_ADDR (0x10004*4) |
#define PT_TEXT_END_ADDR (0x10008*4) |
#endif |
+#endif |
/* Under uClinux, programs are loaded at non-zero offsets, which we need |
to tell gdb about. */ |
@@ -4522,7 +4874,7 @@ linux_qxfer_osdata (const char *annex, |
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; |
@@ -4534,9 +4886,9 @@ siginfo_fixup (struct siginfo *siginfo, void *inf_siginfo, int direction) |
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)); |
} |
} |
@@ -4545,8 +4897,8 @@ linux_xfer_siginfo (const char *annex, unsigned char *readbuf, |
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; |
@@ -4694,6 +5046,12 @@ linux_supports_disable_randomization (void) |
#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) |
@@ -5083,7 +5441,16 @@ get_dynamic (const int pid, const int is_elf64) |
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; |
} |
@@ -5109,7 +5476,9 @@ get_dynamic (const int pid, const int is_elf64) |
} |
/* Return &_r_debug in the inferior, or -1 if not present. Return value |
- can be 0 if the inferior does not yet have the library list initialized. */ |
+ can be 0 if the inferior does not yet have the library list initialized. |
+ We look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of |
+ DT_DEBUG, although they sometimes contain an unused DT_DEBUG entry too. */ |
static CORE_ADDR |
get_r_debug (const int pid, const int is_elf64) |
@@ -5117,19 +5486,37 @@ get_r_debug (const int pid, const int is_elf64) |
CORE_ADDR dynamic_memaddr; |
const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn); |
unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */ |
+ CORE_ADDR map = -1; |
dynamic_memaddr = get_dynamic (pid, is_elf64); |
if (dynamic_memaddr == 0) |
- return (CORE_ADDR) -1; |
+ return map; |
while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0) |
{ |
if (is_elf64) |
{ |
Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; |
+#ifdef DT_MIPS_RLD_MAP |
+ union |
+ { |
+ Elf64_Xword map; |
+ unsigned char buf[sizeof (Elf64_Xword)]; |
+ } |
+ rld_map; |
+ |
+ if (dyn->d_tag == DT_MIPS_RLD_MAP) |
+ { |
+ if (linux_read_memory (dyn->d_un.d_val, |
+ rld_map.buf, sizeof (rld_map.buf)) == 0) |
+ return rld_map.map; |
+ else |
+ break; |
+ } |
+#endif /* DT_MIPS_RLD_MAP */ |
- if (dyn->d_tag == DT_DEBUG) |
- return dyn->d_un.d_val; |
+ if (dyn->d_tag == DT_DEBUG && map == -1) |
+ map = dyn->d_un.d_val; |
if (dyn->d_tag == DT_NULL) |
break; |
@@ -5137,9 +5524,26 @@ get_r_debug (const int pid, const int is_elf64) |
else |
{ |
Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; |
+#ifdef DT_MIPS_RLD_MAP |
+ union |
+ { |
+ Elf32_Word map; |
+ unsigned char buf[sizeof (Elf32_Word)]; |
+ } |
+ rld_map; |
+ |
+ if (dyn->d_tag == DT_MIPS_RLD_MAP) |
+ { |
+ if (linux_read_memory (dyn->d_un.d_val, |
+ rld_map.buf, sizeof (rld_map.buf)) == 0) |
+ return rld_map.map; |
+ else |
+ break; |
+ } |
+#endif /* DT_MIPS_RLD_MAP */ |
- if (dyn->d_tag == DT_DEBUG) |
- return dyn->d_un.d_val; |
+ if (dyn->d_tag == DT_DEBUG && map == -1) |
+ map = dyn->d_un.d_val; |
if (dyn->d_tag == DT_NULL) |
break; |
@@ -5148,7 +5552,7 @@ get_r_debug (const int pid, const int is_elf64) |
dynamic_memaddr += dyn_size; |
} |
- return (CORE_ADDR) -1; |
+ return map; |
} |
/* Read one pointer from MEMADDR in the inferior. */ |
@@ -5156,8 +5560,30 @@ get_r_debug (const int pid, const int is_elf64) |
static int |
read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) |
{ |
- *ptr = 0; |
- return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size); |
+ int ret; |
+ |
+ /* Go through a union so this works on either big or little endian |
+ hosts, when the inferior's pointer size is smaller than the size |
+ of CORE_ADDR. It is assumed the inferior's endianness is the |
+ same of the superior's. */ |
+ union |
+ { |
+ CORE_ADDR core_addr; |
+ unsigned int ui; |
+ unsigned char uc; |
+ } addr; |
+ |
+ ret = linux_read_memory (memaddr, &addr.uc, ptr_size); |
+ if (ret == 0) |
+ { |
+ if (ptr_size == sizeof (CORE_ADDR)) |
+ *ptr = addr.core_addr; |
+ else if (ptr_size == sizeof (unsigned int)) |
+ *ptr = addr.ui; |
+ else |
+ gdb_assert_not_reached ("unhandled pointer size"); |
+ } |
+ return ret; |
} |
struct link_map_offsets |
@@ -5184,7 +5610,7 @@ struct link_map_offsets |
int l_prev_offset; |
}; |
-/* Construct qXfer:libraries:read reply. */ |
+/* Construct qXfer:libraries-svr4:read reply. */ |
static int |
linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, |
@@ -5219,6 +5645,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, |
32 /* l_prev offset in link_map. */ |
}; |
const struct link_map_offsets *lmo; |
+ unsigned int machine; |
if (writebuf != NULL) |
return -2; |
@@ -5227,13 +5654,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, |
pid = lwpid_of (get_thread_lwp (current_inferior)); |
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); |
- is_elf64 = elf_64_file_p (filename); |
+ is_elf64 = elf_64_file_p (filename, &machine); |
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; |
if (priv->r_debug == 0) |
priv->r_debug = get_r_debug (pid, is_elf64); |
- if (priv->r_debug == (CORE_ADDR) -1 || priv->r_debug == 0) |
+ /* 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) |
+ return -1; |
+ |
+ if (priv->r_debug == 0) |
{ |
document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n"); |
} |
@@ -5336,7 +5769,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, |
lm_addr = l_next; |
} |
done: |
- strcpy (p, "</library-list-svr4>"); |
+ if (!header_done) |
+ { |
+ /* Empty list; terminate `<library-list-svr4'. */ |
+ strcpy (p, "/>"); |
+ } |
+ else |
+ strcpy (p, "</library-list-svr4>"); |
} |
document_len = strlen (document); |
@@ -5416,6 +5855,7 @@ static struct target_ops linux_target_ops = { |
linux_supports_disable_randomization, |
linux_get_min_fast_tracepoint_insn_len, |
linux_qxfer_libraries_svr4, |
+ linux_supports_agent, |
}; |
static void |
@@ -5438,6 +5878,7 @@ initialize_low (void) |
the_low_target.breakpoint_len); |
linux_init_signals (); |
linux_test_for_tracefork (); |
+ linux_ptrace_init_warnings (); |
#ifdef HAVE_LINUX_REGSETS |
for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++) |
; |