return 0;
}
+/* Return the ptrace options that we want to try to enable. */
+
+static int
+linux_nat_ptrace_options (int attached)
+{
+ int options = 0;
+
+ if (!attached)
+ options |= PTRACE_O_EXITKILL;
+
+ options |= (PTRACE_O_TRACESYSGOOD
+ | PTRACE_O_TRACEVFORKDONE
+ | PTRACE_O_TRACEVFORK
+ | PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEEXEC);
+
+ return options;
+}
+
/* Initialize ptrace warnings and check for supported ptrace
features given PID.
static void
linux_init_ptrace (pid_t pid, int attached)
{
- linux_enable_event_reporting (pid, attached);
+ int options = linux_nat_ptrace_options (attached);
+
+ linux_enable_event_reporting (pid, options);
linux_ptrace_init_warnings ();
}
attach_proc_task_lwp_callback);
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
}
/* Get pending status of LP. */
if (target_can_async_p ())
{
- target_async (inferior_event_handler, 0);
+ target_async (1);
/* Tell the event loop we have something to process. */
async_file_mark ();
}
if (resume_many)
iterate_over_lwps (ptid, linux_nat_resume_callback, lp);
- linux_resume_one_lwp (lp, step, signo);
-
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: %s %s, %s (resume event thread)\n",
step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
- target_pid_to_str (ptid),
+ target_pid_to_str (lp->ptid),
(signo != GDB_SIGNAL_0
? strsignal (gdb_signal_to_host (signo)) : "0"));
+ linux_resume_one_lwp (lp, step, signo);
+
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
}
/* Send a signal to an LWP. */
add_thread (new_lp->ptid);
}
+ /* Even if we're stopping the thread for some reason
+ internal to this module, from the user/frontend's
+ perspective, this new thread is running. */
+ set_running (new_lp->ptid, 1);
if (!stopping)
{
- set_running (new_lp->ptid, 1);
set_executing (new_lp->ptid, 1);
/* thread_db_attach_lwp -> lin_lwp_attach_lwp forced
resume_stop. */
if (lp->must_set_ptrace_flags)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+ int options = linux_nat_ptrace_options (inf->attach_flag);
- linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+ linux_enable_event_reporting (ptid_get_lwp (lp->ptid), options);
lp->must_set_ptrace_flags = 0;
}
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "SWC: Delayed SIGSTOP caught for %s.\n",
+ "SWC: Expected SIGSTOP caught for %s.\n",
target_pid_to_str (lp->ptid));
/* Reset SIGNALLED only after the stop_wait_callback call
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "CSBB: Push back software "
- "breakpoint for %s\n",
+ "CSBB: %s stopped by software "
+ "breakpoint\n",
target_pid_to_str (lp->ptid));
/* Back up the PC if necessary. */
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "CSBB: Push back hardware "
- "breakpoint/watchpoint for %s\n",
+ "CSBB: %s stopped by hardware "
+ "breakpoint/watchpoint\n",
target_pid_to_str (lp->ptid));
lp->stop_pc = pc;
lp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
return 1;
}
+ else if (siginfo.si_code == TRAP_TRACE)
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "CSBB: %s stopped by trace\n",
+ target_pid_to_str (lp->ptid));
+ }
}
}
#else
breakpoint instruction. */
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "CB: Push back software breakpoint for %s\n",
+ "CSBB: %s stopped by software breakpoint\n",
target_pid_to_str (lp->ptid));
/* Back up the PC if necessary. */
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "CB: Push back hardware breakpoint for %s\n",
+ "CSBB: stopped by hardware breakpoint %s\n",
target_pid_to_str (lp->ptid));
lp->stop_pc = pc;
if (WIFSTOPPED (status) && lp->must_set_ptrace_flags)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+ int options = linux_nat_ptrace_options (inf->attach_flag);
- linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+ linux_enable_event_reporting (ptid_get_lwp (lp->ptid), options);
lp->must_set_ptrace_flags = 0;
}
if (lp->signalled
&& WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
{
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLW: Delayed SIGSTOP caught for %s.\n",
- target_pid_to_str (lp->ptid));
-
lp->signalled = 0;
- if (lp->last_resume_kind != resume_stop)
+ if (lp->last_resume_kind == resume_stop)
{
- /* This is a delayed SIGSTOP. */
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: resume_stop SIGSTOP caught for %s.\n",
+ target_pid_to_str (lp->ptid));
+ }
+ else
+ {
+ /* This is a delayed SIGSTOP. Filter out the event. */
- linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
+ "LLW: %s %s, 0, 0 (discard delayed SIGSTOP)\n",
lp->step ?
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (lp->ptid));
+ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
gdb_assert (lp->resumed);
-
- /* Discard the event. */
return NULL;
}
}
return linux_thread_alive (ptid);
}
+/* Implement the to_update_thread_list target method for this
+ target. */
+
+static void
+linux_nat_update_thread_list (struct target_ops *ops)
+{
+ if (linux_supports_traceclone ())
+ {
+ /* With support for clone events, we add/delete threads from the
+ list as clone/exit events are processed, so just try deleting
+ exited threads still in the thread list. */
+ delete_exited_threads ();
+ }
+ else
+ prune_threads ();
+}
+
static char *
linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
static char *
linux_child_pid_to_exec_file (struct target_ops *self, int pid)
{
- static char buf[PATH_MAX];
- char name[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);
-
- return buf;
+ return linux_proc_pid_to_exec_file (pid);
}
/* Implement the to_xfer_partial interface for memory reads using the /proc
async_terminal_is_ours = 1;
}
-static void (*async_client_callback) (enum inferior_event_type event_type,
- void *context);
-static void *async_client_context;
-
/* SIGCHLD handler that serves two purposes: In non-stop/async mode,
so we notice when any child changes state, and notify the
event-loop; it allows us to use sigsuspend in linux_nat_wait_1
static void
handle_target_event (int error, gdb_client_data client_data)
{
- (*async_client_callback) (INF_REG_EVENT, async_client_context);
+ inferior_event_handler (INF_REG_EVENT, NULL);
}
/* Create/destroy the target events pipe. Returns previous state. */
/* target_async implementation. */
static void
-linux_nat_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context)
+linux_nat_async (struct target_ops *ops, int enable)
{
- if (callback != NULL)
+ if (enable)
{
- async_client_callback = callback;
- async_client_context = context;
if (!linux_async_pipe (1))
{
add_file_handler (linux_nat_event_pipe[0],
}
else
{
- async_client_callback = callback;
- async_client_context = context;
delete_file_handler (linux_nat_event_pipe[0]);
linux_async_pipe (0);
}
{
/* Unregister from the event loop. */
if (linux_nat_is_async_p (self))
- linux_nat_async (self, NULL, NULL);
+ linux_nat_async (self, 0);
if (linux_ops->to_close)
linux_ops->to_close (linux_ops);
t->to_kill = linux_nat_kill;
t->to_mourn_inferior = linux_nat_mourn_inferior;
t->to_thread_alive = linux_nat_thread_alive;
+ t->to_update_thread_list = linux_nat_update_thread_list;
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;
sigdelset (&suspend_mask, SIGCHLD);
sigemptyset (&blocked_mask);
-
- /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to
- support read-only process state. */
- linux_ptrace_set_additional_flags (PTRACE_O_TRACESYSGOOD
- | PTRACE_O_TRACEVFORKDONE
- | PTRACE_O_TRACEVFORK
- | PTRACE_O_TRACEFORK
- | PTRACE_O_TRACEEXEC);
}
\f