/* GNU/Linux native-dependent code common to multiple platforms.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GDB.
#include "inf-ptrace.h"
#include "auxv.h"
#include <sys/param.h> /* for MAXPATHLEN */
-#include <sys/procfs.h> /* for elf_gregset etc. */
+#include <sys/procfs.h> /* for elf_gregset etc. */
#include "elf-bfd.h" /* for elfcore_write_* */
#include "gregset.h" /* for gregset */
#include "gdbcore.h" /* for get_exec_file */
#include <ctype.h> /* for isdigit */
-#include "gdbthread.h" /* for struct thread_info etc. */
+#include "gdbthread.h" /* for struct thread_info etc. */
#include "gdb_stat.h" /* for struct stat */
#include <fcntl.h> /* for O_RDONLY */
#include "inf-loop.h"
# endif
#endif /* HAVE_PERSONALITY */
-/* This comment documents high-level logic of this file.
+/* This comment documents high-level logic of this file.
Waiting for events in sync mode
===============================
When waiting for an event in a specific thread, we just use waitpid, passing
the specific pid, and not passing WNOHANG.
-When waiting for an event in all threads, waitpid is not quite good. Prior to
+When waiting for an event in all threads, waitpid is not quite good. Prior to
version 2.4, Linux can either wait for event in main thread, or in secondary
-threads. (2.4 has the __WALL flag). So, if we use blocking waitpid, we might
+threads. (2.4 has the __WALL flag). So, if we use blocking waitpid, we might
miss an event. The solution is to use non-blocking waitpid, together with
sigsuspend. First, we use non-blocking waitpid to get an event in the main
-process, if any. Second, we use non-blocking waitpid with the __WCLONED
+process, if any. Second, we use non-blocking waitpid with the __WCLONED
flag to check for events in cloned processes. If nothing is found, we use
sigsuspend to wait for SIGCHLD. When SIGCHLD arrives, it means something
happened to a child process -- and SIGCHLD will be delivered both for events
in main debugged process and in cloned processes. As soon as we know there's
-an event, we get back to calling nonblocking waitpid with and without __WCLONED.
+an event, we get back to calling nonblocking waitpid with and without
+__WCLONED.
Note that SIGCHLD should be blocked between waitpid and sigsuspend calls,
-so that we don't miss a signal. If SIGCHLD arrives in between, when it's
+so that we don't miss a signal. If SIGCHLD arrives in between, when it's
blocked, the signal becomes pending and sigsuspend immediately
notices it and returns.
#define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
-/* options set using PTRACE_SETOPTIONS */
+/* Options set using PTRACE_SETOPTIONS. */
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
show_debug_linux_nat_async (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Debugging of GNU/Linux async lwp module is %s.\n"),
+ fprintf_filtered (file,
+ _("Debugging of GNU/Linux async lwp module is %s.\n"),
value);
}
struct cmd_list_element *c, const char *value)
{
#ifdef HAVE_PERSONALITY
- fprintf_filtered (file, _("\
-Disabling randomization of debuggee's virtual address space is %s.\n"),
+ fprintf_filtered (file,
+ _("Disabling randomization of debuggee's "
+ "virtual address space is %s.\n"),
value);
#else /* !HAVE_PERSONALITY */
- fputs_filtered (_("\
-Disabling randomization of debuggee's virtual address space is unsupported on\n\
-this platform.\n"), file);
+ fputs_filtered (_("Disabling randomization of debuggee's "
+ "virtual address space is unsupported on\n"
+ "this platform.\n"), file);
#endif /* !HAVE_PERSONALITY */
}
static void
-set_disable_randomization (char *args, int from_tty, struct cmd_list_element *c)
+set_disable_randomization (char *args, int from_tty,
+ struct cmd_list_element *c)
{
#ifndef HAVE_PERSONALITY
- error (_("\
-Disabling randomization of debuggee's virtual address space is unsupported on\n\
-this platform."));
+ error (_("Disabling randomization of debuggee's "
+ "virtual address space is unsupported on\n"
+ "this platform."));
#endif /* !HAVE_PERSONALITY */
}
-static int linux_parent_pid;
-
struct simple_pid_list
{
int pid;
static int linux_supports_tracefork_flag = -1;
-/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACESYSGOOD
- can not be used, 1 if it can. */
+/* This variable is a tri-state flag: -1 for unknown, 0 if
+ PTRACE_O_TRACESYSGOOD can not be used, 1 if it can. */
static int linux_supports_tracesysgood_flag = -1;
static int linux_supports_tracevforkdone_flag = -1;
-/* Async mode support */
+/* Async mode support. */
/* Zero if the async mode, although enabled, is masked, which means
linux_nat_wait should behave as if async mode was off. */
}
static void linux_nat_async (void (*callback)
- (enum inferior_event_type event_type, void *context),
+ (enum inferior_event_type event_type,
+ void *context),
void *context);
static int linux_nat_async_mask (int mask);
static int kill_lwp (int lwpid, int signo);
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;
}
static int
-pull_pid_from_list (struct simple_pid_list **listp, int pid, int *status)
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
{
struct simple_pid_list **p;
if ((*p)->pid == pid)
{
struct simple_pid_list *next = (*p)->next;
- *status = (*p)->status;
+
+ *statusp = (*p)->status;
xfree (*p);
*p = next;
return 1;
static void
linux_tracefork_child (void)
{
- int ret;
-
ptrace (PTRACE_TRACEME, 0, 0, 0);
kill (getpid (), SIGSTOP);
fork ();
/* Wrapper function for waitpid which handles EINTR. */
static int
-my_waitpid (int pid, int *status, int flags)
+my_waitpid (int pid, int *statusp, int flags)
{
int ret;
do
{
- ret = waitpid (pid, status, flags);
+ ret = waitpid (pid, statusp, flags);
}
while (ret == -1 && errno == EINTR);
else if (ret != child_pid)
error (_("linux_test_for_tracefork: waitpid: unexpected result %d."), ret);
if (! WIFSTOPPED (status))
- error (_("linux_test_for_tracefork: waitpid: unexpected status %d."), status);
+ error (_("linux_test_for_tracefork: waitpid: unexpected status %d."),
+ status);
ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
if (ret != 0)
ret = my_waitpid (child_pid, &status, 0);
if (ret != child_pid)
- warning (_("linux_test_for_tracefork: failed to wait for killed child"));
+ warning (_("linux_test_for_tracefork: failed "
+ "to wait for killed child"));
else if (!WIFSIGNALED (status))
- warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
- "killed child"), status);
+ warning (_("linux_test_for_tracefork: unexpected "
+ "wait status 0x%x from killed child"), status);
restore_child_signals_mask (&prev_mask);
return;
my_waitpid (second_pid, &second_status, 0);
ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
if (ret != 0)
- warning (_("linux_test_for_tracefork: failed to kill second child"));
+ warning (_("linux_test_for_tracefork: "
+ "failed to kill second child"));
my_waitpid (second_pid, &status, 0);
}
}
in the foreground, the user will not be able to ctrl-c to get
back the terminal, effectively hanging the debug session. */
fprintf_filtered (gdb_stderr, _("\
-Can not resume the parent process over vfork in the foreground while \n\
+Can not resume the parent process over vfork in the foreground while\n\
holding the child stopped. Try \"set detach-on-fork\" or \
\"set schedule-multiple\".\n"));
+ /* FIXME output string > 80 columns. */
return 1;
}
{
struct lwp_info *child_lp = NULL;
- /* We're already attached to the parent, by default. */
+ /* We're already attached to the parent, by default. */
/* Detach new forked process? */
if (detach_fork)
{
target_terminal_ours ();
fprintf_filtered (gdb_stdlog,
- "Detaching after fork from child process %d.\n",
+ "Detaching after fork from "
+ "child process %d.\n",
child_pid);
}
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "LCFF: no VFORK_DONE support, sleeping a bit\n");
+ "LCFF: no VFORK_DONE "
+ "support, sleeping a bit\n");
usleep (10000);
}
else
{
- struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
struct program_space *parent_pspace;
{
target_terminal_ours ();
if (has_vforked)
- fprintf_filtered (gdb_stdlog, _("\
-Attaching after process %d vfork to child process %d.\n"),
+ fprintf_filtered (gdb_stdlog,
+ _("Attaching after process %d "
+ "vfork to child process %d.\n"),
parent_pid, child_pid);
else
- fprintf_filtered (gdb_stdlog, _("\
-Attaching after process %d fork to child process %d.\n"),
+ fprintf_filtered (gdb_stdlog,
+ _("Attaching after process %d "
+ "fork to child process %d.\n"),
parent_pid, child_pid);
}
}
\f
-static void
+static int
linux_child_insert_fork_catchpoint (int pid)
{
- if (! linux_supports_tracefork (pid))
- error (_("Your system does not support fork catchpoints."));
+ return !linux_supports_tracefork (pid);
}
-static void
+static int
linux_child_insert_vfork_catchpoint (int pid)
{
- if (!linux_supports_tracefork (pid))
- error (_("Your system does not support vfork catchpoints."));
+ return !linux_supports_tracefork (pid);
}
-static void
+static int
linux_child_insert_exec_catchpoint (int pid)
{
- if (!linux_supports_tracefork (pid))
- error (_("Your system does not support exec catchpoints."));
+ return !linux_supports_tracefork (pid);
}
static int
linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
int table_size, int *table)
{
- if (! linux_supports_tracesysgood (pid))
- error (_("Your system does not support syscall catchpoints."));
+ if (!linux_supports_tracesysgood (pid))
+ return 1;
+
/* On GNU/Linux, we ignore the arguments. It means that we only
enable the syscall catchpoints, but do not disable them.
-
+
Also, we do not use the `table' information because we do not
filter system calls here. We let GDB do the logic for us. */
return 0;
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 int cancel_breakpoint (struct lwp_info *lp);
\f
/* Convert wait status STATUS to a string. Used for printing debug
}
else if (WIFSIGNALED (status))
snprintf (buf, sizeof (buf), "%s (terminated)",
- strsignal (WSTOPSIG (status)));
+ strsignal (WTERMSIG (status)));
else
snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status));
else if (non_stop && !is_executing (lp->ptid))
{
struct thread_info *tp = find_thread_ptid (lp->ptid);
- signo = tp->stop_signal;
+
+ signo = tp->suspend.stop_signal;
}
else if (!non_stop)
{
if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
{
struct thread_info *tp = find_thread_ptid (lp->ptid);
- signo = tp->stop_signal;
+
+ signo = tp->suspend.stop_signal;
}
}
else if (!signal_pass_state (signo))
{
if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "\
-GPT: lwp %s had signal %s, but it is in no pass state\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "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));
}
{
int pid;
int status;
- enum target_signal sig;
struct lwp_info *main_lwp;
pid = GET_PID (inferior_ptid);
pass it along with PTRACE_DETACH. */
args = alloca (8);
sprintf (args, "%d", (int) WSTOPSIG (status));
- fprintf_unfiltered (gdb_stdlog,
- "LND: Sending signal %s to %s\n",
- args,
- target_pid_to_str (main_lwp->ptid));
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LND: Sending signal %s to %s\n",
+ args,
+ target_pid_to_str (main_lwp->ptid));
}
delete_lwp (main_lwp->ptid);
lp->stopped_by_watchpoint = 0;
}
else if (lp->stopped && debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (has pending)\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "RC: Not resuming sibling %s (has pending)\n",
target_pid_to_str (lp->ptid));
else if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (not stopped)\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "RC: Not resuming sibling %s (not stopped)\n",
target_pid_to_str (lp->ptid));
return 0;
"LLR: Preparing to %s %s, %s, inferior_ptid %s\n",
step ? "step" : "resume",
target_pid_to_str (ptid),
- signo ? strsignal (signo) : "0",
+ (signo != TARGET_SIGNAL_0
+ ? strsignal (target_signal_to_host (signo)) : "0"),
target_pid_to_str (inferior_ptid));
block_child_signals (&prev_mask);
if (lp->status && WIFSTOPPED (lp->status))
{
- int saved_signo;
+ enum target_signal saved_signo;
struct inferior *inf;
inf = find_inferior_pid (ptid_get_pid (lp->ptid));
/* Defer to common code if we're gaining control of the
inferior. */
- if (inf->stop_soon == NO_STOP_QUIETLY
+ if (inf->control.stop_soon == NO_STOP_QUIETLY
&& signal_stop_state (saved_signo) == 0
&& signal_print_state (saved_signo) == 0
&& signal_pass_state (saved_signo) == 1)
"LLR: %s %s, %s (resume event thread)\n",
step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (ptid),
- signo ? strsignal (signo) : "0");
+ (signo != TARGET_SIGNAL_0
+ ? strsignal (target_signal_to_host (signo)) : "0"));
restore_child_signals_mask (&prev_mask);
if (target_can_async_p ())
fprintf_unfiltered (gdb_stdlog,
"LHST: stopping for %s of syscall %d"
" for LWP %ld\n",
- lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY
+ lp->syscall_state
+ == TARGET_WAITKIND_SYSCALL_ENTRY
? "entry" : "return",
syscall_number,
GET_LWP (lp->ptid));
PT_CONTINUE, can not trigger a syscall trace event. */
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "LHST: caught syscall event with no syscall catchpoints."
+ "LHST: caught syscall event "
+ "with no syscall catchpoints."
" %d for LWP %ld, ignoring\n",
syscall_number,
GET_LWP (lp->ptid));
{
int pid = GET_LWP (lp->ptid);
struct target_waitstatus *ourstatus = &lp->waitstatus;
- struct lwp_info *new_lp = NULL;
int event = status >> 16;
if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
ourstatus->kind = TARGET_WAITKIND_VFORKED;
else
{
- struct cleanup *old_chain;
+ struct lwp_info *new_lp;
ourstatus->kind = TARGET_WAITKIND_IGNORE;
+
new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (lp->ptid)));
new_lp->cloned = 1;
new_lp->stopped = 1;
catchpoints. */
if (!stopping)
{
- int signo;
+ enum target_signal signo;
new_lp->stopped = 0;
new_lp->resumed = 1;
linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
0, signo);
}
+ else
+ {
+ if (status != 0)
+ {
+ /* We created NEW_LP so it cannot yet contain STATUS. */
+ gdb_assert (new_lp->status == 0);
+
+ /* Save the wait status to report later. */
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: waitpid of new LWP %ld, "
+ "saving status %s\n",
+ (long) GET_LWP (new_lp->ptid),
+ status_to_str (status));
+ new_lp->status = status;
+ }
+ }
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "LHEW: Got clone event from LWP %ld, resuming\n",
+ "LHEW: Got clone event "
+ "from LWP %ld, resuming\n",
GET_LWP (lp->ptid));
linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
0, TARGET_SIGNAL_0);
if (current_inferior ()->waiting_for_vfork_done)
{
if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "\
-LHEW: Got expected PTRACE_EVENT_VFORK_DONE from LWP %ld: stopping\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: Got expected PTRACE_EVENT_"
+ "VFORK_DONE from LWP %ld: stopping\n",
GET_LWP (lp->ptid));
ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
}
if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "\
-LHEW: Got PTRACE_EVENT_VFORK_DONE from LWP %ld: resuming\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: Got PTRACE_EVENT_VFORK_DONE "
+ "from LWP %ld: resuming\n",
GET_LWP (lp->ptid));
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
return 1;
linux_nat_has_pending_sigint (int pid)
{
sigset_t pending, blocked, ignored;
- int i;
linux_proc_pending_signals (pid, &pending, &blocked, &ignored);
return lp->stopped_data_address_p;
}
+/* Commonly any breakpoint / watchpoint generate only SIGTRAP. */
+
+static int
+sigtrap_is_event (int status)
+{
+ return WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP;
+}
+
+/* SIGTRAP-like events recognizer. */
+
+static int (*linux_nat_status_is_event) (int status) = sigtrap_is_event;
+
+/* Check for SIGTRAP-like events in LP. */
+
+static int
+linux_nat_lp_status_is_event (struct lwp_info *lp)
+{
+ /* We check for lp->waitstatus in addition to lp->status, because we can
+ have pending process exits recorded in lp->status
+ and W_EXITCODE(0,0) == 0. We should probably have an additional
+ lp->status_p flag. */
+
+ return (lp->waitstatus.kind == TARGET_WAITKIND_IGNORE
+ && linux_nat_status_is_event (lp->status));
+}
+
+/* Set alternative SIGTRAP-like events recognizer. If
+ breakpoint_inserted_here_p there then gdbarch_decr_pc_after_break will be
+ applied. */
+
+void
+linux_nat_set_status_is_event (struct target_ops *t,
+ int (*status_is_event) (int status))
+{
+ linux_nat_status_is_event = status_is_event;
+}
+
/* Wait until LP is stopped. */
static int
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "PTRACE_CONT %s, 0, 0 (%s) (discarding SIGINT)\n",
+ "PTRACE_CONT %s, 0, 0 (%s) "
+ "(discarding SIGINT)\n",
target_pid_to_str (lp->ptid),
errno ? safe_strerror (errno) : "OK");
if (WSTOPSIG (status) != SIGSTOP)
{
- if (WSTOPSIG (status) == SIGTRAP)
+ 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
save_sigtrap (lp);
- /* Now resume this LWP and get the SIGSTOP event. */
+ /* Now resume this LWP and get the SIGSTOP event. */
errno = 0;
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
if (debug_linux_nat)
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). */
+ 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. */
+ queue. */
if (lp->status)
{
if (debug_linux_nat)
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
}
- /* Save the sigtrap event. */
+ /* 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. */
+ SIGSTOP, and didn't accidentally trip a breakpoint. */
if (debug_linux_nat)
{
status_to_str ((int) status),
target_pid_to_str (lp->ptid));
}
- /* Now resume this LWP and get the SIGSTOP event. */
+ /* Now resume this LWP and get the SIGSTOP event. */
errno = 0;
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
if (debug_linux_nat)
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). */
+ 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
gdb_assert (count != NULL);
/* Count only resumed LWPs that have a SIGTRAP event pending. */
- if (lp->status != 0 && lp->resumed
- && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP)
+ if (lp->resumed && linux_nat_lp_status_is_event (lp))
(*count)++;
return 0;
gdb_assert (selector != NULL);
- /* Select only resumed LWPs that have a SIGTRAP event pending. */
- if (lp->status != 0 && lp->resumed
- && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP)
+ /* Select only resumed LWPs that have a SIGTRAP event pending. */
+ if (lp->resumed && linux_nat_lp_status_is_event (lp))
if ((*selector)-- == 0)
return 1;
delete or disable the breakpoint, but the LWP will have already
tripped on it. */
- if (lp->waitstatus.kind == TARGET_WAITKIND_IGNORE
- && lp->status != 0
- && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
+ if (linux_nat_lp_status_is_event (lp)
&& cancel_breakpoint (lp))
/* Throw away the SIGTRAP. */
lp->status = 0;
}
/* Make sure we don't report an event for the exit of an LWP not in
- our list, i.e. not part of the current process. This can happen
+ our list, i.e. not part of the current process. This can happen
if we detach from a program we original forked and then it
exits. */
if (!WIFSTOPPED (status) && !lp)
return NULL;
}
- if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+ if (linux_nat_status_is_event (status))
{
/* Save the trap's siginfo in case we need it later. */
save_siginfo (lp);
lp = linux_nat_filter_event (lwpid, status, options);
+ /* STATUS is now no longer valid, use LP->STATUS instead. */
+ status = 0;
+
if (lp
&& ptid_is_pid (ptid)
&& ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
gdb_assert (lp->resumed);
if (debug_linux_nat)
- fprintf (stderr, "LWP %ld got an event %06x, leaving pending.\n",
- ptid_get_lwp (lp->ptid), status);
+ fprintf (stderr,
+ "LWP %ld got an event %06x, leaving pending.\n",
+ ptid_get_lwp (lp->ptid), lp->status);
if (WIFSTOPPED (lp->status))
{
always cancels breakpoint hits in all
threads. */
if (non_stop
- && lp->waitstatus.kind == TARGET_WAITKIND_IGNORE
- && WSTOPSIG (lp->status) == SIGTRAP
+ && linux_nat_lp_status_is_event (lp)
&& cancel_breakpoint (lp))
{
/* Throw away the SIGTRAP. */
if (debug_linux_nat)
fprintf (stderr,
- "LLW: LWP %ld hit a breakpoint while waiting "
- "for another process; cancelled it\n",
+ "LLW: LWP %ld hit a breakpoint while"
+ " waiting for another process;"
+ " cancelled it\n",
ptid_get_lwp (lp->ptid));
}
lp->stopped = 1;
lp->signalled = 0;
}
}
- else if (WIFEXITED (status) || WIFSIGNALED (status))
+ else if (WIFEXITED (lp->status) || WIFSIGNALED (lp->status))
{
if (debug_linux_nat)
- fprintf (stderr, "Process %ld exited while stopping LWPs\n",
+ fprintf (stderr,
+ "Process %ld exited while stopping LWPs\n",
ptid_get_lwp (lp->ptid));
/* This was the last lwp in the process. Since
if (WIFSTOPPED (status))
{
- int signo = target_signal_from_host (WSTOPSIG (status));
+ enum target_signal signo = target_signal_from_host (WSTOPSIG (status));
struct inferior *inf;
inf = find_inferior_pid (ptid_get_pid (lp->ptid));
skip the signal handler, or, if we're gaining control of the
inferior. */
if (!lp->step
- && inf->stop_soon == NO_STOP_QUIETLY
+ && inf->control.stop_soon == NO_STOP_QUIETLY
&& signal_stop_state (signo) == 0
&& signal_print_state (signo) == 0
&& signal_pass_state (signo) == 1)
lp->step ?
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (lp->ptid),
- signo ? strsignal (signo) : "0");
+ (signo != TARGET_SIGNAL_0
+ ? strsignal (target_signal_to_host (signo))
+ : "0"));
lp->stopped = 0;
goto retry;
}
else
lp->resumed = 0;
- if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+ if (linux_nat_status_is_event (status))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
fprintf_unfiltered (gdb_stdlog, "LLW: exit\n");
restore_child_signals_mask (&prev_mask);
- lp->core = linux_nat_core_of_thread_1 (lp->ptid);
+
+ 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);
+
return lp->ptid;
}
ptid_t event_ptid;
if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "linux_nat_wait: [%s]\n", target_pid_to_str (ptid));
+ fprintf_unfiltered (gdb_stdlog,
+ "linux_nat_wait: [%s]\n", target_pid_to_str (ptid));
/* Flush the async file first. */
if (target_can_async_p ())
else
{
ptid_t ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
/* Stop all threads before killing them, since ptrace requires
that the thread is stopped to sucessfully PTRACE_KILL. */
iterate_over_lwps (ptid, stop_callback, NULL);
return normal_pid_to_str (ptid);
}
+static char *
+linux_nat_thread_name (struct thread_info *thr)
+{
+ int pid = ptid_get_pid (thr->ptid);
+ long lwp = ptid_get_lwp (thr->ptid);
+#define FORMAT "/proc/%d/task/%ld/comm"
+ char buf[sizeof (FORMAT) + 30];
+ FILE *comm_file;
+ char *result = NULL;
+
+ snprintf (buf, sizeof (buf), FORMAT, pid, lwp);
+ comm_file = fopen (buf, "r");
+ if (comm_file)
+ {
+ /* Not exported by the kernel, so we define it here. */
+#define COMM_LEN 16
+ static char line[COMM_LEN + 1];
+
+ if (fgets (line, sizeof (line), comm_file))
+ {
+ char *nl = strchr (line, '\n');
+
+ if (nl)
+ *nl = '\0';
+ if (*line != '\0')
+ result = line;
+ }
+
+ fclose (comm_file);
+ }
+
+#undef COMM_LEN
+#undef FORMAT
+
+ return result;
+}
+
/* Accepts an integer PID; Returns a string representing a file that
can be opened to get the symbols for the child process. */
regions in the inferior for a corefile. */
static int
-linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
- unsigned long,
- int, int, int, void *), void *obfd)
+linux_nat_find_memory_regions (find_memory_region_ftype func, void *obfd)
{
int pid = PIDGET (inferior_ptid);
char mapsfilename[MAXPATHLEN];
long long addr, endaddr, size, offset, inode;
char permissions[8], device[8], filename[MAXPATHLEN];
int read, write, exec;
- int ret;
struct cleanup *cleanup;
/* Compose the filename for the /proc memory map, and open it. */
if (info_verbose)
{
fprintf_filtered (gdb_stdout,
- "Save segment, %lld bytes at %s (%c%c%c)",
- size, paddress (target_gdbarch, addr),
+ "Save segment, %s bytes at %s (%c%c%c)",
+ plongest (size), paddress (target_gdbarch, addr),
read ? 'r' : ' ',
write ? 'w' : ' ', exec ? 'x' : ' ');
if (filename[0])
static int
find_signalled_thread (struct thread_info *info, void *data)
{
- if (info->stop_signal != TARGET_SIGNAL_0
+ if (info->suspend.stop_signal != TARGET_SIGNAL_0
&& ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
return 1;
iterate_over_threads (find_signalled_thread, NULL);
if (info)
- return info->stop_signal;
+ return info->suspend.stop_signal;
else
return TARGET_SIGNAL_0;
}
char *note_data, int *note_size,
enum target_signal stop_signal)
{
- gdb_gregset_t gregs;
- gdb_fpregset_t fpregs;
unsigned long lwp = ptid_get_lwp (ptid);
struct gdbarch *gdbarch = target_gdbarch;
struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
sect_list = gdbarch_core_regset_sections (gdbarch);
- 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,
- lwp,
- stop_signal, &gregs);
-
/* 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
if (core_regset_p && sect_list != NULL)
while (sect_list->sect_name != NULL)
{
- /* .reg was already handled above. */
- if (strcmp (sect_list->sect_name, ".reg") == 0)
- {
- sect_list++;
- continue;
- }
regset = gdbarch_regset_from_core_section (gdbarch,
sect_list->sect_name,
sect_list->size);
gdb_regset = xmalloc (sect_list->size);
regset->collect_regset (regset, regcache, -1,
gdb_regset, sect_list->size);
- note_data = (char *) elfcore_write_register_note (obfd,
- note_data,
- note_size,
- sect_list->sect_name,
- 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++;
}
the new support, the code below should be deleted. */
else
{
+ gdb_gregset_t gregs;
+ gdb_fpregset_t fpregs;
+
+ 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, lwp, target_signal_to_host (stop_signal),
+ &gregs);
+
if (core_regset_p
&& (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
- sizeof (fpregs))) != NULL
- && regset->collect_regset != NULL)
+ sizeof (fpregs)))
+ != NULL && regset->collect_regset != NULL)
regset->collect_regset (regset, regcache, -1,
&fpregs, sizeof (fpregs));
else
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;
linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
{
struct linux_nat_corefile_thread_data thread_args;
- struct cleanup *old_chain;
/* 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 current_ptid = inferior_ptid;
ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
gdb_byte *auxv;
int auxv_len;
int cwd_f = 1;
int exe_f = 1;
int mappings_f = 0;
- int environ_f = 0;
int status_f = 0;
int stat_f = 0;
int all = 0;
}
else
{
- /* [...] (future options here) */
+ /* [...] (future options here). */
}
argv++;
}
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
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);
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);
+ 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 SIGALRM: %lu\n"),
(unsigned long) ltmp);
if (fscanf (procfile, "%ld ", <mp) > 0)
- printf_filtered (_("start time (jiffies since system boot): %ld\n"),
- ltmp);
+ 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);
+ 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 (_("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? */
+#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? */
+ 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);
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? */
+ if (fscanf (procfile, "%lu ", <mp) > 0) /* FIXME arch? */
printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
#endif
do_cleanups (cleanup);
SIGS to match. */
void
-linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored)
+linux_proc_pending_signals (int pid, sigset_t *pending,
+ sigset_t *blocked, sigset_t *ignored)
{
FILE *procfile;
char buffer[MAXPATHLEN], fname[MAXPATHLEN];
- int signum;
struct cleanup *cleanup;
sigemptyset (pending);
static LONGEST
linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
/* We make the process list snapshot when the object starts to be
read. */
gdb_assert (object == TARGET_OBJECT_OSDATA);
+ if (!annex)
+ {
+ if (offset == 0)
+ {
+ if (len_avail != -1 && len_avail != 0)
+ obstack_free (&obstack, NULL);
+ len_avail = 0;
+ buf = NULL;
+ obstack_init (&obstack);
+ obstack_grow_str (&obstack, "<osdata type=\"types\">\n");
+
+ obstack_xml_printf (&obstack,
+ "<item>"
+ "<column name=\"Type\">processes</column>"
+ "<column name=\"Description\">"
+ "Listing of all processes</column>"
+ "</item>");
+
+ obstack_grow_str0 (&obstack, "</osdata>\n");
+ buf = obstack_finish (&obstack);
+ len_avail = strlen (buf);
+ }
+
+ if (offset >= len_avail)
+ {
+ /* Done. Get rid of the obstack. */
+ obstack_free (&obstack, NULL);
+ buf = NULL;
+ len_avail = 0;
+ return 0;
+ }
+
+ if (len > len_avail - offset)
+ len = len_avail - offset;
+ memcpy (readbuf, buf + offset, len);
+
+ return len;
+ }
+
if (strcmp (annex, "processes") != 0)
return 0;
if (offset == 0)
{
if (len_avail != -1 && len_avail != 0)
- obstack_free (&obstack, NULL);
+ obstack_free (&obstack, NULL);
len_avail = 0;
buf = NULL;
obstack_init (&obstack);
dirp = opendir ("/proc");
if (dirp)
- {
- struct dirent *dp;
- while ((dp = readdir (dirp)) != NULL)
- {
- struct stat statbuf;
- char procentry[sizeof ("/proc/4294967295")];
-
- if (!isdigit (dp->d_name[0])
- || NAMELEN (dp) > sizeof ("4294967295") - 1)
- continue;
-
- sprintf (procentry, "/proc/%s", dp->d_name);
- if (stat (procentry, &statbuf) == 0
- && S_ISDIR (statbuf.st_mode))
- {
- char *pathname;
- FILE *f;
- char cmd[MAXPATHLEN + 1];
- struct passwd *entry;
-
- pathname = xstrprintf ("/proc/%s/cmdline", dp->d_name);
- entry = getpwuid (statbuf.st_uid);
-
- if ((f = fopen (pathname, "r")) != NULL)
- {
- size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
- if (len > 0)
- {
- int i;
- for (i = 0; i < len; i++)
- if (cmd[i] == '\0')
- cmd[i] = ' ';
- cmd[len] = '\0';
-
- obstack_xml_printf (
- &obstack,
- "<item>"
- "<column name=\"pid\">%s</column>"
- "<column name=\"user\">%s</column>"
- "<column name=\"command\">%s</column>"
- "</item>",
- dp->d_name,
- entry ? entry->pw_name : "?",
- cmd);
- }
- fclose (f);
- }
-
- xfree (pathname);
- }
- }
-
- closedir (dirp);
- }
+ {
+ struct dirent *dp;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ struct stat statbuf;
+ char procentry[sizeof ("/proc/4294967295")];
+
+ if (!isdigit (dp->d_name[0])
+ || NAMELEN (dp) > sizeof ("4294967295") - 1)
+ continue;
+
+ sprintf (procentry, "/proc/%s", dp->d_name);
+ if (stat (procentry, &statbuf) == 0
+ && S_ISDIR (statbuf.st_mode))
+ {
+ char *pathname;
+ FILE *f;
+ char cmd[MAXPATHLEN + 1];
+ struct passwd *entry;
+
+ pathname = xstrprintf ("/proc/%s/cmdline", dp->d_name);
+ entry = getpwuid (statbuf.st_uid);
+
+ if ((f = fopen (pathname, "r")) != NULL)
+ {
+ size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
+
+ if (len > 0)
+ {
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (cmd[i] == '\0')
+ cmd[i] = ' ';
+ cmd[len] = '\0';
+
+ obstack_xml_printf (
+ &obstack,
+ "<item>"
+ "<column name=\"pid\">%s</column>"
+ "<column name=\"user\">%s</column>"
+ "<column name=\"command\">%s</column>"
+ "</item>",
+ dp->d_name,
+ entry ? entry->pw_name : "?",
+ cmd);
+ }
+ fclose (f);
+ }
+
+ xfree (pathname);
+ }
+ }
+
+ closedir (dirp);
+ }
obstack_grow_str0 (&obstack, "</osdata>\n");
buf = obstack_finish (&obstack);
{
if (!lwp->stopped)
{
- int pid, status;
ptid_t ptid = lwp->ptid;
if (debug_linux_nat)
if (debug_linux_nat)
{
if (find_thread_ptid (lwp->ptid)->stop_requested)
- fprintf_unfiltered (gdb_stdlog, "\
-LNSL: already stopped/stop_requested %s\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "LNSL: already stopped/stop_requested %s\n",
target_pid_to_str (lwp->ptid));
else
- fprintf_unfiltered (gdb_stdlog, "\
-LNSL: already stopped/no stop_requested yet %s\n",
+ fprintf_unfiltered (gdb_stdlog,
+ "LNSL: already stopped/no "
+ "stop_requested yet %s\n",
target_pid_to_str (lwp->ptid));
}
}
for (;;)
{
int n;
+
content = xrealloc (content, content_read + 1024);
n = fread (content + content_read, 1, 1024, f);
content_read += n;
make_cleanup (xfree, content);
p = strchr (content, '(');
- p = strchr (p, ')') + 2; /* skip ")" and a whitespace. */
+
+ /* 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. */
- p = strtok_r (p, " ", &ts);
- for (i = 0; i != 36; ++i)
+ if (p != NULL)
+ p = strtok_r (p, " ", &ts);
+ for (i = 0; p != NULL && i != 36; ++i)
p = strtok_r (NULL, " ", &ts);
- if (sscanf (p, "%d", &core) == 0)
+ if (p == NULL || sscanf (p, "%d", &core) == 0)
core = -1;
do_cleanups (back_to);
linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
{
struct lwp_info *info = find_lwp_pid (ptid);
+
if (info)
return info->core;
return -1;
t->to_mourn_inferior = linux_nat_mourn_inferior;
t->to_thread_alive = linux_nat_thread_alive;
t->to_pid_to_str = linux_nat_pid_to_str;
+ t->to_thread_name = linux_nat_thread_name;
t->to_has_thread_control = tc_schedlock;
t->to_thread_address_space = linux_nat_thread_address_space;
t->to_stopped_by_watchpoint = linux_nat_stopped_by_watchpoint;
void
_initialize_linux_nat (void)
{
- sigset_t mask;
-
add_info ("proc", 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.\n\