static void block_child_signals (sigset_t *prev_mask);
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 struct lwp_info *find_lwp_pid (ptid_t ptid);
+
\f
/* Trivial list manipulation functions to keep track of a list of
new stopped processes. */
parent_pid = ptid_get_pid (inferior_ptid);
child_pid = PIDGET (inferior_thread ()->pending_follow.value.related_pid);
+ if (!detach_fork)
+ linux_enable_event_reporting (pid_to_ptid (child_pid));
+
if (! follow_child)
{
/* We're already attached to the parent, by default. */
}
else
{
- struct fork_info *fp;
struct inferior *parent_inf, *child_inf;
+ struct lwp_info *lp;
+ struct cleanup *old_chain;
/* Add process to GDB's tables. */
child_inf = add_inferior (child_pid);
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
- /* Retain child fork in ptrace (stopped) state. */
- fp = find_fork_pid (child_pid);
- if (!fp)
- fp = add_fork (child_pid);
- fork_save_infrun_state (fp, 0);
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = ptid_build (child_pid, child_pid, 0);
+ add_thread (inferior_ptid);
+ lp = add_lwp (inferior_ptid);
+ lp->stopped = 1;
+
+ check_for_thread_db ();
+
+ do_cleanups (old_chain);
}
if (has_vforked)
{
struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
+ struct lwp_info *lp;
/* Before detaching from the parent, remove all breakpoints from it. */
remove_breakpoints ();
if (has_vforked)
{
+ struct lwp_info *parent_lwp;
+
linux_parent_pid = parent_pid;
+
+ /* Get rid of the inferior on the core side as well. */
+ inferior_ptid = null_ptid;
detach_inferior (parent_pid);
- }
- else if (!detach_fork)
- {
- struct fork_info *fp;
- /* Retain parent fork in ptrace (stopped) state. */
- fp = find_fork_pid (parent_pid);
- if (!fp)
- fp = add_fork (parent_pid);
- fork_save_infrun_state (fp, 0);
- /* Also add an entry for the child fork. */
- fp = find_fork_pid (child_pid);
- if (!fp)
- fp = add_fork (child_pid);
- fork_save_infrun_state (fp, 0);
+ /* Also get rid of all its lwps. We will detach from this
+ inferior soon-ish, but, we will still get an exit event
+ reported through waitpid when it exits. If we didn't get
+ rid of the lwps from our list, we would end up reporting
+ the inferior exit to the core, which would then try to
+ mourn a non-existing (from the core's perspective)
+ inferior. */
+ parent_lwp = find_lwp_pid (pid_to_ptid (parent_pid));
+ purge_lwp_list (GET_PID (parent_lwp->ptid));
+ linux_parent_pid = parent_pid;
}
- else
+ else if (detach_fork)
target_detach (NULL, 0);
inferior_ptid = ptid_build (child_pid, child_pid, 0);
+ add_thread (inferior_ptid);
+ lp = add_lwp (inferior_ptid);
+ lp->stopped = 1;
- linux_nat_switch_fork (inferior_ptid);
check_for_thread_db ();
}
return NULL;
}
-/* Update our internal state when changing from one fork (checkpoint,
- et cetera) to another indicated by NEW_PTID. We can only switch
- single-threaded applications, so we only create one new LWP, and
- the previous list is discarded. */
+/* 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
+ is discarded. */
void
linux_nat_switch_fork (ptid_t new_ptid)
{
struct lwp_info *lp;
- init_lwp_list ();
+ purge_lwp_list (GET_PID (inferior_ptid));
+
lp = add_lwp (new_ptid);
lp->stopped = 1;
- init_thread_list ();
- add_thread_silent (new_ptid);
+ /* This changes the thread's ptid while preserving the gdb thread
+ num. Also changes the inferior pid, while preserving the
+ inferior num. */
+ thread_change_ptid (inferior_ptid, new_ptid);
+
+ /* We've just told GDB core that the thread changed target id, but,
+ in fact, it really is a different thread, with different register
+ contents. */
+ registers_changed ();
}
/* Handle the exit of a single thread LP. */
static void
exit_lwp (struct lwp_info *lp)
{
- struct thread_info *th = find_thread_pid (lp->ptid);
+ struct thread_info *th = find_thread_ptid (lp->ptid);
if (th)
{
have the last signal recorded in
thread_info->stop_signal. */
- struct thread_info *tp = find_thread_pid (lp->ptid);
+ struct thread_info *tp = find_thread_ptid (lp->ptid);
signo = tp->stop_signal;
}
{
if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
{
- struct thread_info *tp = find_thread_pid (lp->ptid);
+ struct thread_info *tp = find_thread_ptid (lp->ptid);
if (tp->stop_signal != TARGET_SIGNAL_0
&& signal_pass_state (tp->stop_signal))
*status = W_STOPCODE (target_signal_to_host (tp->stop_signal));
ourstatus->value.related_pid = ptid_build (new_pid, new_pid, 0);
+ if (event == PTRACE_EVENT_FORK
+ && linux_fork_checkpointing_p (GET_PID (lp->ptid)))
+ {
+ struct fork_info *fp;
+
+ /* Handle checkpointing by linux-fork.c here as a special
+ case. We don't want the follow-fork-mode or 'catch fork'
+ to interfere with this. */
+
+ /* This won't actually modify the breakpoint list, but will
+ physically remove the breakpoints from the child. */
+ detach_breakpoints (new_pid);
+
+ /* Retain child fork in ptrace (stopped) state. */
+ fp = find_fork_pid (new_pid);
+ if (!fp)
+ fp = add_fork (new_pid);
+
+ /* Report as spurious, so that infrun doesn't want to follow
+ this fork. We're actually doing an infcall in
+ linux-fork.c. */
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ linux_enable_event_reporting (pid_to_ptid (new_pid));
+
+ /* Report the stop to the core. */
+ return 0;
+ }
+
if (event == PTRACE_EVENT_FORK)
ourstatus->kind = TARGET_WAITKIND_FORKED;
else if (event == PTRACE_EVENT_VFORK)
if (event == PTRACE_EVENT_EXEC)
{
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: Got exec event from LWP %ld\n",
+ GET_LWP (lp->ptid));
+
ourstatus->kind = TARGET_WAITKIND_EXECD;
ourstatus->value.execd_pathname
= xstrdup (linux_child_pid_to_exec_file (pid));
return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf,
offset, len);
+ /* The target is connected but no live inferior is selected. Pass
+ this request down to a lower stratum (e.g., the executable
+ file). */
+ if (object == TARGET_OBJECT_MEMORY && ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
old_chain = save_inferior_ptid ();
if (is_lwp (inferior_ptid))
if (info_verbose)
{
fprintf_filtered (gdb_stdout,
- "Save segment, %lld bytes at 0x%s (%c%c%c)",
- size, paddr_nz (addr),
+ "Save segment, %lld bytes at %s (%c%c%c)",
+ size, paddress (target_gdbarch, addr),
read ? 'r' : ' ',
write ? 'w' : ' ', exec ? 'x' : ' ');
if (filename[0])
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
unsigned long lwp = ptid_get_lwp (ptid);
- struct regcache *regcache = get_thread_regcache (ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = target_gdbarch;
+ struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
const struct regset *regset;
int core_regset_p;
struct cleanup *old_chain;
cleanup = make_cleanup_fclose (procfile);
printf_filtered (_("Mapped address spaces:\n\n"));
- if (gdbarch_addr_bit (current_gdbarch) == 32)
+ if (gdbarch_addr_bit (target_gdbarch) == 32)
{
printf_filtered ("\t%10s %10s %10s %10s %7s\n",
"Start Addr",
a generic local_address_string instead to print out
the addresses; that makes sense to me, too. */
- if (gdbarch_addr_bit (current_gdbarch) == 32)
+ if (gdbarch_addr_bit (target_gdbarch) == 32)
{
printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
(unsigned long) addr, /* FIXME: pr_addr */
return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
offset, len);
+ /* GDB calculates all the addresses in possibly larget width of the address.
+ Address width needs to be masked before its final use - either by
+ linux_proc_xfer_partial or inf_ptrace_xfer_partial.
+
+ Compare ADDR_BIT first to avoid a compiler warning on shift overflow. */
+
+ if (object == TARGET_OBJECT_MEMORY)
+ {
+ int addr_bit = gdbarch_addr_bit (target_gdbarch);
+
+ if (addr_bit < (sizeof (ULONGEST) * HOST_CHAR_BIT))
+ offset &= ((ULONGEST) 1 << addr_bit) - 1;
+ }
+
xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
offset, len);
if (xfer != 0)
/* True if we want to support multi-process. To be removed when GDB
supports multi-exec. */
-int linux_multi_process = 0;
+int linux_multi_process = 1;
static int
linux_nat_supports_multi_process (void)
if (debug_linux_nat)
{
- if (find_thread_pid (lwp->ptid)->stop_requested)
+ if (find_thread_ptid (lwp->ptid)->stop_requested)
fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/stop_requested %s\n",
target_pid_to_str (lwp->ptid));