#include "defs.h"
#include "inferior.h"
+#include "infrun.h"
#include "target.h"
#include "nat/linux-nat.h"
#include "nat/linux-waitpid.h"
#endif
#include <sys/ptrace.h>
#include "linux-nat.h"
-#include "linux-ptrace.h"
-#include "linux-procfs.h"
+#include "nat/linux-ptrace.h"
+#include "nat/linux-procfs.h"
#include "linux-fork.h"
#include "gdbthread.h"
#include "gdbcmd.h"
#include "terminal.h"
#include <sys/vfs.h>
#include "solib.h"
-#include "linux-osdata.h"
+#include "nat/linux-osdata.h"
#include "linux-tdep.h"
#include "symfile.h"
#include "agent.h"
#include "buffer.h"
#include "target-descriptions.h"
#include "filestuff.h"
+#include "objfiles.h"
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
Called by our to_xfer_partial. */
static target_xfer_partial_ftype *super_xfer_partial;
+/* The saved to_close method, inherited from inf-ptrace.c.
+ Called by our to_close. */
+static void (*super_close) (struct target_ops *);
+
static unsigned int debug_linux_nat;
static void
show_debug_linux_nat (struct ui_file *file, int from_tty,
if (detach_fork)
{
struct cleanup *old_chain;
+ int status = W_STOPCODE (0);
/* Before detaching from the child, remove all breakpoints
from it. If we forked, then this has already been taken
if (linux_nat_prepare_to_resume != NULL)
linux_nat_prepare_to_resume (child_lp);
- ptrace (PTRACE_DETACH, child_pid, 0, 0);
+
+ /* When debugging an inferior in an architecture that supports
+ hardware single stepping on a kernel without commit
+ 6580807da14c423f0d0a708108e6df6ebc8bc83d, the vfork child
+ process starts with the TIF_SINGLESTEP/X86_EFLAGS_TF bits
+ set if the parent process had them set.
+ To work around this, single step the child process
+ once before detaching to clear the flags. */
+
+ if (!gdbarch_software_single_step_p (target_thread_architecture
+ (child_lp->ptid)))
+ {
+ linux_disable_event_reporting (child_pid);
+ if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
+ perror_with_name (_("Couldn't do single step"));
+ if (my_waitpid (child_pid, &status, 0) < 0)
+ perror_with_name (_("Couldn't wait vfork process"));
+ }
+
+ if (WIFSTOPPED (status))
+ {
+ int signo;
+
+ signo = WSTOPSIG (status);
+ if (signo != 0
+ && !signal_pass_state (gdb_signal_from_host (signo)))
+ signo = 0;
+ ptrace (PTRACE_DETACH, child_pid, 0, signo);
+ }
do_cleanups (old_chain);
}
}
static int
-linux_child_insert_vfork_catchpoint (int pid)
+linux_child_insert_vfork_catchpoint (struct target_ops *self, int pid)
{
return !linux_supports_tracefork ();
}
static int
-linux_child_remove_vfork_catchpoint (int pid)
+linux_child_remove_vfork_catchpoint (struct target_ops *self, int pid)
{
return 0;
}
static int
-linux_child_insert_exec_catchpoint (int pid)
+linux_child_insert_exec_catchpoint (struct target_ops *self, int pid)
{
return !linux_supports_tracefork ();
}
static int
-linux_child_remove_exec_catchpoint (int pid)
+linux_child_remove_exec_catchpoint (struct target_ops *self, int pid)
{
return 0;
}
static int
-linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
+linux_child_set_syscall_catchpoint (struct target_ops *self,
+ int pid, int needed, int any_count,
int table_size, int *table)
{
if (!linux_supports_tracesysgood ())
/* Update signals to pass to the inferior. */
static void
-linux_nat_pass_signals (int numsigs, unsigned char *pass_signals)
+linux_nat_pass_signals (struct target_ops *self,
+ int numsigs, unsigned char *pass_signals)
{
int signo;
/* Prototypes for local functions. */
static int stop_wait_callback (struct lwp_info *lp, void *data);
static int linux_thread_alive (ptid_t ptid);
-static char *linux_child_pid_to_exec_file (int pid);
+static char *linux_child_pid_to_exec_file (struct target_ops *self, int pid);
\f
-/* Convert wait status STATUS to a string. Used for printing debug
- messages only. */
-
-static char *
-status_to_str (int status)
-{
- static char buf[64];
-
- if (WIFSTOPPED (status))
- {
- if (WSTOPSIG (status) == SYSCALL_SIGTRAP)
- snprintf (buf, sizeof (buf), "%s (stopped at syscall)",
- strsignal (SIGTRAP));
- else
- snprintf (buf, sizeof (buf), "%s (stopped)",
- strsignal (WSTOPSIG (status)));
- }
- else if (WIFSIGNALED (status))
- snprintf (buf, sizeof (buf), "%s (terminated)",
- strsignal (WTERMSIG (status)));
- else
- snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status));
-
- return buf;
-}
/* Destroy and free LP. */
#endif /* HAVE_PERSONALITY */
/* Make sure we report all signals during startup. */
- linux_nat_pass_signals (0, NULL);
+ linux_nat_pass_signals (ops, 0, NULL);
linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
}
static void
-linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
+linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
{
struct lwp_info *lp;
int status;
volatile struct gdb_exception ex;
/* Make sure we report all signals during attach. */
- linux_nat_pass_signals (0, NULL);
+ linux_nat_pass_signals (ops, 0, NULL);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
make_cleanup (xfree, message);
buffer_init (&buffer);
- linux_ptrace_attach_warnings (pid, &buffer);
+ linux_ptrace_attach_fail_reason (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);
+ if (*buffer_s != '\0')
+ throw_error (ex.error, "warning: %s\n%s", buffer_s, message);
+ else
+ throw_error (ex.error, "%s", message);
}
/* The ptrace base target adds the main thread with (pid,0,0)
}
}
-/* Resume LWP, with the last stop signal, if it is in pass state. */
+/* Callback for iterate_over_lwps. If LWP is EXCEPT, do nothing.
+ Resume LWP with the last stop signal, if it is in pass state. */
static int
-linux_nat_resume_callback (struct lwp_info *lp, void *data)
+linux_nat_resume_callback (struct lwp_info *lp, void *except)
{
enum gdb_signal signo = GDB_SIGNAL_0;
+ if (lp == except)
+ return 0;
+
if (lp->stopped)
{
struct thread_info *thread;
return;
}
- /* Mark LWP as not stopped to prevent it from being continued by
- linux_nat_resume_callback. */
- lp->stopped = 0;
-
if (resume_many)
- iterate_over_lwps (ptid, linux_nat_resume_callback, NULL);
+ iterate_over_lwps (ptid, linux_nat_resume_callback, lp);
/* Convert to something the lower layer understands. */
ptid = pid_to_ptid (ptid_get_lwp (lp->ptid));
linux_nat_prepare_to_resume (lp);
linux_ops->to_resume (linux_ops, ptid, step, signo);
lp->stopped_by_watchpoint = 0;
+ lp->stopped = 0;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
lp->syscall_state = TARGET_WAITKIND_IGNORE;
ptrace (PTRACE_CONT, ptid_get_lwp (lp->ptid), 0, 0);
+ lp->stopped = 0;
return 1;
}
linux_nat_prepare_to_resume (lp);
linux_ops->to_resume (linux_ops, pid_to_ptid (ptid_get_lwp (lp->ptid)),
lp->step, GDB_SIGNAL_0);
+ lp->stopped = 0;
return 1;
}
linux_ops->to_resume (linux_ops,
pid_to_ptid (ptid_get_lwp (lp->ptid)),
0, GDB_SIGNAL_0);
-
+ lp->stopped = 0;
return 1;
}
ourstatus->kind = TARGET_WAITKIND_EXECD;
ourstatus->value.execd_pathname
- = xstrdup (linux_child_pid_to_exec_file (pid));
+ = xstrdup (linux_child_pid_to_exec_file (NULL, pid));
return 0;
}
}
gdb_assert (WIFSTOPPED (status));
+ lp->stopped = 1;
/* Handle GNU/Linux's syscall SIGTRAPs. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
errno = 0;
ptrace (PTRACE_CONT, ptid_get_lwp (lp->ptid), 0, 0);
+ lp->stopped = 0;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"PTRACE_CONT %s, 0, 0 (%s) "
/* Save the sigtrap event. */
lp->status = status;
- gdb_assert (!lp->stopped);
gdb_assert (lp->signalled);
- lp->stopped = 1;
}
else
{
"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;
if (!WIFSTOPPED (status) && !lp)
return NULL;
+ /* This LWP is stopped now. (And if dead, this prevents it from
+ ever being continued.) */
+ lp->stopped = 1;
+
/* Handle GNU/Linux's syscall SIGTRAPs. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
{
used. */
if (ptid_get_pid (lp->ptid) == ptid_get_lwp (lp->ptid))
{
- lp->stopped = 1;
iterate_over_lwps (pid_to_ptid (ptid_get_pid (lp->ptid)),
stop_and_resume_callback, new_pending_p);
}
" cancelled it\n",
ptid_get_lwp (lp->ptid));
}
- lp->stopped = 1;
}
else
- {
- lp->stopped = 1;
- lp->signalled = 0;
- }
+ lp->signalled = 0;
}
else if (WIFEXITED (lp->status) || WIFSIGNALED (lp->status))
{
pending for the next time we're able to report
it. */
- /* Prevent trying to stop this thread again. We'll
- never try to resume it because it has a pending
- status. */
- lp->stopped = 1;
-
/* Dead LWP's aren't expected to reported a pending
sigstop. */
lp->signalled = 0;
}
static char *
-linux_nat_thread_name (struct thread_info *thr)
+linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
{
int pid = ptid_get_pid (thr->ptid);
long lwp = ptid_get_lwp (thr->ptid);
can be opened to get the symbols for the child process. */
static char *
-linux_child_pid_to_exec_file (int pid)
+linux_child_pid_to_exec_file (struct target_ops *self, int pid)
{
- char *name1, *name2;
+ static char buf[PATH_MAX];
+ char name[PATH_MAX];
- name1 = xmalloc (PATH_MAX);
- name2 = xmalloc (PATH_MAX);
- make_cleanup (xfree, name1);
- make_cleanup (xfree, name2);
- memset (name2, 0, PATH_MAX);
+ xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
+ memset (buf, 0, PATH_MAX);
+ if (readlink (name, buf, PATH_MAX - 1) <= 0)
+ strcpy (buf, name);
- xsnprintf (name1, PATH_MAX, "/proc/%d/exe", pid);
- if (readlink (name1, name2, PATH_MAX - 1) > 0)
- return name2;
- else
- return name1;
+ return buf;
}
/* Records the thread's register state for the corefile note
section for a corefile, and returns it in a malloc buffer. */
static char *
-linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
+linux_nat_make_corefile_notes (struct target_ops *self,
+ bfd *obfd, int *note_size)
{
/* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
converted to gdbarch_core_regset_sections, this function can go away. */
}
static VEC(static_tracepoint_marker_p) *
-linux_child_static_tracepoint_markers_by_strid (const char *strid)
+linux_child_static_tracepoint_markers_by_strid (struct target_ops *self,
+ const char *strid)
{
char s[IPA_CMD_BUF_SIZE];
struct cleanup *old_chain;
}
static int
-linux_nat_supports_non_stop (void)
+linux_nat_supports_non_stop (struct target_ops *self)
{
return 1;
}
int linux_multi_process = 1;
static int
-linux_nat_supports_multi_process (void)
+linux_nat_supports_multi_process (struct target_ops *self)
{
return linux_multi_process;
}
static int
-linux_nat_supports_disable_randomization (void)
+linux_nat_supports_disable_randomization (struct target_ops *self)
{
#ifdef HAVE_PERSONALITY
return 1;
if (!target_is_async_p ())
{
/* Async mode is disabled. */
- terminal_inferior (self);
+ child_terminal_inferior (self);
return;
}
- terminal_inferior (self);
+ child_terminal_inferior (self);
/* Calls to target_terminal_*() are meant to be idempotent. */
if (!async_terminal_is_ours)
if (!target_is_async_p ())
{
/* Async mode is disabled. */
- terminal_ours (self);
+ child_terminal_ours (self);
return;
}
/* GDB should never give the terminal to the inferior if the
inferior is running in the background (run&, continue&, etc.),
but claiming it sure should. */
- terminal_ours (self);
+ child_terminal_ours (self);
if (async_terminal_is_ours)
return;
}
static void
-linux_nat_stop (ptid_t ptid)
+linux_nat_stop (struct target_ops *self, ptid_t ptid)
{
if (non_stop)
iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
else
- linux_ops->to_stop (ptid);
+ linux_ops->to_stop (linux_ops, ptid);
}
static void
if (linux_ops->to_close)
linux_ops->to_close (linux_ops);
+
+ super_close (self);
}
/* When requests are passed down from the linux-nat layer to the
t->to_async = linux_nat_async;
t->to_terminal_inferior = linux_nat_terminal_inferior;
t->to_terminal_ours = linux_nat_terminal_ours;
+
+ super_close = t->to_close;
t->to_close = linux_nat_close;
/* Methods for non-stop support. */
static int
get_signo (const char *name)
{
- struct minimal_symbol *ms;
+ struct bound_minimal_symbol ms;
int signo;
ms = lookup_minimal_symbol (name, NULL, NULL);
- if (ms == NULL)
+ if (ms.minsym == NULL)
return 0;
- if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (gdb_byte *) &signo,
+ if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), (gdb_byte *) &signo,
sizeof (signo)) != 0)
return 0;