)]}'
{
  "commit": "df5ad102009c41ab4dfadbb8cfb8c8b2a02a4f78",
  "tree": "d3e4ea03469af069618f83928fdc275f6d5bfa83",
  "parents": [
    "577d2167bbed078e99fe8b704f936be8ac7cf83d"
  ],
  "author": {
    "name": "Simon Marchi",
    "email": "simon.marchi@efficios.com",
    "time": "Wed Dec 01 09:40:03 2021 -0500"
  },
  "committer": {
    "name": "Simon Marchi",
    "email": "simon.marchi@efficios.com",
    "time": "Wed Dec 08 21:00:39 2021 -0500"
  },
  "message": "gdb, gdbserver: detach fork child when detaching from fork parent\n\nWhile working with pending fork events, I wondered what would happen if\nthe user detached an inferior while a thread of that inferior had a\npending fork event.  What happens with the fork child, which is\nptrace-attached by the GDB process (or by GDBserver), but not known to\nthe core?  Sure enough, neither the core of GDB or the target detach the\nchild process, so GDB (or GDBserver) just stays ptrace-attached to the\nprocess.  The result is that the fork child process is stuck, while you\nwould expect it to be detached and run.\n\nMake GDBserver detach of fork children it knows about.  That is done in\nthe generic handle_detach function.  Since a process_info already exists\nfor the child, we can simply call detach_inferior on it.\n\nGDB-side, make the linux-nat and remote targets detach of fork children\nknown because of pending fork events.  These pending fork events can be\nstored in:\n\n - thread_info::pending_waitstatus, if the core has consumed the event\n   but then saved it for later (for example, because it got the event\n   while stopping all threads, to present an all-stop stop on top of a\n   non-stop target)\n - thread_info::pending_follow: if we ran to a \"catch fork\" and we\n   detach at that moment\n\nAdditionally, pending fork events can be in target-specific fields:\n\n - For linux-nat, they can be in lwp_info::status and\n   lwp_info::waitstatus.\n - For the remote target, they could be stored as pending stop replies,\n   saved in `remote_state::notif_state::pending_event`, if not\n   acknowledged yet, or in `remote_state::stop_reply_queue`, if\n   acknowledged.  I followed the model of remove_new_fork_children for\n   this: call remote_notif_get_pending_events to process /\n   acknowledge any unacknowledged notification, then look through\n   stop_reply_queue.\n\nUpdate the gdb.threads/pending-fork-event.exp test (and rename it to\ngdb.threads/pending-fork-event-detach.exp) to try to detach the process\nwhile it is stopped with a pending fork event.  In order to verify that\nthe fork child process is correctly detached and resumes execution\noutside of GDB\u0027s control, make that process create a file in the test\noutput directory, and make the test wait $timeout seconds for that file\nto appear (it happens instantly if everything goes well).\n\nThis test catches a bug in linux-nat.c, also reported as PR 28512\n(\"waitstatus.h:300: internal-error: gdb_signal target_waitstatus::sig()\nconst: Assertion `m_kind \u003d\u003d TARGET_WAITKIND_STOPPED || m_kind \u003d\u003d\nTARGET_WAITKIND_SIGNALLED\u0027 failed.).  When detaching a thread with a\npending event, get_detach_signal unconditionally fetches the signal\nstored in the waitstatus (`tp-\u003epending_waitstatus ().sig ()`).  However,\nthat is only valid if the pending event is of type\nTARGET_WAITKIND_STOPPED, and this is now enforced using assertions (iit\nwould also be valid for TARGET_WAITKIND_SIGNALLED, but that would mean\nthe thread does not exist anymore, so we wouldn\u0027t be detaching it).  Add\na condition in get_detach_signal to access the signal number only if the\nwait status is of kind TARGET_WAITKIND_STOPPED, and use GDB_SIGNAL_0\ninstead (since the thread was not stopped with a signal to begin with).\n\nAdd another test, gdb.threads/pending-fork-event-ns.exp, specifically to\nverify that we consider events in pending stop replies in the remote\ntarget.  This test has many threads constantly forking, and we detach\nfrom the program while the program is executing.  That gives us some\nchance that we detach while a fork stop reply is stored in the remote\ntarget.  To verify that we correctly detach all fork children, we ask\nthe parent to exit by sending it a SIGUSR1 signal and have it write a\nfile to the filesystem before exiting.  Because the parent\u0027s main thread\njoins the forking threads, and the forking threads wait for their fork\nchildren to exit, if some fork child is not detach by GDB, the parent\nwill not write the file, and the test will time out.  If I remove the\nnew remote_detach_pid calls in remote.c, the test fails eventually if I\nrun it in a loop.\n\nThere is a known limitation: we don\u0027t remove breakpoints from the\nchildren before detaching it.  So the children, could hit a trap\ninstruction after being detached and crash.  I know this is wrong, and\nit should be fixed, but I would like to handle that later.  The current\npatch doesn\u0027t fix everything, but it\u0027s a step in the right direction.\n\nChange-Id: I6d811a56f520e3cb92d5ea563ad38976f92e93dd\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d28512\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "2f8cf498b73c29f2b3d930e50fbaf803a27191cc",
      "old_mode": 33188,
      "old_path": "gdb/linux-nat.c",
      "new_id": "9d4b05a2167d1cb4b7682818a726c6405682bffd",
      "new_mode": 33188,
      "new_path": "gdb/linux-nat.c"
    },
    {
      "type": "modify",
      "old_id": "d70acdc26c06e00e82e85a137acaaa75f2678d3e",
      "old_mode": 33188,
      "old_path": "gdb/remote.c",
      "new_id": "1f977d57fbaa3852eb1c6af1fbb9c95ad8d39c3f",
      "new_mode": 33188,
      "new_path": "gdb/remote.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5b9f9940f832b28c6db6c8f892498c52e4a2b67b",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/pending-fork-event-detach-ns.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "9a3ac835eae0ca55cdc29225eb7f356047be85e9",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/pending-fork-event-detach-ns.exp"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5536381847b14a9e7ff5210f93ba5aa5e37c70b3",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/pending-fork-event-detach-touch-file.c"
    },
    {
      "type": "rename",
      "old_id": "a39ca75a49aca19469b0285da3b916b57950c5f9",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.threads/pending-fork-event.c",
      "new_id": "ecfed98fdfda42c425f46fd336ab51af44c3e180",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/pending-fork-event-detach.c",
      "score": 89
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "433660a07ae38aa8fd1b56c5474fb285fde5bb1b",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/pending-fork-event-detach.exp"
    },
    {
      "type": "delete",
      "old_id": "51af07f56bdd20e130d0cd193eb09978b563c36c",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.threads/pending-fork-event.exp",
      "new_id": "0000000000000000000000000000000000000000",
      "new_mode": 0,
      "new_path": "/dev/null"
    },
    {
      "type": "modify",
      "old_id": "70fa2b3a8013540c992a6497914d1ba032313c6a",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/lib/gdb.exp",
      "new_id": "8b7445b758190909805b3b63a342ba29f3b47ba1",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/lib/gdb.exp"
    },
    {
      "type": "modify",
      "old_id": "34991df449bfb859b1d753fee334ce684d7b4ede",
      "old_mode": 33188,
      "old_path": "gdbserver/linux-low.cc",
      "new_id": "87888044c1f8e48a9dd06ff92860d69f48b54a90",
      "new_mode": 33188,
      "new_path": "gdbserver/linux-low.cc"
    },
    {
      "type": "modify",
      "old_id": "819f915ea9a38e06fe4aaaaf052e9b7ba5926053",
      "old_mode": 33188,
      "old_path": "gdbserver/linux-low.h",
      "new_id": "b563537216a6b2cee00c6a2855bc462ff5fa8839",
      "new_mode": 33188,
      "new_path": "gdbserver/linux-low.h"
    },
    {
      "type": "modify",
      "old_id": "8dde6fb0729512e24d741a67900f7cdbf744829d",
      "old_mode": 33188,
      "old_path": "gdbserver/server.cc",
      "new_id": "27e2aba01214727631eb29a0dbe1b3434f4f1f3d",
      "new_mode": 33188,
      "new_path": "gdbserver/server.cc"
    },
    {
      "type": "modify",
      "old_id": "136b5104de8583661904adf5c321c4303c231c08",
      "old_mode": 33188,
      "old_path": "gdbserver/target.cc",
      "new_id": "aa3d42462f5207440233f69449ce8c29bbd09325",
      "new_mode": 33188,
      "new_path": "gdbserver/target.cc"
    },
    {
      "type": "modify",
      "old_id": "1b0a1201d755672a9b0dd0512a23b6717d8b442f",
      "old_mode": 33188,
      "old_path": "gdbserver/target.h",
      "new_id": "331a21aa57a33ee1ebc6a5011ecff68855158660",
      "new_mode": 33188,
      "new_path": "gdbserver/target.h"
    }
  ]
}
