gdb/
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index f93ea9fe25aec508cf823b7a5d8ccd29fd4a1eee..f8d7a5c11141ba14bb380fcc71989e1b707314a1 100644 (file)
@@ -338,6 +338,12 @@ static int stop_callback (struct lwp_info *lp, void *data);
 
 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.  */
@@ -587,6 +593,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
     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. */
@@ -617,8 +626,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
        }
       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);
@@ -627,11 +637,16 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          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)
@@ -692,6 +707,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
     {
       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 ();
@@ -733,30 +749,33 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
 
       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 ();
     }
 
@@ -1073,22 +1092,30 @@ iterate_over_lwps (ptid_t filter,
   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.  */
@@ -1096,7 +1123,7 @@ linux_nat_switch_fork (ptid_t new_ptid)
 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)
     {
@@ -1426,7 +1453,7 @@ get_pending_status (struct lwp_info *lp, int *status)
             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;
        }
 
@@ -1455,7 +1482,7 @@ GPT: lwp %s had signal %s, but it is in no pass state\n",
     {
       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));
@@ -1815,6 +1842,34 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 
       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)
@@ -1892,6 +1947,11 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 
   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));
@@ -3285,6 +3345,12 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
     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))
@@ -3434,8 +3500,8 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
       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])
@@ -3484,8 +3550,8 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
   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;
@@ -3780,7 +3846,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 
          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",
@@ -3806,7 +3872,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
                 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 */
@@ -4284,7 +4350,7 @@ linux_nat_supports_non_stop (void)
 /* 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)
@@ -4515,7 +4581,7 @@ linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 
       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));
This page took 0.027345 seconds and 4 git commands to generate.