From bba91f717b7779f39d71282835cceaaeda7ef588 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Thu, 8 Dec 2022 01:03:58 -0600
Subject: [PATCH] Fix multi thread bug in AIX

---
 gdb/aix-thread.c     | 149 ++++++++++++++++---------------------------
 gdb/rs6000-aix-nat.c |  66 ++++++++++++++++++-
 2 files changed, 118 insertions(+), 97 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index e556c153576..6e6f8619b64 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -508,14 +508,13 @@ pdc_read_data (pthdb_user_t user_current_pid, void *buf,
   /* This is needed to eliminate the dependency of current thread
      which is null so that thread reads the correct target memory.  */
   {
-    scoped_restore_current_thread restore_current_thread;
+    scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
     /* Before the first inferior is added, we pass inferior_ptid.pid ()
        from pd_enable () which is 0.  There is no need to switch threads
        during first initialisation.  In the rest of the callbacks the
        current thread needs to be correct.  */
     if (user_current_pid != 0)
-      switch_to_thread (current_inferior ()->process_target (),
-			ptid_t (user_current_pid));
+      inferior_ptid = ptid_t (user_current_pid);
     status = target_read_memory (addr, (gdb_byte *) buf, len);
   }
   ret = status == 0 ? PDC_SUCCESS : PDC_FAILURE;
@@ -639,36 +638,24 @@ pcmp (const void *p1v, const void *p2v)
   return p1->pthid < p2->pthid ? -1 : p1->pthid > p2->pthid;
 }
 
-/* iterate_over_threads() callback for counting GDB threads.
+/* iterate_over_threads() callback for counting GDB threads.  */
 
-   Do not count the main thread (whose tid is zero).  This matches
-   the list of threads provided by the pthreaddebug library, which
-   does not include that main thread either, and thus allows us
-   to compare the two lists.  */
 
 static int
 giter_count (struct thread_info *thread, void *countp)
 {
-  if (PD_TID (thread->ptid))
-    (*(int *) countp)++;
+  (*(int *) countp)++;
   return 0;
 }
 
-/* iterate_over_threads() callback for accumulating GDB thread pids.
-
-   Do not include the main thread (whose tid is zero).  This matches
-   the list of threads provided by the pthreaddebug library, which
-   does not include that main thread either, and thus allows us
-   to compare the two lists.  */
+/* iterate_over_threads() callback for accumulating GDB thread pids.  */
 
 static int
 giter_accum (struct thread_info *thread, void *bufp)
 {
-  if (PD_TID (thread->ptid))
-    {
-      **(struct thread_info ***) bufp = thread;
-      (*(struct thread_info ***) bufp)++;
-    }
+  **(struct thread_info ***) bufp = thread;
+  (*(struct thread_info ***) bufp)++;
+    
   return 0;
 }
 
@@ -703,30 +690,6 @@ gcmp (const void *t1v, const void *t2v)
   return ptid_cmp (t1->ptid, t2->ptid);
 }
 
-/* Search through the list of all kernel threads for the thread
-   that has stopped on a SIGTRAP signal, and return its TID.
-   Return 0 if none found.  */
-
-static pthdb_tid_t
-get_signaled_thread (int pid)
-{
-  struct thrdsinfo64 thrinf;
-  tid_t ktid = 0;
-
-  while (1)
-    {
-      if (getthrds (pid, &thrinf,
-		    sizeof (thrinf), &ktid, 1) != 1)
-	break;
-
-      if (thrinf.ti_cursig == SIGTRAP)
-	return thrinf.ti_tid;
-    }
-
-  /* Didn't find any thread stopped on a SIGTRAP signal.  */
-  return 0;
-}
-
 /* Synchronize GDB's thread list with libpthdebug's.
 
    There are some benefits of doing this every time the inferior stops:
@@ -740,8 +703,8 @@ get_signaled_thread (int pid)
      - simplifies the demands placed on libpthdebug, which seems to
        have difficulty with certain call patterns */
 
-static void
-sync_threadlists (int pid)
+static ptid_t 
+sync_threadlists (ptid_t ptid)
 {
   int cmd, status;
   int pcount, psize, pi, gcount, gi;
@@ -750,6 +713,15 @@ sync_threadlists (int pid)
   pthdb_pthread_t pdtid;
   pthread_t pthid;
   pthdb_tid_t tid;
+  process_stratum_target *proc_target
+	= current_inferior ()->process_target ();
+  thread_info *tp;
+  pid_t pid = ptid.pid ();
+
+  /* This ptid should hold the ptid of a new thread 
+     or return the incoming ptid incase of delete thread.  */
+
+  ptid_t post_sync_ptid = ptid;
 
   /* Accumulate an array of libpthdebug threads sorted by pthread id.  */
 
@@ -810,12 +782,10 @@ sync_threadlists (int pid)
 	  priv->pdtid = pbuf[pi].pdtid;
 	  priv->tid = pbuf[pi].tid;
 
-	  process_stratum_target *proc_target
-	    = current_inferior ()->process_target ();
 	  thread = add_thread_with_info (proc_target,
-					 ptid_t (pid, 0, pbuf[pi].pthid),
+					 ptid_t (pid, pbuf[pi].tid, pbuf[pi].pthid),
 					 priv);
-
+	  post_sync_ptid = thread->ptid;
 	  pi++;
 	}
       else
@@ -823,7 +793,7 @@ sync_threadlists (int pid)
 	  ptid_t pptid, gptid;
 	  int cmp_result;
 
-	  pptid = ptid_t (pid, 0, pbuf[pi].pthid);
+	  pptid = ptid_t (pid, pbuf[pi].tid, pbuf[pi].pthid);
 	  gptid = gbuf[gi]->ptid;
 	  pdtid = pbuf[pi].pdtid;
 	  tid = pbuf[pi].tid;
@@ -841,15 +811,31 @@ sync_threadlists (int pid)
 	    }
 	  else if (cmp_result > 0)
 	    {
-	      delete_thread (gbuf[gi]);
-	      gi++;
+	      if (gptid.is_pid ())
+		{
+		  gdb_assert (gptid.pid () == pptid.pid ());
+		  thread_change_ptid (proc_target, gptid, pptid);
+		  aix_thread_info *priv = new aix_thread_info;
+		  priv->pdtid = pbuf[pi].pdtid;
+		  priv->tid = pbuf[pi].tid;
+		  tp = find_thread_ptid (proc_target, pptid);
+		  tp->priv.reset (priv);
+		  pi++;
+		  gi++;
+		  post_sync_ptid = pptid;
+		}
+	      else
+		{
+		  delete_thread (gbuf[gi]);
+		  gi++;
+		}
 	    }
 	  else
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
 	      thread = add_thread (proc_target, pptid);
-
+	      post_sync_ptid = pptid;	
 	      aix_thread_info *priv = new aix_thread_info;
 	      thread->priv.reset (priv);
 	      priv->pdtid = pdtid;
@@ -861,18 +847,7 @@ sync_threadlists (int pid)
 
   xfree (pbuf);
   xfree (gbuf);
-}
-
-/* Iterate_over_threads() callback for locating a thread, using
-   the TID of its associated kernel thread.  */
-
-static int
-iter_tid (struct thread_info *thread, void *tidp)
-{
-  const pthdb_tid_t tid = *(pthdb_tid_t *)tidp;
-  aix_thread_info *priv = get_aix_thread_info (thread);
-
-  return priv->tid == tid;
+  return post_sync_ptid;
 }
 
 /* Synchronize libpthdebug's state with the inferior and with GDB,
@@ -881,33 +856,23 @@ iter_tid (struct thread_info *thread, void *tidp)
    return a pid-only ptid with PID.  */
 
 static ptid_t
-pd_update (int pid)
+pd_update (ptid_t ptid)
 {
   int status;
-  ptid_t ptid;
   pthdb_tid_t tid;
   struct thread_info *thread = NULL;
+  ptid_t post_sync_ptid;
 
   if (!pd_active)
-    return ptid_t (pid);
+    return ptid;
 
   status = pthdb_session_update (pd_session);
   if (status != PTHDB_SUCCESS)
-    return ptid_t (pid);
+    return ptid;
 
-  sync_threadlists (pid);
+  post_sync_ptid = sync_threadlists (ptid);
 
-  /* Define "current thread" as one that just received a trap signal.  */
-
-  tid = get_signaled_thread (pid);
-  if (tid != 0)
-    thread = iterate_over_threads (iter_tid, &tid);
-  if (!thread)
-    ptid = ptid_t (pid);
-  else
-    ptid = thread->ptid;
-
-  return ptid;
+  return post_sync_ptid;
 }
 
 /* Try to start debugging threads in the current process.
@@ -915,19 +880,19 @@ pd_update (int pid)
    for that thread.  Otherwise, return a ptid-only ptid using PID.  */
 
 static ptid_t
-pd_activate (int pid)
+pd_activate (ptid_t ptid)
 {
   int status;
 		
-  status = pthdb_session_init (pid, arch64 ? PEM_64BIT : PEM_32BIT,
+  status = pthdb_session_init (ptid.pid (), arch64 ? PEM_64BIT : PEM_32BIT,
 			       PTHDB_FLAG_REGS, &pd_callbacks, 
 			       &pd_session);
   if (status != PTHDB_SUCCESS)
     {
-      return ptid_t (pid);
+      return ptid;
     }
   pd_active = 1;
-  return pd_update (pid);
+  return pd_update (ptid);
 }
 
 /* Undo the effects of pd_activate().  */
@@ -983,7 +948,7 @@ pd_enable (void)
   /* If we're debugging a core file or an attached inferior, the
      pthread library may already have been initialized, so try to
      activate thread debugging.  */
-  pd_activate (inferior_ptid.pid ());
+  pd_activate (inferior_ptid);
 }
 
 /* Undo the effects of pd_enable().  */
@@ -1091,10 +1056,6 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   if (ptid.pid () == -1)
     return ptid_t (-1);
 
-  /* The target beneath does not deal with threads, so it should only return
-     pid-only ptids.  */
-  gdb_assert (ptid.is_pid ());
-
   /* Check whether libpthdebug might be ready to be initialized.  */
   if (!pd_active && status->kind () == TARGET_WAITKIND_STOPPED
       && status->sig () == GDB_SIGNAL_TRAP)
@@ -1106,10 +1067,10 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
 
       if (regcache_read_pc (regcache)
 	  - gdbarch_decr_pc_after_break (gdbarch) == pd_brk_addr)
-	return pd_activate (ptid.pid ());
+	return pd_activate (ptid);
     }
 
-  return pd_update (ptid.pid ());
+  return pd_update (ptid);
 }
 
 /* Record that the 64-bit general-purpose registers contain VALS.  */
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 2ac1f6e70b6..fe7ca4f3f2a 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -99,6 +99,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  std::string pid_to_str (ptid_t) override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -619,6 +621,64 @@ rs6000_nat_target::xfer_partial (enum target_object object,
     }
 }
 
+/* Search through the list of all kernel threads for the thread
+   that has stopped on a SIGTRAP or SIGINT signal, and return
+   its TID.  Return 0 if none found.  */
+
+static tid_t
+get_signaled_thread_rs6000 (int pid)
+{
+  struct thrdsinfo64 thrinf;
+  tid_t ktid = 0;
+
+  while (1)
+    {
+      if (getthrds (pid, &thrinf,
+                    sizeof (thrinf), &ktid, 1) != 1)
+        break;
+
+      if (thrinf.ti_cursig != 0)
+        return thrinf.ti_tid;
+    }
+
+  /* Didn't find any thread stopped on a SIGTRAP signal.  */
+  return 0;
+}
+
+/* If my process is pthreaded I need to return that ptid else ptid_t
+   (pid).  */
+
+static ptid_t
+find_the_return_ptid (pid_t pid)
+{
+  ptid_t ptid = ptid_t (pid);
+  process_stratum_target *proc_target
+        = current_inferior ()->process_target ();
+  inferior *inf = find_inferior_pid (proc_target, pid);
+  thread_info *tp = find_thread_ptid (inf, ptid_t (pid));
+  if (tp == nullptr)
+    for (thread_info *tp1 : inf->threads ())
+       if (tp1->ptid.lwp () == get_signaled_thread_rs6000 (pid))
+         return tp1->ptid;
+  return ptid;
+}
+
+/* Returning "thread" or "process" info as control comes here 
+   during a process switch in multi process debugging.  This 
+   is needed for "info threads" command as a process can be
+   threaded or non threaded in multi process case.  */
+
+std::string
+rs6000_nat_target::pid_to_str (ptid_t ptid)
+{
+  if (ptid.tid () != 0)
+    return string_printf (_("Thread %s"), pulongest (ptid.tid ()));
+
+  else
+    return string_printf (_("Process %s"), pulongest (ptid.pid ()));
+}
+
+
 /* Wait for the child specified by PTID to do something.  Return the
    process ID of the child, or MINUS_ONE_PTID in case of error; store
    the status in *OURSTATUS.  */
@@ -672,7 +732,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	      if (parent_pid > 0)
 		{
 		  ourstatus->set_forked (ptid_t (pid));
-		  return ptid_t (parent_pid);
+		  return find_the_return_ptid (parent_pid);
 		}
 	      aix_remember_child (pid);
 	    }
@@ -687,7 +747,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	      if (child_pid > 0)
 		{
 		  ourstatus->set_forked (ptid_t (child_pid));
-		  return ptid_t (pid);
+		  return find_the_return_ptid (pid);
 		}
 	      aix_remember_parent (pid);
 	    }
@@ -712,7 +772,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
   else
     *ourstatus = host_status_to_waitstatus (status);
 
-  return ptid_t (pid);
+  return find_the_return_ptid (pid);
 }
 
 
-- 
2.31.1

