)]}'
{
  "commit": "55dbaa6ea760489a0973d99338f69beec9c6b682",
  "tree": "80f2d98e86c64172ce506f59dc7fb48127d87f2b",
  "parents": [
    "99d4f8d6aff1d2cd67a11ba5b6fe03c96e5b38bd"
  ],
  "author": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Wed Jul 16 19:29:55 2025 +0100"
  },
  "committer": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Fri Sep 12 17:57:07 2025 +0100"
  },
  "message": "gdb: ensure normal stop finishes the thread state of all threads\n\nThis patch fixes a multi-target issue where the normal_stop function\ncan fail to finish the thread state of threads from a non current\ntarget, this leaves the threads marked as running in GDB core, while\nthe threads is actually stopped.\n\nFor testing I used this test program:\n\n  #include \u003cunistd.h\u003e\n\n  int\n  main ()\n  {\n    while (1)\n      sleep (1);\n    return 0;\n  }\n\nCompile this to make \u0027/tmp/spin\u0027, then the bug can be shown using this\ncommand:\n\n  $ gdb -ex \u0027file /tmp/spin\u0027 \\\n        -ex \u0027start\u0027 \\\n\t-ex \u0027add-inferior\u0027 \\\n\t-ex \u0027inferior 2\u0027 \\\n\t-ex \u0027set sysroot\u0027 \\\n\t-ex \u0027target extended-remote | gdbserver --multi --once - /tmp/spin\u0027 \\\n        -ex \u0027inferior 1\u0027 \\\n\t-ex \u0027continue\u0026\u0027 \\\n\t-ex \u0027inferior 2\u0027 \\\n\t-ex \u0027search sleep\u0027 \\\n\t-ex \u0027break $_ inferior 2\u0027 \\\n\t-ex \u0027continue\u0027 \\\n\t-ex \u0027info threads\u0027\n\nThe interesting part of the output is:\n\n    Id   Target Id                     Frame\n    1.1  process 1610445 \"spin\"        (running)\n  * 2.1  Thread 1610451.1610451 \"spin\" main () at spin.c:7\n  (gdb)\n\nNotice that thread 1.1 is marked as running when it should be\nstopped.  We can see that the thread is actually stopped if we try\nthis:\n\n  (gdb) inferior 1\n  [Switching to inferior 1 [process 1610445] (/tmp/spin)]\n  [Switching to thread 1.1 (process 1610445)](running)\n  (gdb) continue\n  Cannot execute this command while the selected thread is running.\n  (gdb) interrupt\n  (gdb) info threads\n    Id   Target Id                     Frame\n  * 1.1  process 1610445 \"spin\"        (running)\n    2.1  Thread 1610451.1610451 \"spin\" main () at spin.c:7\n  (gdb)\n\nWe can see the expected behaviour if both inferiors run on the same\ntarget, like this:\n\n  $ gdb -ex \u0027file /tmp/spin\u0027 \\\n        -ex \u0027start\u0027 \\\n\t-ex \u0027add-inferior\u0027 \\\n\t-ex \u0027inferior 2\u0027 \\\n\t-ex \u0027file /tmp/spin\u0027 \\\n\t-ex \u0027start\u0027 \\\n\t-ex \u0027inferior 1\u0027 \\\n\t-ex \u0027continue\u0026\u0027 \\\n\t-ex \u0027inferior 2\u0027 \\\n\t-ex \u0027search sleep\u0027 \\\n\t-ex \u0027break $_ inferior 2\u0027 \\\n\t-ex \u0027continue\u0027 \\\n\t-ex \u0027info threads\u0027\n\nThe \u0027info threads\u0027 from this series of commands looks like this:\n\n    Id   Target Id              Frame\n    1.1  process 1611589 \"spin\" 0x00007ffff7e951e7 in nanosleep () from /lib64/libc.so.6\n  * 2.1  process 1611593 \"spin\" main () at spin.c:7\n  (gdb)\n\nNow both threads are stopped as we\u0027d expect.\n\nThe problem is in normal_stop.  The scoped_finish_thread_state uses\nuser_visible_resume_target to select the target(s) over which GDB will\niterate to find the threads to update.\n\nThe problem with this is that when the ptid_t is minus_one_ptid,\nmeaning all threads, user_visible_resume_target only returns nullptr,\nmeaning all targets, when sched_multi is true.\n\nThis dependency on sched_multi makes sense when _resuming_ threads.\nIf we are resuming all threads, then when sched_multi (the\nschedule-multiple setting) is off (the default), all threads actually\nmeans all threads in the current inferior only.  When sched_multi is\ntrue (schedule-multiple is on) then this means all threads, from all\ninferiors, which means GDB needs to consider every target.\n\nHowever, when stopping an inferior in all-stop mode (non_stop is\nfalse), then GDB wants to stop all threads from all inferiors,\nregardless of the sched_multi setting.\n\nWhat this means is that, when \u0027non_stop\u0027 is false, then we should be\npassing nullptr as the target selection to scoped_finish_thread_state.\n\nMy proposal is that we should stop using user_visible_resume_target in\nthe normal_stop function for the target selection of the\nscoped_finish_thread_state, instead we should manually figure out the\ncorrect target value and pass this in.\n\nThere is precedent for this in GDB, see run_command_1, where\n\u0027finish_target\u0027 is calculated directly within the function rather than\nusing user_visible_resume_target.\n\nAfter this commit, when using two different targets (native and\nremote) as in my first example above, both threads will be correctly\nstopped.\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "289c503963cfa2203d04a36d253e36b475a43241",
      "old_mode": 33188,
      "old_path": "gdb/infrun.c",
      "new_id": "eeef01ae66d565fdd0aa4fec59b219b458ee307d",
      "new_mode": 33188,
      "new_path": "gdb/infrun.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "b5fa5680cbf71fdcf029575cffe1a8256c1493b6",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.multi/interrupt-bg-exec.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "065a1128e5d93d50de3efd294a3853fc54e60cf7",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.multi/interrupt-bg-exec.exp"
    }
  ]
}
