| Index: gdb/linux-nat.c
|
| diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
|
| index 373d1caf43670502309d21f64f0177a3c256a9b6..d2a529ae6d40216237e6390fffff05ad05f7738c 100644
|
| --- a/gdb/linux-nat.c
|
| +++ b/gdb/linux-nat.c
|
| @@ -36,6 +36,7 @@
|
| #include "gdbcmd.h"
|
| #include "regcache.h"
|
| #include "regset.h"
|
| +#include "inf-child.h"
|
| #include "inf-ptrace.h"
|
| #include "auxv.h"
|
| #include <sys/param.h> /* for MAXPATHLEN */
|
| @@ -58,7 +59,13 @@
|
| #include <sys/vfs.h>
|
| #include "solib.h"
|
| #include "linux-osdata.h"
|
| -#include "cli/cli-utils.h"
|
| +#include "linux-tdep.h"
|
| +#include "symfile.h"
|
| +#include "agent.h"
|
| +#include "tracepoint.h"
|
| +#include "exceptions.h"
|
| +#include "linux-ptrace.h"
|
| +#include "buffer.h"
|
|
|
| #ifndef SPUFS_MAGIC
|
| #define SPUFS_MAGIC 0x23c9b64e
|
| @@ -174,12 +181,15 @@ static struct target_ops *linux_ops;
|
| static struct target_ops linux_ops_saved;
|
|
|
| /* The method to call, if any, when a new thread is attached. */
|
| -static void (*linux_nat_new_thread) (ptid_t);
|
| +static void (*linux_nat_new_thread) (struct lwp_info *);
|
| +
|
| +/* Hook to call prior to resuming a thread. */
|
| +static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
|
|
|
| /* The method to call, if any, when the siginfo object needs to be
|
| converted between the layout returned by ptrace, and the layout in
|
| the architecture of the inferior. */
|
| -static int (*linux_nat_siginfo_fixup) (struct siginfo *,
|
| +static int (*linux_nat_siginfo_fixup) (siginfo_t *,
|
| gdb_byte *,
|
| int);
|
|
|
| @@ -285,6 +295,7 @@ static void restore_child_signals_mask (sigset_t *prev_mask);
|
| struct lwp_info;
|
| static struct lwp_info *add_lwp (ptid_t ptid);
|
| static void purge_lwp_list (int pid);
|
| +static void delete_lwp (ptid_t ptid);
|
| static struct lwp_info *find_lwp_pid (ptid_t ptid);
|
|
|
|
|
| @@ -572,6 +583,7 @@ linux_child_post_attach (int pid)
|
| {
|
| linux_enable_event_reporting (pid_to_ptid (pid));
|
| linux_enable_tracesysgood (pid_to_ptid (pid));
|
| + linux_ptrace_init_warnings ();
|
| }
|
|
|
| static void
|
| @@ -579,6 +591,32 @@ linux_child_post_startup_inferior (ptid_t ptid)
|
| {
|
| linux_enable_event_reporting (ptid);
|
| linux_enable_tracesysgood (ptid);
|
| + linux_ptrace_init_warnings ();
|
| +}
|
| +
|
| +/* Return the number of known LWPs in the tgid given by PID. */
|
| +
|
| +static int
|
| +num_lwps (int pid)
|
| +{
|
| + int count = 0;
|
| + struct lwp_info *lp;
|
| +
|
| + for (lp = lwp_list; lp; lp = lp->next)
|
| + if (ptid_get_pid (lp->ptid) == pid)
|
| + count++;
|
| +
|
| + return count;
|
| +}
|
| +
|
| +/* Call delete_lwp with prototype compatible for make_cleanup. */
|
| +
|
| +static void
|
| +delete_lwp_cleanup (void *lp_voidp)
|
| +{
|
| + struct lwp_info *lp = lp_voidp;
|
| +
|
| + delete_lwp (lp->ptid);
|
| }
|
|
|
| static int
|
| @@ -627,6 +665,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
| /* Detach new forked process? */
|
| if (detach_fork)
|
| {
|
| + struct cleanup *old_chain;
|
| +
|
| /* Before detaching from the child, remove all breakpoints
|
| from it. If we forked, then this has already been taken
|
| care of by infrun.c. If we vforked however, any
|
| @@ -649,7 +689,28 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
| child_pid);
|
| }
|
|
|
| + old_chain = save_inferior_ptid ();
|
| + inferior_ptid = ptid_build (child_pid, child_pid, 0);
|
| +
|
| + child_lp = add_lwp (inferior_ptid);
|
| + child_lp->stopped = 1;
|
| + child_lp->last_resume_kind = resume_stop;
|
| + make_cleanup (delete_lwp_cleanup, child_lp);
|
| +
|
| + /* CHILD_LP has new PID, therefore linux_nat_new_thread is not called for it.
|
| + See i386_inferior_data_get for the Linux kernel specifics.
|
| + Ensure linux_nat_prepare_to_resume will reset the hardware debug
|
| + registers. It is done by the linux_nat_new_thread call, which is
|
| + being skipped in add_lwp above for the first lwp of a pid. */
|
| + gdb_assert (num_lwps (GET_PID (child_lp->ptid)) == 1);
|
| + if (linux_nat_new_thread != NULL)
|
| + linux_nat_new_thread (child_lp);
|
| +
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (child_lp);
|
| ptrace (PTRACE_DETACH, child_pid, 0, 0);
|
| +
|
| + do_cleanups (old_chain);
|
| }
|
| else
|
| {
|
| @@ -671,6 +732,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
| child_lp = add_lwp (inferior_ptid);
|
| child_lp->stopped = 1;
|
| child_lp->last_resume_kind = resume_stop;
|
| + child_inf->symfile_flags = SYMFILE_NO_READ;
|
|
|
| /* If this is a vfork child, then the address-space is
|
| shared with the parent. */
|
| @@ -876,6 +938,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
| child_inf->aspace = new_address_space ();
|
| child_inf->pspace = add_program_space (child_inf->aspace);
|
| child_inf->removable = 1;
|
| + child_inf->symfile_flags = SYMFILE_NO_READ;
|
| set_current_program_space (child_inf->pspace);
|
| clone_program_space (child_inf->pspace, parent_pspace);
|
|
|
| @@ -1032,7 +1095,7 @@ linux_nat_pass_signals (int numsigs, unsigned char *pass_signals)
|
|
|
| for (signo = 1; signo < NSIG; signo++)
|
| {
|
| - int target_signo = target_signal_from_host (signo);
|
| + int target_signo = gdb_signal_from_host (signo);
|
| if (target_signo < numsigs && pass_signals[target_signo])
|
| sigaddset (&pass_mask, signo);
|
| }
|
| @@ -1072,6 +1135,15 @@ status_to_str (int status)
|
| return buf;
|
| }
|
|
|
| +/* Destroy and free LP. */
|
| +
|
| +static void
|
| +lwp_free (struct lwp_info *lp)
|
| +{
|
| + xfree (lp->arch_private);
|
| + xfree (lp);
|
| +}
|
| +
|
| /* Remove all LWPs belong to PID from the lwp list. */
|
|
|
| static void
|
| @@ -1092,28 +1164,13 @@ purge_lwp_list (int pid)
|
| else
|
| lpprev->next = lp->next;
|
|
|
| - xfree (lp);
|
| + lwp_free (lp);
|
| }
|
| else
|
| lpprev = lp;
|
| }
|
| }
|
|
|
| -/* Return the number of known LWPs in the tgid given by PID. */
|
| -
|
| -static int
|
| -num_lwps (int pid)
|
| -{
|
| - int count = 0;
|
| - struct lwp_info *lp;
|
| -
|
| - for (lp = lwp_list; lp; lp = lp->next)
|
| - if (ptid_get_pid (lp->ptid) == pid)
|
| - count++;
|
| -
|
| - return count;
|
| -}
|
| -
|
| /* Add the LWP specified by PID to the list. Return a pointer to the
|
| structure describing the new LWP. The LWP should already be stopped
|
| (with an exception for the very first LWP). */
|
| @@ -1138,8 +1195,16 @@ add_lwp (ptid_t ptid)
|
| lp->next = lwp_list;
|
| lwp_list = lp;
|
|
|
| + /* Let the arch specific bits know about this new thread. Current
|
| + clients of this callback take the opportunity to install
|
| + watchpoints in the new thread. Don't do this for the first
|
| + thread though. If we're spawning a child ("run"), the thread
|
| + executes the shell wrapper first, and we shouldn't touch it until
|
| + it execs the program we want to debug. For "attach", it'd be
|
| + okay to call the callback, but it's not necessary, because
|
| + watchpoints can't yet have been inserted into the inferior. */
|
| if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
|
| - linux_nat_new_thread (ptid);
|
| + linux_nat_new_thread (lp);
|
|
|
| return lp;
|
| }
|
| @@ -1165,7 +1230,7 @@ delete_lwp (ptid_t ptid)
|
| else
|
| lwp_list = lp->next;
|
|
|
| - xfree (lp);
|
| + lwp_free (lp);
|
| }
|
|
|
| /* Return a pointer to the structure describing the LWP corresponding
|
| @@ -1215,6 +1280,46 @@ iterate_over_lwps (ptid_t filter,
|
| return NULL;
|
| }
|
|
|
| +/* Iterate like iterate_over_lwps does except when forking-off a child call
|
| + CALLBACK with CALLBACK_DATA specifically only for that new child PID. */
|
| +
|
| +void
|
| +linux_nat_iterate_watchpoint_lwps
|
| + (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data)
|
| +{
|
| + int inferior_pid = ptid_get_pid (inferior_ptid);
|
| + struct inferior *inf = current_inferior ();
|
| +
|
| + if (inf->pid == inferior_pid)
|
| + {
|
| + /* Iterate all the threads of the current inferior. Without specifying
|
| + INFERIOR_PID it would iterate all threads of all inferiors, which is
|
| + inappropriate for watchpoints. */
|
| +
|
| + iterate_over_lwps (pid_to_ptid (inferior_pid), callback, callback_data);
|
| + }
|
| + else
|
| + {
|
| + /* Detaching a new child PID temporarily present in INFERIOR_PID. */
|
| +
|
| + struct lwp_info *child_lp;
|
| + struct cleanup *old_chain;
|
| + pid_t child_pid = GET_PID (inferior_ptid);
|
| + ptid_t child_ptid = ptid_build (child_pid, child_pid, 0);
|
| +
|
| + gdb_assert (!is_lwp (inferior_ptid));
|
| + gdb_assert (find_lwp_pid (child_ptid) == NULL);
|
| + child_lp = add_lwp (child_ptid);
|
| + child_lp->stopped = 1;
|
| + child_lp->last_resume_kind = resume_stop;
|
| + old_chain = make_cleanup (delete_lwp_cleanup, child_lp);
|
| +
|
| + callback (child_lp, callback_data);
|
| +
|
| + do_cleanups (old_chain);
|
| + }
|
| +}
|
| +
|
| /* Update our internal state when changing from one checkpoint to
|
| another indicated by NEW_PTID. We can only switch single-threaded
|
| applications, so we only create one new LWP, and the previous list
|
| @@ -1259,37 +1364,6 @@ exit_lwp (struct lwp_info *lp)
|
| delete_lwp (lp->ptid);
|
| }
|
|
|
| -/* Detect `T (stopped)' in `/proc/PID/status'.
|
| - Other states including `T (tracing stop)' are reported as false. */
|
| -
|
| -static int
|
| -pid_is_stopped (pid_t pid)
|
| -{
|
| - FILE *status_file;
|
| - char buf[100];
|
| - int retval = 0;
|
| -
|
| - snprintf (buf, sizeof (buf), "/proc/%d/status", (int) pid);
|
| - status_file = fopen (buf, "r");
|
| - if (status_file != NULL)
|
| - {
|
| - int have_state = 0;
|
| -
|
| - while (fgets (buf, sizeof (buf), status_file))
|
| - {
|
| - if (strncmp (buf, "State:", 6) == 0)
|
| - {
|
| - have_state = 1;
|
| - break;
|
| - }
|
| - }
|
| - if (have_state && strstr (buf, "T (stopped)") != NULL)
|
| - retval = 1;
|
| - fclose (status_file);
|
| - }
|
| - return retval;
|
| -}
|
| -
|
| /* Wait for the LWP specified by LP, which we have just attached to.
|
| Returns a wait status for that LWP, to cache. */
|
|
|
| @@ -1300,7 +1374,7 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
|
| pid_t new_pid, pid = GET_LWP (ptid);
|
| int status;
|
|
|
| - if (pid_is_stopped (pid))
|
| + if (linux_proc_pid_is_stopped (pid))
|
| {
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| @@ -1544,11 +1618,33 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
|
| struct lwp_info *lp;
|
| int status;
|
| ptid_t ptid;
|
| + volatile struct gdb_exception ex;
|
|
|
| /* Make sure we report all signals during attach. */
|
| linux_nat_pass_signals (0, NULL);
|
|
|
| - linux_ops->to_attach (ops, args, from_tty);
|
| + TRY_CATCH (ex, RETURN_MASK_ERROR)
|
| + {
|
| + linux_ops->to_attach (ops, args, from_tty);
|
| + }
|
| + if (ex.reason < 0)
|
| + {
|
| + pid_t pid = parse_pid_to_attach (args);
|
| + struct buffer buffer;
|
| + char *message, *buffer_s;
|
| +
|
| + message = xstrdup (ex.message);
|
| + make_cleanup (xfree, message);
|
| +
|
| + buffer_init (&buffer);
|
| + linux_ptrace_attach_warnings (pid, &buffer);
|
| +
|
| + buffer_grow_str0 (&buffer, "");
|
| + buffer_s = buffer_finish (&buffer);
|
| + make_cleanup (xfree, buffer_s);
|
| +
|
| + throw_error (ex.error, "%s%s", buffer_s, message);
|
| + }
|
|
|
| /* The ptrace base target adds the main thread with (pid,0,0)
|
| format. Decorate it with lwp info. */
|
| @@ -1576,16 +1672,16 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
|
| }
|
| else if (WIFSIGNALED (status))
|
| {
|
| - enum target_signal signo;
|
| + enum gdb_signal signo;
|
|
|
| target_terminal_ours ();
|
| target_mourn_inferior ();
|
|
|
| - signo = target_signal_from_host (WTERMSIG (status));
|
| + signo = gdb_signal_from_host (WTERMSIG (status));
|
| error (_("Unable to attach: program terminated with signal "
|
| "%s, %s."),
|
| - target_signal_to_name (signo),
|
| - target_signal_to_string (signo));
|
| + gdb_signal_to_name (signo),
|
| + gdb_signal_to_string (signo));
|
| }
|
|
|
| internal_error (__FILE__, __LINE__,
|
| @@ -1612,7 +1708,7 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
|
| static int
|
| get_pending_status (struct lwp_info *lp, int *status)
|
| {
|
| - enum target_signal signo = TARGET_SIGNAL_0;
|
| + enum gdb_signal signo = GDB_SIGNAL_0;
|
|
|
| /* If we paused threads momentarily, we may have stored pending
|
| events in lp->status or lp->waitstatus (see stop_wait_callback),
|
| @@ -1625,7 +1721,7 @@ get_pending_status (struct lwp_info *lp, int *status)
|
| stop_signal make sense as a real signal to pass to the inferior.
|
| Some catchpoint related events, like
|
| TARGET_WAITKIND_(V)FORK|EXEC|SYSCALL, have their stop_signal set
|
| - to TARGET_SIGNAL_SIGTRAP when the catchpoint triggers. But,
|
| + to GDB_SIGNAL_SIGTRAP when the catchpoint triggers. But,
|
| those traps are debug API (ptrace in our case) related and
|
| induced; the inferior wouldn't see them if it wasn't being
|
| traced. Hence, we should never pass them to the inferior, even
|
| @@ -1636,9 +1732,9 @@ get_pending_status (struct lwp_info *lp, int *status)
|
| this is really a corner case. */
|
|
|
| if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
|
| - signo = TARGET_SIGNAL_0; /* a pending ptrace event, not a real signal. */
|
| + signo = GDB_SIGNAL_0; /* a pending ptrace event, not a real signal. */
|
| else if (lp->status)
|
| - signo = target_signal_from_host (WSTOPSIG (lp->status));
|
| + signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
| else if (non_stop && !is_executing (lp->ptid))
|
| {
|
| struct thread_info *tp = find_thread_ptid (lp->ptid);
|
| @@ -1662,7 +1758,7 @@ get_pending_status (struct lwp_info *lp, int *status)
|
|
|
| *status = 0;
|
|
|
| - if (signo == TARGET_SIGNAL_0)
|
| + if (signo == GDB_SIGNAL_0)
|
| {
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| @@ -1676,17 +1772,17 @@ get_pending_status (struct lwp_info *lp, int *status)
|
| "GPT: lwp %s had signal %s, "
|
| "but it is in no pass state\n",
|
| target_pid_to_str (lp->ptid),
|
| - target_signal_to_string (signo));
|
| + gdb_signal_to_string (signo));
|
| }
|
| else
|
| {
|
| - *status = W_STOPCODE (target_signal_to_host (signo));
|
| + *status = W_STOPCODE (gdb_signal_to_host (signo));
|
|
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "GPT: lwp %s has pending signal %s\n",
|
| target_pid_to_str (lp->ptid),
|
| - target_signal_to_string (signo));
|
| + gdb_signal_to_string (signo));
|
| }
|
|
|
| return 0;
|
| @@ -1723,6 +1819,8 @@ detach_callback (struct lwp_info *lp, void *data)
|
| /* Pass on any pending signal for this LWP. */
|
| get_pending_status (lp, &status);
|
|
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| errno = 0;
|
| if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
|
| WSTOPSIG (status)) < 0)
|
| @@ -1750,8 +1848,8 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
|
|
|
| pid = GET_PID (inferior_ptid);
|
|
|
| - if (target_can_async_p ())
|
| - linux_nat_async (NULL, 0);
|
| + /* Don't unregister from the event loop, as there may be other
|
| + inferiors running. */
|
|
|
| /* Stop all threads before detaching. ptrace requires that the
|
| thread is stopped to sucessfully detach. */
|
| @@ -1783,6 +1881,8 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
|
| target_pid_to_str (main_lwp->ptid));
|
| }
|
|
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (main_lwp);
|
| delete_lwp (main_lwp->ptid);
|
|
|
| if (forks_exist_p ())
|
| @@ -1792,9 +1892,6 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
|
| the current fork, and context-switch to the first
|
| available. */
|
| linux_fork_detach (args, from_tty);
|
| -
|
| - if (non_stop && target_can_async_p ())
|
| - target_async (inferior_event_handler, 0);
|
| }
|
| else
|
| linux_ops->to_detach (ops, args, from_tty);
|
| @@ -1803,7 +1900,7 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
|
| /* Resume LP. */
|
|
|
| static void
|
| -resume_lwp (struct lwp_info *lp, int step)
|
| +resume_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
|
| {
|
| if (lp->stopped)
|
| {
|
| @@ -1821,15 +1918,20 @@ resume_lwp (struct lwp_info *lp, int step)
|
| {
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| - "RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
|
| - target_pid_to_str (lp->ptid));
|
| + "RC: Resuming sibling %s, %s, %s\n",
|
| + target_pid_to_str (lp->ptid),
|
| + (signo != GDB_SIGNAL_0
|
| + ? strsignal (gdb_signal_to_host (signo))
|
| + : "0"),
|
| + step ? "step" : "resume");
|
|
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops,
|
| pid_to_ptid (GET_LWP (lp->ptid)),
|
| - step, TARGET_SIGNAL_0);
|
| + step, signo);
|
| lp->stopped = 0;
|
| lp->step = step;
|
| - memset (&lp->siginfo, 0, sizeof (lp->siginfo));
|
| lp->stopped_by_watchpoint = 0;
|
| }
|
| else
|
| @@ -1849,10 +1951,27 @@ resume_lwp (struct lwp_info *lp, int step)
|
| }
|
| }
|
|
|
| +/* Resume LWP, with the last stop signal, if it is in pass state. */
|
| +
|
| static int
|
| -resume_callback (struct lwp_info *lp, void *data)
|
| +linux_nat_resume_callback (struct lwp_info *lp, void *data)
|
| {
|
| - resume_lwp (lp, 0);
|
| + enum gdb_signal signo = GDB_SIGNAL_0;
|
| +
|
| + if (lp->stopped)
|
| + {
|
| + struct thread_info *thread;
|
| +
|
| + thread = find_thread_ptid (lp->ptid);
|
| + if (thread != NULL)
|
| + {
|
| + if (signal_pass_state (thread->suspend.stop_signal))
|
| + signo = thread->suspend.stop_signal;
|
| + thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| + }
|
| + }
|
| +
|
| + resume_lwp (lp, 0, signo);
|
| return 0;
|
| }
|
|
|
| @@ -1874,7 +1993,7 @@ resume_set_callback (struct lwp_info *lp, void *data)
|
|
|
| static void
|
| linux_nat_resume (struct target_ops *ops,
|
| - ptid_t ptid, int step, enum target_signal signo)
|
| + ptid_t ptid, int step, enum gdb_signal signo)
|
| {
|
| sigset_t prev_mask;
|
| struct lwp_info *lp;
|
| @@ -1885,8 +2004,8 @@ linux_nat_resume (struct target_ops *ops,
|
| "LLR: Preparing to %s %s, %s, inferior_ptid %s\n",
|
| step ? "step" : "resume",
|
| target_pid_to_str (ptid),
|
| - (signo != TARGET_SIGNAL_0
|
| - ? strsignal (target_signal_to_host (signo)) : "0"),
|
| + (signo != GDB_SIGNAL_0
|
| + ? strsignal (gdb_signal_to_host (signo)) : "0"),
|
| target_pid_to_str (inferior_ptid));
|
|
|
| block_child_signals (&prev_mask);
|
| @@ -1931,8 +2050,8 @@ linux_nat_resume (struct target_ops *ops,
|
|
|
| /* FIXME: What should we do if we are supposed to continue
|
| this thread with a signal? */
|
| - gdb_assert (signo == TARGET_SIGNAL_0);
|
| - signo = target_signal_from_host (WSTOPSIG (lp->status));
|
| + gdb_assert (signo == GDB_SIGNAL_0);
|
| + signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
| lp->status = 0;
|
| }
|
| }
|
| @@ -1941,7 +2060,7 @@ linux_nat_resume (struct target_ops *ops,
|
| {
|
| /* FIXME: What should we do if we are supposed to continue
|
| this thread with a signal? */
|
| - gdb_assert (signo == TARGET_SIGNAL_0);
|
| + gdb_assert (signo == GDB_SIGNAL_0);
|
|
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| @@ -1959,17 +2078,18 @@ linux_nat_resume (struct target_ops *ops,
|
| }
|
|
|
| /* Mark LWP as not stopped to prevent it from being continued by
|
| - resume_callback. */
|
| + linux_nat_resume_callback. */
|
| lp->stopped = 0;
|
|
|
| if (resume_many)
|
| - iterate_over_lwps (ptid, resume_callback, NULL);
|
| + iterate_over_lwps (ptid, linux_nat_resume_callback, NULL);
|
|
|
| /* Convert to something the lower layer understands. */
|
| ptid = pid_to_ptid (GET_LWP (lp->ptid));
|
|
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, ptid, step, signo);
|
| - memset (&lp->siginfo, 0, sizeof (lp->siginfo));
|
| lp->stopped_by_watchpoint = 0;
|
|
|
| if (debug_linux_nat)
|
| @@ -1977,8 +2097,8 @@ linux_nat_resume (struct target_ops *ops,
|
| "LLR: %s %s, %s (resume event thread)\n",
|
| step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
| target_pid_to_str (ptid),
|
| - (signo != TARGET_SIGNAL_0
|
| - ? strsignal (target_signal_to_host (signo)) : "0"));
|
| + (signo != GDB_SIGNAL_0
|
| + ? strsignal (gdb_signal_to_host (signo)) : "0"));
|
|
|
| restore_child_signals_mask (&prev_mask);
|
| if (target_can_async_p ())
|
| @@ -2137,8 +2257,10 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
|
| /* Note that gdbarch_get_syscall_number may access registers, hence
|
| fill a regcache. */
|
| registers_changed ();
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - lp->step, TARGET_SIGNAL_0);
|
| + lp->step, GDB_SIGNAL_0);
|
| return 1;
|
| }
|
|
|
| @@ -2257,7 +2379,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
| RT signal, it can only be queued once. We need to be
|
| careful to not resume the LWP if we wanted it to
|
| stop. In that case, we'll leave the SIGSTOP pending.
|
| - It will later be reported as TARGET_SIGNAL_0. */
|
| + It will later be reported as GDB_SIGNAL_0. */
|
| tp = find_thread_ptid (new_lp->ptid);
|
| if (tp != NULL && tp->stop_requested)
|
| new_lp->last_resume_kind = resume_stop;
|
| @@ -2324,8 +2446,10 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
| fprintf_unfiltered (gdb_stdlog,
|
| "LHEW: resuming new LWP %ld\n",
|
| GET_LWP (new_lp->ptid));
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (new_lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
|
| - 0, TARGET_SIGNAL_0);
|
| + 0, GDB_SIGNAL_0);
|
| new_lp->stopped = 0;
|
| }
|
| }
|
| @@ -2333,8 +2457,10 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "LHEW: resuming parent LWP %d\n", pid);
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - 0, TARGET_SIGNAL_0);
|
| + 0, GDB_SIGNAL_0);
|
|
|
| return 1;
|
| }
|
| @@ -2383,37 +2509,6 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
| _("unknown ptrace event %d"), event);
|
| }
|
|
|
| -/* Return non-zero if LWP is a zombie. */
|
| -
|
| -static int
|
| -linux_lwp_is_zombie (long lwp)
|
| -{
|
| - char buffer[MAXPATHLEN];
|
| - FILE *procfile;
|
| - int retval;
|
| - int have_state;
|
| -
|
| - xsnprintf (buffer, sizeof (buffer), "/proc/%ld/status", lwp);
|
| - procfile = fopen (buffer, "r");
|
| - if (procfile == NULL)
|
| - {
|
| - warning (_("unable to open /proc file '%s'"), buffer);
|
| - return 0;
|
| - }
|
| -
|
| - have_state = 0;
|
| - while (fgets (buffer, sizeof (buffer), procfile) != NULL)
|
| - if (strncmp (buffer, "State:", 6) == 0)
|
| - {
|
| - have_state = 1;
|
| - break;
|
| - }
|
| - retval = (have_state
|
| - && strcmp (buffer, "State:\tZ (zombie)\n") == 0);
|
| - fclose (procfile);
|
| - return retval;
|
| -}
|
| -
|
| /* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
|
| exited. */
|
|
|
| @@ -2467,10 +2562,10 @@ wait_lwp (struct lwp_info *lp)
|
|
|
| This is racy, what if the tgl becomes a zombie right after we check?
|
| Therefore always use WNOHANG with sigsuspend - it is equivalent to
|
| - waiting waitpid but the linux_lwp_is_zombie is safe this way. */
|
| + waiting waitpid but linux_proc_pid_is_zombie is safe this way. */
|
|
|
| if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)
|
| - && linux_lwp_is_zombie (GET_LWP (lp->ptid)))
|
| + && linux_proc_pid_is_zombie (GET_LWP (lp->ptid)))
|
| {
|
| thread_dead = 1;
|
| if (debug_linux_nat)
|
| @@ -2548,22 +2643,6 @@ wait_lwp (struct lwp_info *lp)
|
| return status;
|
| }
|
|
|
| -/* Save the most recent siginfo for LP. This is currently only called
|
| - for SIGTRAP; some ports use the si_addr field for
|
| - target_stopped_data_address. In the future, it may also be used to
|
| - restore the siginfo of requeued signals. */
|
| -
|
| -static void
|
| -save_siginfo (struct lwp_info *lp)
|
| -{
|
| - errno = 0;
|
| - ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
|
| - (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
|
| -
|
| - if (errno != 0)
|
| - memset (&lp->siginfo, 0, sizeof (lp->siginfo));
|
| -}
|
| -
|
| /* Send a SIGSTOP to LP. */
|
|
|
| static int
|
| @@ -2596,6 +2675,14 @@ stop_callback (struct lwp_info *lp, void *data)
|
| return 0;
|
| }
|
|
|
| +/* Request a stop on LWP. */
|
| +
|
| +void
|
| +linux_stop_lwp (struct lwp_info *lwp)
|
| +{
|
| + stop_callback (lwp, NULL);
|
| +}
|
| +
|
| /* Return non-zero if LWP PID has a pending SIGINT. */
|
|
|
| static int
|
| @@ -2796,110 +2883,36 @@ stop_wait_callback (struct lwp_info *lp, void *data)
|
|
|
| if (WSTOPSIG (status) != SIGSTOP)
|
| {
|
| - if (linux_nat_status_is_event (status))
|
| - {
|
| - /* If a LWP other than the LWP that we're reporting an
|
| - event for has hit a GDB breakpoint (as opposed to
|
| - some random trap signal), then just arrange for it to
|
| - hit it again later. We don't keep the SIGTRAP status
|
| - and don't forward the SIGTRAP signal to the LWP. We
|
| - will handle the current event, eventually we will
|
| - resume all LWPs, and this one will get its breakpoint
|
| - trap again.
|
| -
|
| - If we do not do this, then we run the risk that the
|
| - user will delete or disable the breakpoint, but the
|
| - thread will have already tripped on it. */
|
| -
|
| - /* Save the trap's siginfo in case we need it later. */
|
| - save_siginfo (lp);
|
| -
|
| - save_sigtrap (lp);
|
| -
|
| - /* Now resume this LWP and get the SIGSTOP event. */
|
| - errno = 0;
|
| - ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
| - if (debug_linux_nat)
|
| - {
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "PTRACE_CONT %s, 0, 0 (%s)\n",
|
| - target_pid_to_str (lp->ptid),
|
| - errno ? safe_strerror (errno) : "OK");
|
| -
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "SWC: Candidate SIGTRAP event in %s\n",
|
| - target_pid_to_str (lp->ptid));
|
| - }
|
| - /* Hold this event/waitstatus while we check to see if
|
| - there are any more (we still want to get that SIGSTOP). */
|
| - stop_wait_callback (lp, NULL);
|
| -
|
| - /* Hold the SIGTRAP for handling by linux_nat_wait. If
|
| - there's another event, throw it back into the
|
| - queue. */
|
| - if (lp->status)
|
| - {
|
| - if (debug_linux_nat)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "SWC: kill %s, %s\n",
|
| - target_pid_to_str (lp->ptid),
|
| - status_to_str ((int) status));
|
| - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
|
| - }
|
| + /* The thread was stopped with a signal other than SIGSTOP. */
|
|
|
| - /* Save the sigtrap event. */
|
| - lp->status = status;
|
| - return 0;
|
| - }
|
| - else
|
| - {
|
| - /* The thread was stopped with a signal other than
|
| - SIGSTOP, and didn't accidentally trip a breakpoint. */
|
| + save_sigtrap (lp);
|
|
|
| - if (debug_linux_nat)
|
| - {
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "SWC: Pending event %s in %s\n",
|
| - status_to_str ((int) status),
|
| - target_pid_to_str (lp->ptid));
|
| - }
|
| - /* Now resume this LWP and get the SIGSTOP event. */
|
| - errno = 0;
|
| - ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
| - if (debug_linux_nat)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "SWC: PTRACE_CONT %s, 0, 0 (%s)\n",
|
| - target_pid_to_str (lp->ptid),
|
| - errno ? safe_strerror (errno) : "OK");
|
| -
|
| - /* Hold this event/waitstatus while we check to see if
|
| - there are any more (we still want to get that SIGSTOP). */
|
| - stop_wait_callback (lp, NULL);
|
| -
|
| - /* If the lp->status field is still empty, use it to
|
| - hold this event. If not, then this event must be
|
| - returned to the event queue of the LWP. */
|
| - if (lp->status)
|
| - {
|
| - if (debug_linux_nat)
|
| - {
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "SWC: kill %s, %s\n",
|
| - target_pid_to_str (lp->ptid),
|
| - status_to_str ((int) status));
|
| - }
|
| - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
|
| - }
|
| - else
|
| - lp->status = status;
|
| - return 0;
|
| - }
|
| + if (debug_linux_nat)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "SWC: Pending event %s in %s\n",
|
| + status_to_str ((int) status),
|
| + target_pid_to_str (lp->ptid));
|
| +
|
| + /* Save the sigtrap event. */
|
| + lp->status = status;
|
| + gdb_assert (!lp->stopped);
|
| + gdb_assert (lp->signalled);
|
| + lp->stopped = 1;
|
| }
|
| else
|
| {
|
| /* We caught the SIGSTOP that we intended to catch, so
|
| there's no SIGSTOP pending. */
|
| +
|
| + if (debug_linux_nat)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "SWC: Delayed SIGSTOP caught for %s.\n",
|
| + target_pid_to_str (lp->ptid));
|
| +
|
| lp->stopped = 1;
|
| +
|
| + /* Reset SIGNALLED only after the stop_wait_callback call
|
| + above as it does gdb_assert on SIGNALLED. */
|
| lp->signalled = 0;
|
| }
|
| }
|
| @@ -3153,7 +3166,7 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "SARC: re-resuming LWP %ld\n",
|
| GET_LWP (lp->ptid));
|
| - resume_lwp (lp, lp->step);
|
| + resume_lwp (lp, lp->step, GDB_SIGNAL_0);
|
| }
|
| else
|
| {
|
| @@ -3249,12 +3262,7 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
|
| }
|
|
|
| if (linux_nat_status_is_event (status))
|
| - {
|
| - /* Save the trap's siginfo in case we need it later. */
|
| - save_siginfo (lp);
|
| -
|
| - save_sigtrap (lp);
|
| - }
|
| + save_sigtrap (lp);
|
|
|
| /* Check if the thread has exited. */
|
| if ((WIFEXITED (status) || WIFSIGNALED (status))
|
| @@ -3332,8 +3340,10 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
|
|
|
| registers_changed ();
|
|
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - lp->step, TARGET_SIGNAL_0);
|
| + lp->step, GDB_SIGNAL_0);
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
|
| @@ -3363,8 +3373,10 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
|
| lp->ignore_sigint = 0;
|
|
|
| registers_changed ();
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - lp->step, TARGET_SIGNAL_0);
|
| + lp->step, GDB_SIGNAL_0);
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "LLW: %s %s, 0, 0 (discard SIGINT)\n",
|
| @@ -3405,7 +3417,7 @@ check_zombie_leaders (void)
|
| /* Check if there are other threads in the group, as we may
|
| have raced with the inferior simply exiting. */
|
| && num_lwps (inf->pid) > 1
|
| - && linux_lwp_is_zombie (inf->pid))
|
| + && linux_proc_pid_is_zombie (inf->pid))
|
| {
|
| if (debug_linux_nat)
|
| fprintf_unfiltered (gdb_stdlog,
|
| @@ -3523,52 +3535,6 @@ retry:
|
| lp = NULL;
|
| }
|
|
|
| - if (lp && lp->signalled && lp->last_resume_kind != resume_stop)
|
| - {
|
| - /* A pending SIGSTOP may interfere with the normal stream of
|
| - events. In a typical case where interference is a problem,
|
| - we have a SIGSTOP signal pending for LWP A while
|
| - single-stepping it, encounter an event in LWP B, and take the
|
| - pending SIGSTOP while trying to stop LWP A. After processing
|
| - the event in LWP B, LWP A is continued, and we'll never see
|
| - the SIGTRAP associated with the last time we were
|
| - single-stepping LWP A. */
|
| -
|
| - /* Resume the thread. It should halt immediately returning the
|
| - pending SIGSTOP. */
|
| - registers_changed ();
|
| - linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - lp->step, TARGET_SIGNAL_0);
|
| - if (debug_linux_nat)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "LLW: %s %s, 0, 0 (expect SIGSTOP)\n",
|
| - lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
| - target_pid_to_str (lp->ptid));
|
| - lp->stopped = 0;
|
| - gdb_assert (lp->resumed);
|
| -
|
| - /* Catch the pending SIGSTOP. */
|
| - status = lp->status;
|
| - lp->status = 0;
|
| -
|
| - stop_wait_callback (lp, NULL);
|
| -
|
| - /* If the lp->status field isn't empty, we caught another signal
|
| - while flushing the SIGSTOP. Return it back to the event
|
| - queue of the LWP, as we already have an event to handle. */
|
| - if (lp->status)
|
| - {
|
| - if (debug_linux_nat)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "LLW: kill %s, %s\n",
|
| - target_pid_to_str (lp->ptid),
|
| - status_to_str (lp->status));
|
| - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
|
| - }
|
| -
|
| - lp->status = status;
|
| - }
|
| -
|
| if (!target_can_async_p ())
|
| {
|
| /* Causes SIGINT to be passed on to the attached process. */
|
| @@ -3773,7 +3739,7 @@ retry:
|
|
|
| if (WIFSTOPPED (status))
|
| {
|
| - enum target_signal signo = target_signal_from_host (WSTOPSIG (status));
|
| + enum gdb_signal signo = gdb_signal_from_host (WSTOPSIG (status));
|
|
|
| /* When using hardware single-step, we need to report every signal.
|
| Otherwise, signals in pass_mask may be short-circuited. */
|
| @@ -3786,6 +3752,8 @@ retry:
|
| newly attached threads may cause an unwanted delay in
|
| getting them running. */
|
| registers_changed ();
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| lp->step, signo);
|
| if (debug_linux_nat)
|
| @@ -3794,8 +3762,8 @@ retry:
|
| lp->step ?
|
| "PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
| target_pid_to_str (lp->ptid),
|
| - (signo != TARGET_SIGNAL_0
|
| - ? strsignal (target_signal_to_host (signo))
|
| + (signo != GDB_SIGNAL_0
|
| + ? strsignal (gdb_signal_to_host (signo))
|
| : "0"));
|
| lp->stopped = 0;
|
| goto retry;
|
| @@ -3806,7 +3774,7 @@ retry:
|
| /* Only do the below in all-stop, as we currently use SIGINT
|
| to implement target_stop (see linux_nat_stop) in
|
| non-stop. */
|
| - if (signo == TARGET_SIGNAL_INT && signal_pass_state (signo) == 0)
|
| + if (signo == GDB_SIGNAL_INT && signal_pass_state (signo) == 0)
|
| {
|
| /* If ^C/BREAK is typed at the tty/console, SIGINT gets
|
| forwarded to the entire process group, that is, all LWPs
|
| @@ -3895,14 +3863,14 @@ retry:
|
| /* A thread that has been requested to stop by GDB with
|
| target_stop, and it stopped cleanly, so report as SIG0. The
|
| use of SIGSTOP is an implementation detail. */
|
| - ourstatus->value.sig = TARGET_SIGNAL_0;
|
| + ourstatus->value.sig = GDB_SIGNAL_0;
|
| }
|
|
|
| if (ourstatus->kind == TARGET_WAITKIND_EXITED
|
| || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
|
| lp->core = -1;
|
| else
|
| - lp->core = linux_nat_core_of_thread_1 (lp->ptid);
|
| + lp->core = linux_common_core_of_thread (lp->ptid);
|
|
|
| return lp->ptid;
|
| }
|
| @@ -3942,10 +3910,11 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
|
| lp->step);
|
|
|
| registers_changed ();
|
| + if (linux_nat_prepare_to_resume != NULL)
|
| + linux_nat_prepare_to_resume (lp);
|
| linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
| - lp->step, TARGET_SIGNAL_0);
|
| + lp->step, GDB_SIGNAL_0);
|
| lp->stopped = 0;
|
| - memset (&lp->siginfo, 0, sizeof (lp->siginfo));
|
| lp->stopped_by_watchpoint = 0;
|
| }
|
|
|
| @@ -4138,7 +4107,7 @@ linux_nat_mourn_inferior (struct target_ops *ops)
|
| layout of the inferiors' architecture. */
|
|
|
| static void
|
| -siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
|
| +siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
|
| {
|
| int done = 0;
|
|
|
| @@ -4150,9 +4119,9 @@ siginfo_fixup (struct siginfo *siginfo, gdb_byte *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));
|
| }
|
| }
|
|
|
| @@ -4162,8 +4131,8 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
|
| const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
|
| {
|
| int pid;
|
| - struct siginfo siginfo;
|
| - gdb_byte inf_siginfo[sizeof (struct siginfo)];
|
| + siginfo_t siginfo;
|
| + gdb_byte inf_siginfo[sizeof (siginfo_t)];
|
|
|
| gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
|
| gdb_assert (readbuf || writebuf);
|
| @@ -4344,744 +4313,59 @@ linux_child_pid_to_exec_file (int pid)
|
| return name1;
|
| }
|
|
|
| -/* Service function for corefiles and info proc. */
|
| -
|
| -static int
|
| -read_mapping (FILE *mapfile,
|
| - long long *addr,
|
| - long long *endaddr,
|
| - char *permissions,
|
| - long long *offset,
|
| - char *device, long long *inode, char *filename)
|
| -{
|
| - int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx",
|
| - addr, endaddr, permissions, offset, device, inode);
|
| -
|
| - filename[0] = '\0';
|
| - if (ret > 0 && ret != EOF)
|
| - {
|
| - /* Eat everything up to EOL for the filename. This will prevent
|
| - weird filenames (such as one with embedded whitespace) from
|
| - confusing this code. It also makes this code more robust in
|
| - respect to annotations the kernel may add after the filename.
|
| -
|
| - Note the filename is used for informational purposes
|
| - only. */
|
| - ret += fscanf (mapfile, "%[^\n]\n", filename);
|
| - }
|
| -
|
| - return (ret != 0 && ret != EOF);
|
| -}
|
| -
|
| -/* Fills the "to_find_memory_regions" target vector. Lists the memory
|
| - regions in the inferior for a corefile. */
|
| -
|
| -static int
|
| -linux_nat_find_memory_regions (find_memory_region_ftype func, void *obfd)
|
| -{
|
| - int pid = PIDGET (inferior_ptid);
|
| - char mapsfilename[MAXPATHLEN];
|
| - FILE *mapsfile;
|
| - long long addr, endaddr, size, offset, inode;
|
| - char permissions[8], device[8], filename[MAXPATHLEN];
|
| - int read, write, exec;
|
| - struct cleanup *cleanup;
|
| -
|
| - /* Compose the filename for the /proc memory map, and open it. */
|
| - sprintf (mapsfilename, "/proc/%d/maps", pid);
|
| - if ((mapsfile = fopen (mapsfilename, "r")) == NULL)
|
| - error (_("Could not open %s."), mapsfilename);
|
| - cleanup = make_cleanup_fclose (mapsfile);
|
| -
|
| - if (info_verbose)
|
| - fprintf_filtered (gdb_stdout,
|
| - "Reading memory regions from %s\n", mapsfilename);
|
| -
|
| - /* Now iterate until end-of-file. */
|
| - while (read_mapping (mapsfile, &addr, &endaddr, &permissions[0],
|
| - &offset, &device[0], &inode, &filename[0]))
|
| - {
|
| - size = endaddr - addr;
|
| -
|
| - /* Get the segment's permissions. */
|
| - read = (strchr (permissions, 'r') != 0);
|
| - write = (strchr (permissions, 'w') != 0);
|
| - exec = (strchr (permissions, 'x') != 0);
|
| -
|
| - if (info_verbose)
|
| - {
|
| - fprintf_filtered (gdb_stdout,
|
| - "Save segment, %s bytes at %s (%c%c%c)",
|
| - plongest (size), paddress (target_gdbarch, addr),
|
| - read ? 'r' : ' ',
|
| - write ? 'w' : ' ', exec ? 'x' : ' ');
|
| - if (filename[0])
|
| - fprintf_filtered (gdb_stdout, " for %s", filename);
|
| - fprintf_filtered (gdb_stdout, "\n");
|
| - }
|
| -
|
| - /* Invoke the callback function to create the corefile
|
| - segment. */
|
| - func (addr, size, read, write, exec, obfd);
|
| - }
|
| - do_cleanups (cleanup);
|
| - return 0;
|
| -}
|
| -
|
| -static int
|
| -find_signalled_thread (struct thread_info *info, void *data)
|
| -{
|
| - if (info->suspend.stop_signal != TARGET_SIGNAL_0
|
| - && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
|
| - return 1;
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -static enum target_signal
|
| -find_stop_signal (void)
|
| -{
|
| - struct thread_info *info =
|
| - iterate_over_threads (find_signalled_thread, NULL);
|
| -
|
| - if (info)
|
| - return info->suspend.stop_signal;
|
| - else
|
| - return TARGET_SIGNAL_0;
|
| -}
|
| -
|
| /* Records the thread's register state for the corefile note
|
| section. */
|
|
|
| static char *
|
| -linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
|
| - char *note_data, int *note_size,
|
| - enum target_signal stop_signal)
|
| +linux_nat_collect_thread_registers (const struct regcache *regcache,
|
| + ptid_t ptid, bfd *obfd,
|
| + char *note_data, int *note_size,
|
| + enum gdb_signal stop_signal)
|
| {
|
| - unsigned long lwp = ptid_get_lwp (ptid);
|
| - struct gdbarch *gdbarch = target_gdbarch;
|
| - struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
|
| + struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| const struct regset *regset;
|
| int core_regset_p;
|
| - struct cleanup *old_chain;
|
| - struct core_regset_section *sect_list;
|
| - char *gdb_regset;
|
| -
|
| - old_chain = save_inferior_ptid ();
|
| - inferior_ptid = ptid;
|
| - target_fetch_registers (regcache, -1);
|
| - do_cleanups (old_chain);
|
| + gdb_gregset_t gregs;
|
| + gdb_fpregset_t fpregs;
|
|
|
| core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
|
| - sect_list = gdbarch_core_regset_sections (gdbarch);
|
| -
|
| - /* The loop below uses the new struct core_regset_section, which stores
|
| - the supported section names and sizes for the core file. Note that
|
| - note PRSTATUS needs to be treated specially. But the other notes are
|
| - structurally the same, so they can benefit from the new struct. */
|
| - if (core_regset_p && sect_list != NULL)
|
| - while (sect_list->sect_name != NULL)
|
| - {
|
| - regset = gdbarch_regset_from_core_section (gdbarch,
|
| - sect_list->sect_name,
|
| - sect_list->size);
|
| - gdb_assert (regset && regset->collect_regset);
|
| - gdb_regset = xmalloc (sect_list->size);
|
| - regset->collect_regset (regset, regcache, -1,
|
| - gdb_regset, sect_list->size);
|
| -
|
| - if (strcmp (sect_list->sect_name, ".reg") == 0)
|
| - note_data = (char *) elfcore_write_prstatus
|
| - (obfd, note_data, note_size,
|
| - lwp, target_signal_to_host (stop_signal),
|
| - gdb_regset);
|
| - else
|
| - note_data = (char *) elfcore_write_register_note
|
| - (obfd, note_data, note_size,
|
| - sect_list->sect_name, gdb_regset,
|
| - sect_list->size);
|
| - xfree (gdb_regset);
|
| - sect_list++;
|
| - }
|
|
|
| - /* For architectures that does not have the struct core_regset_section
|
| - implemented, we use the old method. When all the architectures have
|
| - the new support, the code below should be deleted. */
|
| + if (core_regset_p
|
| + && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
|
| + sizeof (gregs)))
|
| + != NULL && regset->collect_regset != NULL)
|
| + regset->collect_regset (regset, regcache, -1, &gregs, sizeof (gregs));
|
| else
|
| - {
|
| - gdb_gregset_t gregs;
|
| - gdb_fpregset_t fpregs;
|
| + fill_gregset (regcache, &gregs, -1);
|
|
|
| - if (core_regset_p
|
| - && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
|
| - sizeof (gregs)))
|
| - != NULL && regset->collect_regset != NULL)
|
| - regset->collect_regset (regset, regcache, -1,
|
| - &gregs, sizeof (gregs));
|
| - else
|
| - fill_gregset (regcache, &gregs, -1);
|
| + note_data = (char *) elfcore_write_prstatus
|
| + (obfd, note_data, note_size, ptid_get_lwp (ptid),
|
| + gdb_signal_to_host (stop_signal), &gregs);
|
|
|
| - note_data = (char *) elfcore_write_prstatus
|
| - (obfd, note_data, note_size, lwp, target_signal_to_host (stop_signal),
|
| - &gregs);
|
| -
|
| - if (core_regset_p
|
| - && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
|
| - sizeof (fpregs)))
|
| + if (core_regset_p
|
| + && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
|
| + sizeof (fpregs)))
|
| != NULL && regset->collect_regset != NULL)
|
| - regset->collect_regset (regset, regcache, -1,
|
| - &fpregs, sizeof (fpregs));
|
| - else
|
| - fill_fpregset (regcache, &fpregs, -1);
|
| + regset->collect_regset (regset, regcache, -1, &fpregs, sizeof (fpregs));
|
| + else
|
| + fill_fpregset (regcache, &fpregs, -1);
|
|
|
| - note_data = (char *) elfcore_write_prfpreg (obfd,
|
| - note_data,
|
| - note_size,
|
| - &fpregs, sizeof (fpregs));
|
| - }
|
| + note_data = (char *) elfcore_write_prfpreg (obfd, note_data, note_size,
|
| + &fpregs, sizeof (fpregs));
|
|
|
| return note_data;
|
| }
|
|
|
| -struct linux_nat_corefile_thread_data
|
| -{
|
| - bfd *obfd;
|
| - char *note_data;
|
| - int *note_size;
|
| - int num_notes;
|
| - enum target_signal stop_signal;
|
| -};
|
| -
|
| -/* Called by gdbthread.c once per thread. Records the thread's
|
| - register state for the corefile note section. */
|
| -
|
| -static int
|
| -linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
|
| -{
|
| - struct linux_nat_corefile_thread_data *args = data;
|
| -
|
| - args->note_data = linux_nat_do_thread_registers (args->obfd,
|
| - ti->ptid,
|
| - args->note_data,
|
| - args->note_size,
|
| - args->stop_signal);
|
| - args->num_notes++;
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -/* Enumerate spufs IDs for process PID. */
|
| -
|
| -static void
|
| -iterate_over_spus (int pid, void (*callback) (void *, int), void *data)
|
| -{
|
| - char path[128];
|
| - DIR *dir;
|
| - struct dirent *entry;
|
| -
|
| - xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
|
| - dir = opendir (path);
|
| - if (!dir)
|
| - return;
|
| -
|
| - rewinddir (dir);
|
| - while ((entry = readdir (dir)) != NULL)
|
| - {
|
| - struct stat st;
|
| - struct statfs stfs;
|
| - int fd;
|
| -
|
| - fd = atoi (entry->d_name);
|
| - if (!fd)
|
| - continue;
|
| -
|
| - xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
|
| - if (stat (path, &st) != 0)
|
| - continue;
|
| - if (!S_ISDIR (st.st_mode))
|
| - continue;
|
| -
|
| - if (statfs (path, &stfs) != 0)
|
| - continue;
|
| - if (stfs.f_type != SPUFS_MAGIC)
|
| - continue;
|
| -
|
| - callback (data, fd);
|
| - }
|
| -
|
| - closedir (dir);
|
| -}
|
| -
|
| -/* Generate corefile notes for SPU contexts. */
|
| -
|
| -struct linux_spu_corefile_data
|
| -{
|
| - bfd *obfd;
|
| - char *note_data;
|
| - int *note_size;
|
| -};
|
| -
|
| -static void
|
| -linux_spu_corefile_callback (void *data, int fd)
|
| -{
|
| - struct linux_spu_corefile_data *args = data;
|
| - int i;
|
| -
|
| - static const char *spu_files[] =
|
| - {
|
| - "object-id",
|
| - "mem",
|
| - "regs",
|
| - "fpcr",
|
| - "lslr",
|
| - "decr",
|
| - "decr_status",
|
| - "signal1",
|
| - "signal1_type",
|
| - "signal2",
|
| - "signal2_type",
|
| - "event_mask",
|
| - "event_status",
|
| - "mbox_info",
|
| - "ibox_info",
|
| - "wbox_info",
|
| - "dma_info",
|
| - "proxydma_info",
|
| - };
|
| -
|
| - for (i = 0; i < sizeof (spu_files) / sizeof (spu_files[0]); i++)
|
| - {
|
| - char annex[32], note_name[32];
|
| - gdb_byte *spu_data;
|
| - LONGEST spu_len;
|
| -
|
| - xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[i]);
|
| - spu_len = target_read_alloc (¤t_target, TARGET_OBJECT_SPU,
|
| - annex, &spu_data);
|
| - if (spu_len > 0)
|
| - {
|
| - xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
|
| - args->note_data = elfcore_write_note (args->obfd, args->note_data,
|
| - args->note_size, note_name,
|
| - NT_SPU, spu_data, spu_len);
|
| - xfree (spu_data);
|
| - }
|
| - }
|
| -}
|
| -
|
| -static char *
|
| -linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
|
| -{
|
| - struct linux_spu_corefile_data args;
|
| -
|
| - args.obfd = obfd;
|
| - args.note_data = note_data;
|
| - args.note_size = note_size;
|
| -
|
| - iterate_over_spus (PIDGET (inferior_ptid),
|
| - linux_spu_corefile_callback, &args);
|
| -
|
| - return args.note_data;
|
| -}
|
| -
|
| -/* Fills the "to_make_corefile_note" target vector. Builds the note
|
| - section for a corefile, and returns it in a malloc buffer. */
|
| +/* Fills the "to_make_corefile_note" target vector. Builds the note
|
| + section for a corefile, and returns it in a malloc buffer. */
|
|
|
| static char *
|
| linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
|
| {
|
| - struct linux_nat_corefile_thread_data thread_args;
|
| - /* The variable size must be >= sizeof (prpsinfo_t.pr_fname). */
|
| - char fname[16] = { '\0' };
|
| - /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs). */
|
| - char psargs[80] = { '\0' };
|
| - char *note_data = NULL;
|
| - ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
|
| - gdb_byte *auxv;
|
| - int auxv_len;
|
| -
|
| - if (get_exec_file (0))
|
| - {
|
| - strncpy (fname, lbasename (get_exec_file (0)), sizeof (fname));
|
| - strncpy (psargs, get_exec_file (0), sizeof (psargs));
|
| - if (get_inferior_args ())
|
| - {
|
| - char *string_end;
|
| - char *psargs_end = psargs + sizeof (psargs);
|
| -
|
| - /* linux_elfcore_write_prpsinfo () handles zero unterminated
|
| - strings fine. */
|
| - string_end = memchr (psargs, 0, sizeof (psargs));
|
| - if (string_end != NULL)
|
| - {
|
| - *string_end++ = ' ';
|
| - strncpy (string_end, get_inferior_args (),
|
| - psargs_end - string_end);
|
| - }
|
| - }
|
| - note_data = (char *) elfcore_write_prpsinfo (obfd,
|
| - note_data,
|
| - note_size, fname, psargs);
|
| - }
|
| -
|
| - /* Dump information for threads. */
|
| - thread_args.obfd = obfd;
|
| - thread_args.note_data = note_data;
|
| - thread_args.note_size = note_size;
|
| - thread_args.num_notes = 0;
|
| - thread_args.stop_signal = find_stop_signal ();
|
| - iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
|
| - gdb_assert (thread_args.num_notes != 0);
|
| - note_data = thread_args.note_data;
|
| -
|
| - auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV,
|
| - NULL, &auxv);
|
| - if (auxv_len > 0)
|
| - {
|
| - note_data = elfcore_write_note (obfd, note_data, note_size,
|
| - "CORE", NT_AUXV, auxv, auxv_len);
|
| - xfree (auxv);
|
| - }
|
| -
|
| - note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
|
| -
|
| - make_cleanup (xfree, note_data);
|
| - return note_data;
|
| -}
|
| -
|
| -/* Implement the "info proc" command. */
|
| -
|
| -enum info_proc_what
|
| - {
|
| - /* Display the default cmdline, cwd and exe outputs. */
|
| - IP_MINIMAL,
|
| -
|
| - /* Display `info proc mappings'. */
|
| - IP_MAPPINGS,
|
| -
|
| - /* Display `info proc status'. */
|
| - IP_STATUS,
|
| -
|
| - /* Display `info proc stat'. */
|
| - IP_STAT,
|
| -
|
| - /* Display `info proc cmdline'. */
|
| - IP_CMDLINE,
|
| -
|
| - /* Display `info proc exe'. */
|
| - IP_EXE,
|
| -
|
| - /* Display `info proc cwd'. */
|
| - IP_CWD,
|
| -
|
| - /* Display all of the above. */
|
| - IP_ALL
|
| - };
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
|
| -{
|
| - /* A long is used for pid instead of an int to avoid a loss of precision
|
| - compiler warning from the output of strtoul. */
|
| - long pid = PIDGET (inferior_ptid);
|
| - FILE *procfile;
|
| - char buffer[MAXPATHLEN];
|
| - char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
|
| - int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
|
| - int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
|
| - int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
|
| - int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
|
| - int status_f = (what == IP_STATUS || what == IP_ALL);
|
| - int stat_f = (what == IP_STAT || what == IP_ALL);
|
| - struct stat dummy;
|
| -
|
| - if (args && isdigit (args[0]))
|
| - pid = strtoul (args, &args, 10);
|
| -
|
| - args = skip_spaces (args);
|
| - if (args && args[0])
|
| - error (_("Too many parameters: %s"), args);
|
| -
|
| - if (pid == 0)
|
| - error (_("No current process: you must name one."));
|
| -
|
| - sprintf (fname1, "/proc/%ld", pid);
|
| - if (stat (fname1, &dummy) != 0)
|
| - error (_("No /proc directory: '%s'"), fname1);
|
| -
|
| - printf_filtered (_("process %ld\n"), pid);
|
| - if (cmdline_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/cmdline", pid);
|
| - if ((procfile = fopen (fname1, "r")) != NULL)
|
| - {
|
| - struct cleanup *cleanup = make_cleanup_fclose (procfile);
|
| -
|
| - if (fgets (buffer, sizeof (buffer), procfile))
|
| - printf_filtered ("cmdline = '%s'\n", buffer);
|
| - else
|
| - warning (_("unable to read '%s'"), fname1);
|
| - do_cleanups (cleanup);
|
| - }
|
| - else
|
| - warning (_("unable to open /proc file '%s'"), fname1);
|
| - }
|
| - if (cwd_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/cwd", pid);
|
| - memset (fname2, 0, sizeof (fname2));
|
| - if (readlink (fname1, fname2, sizeof (fname2)) > 0)
|
| - printf_filtered ("cwd = '%s'\n", fname2);
|
| - else
|
| - warning (_("unable to read link '%s'"), fname1);
|
| - }
|
| - if (exe_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/exe", pid);
|
| - memset (fname2, 0, sizeof (fname2));
|
| - if (readlink (fname1, fname2, sizeof (fname2)) > 0)
|
| - printf_filtered ("exe = '%s'\n", fname2);
|
| - else
|
| - warning (_("unable to read link '%s'"), fname1);
|
| - }
|
| - if (mappings_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/maps", pid);
|
| - if ((procfile = fopen (fname1, "r")) != NULL)
|
| - {
|
| - long long addr, endaddr, size, offset, inode;
|
| - char permissions[8], device[8], filename[MAXPATHLEN];
|
| - struct cleanup *cleanup;
|
| -
|
| - cleanup = make_cleanup_fclose (procfile);
|
| - printf_filtered (_("Mapped address spaces:\n\n"));
|
| - if (gdbarch_addr_bit (target_gdbarch) == 32)
|
| - {
|
| - printf_filtered ("\t%10s %10s %10s %10s %7s\n",
|
| - "Start Addr",
|
| - " End Addr",
|
| - " Size", " Offset", "objfile");
|
| - }
|
| - else
|
| - {
|
| - printf_filtered (" %18s %18s %10s %10s %7s\n",
|
| - "Start Addr",
|
| - " End Addr",
|
| - " Size", " Offset", "objfile");
|
| - }
|
| -
|
| - while (read_mapping (procfile, &addr, &endaddr, &permissions[0],
|
| - &offset, &device[0], &inode, &filename[0]))
|
| - {
|
| - size = endaddr - addr;
|
| -
|
| - /* FIXME: carlton/2003-08-27: Maybe the printf_filtered
|
| - calls here (and possibly above) should be abstracted
|
| - out into their own functions? Andrew suggests using
|
| - a generic local_address_string instead to print out
|
| - the addresses; that makes sense to me, too. */
|
| -
|
| - if (gdbarch_addr_bit (target_gdbarch) == 32)
|
| - {
|
| - printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
|
| - (unsigned long) addr, /* FIXME: pr_addr */
|
| - (unsigned long) endaddr,
|
| - (int) size,
|
| - (unsigned int) offset,
|
| - filename[0] ? filename : "");
|
| - }
|
| - else
|
| - {
|
| - printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n",
|
| - (unsigned long) addr, /* FIXME: pr_addr */
|
| - (unsigned long) endaddr,
|
| - (int) size,
|
| - (unsigned int) offset,
|
| - filename[0] ? filename : "");
|
| - }
|
| - }
|
| -
|
| - do_cleanups (cleanup);
|
| - }
|
| - else
|
| - warning (_("unable to open /proc file '%s'"), fname1);
|
| - }
|
| - if (status_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/status", pid);
|
| - if ((procfile = fopen (fname1, "r")) != NULL)
|
| - {
|
| - struct cleanup *cleanup = make_cleanup_fclose (procfile);
|
| -
|
| - while (fgets (buffer, sizeof (buffer), procfile) != NULL)
|
| - puts_filtered (buffer);
|
| - do_cleanups (cleanup);
|
| - }
|
| - else
|
| - warning (_("unable to open /proc file '%s'"), fname1);
|
| - }
|
| - if (stat_f)
|
| - {
|
| - sprintf (fname1, "/proc/%ld/stat", pid);
|
| - if ((procfile = fopen (fname1, "r")) != NULL)
|
| - {
|
| - int itmp;
|
| - char ctmp;
|
| - long ltmp;
|
| - struct cleanup *cleanup = make_cleanup_fclose (procfile);
|
| -
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("Process: %d\n"), itmp);
|
| - if (fscanf (procfile, "(%[^)]) ", &buffer[0]) > 0)
|
| - printf_filtered (_("Exec file: %s\n"), buffer);
|
| - if (fscanf (procfile, "%c ", &ctmp) > 0)
|
| - printf_filtered (_("State: %c\n"), ctmp);
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("Parent process: %d\n"), itmp);
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("Process group: %d\n"), itmp);
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("Session id: %d\n"), itmp);
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("TTY: %d\n"), itmp);
|
| - if (fscanf (procfile, "%d ", &itmp) > 0)
|
| - printf_filtered (_("TTY owner process group: %d\n"), itmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Flags: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Minor faults (no memory page): %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Minor faults, children: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Major faults (memory page faults): %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Major faults, children: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("utime: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("stime: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("utime, children: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("stime, children: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("jiffies remaining in current "
|
| - "time slice: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("'nice' value: %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("jiffies until next timeout: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("jiffies until next SIGALRM: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("start time (jiffies since "
|
| - "system boot): %ld\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Virtual memory size: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Resident set size: %lu\n"),
|
| - (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Start of text: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("End of text: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0)
|
| - printf_filtered (_("Start of stack: 0x%lx\n"), ltmp);
|
| -#if 0 /* Don't know how architecture-dependent the rest is...
|
| - Anyway the signal bitmap info is available from "status". */
|
| - if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */
|
| - printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */
|
| - printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("Blocked signals bitmap: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%ld ", <mp) > 0)
|
| - printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp);
|
| - if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */
|
| - printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
|
| -#endif
|
| - do_cleanups (cleanup);
|
| - }
|
| - else
|
| - warning (_("unable to open /proc file '%s'"), fname1);
|
| - }
|
| -}
|
| -
|
| -/* Implement `info proc' when given without any futher parameters. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc mappings'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_mappings (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc stat'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_stat (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_STAT, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc status'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_status (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_STATUS, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc cwd'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_cwd (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_CWD, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc cmdline'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_cmdline (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc exe'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_exe (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_EXE, from_tty);
|
| -}
|
| -
|
| -/* Implement `info proc all'. */
|
| -
|
| -static void
|
| -linux_nat_info_proc_cmd_all (char *args, int from_tty)
|
| -{
|
| - linux_nat_info_proc_cmd_1 (args, IP_ALL, from_tty);
|
| + /* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
|
| + converted to gdbarch_core_regset_sections, this function can go away. */
|
| + return linux_make_corefile_notes (target_gdbarch, obfd, note_size,
|
| + linux_nat_collect_thread_registers);
|
| }
|
|
|
| /* Implement the to_xfer_partial interface for memory reads using the /proc
|
| @@ -5359,6 +4643,73 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
|
| offset, len);
|
| }
|
|
|
| +static void
|
| +cleanup_target_stop (void *arg)
|
| +{
|
| + ptid_t *ptid = (ptid_t *) arg;
|
| +
|
| + gdb_assert (arg != NULL);
|
| +
|
| + /* Unpause all */
|
| + target_resume (*ptid, 0, GDB_SIGNAL_0);
|
| +}
|
| +
|
| +static VEC(static_tracepoint_marker_p) *
|
| +linux_child_static_tracepoint_markers_by_strid (const char *strid)
|
| +{
|
| + char s[IPA_CMD_BUF_SIZE];
|
| + struct cleanup *old_chain;
|
| + int pid = ptid_get_pid (inferior_ptid);
|
| + VEC(static_tracepoint_marker_p) *markers = NULL;
|
| + struct static_tracepoint_marker *marker = NULL;
|
| + char *p = s;
|
| + ptid_t ptid = ptid_build (pid, 0, 0);
|
| +
|
| + /* Pause all */
|
| + target_stop (ptid);
|
| +
|
| + memcpy (s, "qTfSTM", sizeof ("qTfSTM"));
|
| + s[sizeof ("qTfSTM")] = 0;
|
| +
|
| + agent_run_command (pid, s, strlen (s) + 1);
|
| +
|
| + old_chain = make_cleanup (free_current_marker, &marker);
|
| + make_cleanup (cleanup_target_stop, &ptid);
|
| +
|
| + while (*p++ == 'm')
|
| + {
|
| + if (marker == NULL)
|
| + marker = XCNEW (struct static_tracepoint_marker);
|
| +
|
| + do
|
| + {
|
| + parse_static_tracepoint_marker_definition (p, &p, marker);
|
| +
|
| + if (strid == NULL || strcmp (strid, marker->str_id) == 0)
|
| + {
|
| + VEC_safe_push (static_tracepoint_marker_p,
|
| + markers, marker);
|
| + marker = NULL;
|
| + }
|
| + else
|
| + {
|
| + release_static_tracepoint_marker (marker);
|
| + memset (marker, 0, sizeof (*marker));
|
| + }
|
| + }
|
| + while (*p++ == ','); /* comma-separated list */
|
| +
|
| + memcpy (s, "qTsSTM", sizeof ("qTsSTM"));
|
| + s[sizeof ("qTsSTM")] = 0;
|
| + agent_run_command (pid, s, strlen (s) + 1);
|
| + p = s;
|
| + }
|
| +
|
| + do_cleanups (old_chain);
|
| +
|
| + return markers;
|
| +}
|
| +
|
| /* Create a prototype generic GNU/Linux target. The client can override
|
| it with local methods. */
|
|
|
| @@ -5376,11 +4727,13 @@ linux_target_install_ops (struct target_ops *t)
|
| t->to_post_startup_inferior = linux_child_post_startup_inferior;
|
| t->to_post_attach = linux_child_post_attach;
|
| t->to_follow_fork = linux_child_follow_fork;
|
| - t->to_find_memory_regions = linux_nat_find_memory_regions;
|
| t->to_make_corefile_notes = linux_nat_make_corefile_notes;
|
|
|
| super_xfer_partial = t->to_xfer_partial;
|
| t->to_xfer_partial = linux_xfer_partial;
|
| +
|
| + t->to_static_tracepoint_markers_by_strid
|
| + = linux_child_static_tracepoint_markers_by_strid;
|
| }
|
|
|
| struct target_ops *
|
| @@ -5603,7 +4956,7 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
|
| return;
|
| }
|
|
|
| -/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other
|
| +/* Stop an LWP, and push a GDB_SIGNAL_0 stop status if no other
|
| event came out. */
|
|
|
| static int
|
| @@ -5665,8 +5018,8 @@ static void
|
| linux_nat_close (int quitting)
|
| {
|
| /* Unregister from the event loop. */
|
| - if (target_is_async_p ())
|
| - target_async (NULL, 0);
|
| + if (linux_nat_is_async_p ())
|
| + linux_nat_async (NULL, 0);
|
|
|
| if (linux_ops->to_close)
|
| linux_ops->to_close (quitting);
|
| @@ -5679,7 +5032,7 @@ linux_nat_close (int quitting)
|
| lwpid is a "main" process id or not (it assumes so). We reverse
|
| look up the "main" process id from the lwp here. */
|
|
|
| -struct address_space *
|
| +static struct address_space *
|
| linux_nat_thread_address_space (struct target_ops *t, ptid_t ptid)
|
| {
|
| struct lwp_info *lwp;
|
| @@ -5705,74 +5058,9 @@ linux_nat_thread_address_space (struct target_ops *t, ptid_t ptid)
|
| return inf->aspace;
|
| }
|
|
|
| -int
|
| -linux_nat_core_of_thread_1 (ptid_t ptid)
|
| -{
|
| - struct cleanup *back_to;
|
| - char *filename;
|
| - FILE *f;
|
| - char *content = NULL;
|
| - char *p;
|
| - char *ts = 0;
|
| - int content_read = 0;
|
| - int i;
|
| - int core;
|
| -
|
| - filename = xstrprintf ("/proc/%d/task/%ld/stat",
|
| - GET_PID (ptid), GET_LWP (ptid));
|
| - back_to = make_cleanup (xfree, filename);
|
| -
|
| - f = fopen (filename, "r");
|
| - if (!f)
|
| - {
|
| - do_cleanups (back_to);
|
| - return -1;
|
| - }
|
| -
|
| - make_cleanup_fclose (f);
|
| -
|
| - for (;;)
|
| - {
|
| - int n;
|
| -
|
| - content = xrealloc (content, content_read + 1024);
|
| - n = fread (content + content_read, 1, 1024, f);
|
| - content_read += n;
|
| - if (n < 1024)
|
| - {
|
| - content[content_read] = '\0';
|
| - break;
|
| - }
|
| - }
|
| -
|
| - make_cleanup (xfree, content);
|
| -
|
| - p = strchr (content, '(');
|
| -
|
| - /* Skip ")". */
|
| - if (p != NULL)
|
| - p = strchr (p, ')');
|
| - if (p != NULL)
|
| - p++;
|
| -
|
| - /* If the first field after program name has index 0, then core number is
|
| - the field with index 36. There's no constant for that anywhere. */
|
| - if (p != NULL)
|
| - p = strtok_r (p, " ", &ts);
|
| - for (i = 0; p != NULL && i != 36; ++i)
|
| - p = strtok_r (NULL, " ", &ts);
|
| -
|
| - if (p == NULL || sscanf (p, "%d", &core) == 0)
|
| - core = -1;
|
| -
|
| - do_cleanups (back_to);
|
| -
|
| - return core;
|
| -}
|
| -
|
| /* Return the cached value of the processor core for thread PTID. */
|
|
|
| -int
|
| +static int
|
| linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
|
| {
|
| struct lwp_info *info = find_lwp_pid (ptid);
|
| @@ -5839,7 +5127,8 @@ linux_nat_add_target (struct target_ops *t)
|
|
|
| /* Register a method to call whenever a new thread is attached. */
|
| void
|
| -linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
|
| +linux_nat_set_new_thread (struct target_ops *t,
|
| + void (*new_thread) (struct lwp_info *))
|
| {
|
| /* Save the pointer. We only support a single registered instance
|
| of the GNU/Linux native target, so we do not need to map this to
|
| @@ -5852,7 +5141,7 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
|
| inferior. */
|
| void
|
| linux_nat_set_siginfo_fixup (struct target_ops *t,
|
| - int (*siginfo_fixup) (struct siginfo *,
|
| + int (*siginfo_fixup) (siginfo_t *,
|
| gdb_byte *,
|
| int))
|
| {
|
| @@ -5860,15 +5149,35 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
|
| linux_nat_siginfo_fixup = siginfo_fixup;
|
| }
|
|
|
| -/* Return the saved siginfo associated with PTID. */
|
| -struct siginfo *
|
| -linux_nat_get_siginfo (ptid_t ptid)
|
| +/* Register a method to call prior to resuming a thread. */
|
| +
|
| +void
|
| +linux_nat_set_prepare_to_resume (struct target_ops *t,
|
| + void (*prepare_to_resume) (struct lwp_info *))
|
| {
|
| - struct lwp_info *lp = find_lwp_pid (ptid);
|
| + /* Save the pointer. */
|
| + linux_nat_prepare_to_resume = prepare_to_resume;
|
| +}
|
|
|
| - gdb_assert (lp != NULL);
|
| +/* See linux-nat.h. */
|
| +
|
| +int
|
| +linux_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo)
|
| +{
|
| + int pid;
|
|
|
| - return &lp->siginfo;
|
| + pid = GET_LWP (ptid);
|
| + if (pid == 0)
|
| + pid = GET_PID (ptid);
|
| +
|
| + errno = 0;
|
| + ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, siginfo);
|
| + if (errno != 0)
|
| + {
|
| + memset (siginfo, 0, sizeof (*siginfo));
|
| + return 0;
|
| + }
|
| + return 1;
|
| }
|
|
|
| /* Provide a prototype to silence -Wmissing-prototypes. */
|
| @@ -5877,43 +5186,6 @@ extern initialize_file_ftype _initialize_linux_nat;
|
| void
|
| _initialize_linux_nat (void)
|
| {
|
| - static struct cmd_list_element *info_proc_cmdlist;
|
| -
|
| - add_prefix_cmd ("proc", class_info, linux_nat_info_proc_cmd,
|
| - _("\
|
| -Show /proc process information about any running process.\n\
|
| -Specify any process id, or use the program being debugged by default."),
|
| - &info_proc_cmdlist, "info proc ",
|
| - 1/*allow-unknown*/, &infolist);
|
| -
|
| - add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
|
| -List of mapped memory regions."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
|
| -List process info from /proc/PID/stat."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
|
| -List process info from /proc/PID/status."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
|
| -List current working directory of the process."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
|
| -List command line arguments of the process."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
|
| -List absolute filename for executable of the process."),
|
| - &info_proc_cmdlist);
|
| -
|
| - add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\
|
| -List all available /proc info."),
|
| - &info_proc_cmdlist);
|
| -
|
| add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
|
| &debug_linux_nat, _("\
|
| Set debugging of GNU/Linux lwp module."), _("\
|
|
|