aboutsummaryrefslogtreecommitdiff
path: root/ylwrap
diff options
context:
space:
mode:
authorSimon Marchi <simon.marchi@polymtl.ca>2021-06-07 13:15:05 -0400
committerSimon Marchi <simon.marchi@polymtl.ca>2021-09-28 20:18:30 -0400
commitabe8cab7cb39e5db02d318e56595fa13677b52da (patch)
tree9d2bbb939735b31bc469f231f422bbbbb90439d6 /ylwrap
parentf08d6b8e02a6e80e5fe30134505c530b3cf77b1c (diff)
downloadgdb-abe8cab7cb39e5db02d318e56595fa13677b52da.zip
gdb-abe8cab7cb39e5db02d318e56595fa13677b52da.tar.gz
gdb-abe8cab7cb39e5db02d318e56595fa13677b52da.tar.bz2
gdb: enable target_async around stop_all_threads call in process_initial_stop_replies
The following scenario hangs: - maint set target-non-stop on - `gdbserver --attach` - a multi-threaded program For example: Terminal 1: $ gnome-calculator& [1] 495731 $ ../gdbserver/gdbserver --once --attach :1234 495731 Attached; pid = 495731 Listening on port 1234 Terminal 2: $ ./gdb -nx -q --data-directory=data-directory /usr/bin/gnome-calculator -ex "maint set target-non-stop on" -ex "tar rem :1234" Reading symbols from /usr/bin/gnome-calculator... (No debugging symbols found in /usr/bin/gnome-calculator) Remote debugging using :1234 * hangs * What happens is: - The protocol between gdb and gdbserver is in non-stop mode, but the user-visible behavior is all-stop - On connect, gdbserver sends one stop reply for one thread that is stops, the others stay running - In process_initial_stop_replies, gdb calls stop_all_threads to stop these other threads, because we are using the all-stop user-visible mode - stop_all_threads sends a stop request for all the running threads and then waits for resulting events - At this point, the remote target is in target_async(0) mode, which makes stop_all_threads not consider it for events - stop_all_threads loops indefinitely (it does not even block indefinitely, it is in an infinite busy loop) because there are no event sources. wait_one_event returns a TARGET_WAITKIND_NO_RESUMED wait status. Fix that by making the remote target async around the stop_all_threads call. I haven't implemented it because I'm not sure how to do it, but I think it would be a good idea to have, in stop_all_threads / wait_one / handle_one, an assert to check that if we are expecting one or more event, then there are some targets that are in a state where they can supply some events. Otherwise, we'll necessarily be stuck in this infinite loop, and it's probably due to a bug in GDB. I'm not too sure where to put this or how to express it though. Perhaps in stop_all_threads, here: for (int i = 0; i < waits_needed; i++) { wait_one_event event = wait_one (); *here* if (handle_one (event)) break; } If at that point, the returned event is TARGET_WAITKIND_NO_RESUMED, there's a problem. We expect some event, because we've asked some threads to stop, but all targets are answering that they won't have any events for us. That's a contradiction, and a sign that something has gone wrong. It could perhaps event be: gdb_assert (event.ws.kind != TARGET_WAITKIND_NO_RESUMED); in handle_one, as the idea is the same in prepare_for_detach. A bit more sophisticated would be: we know which targets we are expecting waits from, since we know which threads we have asked to stop. So if any of these targets returns TARGET_WAITKIND_NO_RESUMED, something is fishy. Add a test that tests attaching with gdbserver's --attach flag to a multi-threaded program, and then connecting to it. Without the fix, the test reproduces the hang. Change-Id: If6f6690a4887ca66693ef1af64791dda4c65f24f
Diffstat (limited to 'ylwrap')
0 files changed, 0 insertions, 0 deletions