From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1158) id 1D7E33842AC0; Tue, 15 Nov 2022 12:41:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1D7E33842AC0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1668516064; bh=OO3EVH/ys59frJYVyVAq6Jp/BuEi0unhET8IVrfcdHA=; h=From:To:Subject:Date:From; b=bAakjweoaYptpBgNJq86OPuTOFB2kqodTYbZ5X8C82tbDg+6/LXi/+sWUF1pggdFK oQxjEw/G9IedVDFs5lvQE8ueO+y5vrnRLDoaJb937oJQIn+fiHqYKtBzdAqhBYgPm7 89FvwjmXwDcgIwcF43CE678lM73lV61y+u6Jiqic= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Ulrich Weigand To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Enable multi-process debugging for AIX X-Act-Checkin: binutils-gdb X-Git-Author: Aditya Vidyadhar Kamath X-Git-Refname: refs/heads/master X-Git-Oldrev: 8148339a741b37df6df3c4b3c4a7b9e812a79be7 X-Git-Newrev: c7d0901842fc1b4391e1d7663608b7b43edd9fde Message-Id: <20221115124104.1D7E33842AC0@sourceware.org> Date: Tue, 15 Nov 2022 12:41:04 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dc7d0901842fc= 1b4391e1d7663608b7b43edd9fde commit c7d0901842fc1b4391e1d7663608b7b43edd9fde Author: Aditya Vidyadhar Kamath Date: Tue Nov 15 13:36:18 2022 +0100 Enable multi-process debugging for AIX =20 This patch adds multi-process debugging feature in AIX. =20 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. Diff: --- gdb/rs6000-aix-nat.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 174 insertions(+), 7 deletions(-) diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c index a295781db31..2ac1f6e70b6 100644 --- a/gdb/rs6000-aix-nat.c +++ b/gdb/rs6000-aix-nat.c @@ -54,6 +54,10 @@ #include #include =20 +/* Header files for getting ppid in AIX of a child process. */ +#include +#include + /* 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: =20 ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) over= ride; =20 + /* Fork detection related functions, For adding multi process debugging + support. */ + void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) overr= ide; + protected: =20 - void post_startup_inferior (ptid_t ptid) override - { /* Nothing. */ } + void post_startup_inferior (ptid_t ptid) override; =20 private: enum target_xfer_status @@ -107,6 +114,84 @@ private: =20 static rs6000_nat_target the_rs6000_nat_target; =20 +/* The below declaration is to track number of times, parent has + reported fork event before its children. */ + +static std::list 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 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) !=3D 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 =3D 0; + auto it =3D std::find_if (aix_pending_children.begin (), + aix_pending_children.end (), + [=3D] (pid_t child_pid) + { + return find_my_aix_parent (child_pid) =3D=3D parent_pid; + }); + if (it !=3D aix_pending_children.end ()) + { + child =3D *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 =3D find_my_aix_parent (child_pid); + auto it =3D std::find (aix_pending_parent.begin (), + aix_pending_parent.end (), + my_parent); + if (it !=3D 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; } =20 +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. */ =20 static void @@ -504,7 +630,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_wai= tstatus *ourstatus, pid_t pid; int status, save_errno; =20 - do + while (1) { set_sigint_trap (); =20 @@ -529,17 +655,58 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_w= aitstatus *ourstatus, =20 /* Ignore terminated detached child processes. */ if (!WIFSTOPPED (status) && find_inferior_pid (this, pid) =3D=3D nul= lptr) - pid =3D -1; + continue; + + /* Check for a fork () event. */ + if ((status & 0xff) =3D=3D 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) =3D=3D nullptr) + { + pid_t parent_pid =3D 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 =3D 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 =3D=3D -1); =20 /* AIX has a couple of strange returns from wait(). */ =20 /* stop after load" status. */ if (status =3D=3D 0x57c) ourstatus->set_loaded (); - /* signal 0. I have no idea why wait(2) returns with this status word. = */ - else if (status =3D=3D 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 =3D=3D 0x7f || status =3D=3D 0x17f || status =3D=3D 0x13= 7f) ourstatus->set_spurious (); /* A normal waitstatus. Let the usual macros deal with it. */ else