aboutsummaryrefslogtreecommitdiff
path: root/gdb/rs6000-aix-nat.c
diff options
context:
space:
mode:
authorAditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>2022-11-15 13:36:18 +0100
committerUlrich Weigand <ulrich.weigand@de.ibm.com>2022-11-15 13:40:08 +0100
commitc7d0901842fc1b4391e1d7663608b7b43edd9fde (patch)
treeb5aee4911ef80dabd6b20316ce83eb5079516a52 /gdb/rs6000-aix-nat.c
parent8148339a741b37df6df3c4b3c4a7b9e812a79be7 (diff)
downloadgdb-c7d0901842fc1b4391e1d7663608b7b43edd9fde.zip
gdb-c7d0901842fc1b4391e1d7663608b7b43edd9fde.tar.gz
gdb-c7d0901842fc1b4391e1d7663608b7b43edd9fde.tar.bz2
Enable multi-process debugging for AIX
This patch adds multi-process debugging feature in AIX. Till now AIX supported debugging only one inferior at a time, now we can be able to debug multi process. Users can use set follow fork mode in child or parent and set detach on fork on or off to enable/disable simultaneous debugging of parent/child.
Diffstat (limited to 'gdb/rs6000-aix-nat.c')
-rw-r--r--gdb/rs6000-aix-nat.c181
1 files changed, 174 insertions, 7 deletions
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index a295781..2ac1f6e 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -54,6 +54,10 @@
#include <sys/ldr.h>
#include <sys/systemcfg.h>
+/* Header files for getting ppid in AIX of a child process. */
+#include <procinfo.h>
+#include <sys/types.h>
+
/* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
debugging 32-bit and 64-bit processes. Define a typedef and macros for
accessing fields in the appropriate structures. */
@@ -91,10 +95,13 @@ public:
ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
+ /* Fork detection related functions, For adding multi process debugging
+ support. */
+ void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
+
protected:
- void post_startup_inferior (ptid_t ptid) override
- { /* Nothing. */ }
+ void post_startup_inferior (ptid_t ptid) override;
private:
enum target_xfer_status
@@ -107,6 +114,84 @@ private:
static rs6000_nat_target the_rs6000_nat_target;
+/* The below declaration is to track number of times, parent has
+ reported fork event before its children. */
+
+static std::list<pid_t> aix_pending_parent;
+
+/* The below declaration is for a child process event that
+ is reported before its corresponding parent process in
+ the event of a fork (). */
+
+static std::list<pid_t> aix_pending_children;
+
+static void
+aix_remember_child (pid_t pid)
+{
+ aix_pending_children.push_front (pid);
+}
+
+static void
+aix_remember_parent (pid_t pid)
+{
+ aix_pending_parent.push_front (pid);
+}
+
+/* This function returns a parent of a child process. */
+
+static pid_t
+find_my_aix_parent (pid_t child_pid)
+{
+ struct procsinfo ProcessBuffer1;
+
+ if (getprocs (&ProcessBuffer1, sizeof (ProcessBuffer1),
+ NULL, 0, &child_pid, 1) != 1)
+ return 0;
+ else
+ return ProcessBuffer1.pi_ppid;
+}
+
+/* In the below function we check if there was any child
+ process pending. If it exists we return it from the
+ list, otherwise we return a null. */
+
+static pid_t
+has_my_aix_child_reported (pid_t parent_pid)
+{
+ pid_t child = 0;
+ auto it = std::find_if (aix_pending_children.begin (),
+ aix_pending_children.end (),
+ [=] (pid_t child_pid)
+ {
+ return find_my_aix_parent (child_pid) == parent_pid;
+ });
+ if (it != aix_pending_children.end ())
+ {
+ child = *it;
+ aix_pending_children.erase (it);
+ }
+ return child;
+}
+
+/* In the below function we check if there was any parent
+ process pending. If it exists we return it from the
+ list, otherwise we return a null. */
+
+static pid_t
+has_my_aix_parent_reported (pid_t child_pid)
+{
+ pid_t my_parent = find_my_aix_parent (child_pid);
+ auto it = std::find (aix_pending_parent.begin (),
+ aix_pending_parent.end (),
+ my_parent);
+ if (it != aix_pending_parent.end ())
+ {
+ aix_pending_parent.erase (it);
+ return my_parent;
+ }
+ return 0;
+}
+
/* Given REGNO, a gdb register number, return the corresponding
number suitable for use as a ptrace() parameter. Return -1 if
there's no suitable mapping. Also, set the int pointed to by
@@ -187,6 +272,47 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
return ret;
}
+void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
+{
+
+ /* In AIX to turn on multi process debugging in ptrace
+ PT_MULTI is the option to be passed,
+ with the process ID which can fork () and
+ the data parameter [fourth parameter] must be 1. */
+
+ if (!ARCH64 ())
+ rs6000_ptrace32 (PT_MULTI, ptid.pid(), 0, 1, 0);
+ else
+ rs6000_ptrace64 (PT_MULTI, ptid.pid(), 0, 1, 0);
+}
+
+void
+rs6000_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
+ target_waitkind fork_kind, bool follow_child,
+ bool detach_fork)
+{
+
+ /* Once the fork event is detected the infrun.c code
+ calls the target_follow_fork to take care of
+ follow child and detach the child activity which is
+ done using the function below. */
+
+ inf_ptrace_target::follow_fork (child_inf, child_ptid, fork_kind,
+ follow_child, detach_fork);
+
+ /* If we detach fork and follow child we do not want the child
+ process to geneate events that ptrace can trace. Hence we
+ detach it. */
+
+ if (detach_fork && !follow_child)
+ {
+ if (ARCH64 ())
+ rs6000_ptrace64 (PT_DETACH, child_ptid.pid (), 0, 0, 0);
+ else
+ rs6000_ptrace32 (PT_DETACH, child_ptid.pid (), 0, 0, 0);
+ }
+}
+
/* Fetch register REGNO from the inferior. */
static void
@@ -504,7 +630,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
pid_t pid;
int status, save_errno;
- do
+ while (1)
{
set_sigint_trap ();
@@ -529,17 +655,58 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
/* Ignore terminated detached child processes. */
if (!WIFSTOPPED (status) && find_inferior_pid (this, pid) == nullptr)
- pid = -1;
+ continue;
+
+ /* Check for a fork () event. */
+ if ((status & 0xff) == W_SFWTED)
+ {
+ /* Checking whether it is a parent or a child event. */
+
+ /* If the event is a child we check if there was a parent
+ event recorded before. If yes we got the parent child
+ relationship. If not we push this child and wait for
+ the next fork () event. */
+ if (find_inferior_pid (this, pid) == nullptr)
+ {
+ pid_t parent_pid = has_my_aix_parent_reported (pid);
+ if (parent_pid > 0)
+ {
+ ourstatus->set_forked (ptid_t (pid));
+ return ptid_t (parent_pid);
+ }
+ aix_remember_child (pid);
+ }
+
+ /* If the event is a parent we check if there was a child
+ event recorded before. If yes we got the parent child
+ relationship. If not we push this parent and wait for
+ the next fork () event. */
+ else
+ {
+ pid_t child_pid = has_my_aix_child_reported (pid);
+ if (child_pid > 0)
+ {
+ ourstatus->set_forked (ptid_t (child_pid));
+ return ptid_t (pid);
+ }
+ aix_remember_parent (pid);
+ }
+ continue;
+ }
+
+ break;
}
- while (pid == -1);
/* AIX has a couple of strange returns from wait(). */
/* stop after load" status. */
if (status == 0x57c)
ourstatus->set_loaded ();
- /* signal 0. I have no idea why wait(2) returns with this status word. */
- else if (status == 0x7f)
+ /* 0x7f is signal 0. 0x17f and 0x137f are status returned
+ if we follow parent, a switch is made to a child post parent
+ execution and child continues its execution [user switches
+ to child and presses continue]. */
+ else if (status == 0x7f || status == 0x17f || status == 0x137f)
ourstatus->set_spurious ();
/* A normal waitstatus. Let the usual macros deal with it. */
else