diff options
author | Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com> | 2022-11-15 13:36:18 +0100 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2022-11-15 13:40:08 +0100 |
commit | c7d0901842fc1b4391e1d7663608b7b43edd9fde (patch) | |
tree | b5aee4911ef80dabd6b20316ce83eb5079516a52 /gdb/rs6000-aix-nat.c | |
parent | 8148339a741b37df6df3c4b3c4a7b9e812a79be7 (diff) | |
download | gdb-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.c | 181 |
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 |