* [PATCH 15/23] Fix reconnecting to a gdbserver already debugging multiple processes, I
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
2019-09-06 23:28 ` [PATCH 11/23] tfile_target::close: trace_fd can't be -1 Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 09/23] switch inferior/thread before calling target methods Pedro Alves
` (23 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
The multi-target patch will change the remote target's behavior when:
- the current inferior is connected to an extended-remote target.
- the current inferior is attached to any process.
- some other inferior than than the current one is live.
In current master, we get:
(gdb) tar extended-remote :9999
A program is being debugged already. Kill it? (y or n)
While after multi-target, since each inferior may have its own target
connection, we'll get:
(gdb) tar extended-remote :9999
Already connected to a remote target. Disconnect? (y or n)
That change made gdb.server/extended-remote-restart.exp expose a gdb
bug, because it made "target remote", via gdb_reconnect, just
disconnect from the previous connection, while in current master that
command would kill the inferior before disconnecting. In turn, that
would make a multi-target gdb find processes already running under
control of gdbserver as soon as it reconnects, while in current master
there is never any process around when gdb reconnects, since they'd
all been killed prior to disconnection.
The bug this exposed is that remote_target::remote_add_inferior was
always reusing current_inferior() for the new process, even if the
current inferior was already bound to a process. In the testcase's
case, when we reconnect, the remote is debugging two processes. So
we'd bind the first remote process to the empty current inferior the
first time, and then bind the second remote process to the same
inferior again, essencially losing track of the first process. That
resulted in failed assertions when we look up the inferior for the
first process by PID. The fix is to still prefer binding to the
current inferior (so that plain "target remote" keeps doing what you'd
expect), but not reuse the current inferior if it is already bound to
a process.
This patch tweaks the test to explicitly disconnect before
reconnecting, to avoid GDB killing processes, thus making current GDB
behave the same as it will behave when the multi-target work lands.
That change alone without the GDB fix exposes the bug like so:
(gdb) PASS: gdb.server/extended-remote-restart.exp: kill: 0, follow-child 0: disconnect
target extended-remote localhost:2350
Remote debugging using localhost:2350
src/gdb/thread.c:93: internal-error: thread_info* inferior_thread(): Assertion `tp' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
The original bug that the testcase was written for was related to
killing, (git 9d4a934ce604 ("gdb: Fix assert for extended-remote
target (PR gdb/18050)")), but since the testcase tries reconnecting
with both explicitly killing and not explicitly killing, I think we're
covering the original bug with this testcase change.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (remote_target::remote_add_inferior): Don't bind a
process to the current inferior if the current inferior is already
bound to a process.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.server/extended-remote-restart.exp (test_reload): Explicitly
disconnect before reconnecting.
---
gdb/remote.c | 20 ++++++++++++++++++++
gdb/testsuite/gdb.server/extended-remote-restart.exp | 4 +++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/gdb/remote.c b/gdb/remote.c
index eacaf11976..16ef9dbdfd 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -2371,6 +2371,26 @@ remote_target::remote_add_inferior (bool fake_pid_p, int pid, int attached,
between program/address spaces. We simply bind the inferior
to the program space's address space. */
inf = current_inferior ();
+
+ /* However, if the current inferior is already bound to a
+ process, find some other empty inferior. */
+ if (inf->pid != 0)
+ {
+ inf = nullptr;
+ for (inferior *it : all_inferiors ())
+ if (it->pid == 0)
+ {
+ inf = it;
+ break;
+ }
+ }
+ if (inf == nullptr)
+ {
+ /* Since all inferiors were already bound to a process, add
+ a new inferior. */
+ inf = add_inferior_with_spaces ();
+ }
+ switch_to_inferior_no_thread (inf);
inferior_appeared (inf, pid);
}
diff --git a/gdb/testsuite/gdb.server/extended-remote-restart.exp b/gdb/testsuite/gdb.server/extended-remote-restart.exp
index 1fa46f2073..c78342c010 100644
--- a/gdb/testsuite/gdb.server/extended-remote-restart.exp
+++ b/gdb/testsuite/gdb.server/extended-remote-restart.exp
@@ -113,7 +113,9 @@ proc test_reload { do_kill_p follow_child_p } {
"Check inferior was killed"
}
- # Reconnect to the target.
+ # Disconnect, and reconnect to the target.
+ gdb_test "disconnect" ".*"
+
if { [gdb_reconnect] == 0 } {
pass "reconnect after fork"
} else {
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 17/23] Multi-target support
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (11 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 03/23] Make "show remote exec-file" inferior-aware Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-11 17:11 ` Tom Tromey
2019-09-06 23:28 ` [PATCH 18/23] Add multi-target tests Pedro Alves
` (12 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
This commit adds multi-target support to GDB. What this means is that
with this commit, GDB can now be connected to different targets at the
same time. E.g., you can debug a live native process and a core dump
at the same time, connect to multiple gdbservers, etc.
Actually, the word "target" is overloaded in gdb. We already have a
target stack, with pushes several target_ops instances on top of one
another. We also have "info target" already, which means something
completely different to what this patch does.
So from here on, I'll be using the "target connections" term, to mean
an open process_stratum target, pushed on a target stack. This patch
makes gdb have multiple target stacks, and multiple process_stratum
targets open simultaneously. The user-visible changes / commands will
also use this terminology, but of course it's all open to debate.
User-interface-wise, not that much changes. The main difference is
that each inferior may have its own target connection.
A target connection (e.g., a target extended-remote connection) may
support debugging multiple processes, just as before.
Say you're debugging against gdbserver in extended-remote mode, and
you do "add-inferior" to prepare to spawn a new process, like:
(gdb) target extended-remote :9999
...
(gdb) start
...
(gdb) add-inferior
Added inferior 2
(gdb) inferior 2
[Switching to inferior 2 [<null>] (<noexec>)]
(gdb) file a.out
...
(gdb) start
...
At this point, you have two inferiors connected to the same gdbserver.
With this commit, GDB will maintain a target stack per inferior,
instead of a global target stack.
To preserve the behavior above, by default, "add-inferior" makes the
new inferior inherit a copy of the target stack of the current
inferior. Same across a fork - the child inherits a copy of the
target stack of the parent. While the target stacks are copied, the
targets themselves are not. Instead, target_ops is made a
refcounted_object, which means that target_ops instances are
refcounted, which each inferior counting for a reference.
What if you want to create an inferior and connect it to some _other_
target? For that, this commit introduces a new "add-inferior
-no-connection" option that makes the new inferior not share the
current inferior's target. So you could do:
(gdb) target extended-remote :9999
Remote debugging using :9999
...
(gdb) add-inferior -no-connection
[New inferior 2]
Added inferior 2
(gdb) inferior 2
[Switching to inferior 2 [<null>] (<noexec>)]
(gdb) info inferiors
Num Description Executable
1 process 18401 target:/home/pedro/tmp/main
* 2 <null>
(gdb) tar extended-remote :10000
Remote debugging using :10000
...
(gdb) info inferiors
Num Description Executable
1 process 18401 target:/home/pedro/tmp/main
* 2 process 18450 target:/home/pedro/tmp/main
(gdb)
A following patch will extended "info inferiors" to include a column
indicating which connection an inferior is bound to, along with a
couple other UI tweaks.
Other than that, debugging is the same as before. Users interact with
inferiors and threads as before. The only difference is that
inferiors may be bound to processes running in different machines.
That's pretty much all there is to it in terms of noticeable UI
changes.
On to implementation.
Since we can be connected to different systems at the same time, a
ptid_t is no longer a unique identifier. Instead a thread can be
identified by a pair of ptid_t and 'process_stratum_target *', the
later being the instance of the process_stratum target that owns the
process/thread. Note that process_stratum_target inherits from
target_ops, and all process_stratum targets inherit from
process_stratum_target. In earlier patches, many places in gdb were
converted to refer to threads by thread_info pointer instead of
ptid_t, but there are still places in gdb where we start with a
pid/tid and need to find the corresponding inferior or thread_info
objects. So you'll see in the patch many places adding a
process_stratum_target parameter to functions that used to take only a
ptid_t.
Since each inferior has its own target stack now, we can always find
the process_stratum target for an inferior. That is done via a
inf->process_target() convenience method.
Since each inferior has its own target stack, we need to handle the
"beneath" calls when servicing target calls. The solution I settled
with is just to make sure to switch the current inferior to the
inferior you want before making a target call. Not relying on global
context is just not feasible in current GDB. Fortunately, there
aren't that many places that need to do that, because generally most
code that calls target methods already has the current context
pointing to the right inferior/thread. Note, to emphasize -- there's
no method to "switch to this target stack". Instead, you switch the
current inferior, and that implicitly switches the target stack.
In some spots, we need to iterate over all inferiors so that we reach
all target stacks.
Native targets are still singletons. There's always only a single
instance of such targets.
Remote targets however, we'll have one instance per remote connection.
The exec target is still a singleton. There's only one instance. I
did not see the point of instanciating more than one exec_target
object.
After vfork, we need to make sure to push the exec target on the new
inferior. See exec_on_vfork.
For type safety, functions that need a {target, ptid} pair to identify
a thread, take a process_stratum_target pointer for target parameter
instead of target_ops *. Some shared code in gdb/nat/ also need to
gain a target pointer parameter. This poses an issue, since gdbserver
doesn't have process_stratum_target, only target_ops. To fix this,
this commit renames gdbserver's target_ops to process_stratum_target.
I think this makes sense. There's no concept of target stack in
gdbserver, and gdbserver's target_ops really implements a
process_stratum-like target.
The thread and inferior iterator functions also gain
process_stratum_target parameters. These are used to be able to
iterate over threads and inferiors of a given target. Following usual
conventions, if the target pointer is null, then we iterate over
threads and inferiors of all targets.
I tried converting "add-inferior" to the gdb::option framework, as a
preparatory patch, but that stumbled on the fact that gdb::option does
not support file options yet, for "add-inferior -exec". I have a WIP
patchset that adds that, but it's not a trivial patch, mainly due to
need to integrate readline's filename completion, so I deferred that
to some other time.
In infrun.c/infcmd.c, the main change is that we need to poll events
out of all targets. See do_target_wait. Right after collecting an
event, we switch the current inferior to an inferior bound to the
target that reported the event, so that target methods can be used
while handling the event. This makes most of the code transparent to
multi-targets. See fetch_inferior_event.
infrun.c:stop_all_threads is interesting -- in this function we need
to stop all threads of all targets. What the function does is send an
asynchronous stop request to all threads, and then synchronously waits
for events, with target_wait, rinse repeat, until all it finds are
stopped threads. Now that we have multiple targets, it's not
efficient to synchronously block in target_wait waiting for events out
of one target. Instead, we implement a mini event loop, with
interruptible_select, select'ing on one file descriptor per target.
For this to work, we need to be able to ask the target for a waitable
file descriptor. Such file descriptors already exist, they are the
descriptors registered in the main event loop with add_file_handler,
inside the target_async implementations. This commit adds a new
target_async_wait_fd target method that just returns the file
descriptor in question. See wait_one / stop_all_threads in infrun.c.
The 'threads_executing' global is made a per-target variable. Since
it is only relevant to process_stratum_target targets, this is where
it is put, instead of in target_ops.
You'll notice that remote.c includes some FIXME notes. These refer to
the fact that the global arrays that hold data for the remote packets
supported are still globals. For example, if we connect to two
different servers/stubs, then each might support different remote
protocol features. They might even be different architectures, like
e.g., one ARM baremetal stub, and a x86 gdbserver, to debug a
host/controller scenario as a single program. That isn't going to
work correctly today, because of said globals. I'm leaving fixing
that for another pass, since it does not appear to be trivial, and I'd
rather land the base work first. It's already useful to be able to
debug multiple instances of the same server (e.g., a distributed
cluster, where you have full control over the servers installed), so I
think as is it's already reasonable incremental progress.
Current limitations:
- you can only resume more that one target at the same time if all
targets support asynchronous debugging, and support non-stop mode.
It should be possible to support mixed all-stop + non-stop
backends, but that is left for another time. This means that
currently in order to do multi-target with gdbserver you need to
issue "maint set target-non-stop on". I would like to make that
mode be the default, but we're not there yet. Note that I'm
talking about how the target backend works, only. User-visible
all-stop mode works just fine.
- as explained above, connecting to different remote servers at the
same time is likely to produce bad results if they don't support the
exact set of RSP features.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* ada-tasks.c (print_ada_task_info): Adjust find_thread_ptid call.
(task_command_1): Likewise.
* amd64-fbsd-tdep.c: Include "inferior.h".
(amd64fbsd_get_thread_local_address): Pass down target.
* amd64-linux-nat.c (ps_get_thread_area): Use ps_prochandle
thread's gdbarch instead of target_gdbarch.
* break-catch-sig.c (signal_catchpoint_print_it): Adjust call to
get_last_target_status.
* break-catch-syscall.c (print_it_catch_syscall): Likewise.
* breakpoint.c (breakpoints_should_be_inserted_now): Consider all
inferiors.
(update_inserted_breakpoint_locations): Skip if inferiors with no
execution.
(update_global_location_list): When handling moribund locations,
find representative inferior for location's pspace, and use thread
count of its process_stratum target.
* bsd-uthread.c (bsd_uthread_target::wait): Use
as_process_stratum_target and adjust thread_change_ptid and
add_thread calls.
(bsd_uthread_target::update_thread_list): Use
as_process_stratum_target and adjust find_thread_ptid,
thread_change_ptid and add_thread calls.
* btrace.c (maint_btrace_packet_history_cmd): Adjust
find_thread_ptid call.
* corelow.c (add_to_thread_list): Adjust add_thread call.
(core_target_open): Adjust add_thread_silent and thread_count
calls.
(core_target::pid_to_str): Adjust find_inferior_ptid call.
* ctf.c (ctf_target_open): Adjust add_thread_silent call.
* event-top.c (async_disconnect): Pop targets from all inferiors.
* exec.c (add_target_sections): Push exec target on all inferiors
sharing the program space.
(remove_target_sections): Remove the exec target from all
inferiors sharing the program space.
(exec_on_vfork): New.
* exec.h (exec_on_vfork): Declare.
* fbsd-tdep.c (fbsd_corefile_thread): Adjust
get_thread_arch_regcache call.
* fork-child.c (gdb_startup_inferior): Pass target down to
startup_inferior and set_executing.
* gdbthread.h (struct process_stratum_target): Forward declare.
(add_thread, add_thread_silent, add_thread_with_info)
(in_thread_list): Add process_stratum_target parameter.
(find_thread_ptid(inferior*, ptid_t)): New overload.
(find_thread_ptid, thread_change_ptid): Add process_stratum_target
parameter.
(all_threads()): Delete overload.
(all_threads, all_non_exited_threads): Add process_stratum_target
parameter.
(all_threads_safe): Use brace initialization.
(thread_count): Add process_stratum_target parameter.
(set_resumed, set_running, set_stop_requested, set_executing)
(threads_are_executing, finish_thread_state): Add
process_stratum_target parameter.
(switch_to_thread): Use is_current_thread.
* i386-fbsd-tdep.c: Include "inferior.h".
(i386fbsd_get_thread_local_address): Pass down target.
* inf-child.c (inf_child_target::maybe_unpush_target): Remove
have_inferiors check.
* inf-ptrace.c (inf_ptrace_target::create_inferior)
(inf_ptrace_target::attach): Adjust.
* infcall.c (run_inferior_call): Adjust.
* infcmd.c (run_command_1): Pass target to
scoped_finish_thread_state.
(proceed_thread_callback): Skip inferiors with no execution.
(continue_command): Rename 'all_threads' local to avoid hiding
'all_threads' function. Adjust get_last_target_status call.
(prepare_one_step): Adjust set_running call.
(signal_command): Use user_visible_resume_target. Compare thread
pointers instead of inferior_ptid.
(info_program_command): Adjust to pass down target.
(attach_command): Mark target's 'thread_executing' flag.
(stop_current_target_threads_ns): New, factored out from ...
(interrupt_target_1): ... this. Switch inferior before making
target calls.
* inferior-iter.h
(struct all_inferiors_iterator, struct all_inferiors_range)
(struct all_inferiors_safe_range)
(struct all_non_exited_inferiors_range): Filter on
process_stratum_target too.
* inferior.c (inferior::inferior): Push dummy target on target
stack.
(find_inferior_pid, find_inferior_ptid, number_of_live_inferiors):
Add process_stratum_target parameter, and pass it down.
(have_live_inferiors): Adjust.
(switch_to_inferior_and_push_target): New.
(add_inferior_command, clone_inferior_command): Handle
"-no-connection" parameter. Use
switch_to_inferior_and_push_target.
(_initialize_inferior): Mention "-no-connection" option in
the help of "add-inferior" and "clone-inferior" commands.
* inferior.h: Include "process-stratum-target.h".
(interrupt_target_1): Use bool.
(struct inferior) <push_target, unpush_target, target_is_pushed,
find_target_beneath, top_target, process_target, target_at,
m_stack>: New.
(discard_all_inferiors): Delete.
(find_inferior_pid, find_inferior_ptid, number_of_live_inferiors)
(all_inferiors, all_non_exited_inferiors): Add
process_stratum_target parameter.
* infrun.c: Include "gdb_select.h".
(target_last_proc_target): New global.
(follow_fork_inferior): Push target on new inferior. Pass target
to add_thread_silent. Call exec_on_vfork. Handle target's
reference count.
(follow_fork): Adjust get_last_target_status call. Also consider
target.
(follow_exec): Push target on new inferior.
(struct execution_control_state) <target>: New field.
(user_visible_resume_target): New.
(resume_1): Set target's threads_executing flag. Consider resume
target.
(commit_resume_all_targets): New.
(proceed): Also consider resume target. Skip threads of inferiors
with no execution. Commit resumtion in all targets.
(start_remote): Pass current inferior to wait_for_inferior.
(infrun_thread_stop_requested): Consider target as well. Pass
thread_info pointer to clear_inline_frame_state instead of ptid.
(infrun_thread_thread_exit): Consider target as well.
(random_pending_event_thread): New inferior parameter. Use it.
(do_target_wait): Rename to ...
(do_target_wait_1): ... this. Add inferior parameter, and pass it
down.
(threads_are_resumed_pending_p, do_target_wait): New.
(prepare_for_detach): Adjust calls.
(wait_for_inferior): New inferior parameter. Handle it. Use
do_target_wait_1 instead of do_target_wait.
(fetch_inferior_event): Adjust. Switch to representative
inferior. Pass target down.
(set_last_target_status): Add process_stratum_target parameter.
Save target in global.
(get_last_target_status): Add process_stratum_target parameter and
handle it.
(nullify_last_target_wait_ptid): Clear 'target_last_proc_target'.
(context_switch): Check inferior_ptid == null_ptid before calling
inferior_thread().
(get_inferior_stop_soon): Pass down target.
(wait_one): Rename to ...
(poll_one_curr_target): ... this.
(struct wait_one_event): New.
(wait_one): New.
(stop_all_threads): Adjust.
(handle_no_resumed, handle_inferior_event): Adjust to consider the
event's target.
(switch_back_to_stepped_thread): Also consider target.
(print_stop_event): Update.
(normal_stop): Update. Also consider the resume target.
* infrun.h (wait_for_inferior): Remove declaration.
(user_visible_resume_target): New declaration.
(get_last_target_status, set_last_target_status): New
process_stratum_target parameter.
* inline-frame.c (clear_inline_frame_state(ptid_t)): Add
process_stratum_target parameter, and use it.
(clear_inline_frame_state (thread_info*)): New.
* inline-frame.c (clear_inline_frame_state(ptid_t)): Add
process_stratum_target parameter.
(clear_inline_frame_state (thread_info*)): Declare.
* linux-fork.c (delete_checkpoint_command): Pass target down to
find_thread_ptid.
(checkpoint_command): Adjust.
* linux-nat.c (linux_nat_target::follow_fork): Switch to thread
instead of just tweaking inferior_ptid.
(linux_nat_switch_fork): Pass target down to thread_change_ptid.
(exit_lwp): Pass target down to find_thread_ptid.
(attach_proc_task_lwp_callback): Pass target down to
add_thread/set_running/set_executing.
(linux_nat_target::attach): Pass target down to
thread_change_ptid.
(get_detach_signal): Pass target down to find_thread_ptid.
Consider last target status's target.
(linux_resume_one_lwp_throw, resume_lwp)
(linux_handle_syscall_trap, linux_handle_extended_wait, wait_lwp)
(stop_wait_callback, save_stop_reason, linux_nat_filter_event)
(linux_nat_wait_1, resume_stopped_resumed_lwps): Pass target down.
(linux_nat_target::async_wait_fd): New.
(linux_nat_stop_lwp, linux_nat_target::thread_address_space): Pass
target down.
* linux-nat.h (linux_nat_target::async_wait_fd): Declare.
* linux-tdep.c (get_thread_arch_regcache): Pass target down.
* linux-thread-db.c (struct thread_db_info::process_target): New
field.
(add_thread_db_info): Save target.
(get_thread_db_info): New process_stratum_target parameter. Also
match target.
(delete_thread_db_info): New process_stratum_target parameter.
Also match target.
(thread_from_lwp): Adjust to pass down target.
(thread_db_notice_clone): Pass down target.
(check_thread_db_callback): Pass down target.
(try_thread_db_load_1): Always push the thread_db target.
(try_thread_db_load, record_thread): Pass target down.
(thread_db_target::detach): Pass target down. Always unpush the
thread_db target.
(thread_db_target::wait, thread_db_target::mourn_inferior): Pass
target down. Always unpush the thread_db target.
(find_new_threads_callback, thread_db_find_new_threads_2)
(thread_db_target::update_thread_list): Pass target down.
(thread_db_target::pid_to_str): Pass current inferior down.
(thread_db_target::get_thread_local_address): Pass target down.
(thread_db_target::resume, maintenance_check_libthread_db): Pass
target down.
* ppc-fbsd-tdep.c: Include "inferior.h".
(ppcfbsd_get_thread_local_address): Pass down target.
* proc-service.c (ps_xfer_memory): Switch current inferior and
program space as well.
(get_ps_regcache): Pass target down.
* process-stratum-target.c
(process_stratum_target::thread_address_space)
(process_stratum_target::thread_architecture): Pass target down.
* process-stratum-target.h
(process_stratum_target::threads_executing): New field.
(as_process_stratum_target): New.
* ravenscar-thread.c
(ravenscar_thread_target::update_inferior_ptid): Pass target down.
(ravenscar_thread_target::wait, ravenscar_add_thread): Pass target
down.
* record-btrace.c (record_btrace_target::info_record): Adjust.
(record_btrace_target::record_method)
(record_btrace_target::record_is_replaying)
(record_btrace_target::fetch_registers)
(get_thread_current_frame_id, record_btrace_target::resume)
(record_btrace_target::wait, record_btrace_target::stop): Pass
target down.
* record-full.c (record_full_wait_1): Switch to event thread.
Pass target down.
* regcache.c (regcache::regcache)
(get_thread_arch_aspace_regcache, get_thread_arch_regcache): Add
process_stratum_target parameter and handle it.
(current_thread_target): New global.
(get_thread_regcache): Add process_stratum_target parameter and
handle it. Switch inferior before calling target method.
(get_thread_regcache): Pass target down.
(get_thread_regcache_for_ptid): Pass target down.
(registers_changed_ptid): Add process_stratum_target parameter and
handle it.
(registers_changed_thread, registers_changed): Pass target down.
(test_get_thread_arch_aspace_regcache): New.
(current_regcache_test): Define a couple local test_target_ops
instances and use them for testing.
(readwrite_regcache): Pass process_stratum_target parameter.
(cooked_read_test, cooked_write_test): Pass mock_target down.
* regcache.h (get_thread_regcache, get_thread_arch_regcache)
(get_thread_arch_aspace_regcache): Add process_stratum_target
parameter.
(regcache::target): New method.
(regcache::regcache, regcache::get_thread_arch_aspace_regcache)
(regcache::registers_changed_ptid): Add process_stratum_target
parameter.
(regcache::m_target): New field.
(registers_changed_ptid): Add process_stratum_target parameter.
* remote.c (remote_state::supports_vCont_probed): New field.
(remote_target::async_wait_fd): New method.
(remote_unpush_and_throw): Add remote_target parameter.
(get_current_remote_target): Adjust.
(remote_target::remote_add_inferior): Push target.
(remote_target::remote_add_thread)
(remote_target::remote_notice_new_inferior)
(get_remote_thread_info): Pass target down.
(remote_target::update_thread_list): Skip threads of inferiors
bound to other targets. (remote_target::close): Don't discard
inferiors. (remote_target::add_current_inferior_and_thread)
(remote_target::process_initial_stop_replies)
(remote_target::start_remote)
(remote_target::remote_serial_quit_handler): Pass down target.
(remote_target::remote_unpush_target): New remote_target
parameter. Unpush the target from all inferiors.
(remote_target::remote_unpush_and_throw): New remote_target
parameter. Pass it down.
(remote_target::open_1): Check whether the current inferior has
execution instead of checking whether any inferior is live. Pass
target down.
(remote_target::remote_detach_1): Pass down target. Use
remote_unpush_target.
(extended_remote_target::attach): Pass down target.
(remote_target::remote_vcont_probe): Set supports_vCont_probed.
(remote_target::append_resumption): Pass down target.
(remote_target::append_pending_thread_resumptions)
(remote_target::remote_resume_with_hc, remote_target::resume)
(remote_target::commit_resume): Pass down target. Enable async.
(remote_target::remote_stop_ns): Check supports_vCont_probed.
(remote_target::interrupt_query)
(remote_target::remove_new_fork_children)
(remote_target::check_pending_events_prevent_wildcard_vcont)
(remote_target::remote_parse_stop_reply)
(remote_target::process_stop_reply): Pass down target.
(first_remote_resumed_thread): New remote_target parameter. Pass
it down.
(remote_target::wait_as): Pass down target.
(unpush_and_perror): New remote_target parameter. Pass it down.
(remote_target::readchar, remote_target::remote_serial_write)
(remote_target::getpkt_or_notif_sane_1)
(remote_target::kill_new_fork_children, remote_target::kill): Pass
down target.
(remote_target::mourn_inferior): Pass down target. Use
remote_unpush_target.
(remote_target::core_of_thread)
(remote_target::remote_btrace_maybe_reopen): Pass down target.
(remote_target::pid_to_exec_file)
(remote_target::thread_handle_to_thread_info): Pass down target.
(remote_target::async_wait_fd): New.
* riscv-fbsd-tdep.c: Include "inferior.h".
(riscv_fbsd_get_thread_local_address): Pass down target.
* sol2-tdep.c (sol2_core_pid_to_str): Pass down target.
* solib-spu.c (spu_skip_standalone_loader): Pass down target.
* solib-svr4.c (enable_break): Pass down target.
* spu-multiarch.c (parse_spufs_run): Pass down target.
* spu-tdep.c (spu2ppu_sniffer): Pass down target.
* target-delegates.c: Regenerate.
* target.c (g_target_stack): Delete.
(current_top_target): Return the current inferior's top target.
(target_has_execution_1): Refer to the passed-in inferior's top
target.
(target_supports_terminal_ours): Check whether the initial
inferior was already created.
(decref_target): New.
(target_stack::push): Incref/decref the target.
(push_target, push_target, unpush_target): Adjust.
(target_stack::unpush): Defref target.
(target_is_pushed): Return bool. Adjust to refer to the current
inferior's target stack.
(dispose_inferior): Remove 'args' parameter. Return void.
(target_preopen): Only dispose_inferior of the current inferior.
(target_detach): Hold strong target reference while detaching.
Pass target down.
(target_thread_name): Add assertion.
(target_resume): Pass down target.
(target_ops::beneath, find_target_at): Adjust to refer to the
current inferior's target stack.
(get_dummy_target): New.
(target_pass_ctrlc): Pass the Ctrl-C to the first inferior that
has a thread running.
(initialize_targets): Rename to ...
(_initialize_target): ... this.
* target.h: Include "gdbsupport/refcounted-object.h".
(struct target_ops): Inherit refcounted_object.
(target_ops::shortname, target_ops::longname): Make const.
(target_ops::async_wait_fd): New method.
(target_ops_ref): New typedef.
(get_dummy_target): Declare function.
(target_is_pushed): Return bool.
* thread-iter.c (all_matching_threads_iterator::m_inf_matches)
(all_matching_threads_iterator::all_matching_threads_iterator):
Handle filter target.
* thread-iter.h (struct all_matching_threads_iterator, struct
all_matching_threads_range, class all_non_exited_threads_range):
Filter by target too.
* thread.c (threads_executing): Delete.
(inferior_thread): Pass down current inferior.
(clear_thread_inferior_resources): Pass down thread pointer
instead of ptid_t.
(add_thread_silent, add_thread_with_info, add_thread): Add
process_stratum_target parameter. Use it for thread and inferior
searches.
(is_current_thread): New.
(thread_info::deletable): Use it.
(find_thread_ptid, thread_count, in_thread_list)
(thread_change_ptid, set_resumed, set_running): New
process_stratum_target parameter. Pass it down.
(set_executing): New process_stratum_target parameter. Pass it
down. Adjust reference to 'threads_executing'.
(threads_are_executing): New process_stratum_target parameter.
Adjust reference to 'threads_executing'.
(set_stop_requested, finish_thread_state): New
process_stratum_target parameter. Pass it down.
(switch_to_thread): Also match inferior.
(switch_to_thread): New process_stratum_target parameter. Pass it
down.
(update_threads_executing): Reimplement.
* top.c (quit_force): Pop targets from all inferior.
(gdb_init): Don't call initialize_targets.
* tracefile-tfile.c (tfile_target_open): Pass down target.
* gdbsupport/common-gdbthread.h (struct process_stratum_target):
Forward declare.
(switch_to_thread): Add process_stratum_target parameter.
* mi/mi-interp.c (mi_on_resume_1): Add process_stratum_target
parameter. Use it.
(mi_on_resume): Pass target down.
* nat/fork-inferior.c (startup_inferior): Add
process_stratum_target parameter. Pass it down.
* nat/fork-inferior.h (startup_inferior): Add
process_stratum_target parameter.
* python/py-threadevent.c (py_get_event_thread): Pass target down.
gdb/gdbserver/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* fork-child.c (post_fork_inferior): Pass target down to
startup_inferior.
* inferiors.c (switch_to_thread): Add process_stratum_target
parameter.
* linux-low.c (linux_target_ops): Now a process_stratum_target.
* remote-utils.c (prepare_resume_reply): Pass the target to
switch_to_thread.
* target.c (the_target): Now a process_stratum_target.
(done_accessing_memory): Pass the target to switch_to_thread.
(set_target_ops): Ajust to use process_stratum_target.
* target.h (struct target_ops): Rename to ...
(struct process_stratum_target): ... this.
(the_target, set_target_ops): Adjust.
---
gdb/ada-tasks.c | 4 +-
gdb/amd64-fbsd-tdep.c | 4 +-
gdb/amd64-linux-nat.c | 2 +-
gdb/break-catch-sig.c | 2 +-
gdb/break-catch-syscall.c | 2 +-
gdb/breakpoint.c | 25 +-
gdb/bsd-uthread.c | 20 +-
gdb/btrace.c | 2 +-
gdb/corelow.c | 8 +-
gdb/ctf.c | 2 +-
gdb/event-top.c | 14 +-
gdb/exec.c | 51 +++-
gdb/exec.h | 7 +
gdb/fbsd-tdep.c | 3 +-
gdb/fork-child.c | 7 +-
gdb/gdbserver/fork-child.c | 3 +-
gdb/gdbserver/inferiors.c | 2 +-
gdb/gdbserver/linux-low.c | 2 +-
gdb/gdbserver/remote-utils.c | 2 +-
gdb/gdbserver/target.c | 8 +-
gdb/gdbserver/target.h | 9 +-
gdb/gdbsupport/common-gdbthread.h | 5 +-
gdb/gdbthread.h | 127 +++++----
gdb/i386-fbsd-tdep.c | 4 +-
gdb/inf-child.c | 2 +-
gdb/inf-ptrace.c | 6 +-
gdb/infcall.c | 3 +-
gdb/infcmd.c | 112 +++++---
gdb/inferior-iter.h | 77 +++++-
gdb/inferior.c | 78 ++++--
gdb/inferior.h | 64 ++++-
gdb/infrun.c | 563 +++++++++++++++++++++++++++++---------
gdb/infrun.h | 14 +-
gdb/inline-frame.c | 51 ++--
gdb/inline-frame.h | 12 +-
gdb/linux-fork.c | 4 +-
gdb/linux-nat.c | 73 ++---
gdb/linux-nat.h | 1 +
gdb/linux-tdep.c | 3 +-
gdb/linux-thread-db.c | 110 ++++----
gdb/mi/mi-interp.c | 10 +-
gdb/nat/fork-inferior.c | 8 +-
gdb/nat/fork-inferior.h | 5 +-
gdb/ppc-fbsd-tdep.c | 4 +-
gdb/proc-service.c | 17 +-
gdb/process-stratum-target.c | 4 +-
gdb/process-stratum-target.h | 16 ++
gdb/python/py-threadevent.c | 4 +-
gdb/ravenscar-thread.c | 16 +-
gdb/record-btrace.c | 43 +--
gdb/record-full.c | 11 +-
gdb/regcache.c | 162 +++++++----
gdb/regcache.h | 30 +-
gdb/remote.c | 220 ++++++++-------
gdb/riscv-fbsd-tdep.c | 4 +-
gdb/sol2-tdep.c | 2 +-
gdb/solib-spu.c | 3 +-
gdb/solib-svr4.c | 3 +-
gdb/spu-multiarch.c | 6 +-
gdb/spu-tdep.c | 8 +-
gdb/target-delegates.c | 27 ++
gdb/target.c | 146 +++++++---
gdb/target.h | 16 +-
gdb/thread-iter.c | 14 +-
gdb/thread-iter.h | 25 +-
gdb/thread.c | 139 ++++++----
gdb/top.c | 17 +-
gdb/tracefile-tfile.c | 2 +-
68 files changed, 1686 insertions(+), 764 deletions(-)
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 99458aadb2..ab53f670d2 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -1095,7 +1095,7 @@ print_ada_task_info (struct ui_out *uiout,
/* Print the associated Thread ID. */
if (uiout->is_mi_like_p ())
{
- thread_info *thread = find_thread_ptid (task_info->ptid);
+ thread_info *thread = find_thread_ptid (inf, task_info->ptid);
if (thread != NULL)
uiout->field_signed ("thread-id", thread->global_num);
@@ -1293,7 +1293,7 @@ task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
computed if target_get_ada_task_ptid has not been implemented for
our target (yet). Rather than cause an assertion error in that case,
it's nicer for the user to just refuse to perform the task switch. */
- thread_info *tp = find_thread_ptid (task_info->ptid);
+ thread_info *tp = find_thread_ptid (inf->process_target (), task_info->ptid);
if (tp == NULL)
error (_("Unable to compute thread ID for task %d.\n"
"Cannot switch to this task."),
diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c
index 493e630974..416a34974c 100644
--- a/gdb/amd64-fbsd-tdep.c
+++ b/gdb/amd64-fbsd-tdep.c
@@ -30,6 +30,7 @@
#include "amd64-tdep.h"
#include "fbsd-tdep.h"
#include "solib-svr4.h"
+#include "inferior.h"
/* Support for signal handlers. */
@@ -212,7 +213,8 @@ amd64fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
{
struct regcache *regcache;
- regcache = get_thread_arch_regcache (ptid, gdbarch);
+ regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, gdbarch);
target_fetch_registers (regcache, AMD64_FSBASE_REGNUM);
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 4f1c98a0d1..796dc171fb 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -377,7 +377,7 @@ ps_err_e
ps_get_thread_area (struct ps_prochandle *ph,
lwpid_t lwpid, int idx, void **base)
{
- if (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 32)
+ if (gdbarch_bfd_arch_info (ph->thread->inf->gdbarch)->bits_per_word == 32)
{
unsigned int base_addr;
ps_err_e result;
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
index 76f6db60ab..04168d4700 100644
--- a/gdb/break-catch-sig.c
+++ b/gdb/break-catch-sig.c
@@ -184,7 +184,7 @@ signal_catchpoint_print_it (bpstat bs)
const char *signal_name;
struct ui_out *uiout = current_uiout;
- get_last_target_status (nullptr, &last);
+ get_last_target_status (nullptr, nullptr, &last);
signal_name = signal_to_name_or_int (last.value.sig);
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 0fce15d81b..7f61e43e13 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -185,7 +185,7 @@ print_it_catch_syscall (bpstat bs)
struct syscall s;
struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
- get_last_target_status (nullptr, &last);
+ get_last_target_status (nullptr, nullptr, &last);
get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 9478d2dcf2..0ab27eb611 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -390,7 +390,7 @@ breakpoints_should_be_inserted_now (void)
no threads under GDB's control yet. */
return 1;
}
- else if (target_has_execution)
+ else
{
if (always_inserted_mode)
{
@@ -399,8 +399,10 @@ breakpoints_should_be_inserted_now (void)
return 1;
}
- if (threads_are_executing ())
- return 1;
+ for (inferior *inf : all_inferiors ())
+ if (inf->has_execution ()
+ && threads_are_executing (inf->process_target ()))
+ return 1;
/* Don't remove breakpoints yet if, even though all threads are
stopped, we still have events to process. */
@@ -2888,7 +2890,7 @@ update_inserted_breakpoint_locations (void)
if we aren't attached to any process yet, we should still
insert breakpoints. */
if (!gdbarch_has_global_breakpoints (target_gdbarch ())
- && inferior_ptid == null_ptid)
+ && (inferior_ptid == null_ptid || !target_has_execution))
continue;
val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks,
@@ -2944,7 +2946,7 @@ insert_breakpoint_locations (void)
if we aren't attached to any process yet, we should still
insert breakpoints. */
if (!gdbarch_has_global_breakpoints (target_gdbarch ())
- && inferior_ptid == null_ptid)
+ && (inferior_ptid == null_ptid || !target_has_execution))
continue;
val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks,
@@ -11880,7 +11882,18 @@ update_global_location_list (enum ugll_insert_mode insert_mode)
around. We simply always ignore hardware watchpoint
traps we can no longer explain. */
- old_loc->events_till_retirement = 3 * (thread_count () + 1);
+ process_stratum_target *proc_target = nullptr;
+ for (inferior *inf : all_inferiors ())
+ if (inf->pspace == old_loc->pspace)
+ {
+ proc_target = inf->process_target ();
+ break;
+ }
+ if (proc_target != nullptr)
+ old_loc->events_till_retirement
+ = 3 * (thread_count (proc_target) + 1);
+ else
+ old_loc->events_till_retirement = 1;
old_loc->owner = NULL;
moribund_locations.push_back (old_loc);
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index af048f7a18..cdf8e2cb9c 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -381,9 +381,11 @@ bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status,
{
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
CORE_ADDR addr;
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
/* Pass the request to the layer beneath. */
- ptid = beneath ()->wait (ptid, status, options);
+ ptid = beneath->wait (ptid, status, options);
/* If the process is no longer alive, there's no point in figuring
out the thread ID. It will fail anyway. */
@@ -414,13 +416,13 @@ bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status,
ptid with tid set, then ptid is still the initial thread of
the process. Notify GDB core about it. */
if (inferior_ptid.tid () == 0
- && ptid.tid () != 0 && !in_thread_list (ptid))
- thread_change_ptid (inferior_ptid, ptid);
+ && ptid.tid () != 0 && !in_thread_list (beneath, ptid))
+ thread_change_ptid (beneath, inferior_ptid, ptid);
/* Don't let the core see a ptid without a corresponding thread. */
- thread_info *thread = find_thread_ptid (ptid);
+ thread_info *thread = find_thread_ptid (beneath, ptid);
if (thread == NULL || thread->state == THREAD_EXITED)
- add_thread (ptid);
+ add_thread (beneath, ptid);
return ptid;
}
@@ -467,16 +469,18 @@ bsd_uthread_target::update_thread_list ()
{
ptid_t ptid = ptid_t (pid, 0, addr);
- thread_info *thread = find_thread_ptid (ptid);
+ process_stratum_target *proc_target
+ = as_process_stratum_target (this->beneath ());
+ thread_info *thread = find_thread_ptid (proc_target, ptid);
if (thread == nullptr || thread->state == THREAD_EXITED)
{
/* If INFERIOR_PTID doesn't have a tid member yet, then ptid
is still the initial thread of the process. Notify GDB
core about it. */
if (inferior_ptid.tid () == 0)
- thread_change_ptid (inferior_ptid, ptid);
+ thread_change_ptid (proc_target, inferior_ptid, ptid);
else
- add_thread (ptid);
+ add_thread (proc_target, ptid);
}
addr = bsd_uthread_read_memory_address (addr + offset);
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 466607dbfc..303ac1f2c4 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -3237,7 +3237,7 @@ maint_btrace_packet_history_cmd (const char *arg, int from_tty)
struct btrace_thread_info *btinfo;
unsigned int size, begin, end, from, to;
- thread_info *tp = find_thread_ptid (inferior_ptid);
+ thread_info *tp = find_thread_ptid (current_inferior (), inferior_ptid);
if (tp == NULL)
error (_("No thread."));
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 0fba93f802..d98713fc37 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -312,7 +312,7 @@ add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg)
ptid = ptid_t (pid, lwpid, 0);
- add_thread (ptid);
+ add_thread (inf->process_target (), ptid);
/* Warning, Will Robinson, looking at BFD private data! */
@@ -450,7 +450,7 @@ core_target_open (const char *arg, int from_tty)
{
inferior_appeared (current_inferior (), CORELOW_PID);
inferior_ptid = ptid_t (CORELOW_PID);
- add_thread_silent (inferior_ptid);
+ add_thread_silent (target, inferior_ptid);
}
else
switch_to_thread (thread);
@@ -515,7 +515,7 @@ core_target_open (const char *arg, int from_tty)
/* Current thread should be NUM 1 but the user does not know that.
If a program is single threaded gdb in general does not mention
anything about threads. That is why the test is >= 2. */
- if (thread_count () >= 2)
+ if (thread_count (target) >= 2)
{
try
{
@@ -1008,7 +1008,7 @@ core_target::pid_to_str (ptid_t ptid)
/* Otherwise, this isn't a "threaded" core -- use the PID field, but
only if it isn't a fake PID. */
- inf = find_inferior_ptid (ptid);
+ inf = find_inferior_ptid (this, ptid);
if (inf != NULL && !inf->fake_pid_p)
return normal_pid_to_str (ptid);
diff --git a/gdb/ctf.c b/gdb/ctf.c
index b3c3f0d7b2..c17bd1bbe2 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -1169,7 +1169,7 @@ ctf_target_open (const char *dirname, int from_tty)
inferior_appeared (current_inferior (), CTF_PID);
inferior_ptid = ptid_t (CTF_PID);
- add_thread_silent (inferior_ptid);
+ add_thread_silent (&ctf_ops, inferior_ptid);
merge_uploaded_trace_state_variables (&uploaded_tsvs);
merge_uploaded_tracepoints (&uploaded_tps);
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 2132fb550d..635270cc90 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1095,12 +1095,16 @@ async_disconnect (gdb_client_data arg)
exception_print (gdb_stderr, exception);
}
- try
- {
- pop_all_targets ();
- }
- catch (const gdb_exception &exception)
+ for (inferior *inf : all_inferiors ())
{
+ switch_to_inferior_no_thread (inf);
+ try
+ {
+ pop_all_targets ();
+ }
+ catch (const gdb_exception &exception)
+ {
+ }
}
signal (SIGHUP, SIG_DFL); /*FIXME: ??????????? */
diff --git a/gdb/exec.c b/gdb/exec.c
index 3098fcaadd..53d6303160 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -547,10 +547,23 @@ add_target_sections (void *owner,
table->sections[space + i].owner = owner;
}
+ scoped_restore_current_thread restore_thread;
+ program_space *curr_pspace = current_program_space;
+
/* If these are the first file sections we can provide memory
- from, push the file_stratum target. */
- if (!target_is_pushed (&exec_ops))
- push_target (&exec_ops);
+ from, push the file_stratum target. Must do this in all
+ inferiors sharing the program space. */
+ for (inferior *inf : all_inferiors ())
+ {
+ if (inf->pspace != curr_pspace)
+ continue;
+
+ if (inf->target_is_pushed (&exec_ops))
+ continue;
+
+ switch_to_inferior_no_thread (inf);
+ push_target (&exec_ops);
+ }
}
}
@@ -628,21 +641,39 @@ remove_target_sections (void *owner)
old_count = resize_section_table (table, dest - src);
/* If we don't have any more sections to read memory from,
- remove the file_stratum target from the stack. */
+ remove the file_stratum target from the stack of each
+ inferior sharing the program space. */
if (old_count + (dest - src) == 0)
{
- struct program_space *pspace;
+ scoped_restore_current_thread restore_thread;
+ program_space *curr_pspace = current_program_space;
+
+ for (inferior *inf : all_inferiors ())
+ {
+ if (inf->pspace != curr_pspace)
+ continue;
- ALL_PSPACES (pspace)
- if (pspace->target_sections.sections
- != pspace->target_sections.sections_end)
- return;
+ if (inf->pspace->target_sections.sections
+ != inf->pspace->target_sections.sections_end)
+ continue;
- unpush_target (&exec_ops);
+ switch_to_inferior_no_thread (inf);
+ unpush_target (&exec_ops);
+ }
}
}
}
+/* See exec.h. */
+
+void
+exec_on_vfork ()
+{
+ if (current_program_space->target_sections.sections
+ != current_program_space->target_sections.sections_end)
+ push_target (&exec_ops);
+}
+
\f
enum target_xfer_status
diff --git a/gdb/exec.h b/gdb/exec.h
index e9af480287..539e33f417 100644
--- a/gdb/exec.h
+++ b/gdb/exec.h
@@ -44,6 +44,13 @@ extern int build_section_table (struct bfd *, struct target_section **,
extern void clear_section_table (struct target_section_table *table);
+/* The current inferior is a child vforked and its program space is
+ shared with its parent. This pushes the exec target on the
+ current/child inferior's target stack if there are sections in the
+ program space's section table. */
+
+extern void exec_on_vfork ();
+
/* Read from mappable read-only sections of BFD executable files.
Return TARGET_XFER_OK, if read is successful. Return
TARGET_XFER_EOF if read is done. Return TARGET_XFER_E_IO
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index e81c6c99bf..182494f561 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -673,7 +673,8 @@ fbsd_corefile_thread (struct thread_info *info,
{
struct regcache *regcache;
- regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
+ regcache = get_thread_arch_regcache (info->inf->process_target (),
+ info->ptid, args->gdbarch);
target_fetch_registers (regcache, -1);
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index edfb6a3c5a..384e45b2e0 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -128,10 +128,13 @@ postfork_child_hook ()
ptid_t
gdb_startup_inferior (pid_t pid, int num_traps)
{
- ptid_t ptid = startup_inferior (pid, num_traps, NULL, NULL);
+ inferior *inf = current_inferior ();
+ process_stratum_target *proc_target = inf->process_target ();
+
+ ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
/* Mark all threads non-executing. */
- set_executing (ptid, 0);
+ set_executing (proc_target, ptid, 0);
return ptid;
}
diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
index ddd73094e6..24b31320fd 100644
--- a/gdb/gdbserver/fork-child.c
+++ b/gdb/gdbserver/fork-child.c
@@ -107,7 +107,8 @@ post_fork_inferior (int pid, const char *program)
atexit (restore_old_foreground_pgrp);
#endif
- startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
+ startup_inferior (the_target, pid,
+ START_INFERIOR_TRAPS_EXPECTED,
&cs.last_status, &cs.last_ptid);
current_thread->last_resume_kind = resume_stop;
current_thread->last_status = cs.last_status;
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e35186bda1..09a98a9145 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -216,7 +216,7 @@ current_process (void)
/* See gdbsupport/common-gdbthread.h. */
void
-switch_to_thread (ptid_t ptid)
+switch_to_thread (process_stratum_target *ops, ptid_t ptid)
{
gdb_assert (ptid != minus_one_ptid);
current_thread = find_thread_ptid (ptid);
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 3113017ae6..60efe46002 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -7454,7 +7454,7 @@ linux_get_hwcap2 (int wordsize)
return hwcap2;
}
-static struct target_ops linux_target_ops = {
+static process_stratum_target linux_target_ops = {
linux_create_inferior,
linux_post_create_inferior,
linux_attach,
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 665fc66c53..64eb7118c6 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1210,7 +1210,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
saved_thread = current_thread;
- switch_to_thread (ptid);
+ switch_to_thread (the_target, ptid);
regp = current_target_desc ()->expedite_regs;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index 0b45b6c956..efd412aa69 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -22,7 +22,7 @@
#include "tracepoint.h"
#include "gdbsupport/byte-vector.h"
-struct target_ops *the_target;
+process_stratum_target *the_target;
int
set_desired_thread ()
@@ -119,7 +119,7 @@ done_accessing_memory (void)
/* Restore the previous selected thread. */
cs.general_thread = prev_general_thread;
- switch_to_thread (cs.general_thread);
+ switch_to_thread (the_target, cs.general_thread);
}
int
@@ -284,9 +284,9 @@ start_non_stop (int nonstop)
}
void
-set_target_ops (struct target_ops *target)
+set_target_ops (process_stratum_target *target)
{
- the_target = XNEW (struct target_ops);
+ the_target = XNEW (process_stratum_target);
memcpy (the_target, target, sizeof (*the_target));
}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 67167cca2d..bfa55d7244 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -63,7 +63,10 @@ struct thread_resume
CORE_ADDR step_range_end; /* Exclusive */
};
-struct target_ops
+/* GDBserver doesn't have a concept of strata like GDB, but we call
+ its target vector "process_stratum" anyway for the benefit of
+ shared code. */
+struct process_stratum_target
{
/* Start a new process.
@@ -480,9 +483,9 @@ struct target_ops
bool (*thread_handle) (ptid_t ptid, gdb_byte **handle, int *handle_len);
};
-extern struct target_ops *the_target;
+extern process_stratum_target *the_target;
-void set_target_ops (struct target_ops *);
+void set_target_ops (process_stratum_target *);
#define create_inferior(program, program_args) \
(*the_target->create_inferior) (program, program_args)
diff --git a/gdb/gdbsupport/common-gdbthread.h b/gdb/gdbsupport/common-gdbthread.h
index d692be209c..20f4d89b26 100644
--- a/gdb/gdbsupport/common-gdbthread.h
+++ b/gdb/gdbsupport/common-gdbthread.h
@@ -19,7 +19,10 @@
#ifndef COMMON_COMMON_GDBTHREAD_H
#define COMMON_COMMON_GDBTHREAD_H
+struct process_stratum_target;
+
/* Switch from one thread to another. */
-extern void switch_to_thread (ptid_t ptid);
+extern void switch_to_thread (process_stratum_target *proc_target,
+ ptid_t ptid);
#endif /* COMMON_COMMON_GDBTHREAD_H */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index bb7a71af0b..d00cc3fb8f 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -35,6 +35,7 @@ struct symtab;
#include "gdbsupport/forward-scope-exit.h"
struct inferior;
+struct process_stratum_target;
/* Frontend view of the thread state. Possible extensions: stepping,
finishing, until(ling),...
@@ -305,7 +306,7 @@ public:
from saying that there is an active target and we are stopped at
a breakpoint, for instance. This is a real indicator whether the
thread is off and running. */
- int executing = 0;
+ bool executing = false;
/* Non-zero if this thread is resumed from infrun's perspective.
Note that a thread can be marked both as not-executing and
@@ -420,15 +421,18 @@ extern void init_thread_list (void);
that a new thread is found, and return the pointer to
the new thread. Caller my use this pointer to
initialize the private thread data. */
-extern struct thread_info *add_thread (ptid_t ptid);
+extern struct thread_info *add_thread (process_stratum_target *targ,
+ ptid_t ptid);
-/* Same as add_thread, but does not print a message
- about new thread. */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
+/* Same as add_thread, but does not print a message about new
+ thread. */
+extern struct thread_info *add_thread_silent (process_stratum_target *targ,
+ ptid_t ptid);
/* Same as add_thread, and sets the private info. */
-extern struct thread_info *add_thread_with_info (ptid_t ptid,
- struct private_thread_info *);
+extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
+ ptid_t ptid,
+ private_thread_info *);
/* Delete an existing thread list entry. */
extern void delete_thread (struct thread_info *thread);
@@ -469,14 +473,18 @@ extern int show_inferior_qualified_tids (void);
const char *print_thread_id (struct thread_info *thr);
/* Boolean test for an already-known ptid. */
-extern int in_thread_list (ptid_t ptid);
+extern bool in_thread_list (process_stratum_target *targ, ptid_t ptid);
/* Boolean test for an already-known global thread id (GDB's homegrown
global id, not the system's). */
extern int valid_global_thread_id (int global_id);
+/* Find thread PTID of inferior INF. */
+extern thread_info *find_thread_ptid (inferior *inf, ptid_t ptid);
+
/* Search function to lookup a thread by 'pid'. */
-extern struct thread_info *find_thread_ptid (ptid_t ptid);
+extern struct thread_info *find_thread_ptid (process_stratum_target *targ,
+ ptid_t ptid);
/* Search function to lookup a thread by 'ptid'. Only searches in
threads of INF. */
@@ -501,7 +509,8 @@ extern struct thread_info *any_thread_of_inferior (inferior *inf);
extern struct thread_info *any_live_thread_of_inferior (inferior *inf);
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
-void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
+void thread_change_ptid (process_stratum_target *targ,
+ ptid_t old_ptid, ptid_t new_ptid);
/* Iterator function to call a user-provided callback function
once for each known thread. */
@@ -512,34 +521,44 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
iterators. Must be done after struct thread_info is defined. */
#include "thread-iter.h"
-/* Return a range that can be used to walk over all threads of all
- inferiors, with range-for. Used like this:
+/* Return a range that can be used to walk over threads, with
+ range-for.
+
+ Used like this, it walks over all threads of all inferiors of all
+ targets:
for (thread_info *thr : all_threads ())
{ .... }
-*/
-inline all_threads_range
-all_threads ()
-{
- return {};
-}
-/* Likewise, but accept a filter PTID. */
+ FILTER_PTID can be used to filter out threads that don't match.
+ FILTER_PTID can be:
+
+ - minus_one_ptid, meaning walk all threads of all inferiors of
+ PROC_TARGET. If PROC_TARGET is NULL, then of all targets.
+
+ - A process ptid, in which case walk all threads of the specified
+ process. PROC_TARGET must be non-NULL in this case.
+
+ - A thread ptid, in which case walk that thread only. PROC_TARGET
+ must be non-NULL in this case.
+*/
inline all_matching_threads_range
-all_threads (ptid_t filter_ptid)
+all_threads (process_stratum_target *proc_target = nullptr,
+ ptid_t filter_ptid = minus_one_ptid)
{
- return all_matching_threads_range (filter_ptid);
+ return all_matching_threads_range (proc_target, filter_ptid);
}
/* Return a range that can be used to walk over all non-exited threads
- of all inferiors, with range-for. FILTER_PTID can be used to
- filter out thread that don't match. */
+ of all inferiors, with range-for. Arguments are like all_threads
+ above. */
inline all_non_exited_threads_range
-all_non_exited_threads (ptid_t filter_ptid = minus_one_ptid)
+all_non_exited_threads (process_stratum_target *proc_target = nullptr,
+ ptid_t filter_ptid = minus_one_ptid)
{
- return all_non_exited_threads_range (filter_ptid);
+ return all_non_exited_threads_range (proc_target, filter_ptid);
}
/* Return a range that can be used to walk over all threads of all
@@ -555,10 +574,10 @@ all_non_exited_threads (ptid_t filter_ptid = minus_one_ptid)
inline all_threads_safe_range
all_threads_safe ()
{
- return all_threads_safe_range ();
+ return {};
}
-extern int thread_count (void);
+extern int thread_count (process_stratum_target *proc_target);
/* Return true if we have any thread in any inferior. */
extern bool any_thread_p ();
@@ -572,44 +591,50 @@ extern void switch_to_no_thread ();
/* Switch from one thread to another. Does not read registers. */
extern void switch_to_thread_no_regs (struct thread_info *thread);
-/* Marks or clears thread(s) PTID as resumed. If PTID is
- MINUS_ONE_PTID, applies to all threads. If ptid_is_pid(PTID) is
- true, applies to all threads of the process pointed at by PTID. */
-extern void set_resumed (ptid_t ptid, int resumed);
-
-/* Marks thread PTID is running, or stopped.
- If PTID is minus_one_ptid, marks all threads. */
-extern void set_running (ptid_t ptid, int running);
-
-/* Marks or clears thread(s) PTID as having been requested to stop.
- If PTID is MINUS_ONE_PTID, applies to all threads. If
+/* Marks or clears thread(s) PTID of TARG as resumed. If PTID is
+ MINUS_ONE_PTID, applies to all threads of TARG. If
ptid_is_pid(PTID) is true, applies to all threads of the process
- pointed at by PTID. If STOP, then the THREAD_STOP_REQUESTED
- observer is called with PTID as argument. */
-extern void set_stop_requested (ptid_t ptid, int stop);
-
-/* Marks thread PTID as executing, or not. If PTID is minus_one_ptid,
- marks all threads.
+ pointed at by {TARG,PTID}. */
+extern void set_resumed (process_stratum_target *targ,
+ ptid_t ptid, bool resumed);
+
+/* Marks thread PTID of TARG as running, or as stopped. If PTID is
+ minus_one_ptid, marks all threads of TARG. */
+extern void set_running (process_stratum_target *targ,
+ ptid_t ptid, bool running);
+
+/* Marks or clears thread(s) PTID of TARG as having been requested to
+ stop. If PTID is MINUS_ONE_PTID, applies to all threads of TARG.
+ If ptid_is_pid(PTID) is true, applies to all threads of the process
+ pointed at by {TARG, PTID}. If STOP, then the
+ THREAD_STOP_REQUESTED observer is called with PTID as argument. */
+extern void set_stop_requested (process_stratum_target *targ,
+ ptid_t ptid, bool stop);
+
+/* Marks thread PTID of TARG as executing, or not. If PTID is
+ minus_one_ptid, marks all threads of TARG.
Note that this is different from the running state. See the
description of state and executing fields of struct
thread_info. */
-extern void set_executing (ptid_t ptid, int executing);
+extern void set_executing (process_stratum_target *targ,
+ ptid_t ptid, bool executing);
-/* True if any (known or unknown) thread is or may be executing. */
-extern int threads_are_executing (void);
+/* True if any (known or unknown) thread of TARG is or may be
+ executing. */
+extern bool threads_are_executing (process_stratum_target *targ);
-/* Merge the executing property of thread PTID over to its thread
- state property (frontend running/stopped view).
+/* Merge the executing property of thread PTID of TARG over to its
+ thread state property (frontend running/stopped view).
"not executing" -> "stopped"
"executing" -> "running"
"exited" -> "exited"
- If PTID is minus_one_ptid, go over all threads.
+ If PTID is minus_one_ptid, go over all threads of TARG.
Notifications are only emitted if the thread state did change. */
-extern void finish_thread_state (ptid_t ptid);
+extern void finish_thread_state (process_stratum_target *targ, ptid_t ptid);
/* Calls finish_thread_state on scope exit, unless release() is called
to disengage. */
diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c
index 3848bf890d..291a624b2c 100644
--- a/gdb/i386-fbsd-tdep.c
+++ b/gdb/i386-fbsd-tdep.c
@@ -30,6 +30,7 @@
#include "i387-tdep.h"
#include "fbsd-tdep.h"
#include "solib-svr4.h"
+#include "inferior.h"
/* Support for signal handlers. */
@@ -332,7 +333,8 @@ i386fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
if (tdep->fsbase_regnum == -1)
error (_("Unable to fetch %%gsbase"));
- regcache = get_thread_arch_regcache (ptid, gdbarch);
+ regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, gdbarch);
target_fetch_registers (regcache, tdep->fsbase_regnum + 1);
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 0a73965a0b..4631e323ae 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -206,7 +206,7 @@ inf_child_target::mourn_inferior ()
void
inf_child_target::maybe_unpush_target ()
{
- if (!inf_child_explicitly_opened && !have_inferiors ())
+ if (!inf_child_explicitly_opened)
unpush_target (this);
}
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 4a8e732373..1e36ce60f9 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -136,7 +136,7 @@ inf_ptrace_target::create_inferior (const char *exec_file,
/* We have something that executes now. We'll be running through
the shell at this point (if startup-with-shell is true), but the
pid shouldn't change. */
- add_thread_silent (ptid);
+ add_thread_silent (this, ptid);
unpusher.release ();
@@ -236,10 +236,10 @@ inf_ptrace_target::attach (const char *args, int from_tty)
/* Always add a main thread. If some target extends the ptrace
target, it should decorate the ptid later with more info. */
- thread_info *thr = add_thread_silent (inferior_ptid);
+ thread_info *thr = add_thread_silent (this, inferior_ptid);
/* Don't consider the thread stopped until we've processed its
initial SIGSTOP stop. */
- set_executing (thr->ptid, true);
+ set_executing (this, thr->ptid, true);
unpusher.release ();
}
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 23f17ee0e2..ff7e16848e 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -650,7 +650,8 @@ run_inferior_call (struct call_thread_fsm *sm,
if (!was_running
&& call_thread_ptid == inferior_ptid
&& stop_stack_dummy == STOP_STACK_DUMMY)
- finish_thread_state (user_visible_resume_ptid (0));
+ finish_thread_state (call_thread->inf->process_target (),
+ user_visible_resume_ptid (0));
enable_watchpoints_after_interactive_call_stop ();
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 879f33bbc2..f2774bc1f2 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -653,10 +653,19 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
events --- the frontend shouldn't see them as stopped. In
all-stop, always finish the state of all threads, as we may be
resuming more than just the new process. */
- ptid_t finish_ptid = (non_stop
- ? ptid_t (current_inferior ()->pid)
- : minus_one_ptid);
- scoped_finish_thread_state finish_state (finish_ptid);
+ process_stratum_target *finish_target;
+ ptid_t finish_ptid;
+ if (non_stop)
+ {
+ finish_target = current_inferior ()->process_target ();
+ finish_ptid = ptid_t (current_inferior ()->pid);
+ }
+ else
+ {
+ finish_target = nullptr;
+ finish_ptid = minus_one_ptid;
+ }
+ scoped_finish_thread_state finish_state (finish_target, finish_ptid);
/* Pass zero for FROM_TTY, because at this point the "run" command
has done its thing; now we are setting up the running program. */
@@ -726,6 +735,9 @@ proceed_thread_callback (struct thread_info *thread, void *arg)
if (thread->state != THREAD_STOPPED)
return 0;
+ if (!thread->inf->has_execution ())
+ return 0;
+
switch_to_thread (thread);
clear_proceed_status (0);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
@@ -819,7 +831,7 @@ static void
continue_command (const char *args, int from_tty)
{
int async_exec;
- int all_threads = 0;
+ bool all_threads_p = false;
ERROR_NO_INFERIOR;
@@ -831,17 +843,17 @@ continue_command (const char *args, int from_tty)
{
if (startswith (args, "-a"))
{
- all_threads = 1;
+ all_threads_p = true;
args += sizeof ("-a") - 1;
if (*args == '\0')
args = NULL;
}
}
- if (!non_stop && all_threads)
+ if (!non_stop && all_threads_p)
error (_("`-a' is meaningless in all-stop mode."));
- if (args != NULL && all_threads)
+ if (args != NULL && all_threads_p)
error (_("Can't resume all threads and specify "
"proceed count simultaneously."));
@@ -858,10 +870,11 @@ continue_command (const char *args, int from_tty)
tp = inferior_thread ();
else
{
+ process_stratum_target *last_target;
ptid_t last_ptid;
- get_last_target_status (&last_ptid, nullptr);
- tp = find_thread_ptid (last_ptid);
+ get_last_target_status (&last_target, &last_ptid, nullptr);
+ tp = find_thread_ptid (last_target, last_ptid);
}
if (tp != NULL)
bs = tp->control.stop_bpstat;
@@ -889,7 +902,7 @@ continue_command (const char *args, int from_tty)
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
- if (!non_stop || !all_threads)
+ if (!non_stop || !all_threads_p)
{
ensure_valid_thread ();
ensure_not_running ();
@@ -900,7 +913,7 @@ continue_command (const char *args, int from_tty)
if (from_tty)
printf_filtered (_("Continuing.\n"));
- continue_1 (all_threads);
+ continue_1 (all_threads_p);
}
\f
/* Record the starting point of a "step" or "next" command. */
@@ -1117,7 +1130,7 @@ prepare_one_step (struct step_command_fsm *sm)
/* Pretend that we've ran. */
resume_ptid = user_visible_resume_ptid (1);
- set_running (resume_ptid, 1);
+ set_running (tp->inf->process_target (), resume_ptid, true);
step_into_inline_frame (tp);
sm->count--;
@@ -1309,10 +1322,14 @@ signal_command (const char *signum_exp, int from_tty)
/* This indicates what will be resumed. Either a single thread,
a whole process, or all threads of all processes. */
ptid_t resume_ptid = user_visible_resume_ptid (0);
+ process_stratum_target *resume_target
+ = user_visible_resume_target (resume_ptid);
- for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ thread_info *current = inferior_thread ();
+
+ for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid))
{
- if (tp->ptid == inferior_ptid)
+ if (tp == current)
continue;
if (tp->suspend.stop_signal != GDB_SIGNAL_0
@@ -1974,6 +1991,7 @@ info_program_command (const char *args, int from_tty)
bpstat bs;
int num, stat;
ptid_t ptid;
+ process_stratum_target *proc_target;
if (!target_has_execution)
{
@@ -1982,14 +2000,17 @@ info_program_command (const char *args, int from_tty)
}
if (non_stop)
- ptid = inferior_ptid;
+ {
+ ptid = inferior_ptid;
+ proc_target = current_inferior ()->process_target ();
+ }
else
- get_last_target_status (&ptid, nullptr);
+ get_last_target_status (&proc_target, &ptid, nullptr);
if (ptid == null_ptid || ptid == minus_one_ptid)
error (_("No selected thread."));
- thread_info *tp = find_thread_ptid (ptid);
+ thread_info *tp = find_thread_ptid (proc_target, ptid);
if (tp->state == THREAD_EXITED)
error (_("Invalid selected thread."));
@@ -2778,12 +2799,16 @@ attach_command (const char *args, int from_tty)
add_inferior_continuation (attach_command_continuation, a,
attach_command_continuation_free_args);
+ /* Let infrun consider waiting for events out of this
+ target. */
+ inferior->process_target ()->threads_executing = true;
+
if (!target_is_async_p ())
mark_infrun_async_event_handler ();
return;
}
-
- attach_post_wait (args, from_tty, mode);
+ else
+ attach_post_wait (args, from_tty, mode);
}
/* We had just found out that the target was already attached to an
@@ -2900,20 +2925,15 @@ disconnect_command (const char *args, int from_tty)
deprecated_detach_hook ();
}
-void
-interrupt_target_1 (int all_threads)
-{
- ptid_t ptid;
-
- if (all_threads)
- ptid = minus_one_ptid;
- else
- ptid = inferior_ptid;
+/* Stop PTID in the current target, and tag the PTID threads as having
+ been explicitly requested to stop. PTID can be a thread, a
+ process, or minus_one_ptid, meaning all threads of all inferiors of
+ the current target. */
- if (non_stop)
- target_stop (ptid);
- else
- target_interrupt ();
+static void
+stop_current_target_threads_ns (ptid_t ptid)
+{
+ target_stop (ptid);
/* Tag the thread as having been explicitly requested to stop, so
other parts of gdb know not to resume this thread automatically,
@@ -2921,8 +2941,32 @@ interrupt_target_1 (int all_threads)
non-stop mode, as when debugging a multi-threaded application in
all-stop mode, we will only get one stop event --- it's undefined
which thread will report the event. */
+ set_stop_requested (current_inferior ()->process_target (),
+ ptid, 1);
+}
+
+/* See inferior.h. */
+
+void
+interrupt_target_1 (bool all_threads)
+{
if (non_stop)
- set_stop_requested (ptid, 1);
+ {
+ if (all_threads)
+ {
+ scoped_restore_current_thread restore_thread;
+
+ for (inferior *inf : all_inferiors ())
+ {
+ switch_to_inferior_no_thread (inf);
+ stop_current_target_threads_ns (minus_one_ptid);
+ }
+ }
+ else
+ stop_current_target_threads_ns (inferior_ptid);
+ }
+ else
+ target_interrupt ();
}
/* interrupt [-a]
diff --git a/gdb/inferior-iter.h b/gdb/inferior-iter.h
index b1b595735b..0b2a3e55d8 100644
--- a/gdb/inferior-iter.h
+++ b/gdb/inferior-iter.h
@@ -36,18 +36,24 @@ public:
typedef int difference_type;
/* Create an iterator pointing at HEAD. */
- explicit all_inferiors_iterator (inferior *head)
- : m_inf (head)
- {}
+ explicit all_inferiors_iterator (process_stratum_target *proc_target,
+ inferior *head)
+ : m_proc_target (proc_target)
+ {
+ /* Advance M_INF to the first inferior's position. */
+ for (m_inf = head; m_inf != NULL; m_inf = m_inf->next)
+ if (m_inf_matches ())
+ return;
+ }
/* Create a one-past-end iterator. */
all_inferiors_iterator ()
- : m_inf (nullptr)
+ : m_proc_target (nullptr), m_inf (nullptr)
{}
all_inferiors_iterator &operator++ ()
{
- m_inf = m_inf->next;
+ advance ();
return *this;
}
@@ -58,6 +64,30 @@ public:
{ return m_inf != other.m_inf; }
private:
+ /* Advance to next inferior, skipping filtered inferiors. */
+ void advance ()
+ {
+ /* The loop below is written in the natural way as-if we'd always
+ start at the beginning of the inferior list. This
+ fast-forwards the algorithm to the actual current position. */
+ goto start;
+
+ while (m_inf != NULL)
+ {
+ if (m_inf_matches ())
+ return;
+ start:
+ m_inf = m_inf->next;
+ }
+ }
+
+ bool m_inf_matches ()
+ {
+ return (m_proc_target == nullptr
+ || m_proc_target == m_inf->process_target ());
+ }
+
+ process_stratum_target *m_proc_target;
inferior *m_inf;
};
@@ -80,10 +110,17 @@ using all_non_exited_inferiors_iterator
inferiors with range-for. */
struct all_inferiors_range
{
+ all_inferiors_range (process_stratum_target *proc_target = nullptr)
+ : m_filter_target (proc_target)
+ {}
+
all_inferiors_iterator begin () const
- { return all_inferiors_iterator (inferior_list); }
+ { return all_inferiors_iterator (m_filter_target, inferior_list); }
all_inferiors_iterator end () const
{ return all_inferiors_iterator (); }
+
+private:
+ process_stratum_target *m_filter_target;
};
/* Iterate over all inferiors, safely. */
@@ -97,10 +134,22 @@ using all_inferiors_safe_iterator
struct all_inferiors_safe_range
{
+ explicit all_inferiors_safe_range (process_stratum_target *filter_target)
+ : m_filter_target (filter_target)
+ {}
+
+ all_inferiors_safe_range ()
+ : m_filter_target (nullptr)
+ {}
+
all_inferiors_safe_iterator begin () const
- { return all_inferiors_safe_iterator (inferior_list); }
+ { return all_inferiors_safe_iterator (m_filter_target, inferior_list); }
all_inferiors_safe_iterator end () const
{ return all_inferiors_safe_iterator (); }
+
+private:
+ /* The filter. */
+ process_stratum_target *m_filter_target;
};
/* A range adapter that makes it possible to iterate over all
@@ -108,10 +157,22 @@ struct all_inferiors_safe_range
struct all_non_exited_inferiors_range
{
+ explicit all_non_exited_inferiors_range (process_stratum_target *filter_target)
+ : m_filter_target (filter_target)
+ {}
+
+ all_non_exited_inferiors_range ()
+ : m_filter_target (nullptr)
+ {}
+
all_non_exited_inferiors_iterator begin () const
- { return all_non_exited_inferiors_iterator (inferior_list); }
+ { return all_non_exited_inferiors_iterator (m_filter_target, inferior_list); }
all_non_exited_inferiors_iterator end () const
{ return all_non_exited_inferiors_iterator (); }
+
+private:
+ /* The filter. */
+ process_stratum_target *m_filter_target;
};
#endif /* !defined (INFERIOR_ITER_H) */
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 97cecbe78b..6f4f396453 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -90,6 +90,8 @@ inferior::inferior (int pid_)
registry_data ()
{
inferior_alloc_data (this);
+
+ m_target_stack.push (get_dummy_target ());
}
struct inferior *
@@ -275,14 +277,14 @@ find_inferior_id (int num)
}
struct inferior *
-find_inferior_pid (int pid)
+find_inferior_pid (process_stratum_target *targ, int pid)
{
/* Looking for inferior pid == 0 is always wrong, and indicative of
a bug somewhere else. There may be more than one with pid == 0,
for instance. */
gdb_assert (pid != 0);
- for (inferior *inf : all_inferiors ())
+ for (inferior *inf : all_inferiors (targ))
if (inf->pid == pid)
return inf;
@@ -292,9 +294,9 @@ find_inferior_pid (int pid)
/* See inferior.h */
struct inferior *
-find_inferior_ptid (ptid_t ptid)
+find_inferior_ptid (process_stratum_target *targ, ptid_t ptid)
{
- return find_inferior_pid (ptid.pid ());
+ return find_inferior_pid (targ, ptid.pid ());
}
/* See inferior.h. */
@@ -339,11 +341,11 @@ have_inferiors (void)
in the middle of a 'mourn' operation. */
int
-number_of_live_inferiors (void)
+number_of_live_inferiors (process_stratum_target *proc_target)
{
int num_inf = 0;
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (proc_target))
if (inf->has_execution ())
for (thread_info *tp ATTRIBUTE_UNUSED : inf->non_exited_threads ())
{
@@ -361,7 +363,7 @@ number_of_live_inferiors (void)
int
have_live_inferiors (void)
{
- return number_of_live_inferiors () > 0;
+ return number_of_live_inferiors (NULL) > 0;
}
/* Prune away any unused inferiors, and then prune away no longer used
@@ -695,7 +697,28 @@ add_inferior_with_spaces (void)
return inf;
}
-/* add-inferior [-copies N] [-exec FILENAME] */
+/* Switch to inferior NEW_INF, a new inferior, and unless
+ NO_CONNECTION is true, push the process_stratum_target of ORG_INF
+ to NEW_INF. */
+
+static void
+switch_to_inferior_and_push_target (inferior *new_inf,
+ bool no_connection, inferior *org_inf)
+{
+ process_stratum_target *proc_target = org_inf->process_target ();
+
+ /* Switch over temporarily, while reading executable and
+ symbols. */
+ switch_to_inferior_no_thread (new_inf);
+
+ /* Reuse the target for new inferior. */
+ if (!no_connection && proc_target != NULL)
+ push_target (proc_target);
+
+ printf_filtered (_("Added inferior %d\n"), new_inf->num);
+}
+
+/* add-inferior [-copies N] [-exec FILENAME] [-no-connection] */
static void
add_inferior_command (const char *args, int from_tty)
@@ -703,6 +726,7 @@ add_inferior_command (const char *args, int from_tty)
int i, copies = 1;
gdb::unique_xmalloc_ptr<char> exec;
symfile_add_flags add_flags = 0;
+ bool no_connection = false;
if (from_tty)
add_flags |= SYMFILE_VERBOSE;
@@ -722,6 +746,8 @@ add_inferior_command (const char *args, int from_tty)
error (_("No argument to -copies"));
copies = parse_and_eval_long (*argv);
}
+ else if (strcmp (*argv, "-no-connection") == 0)
+ no_connection = true;
else if (strcmp (*argv, "-exec") == 0)
{
++argv;
@@ -735,32 +761,32 @@ add_inferior_command (const char *args, int from_tty)
}
}
+ inferior *orginf = current_inferior ();
+
scoped_restore_current_pspace_and_thread restore_pspace_thread;
for (i = 0; i < copies; ++i)
{
- struct inferior *inf = add_inferior_with_spaces ();
+ inferior *inf = add_inferior_with_spaces ();
- printf_filtered (_("Added inferior %d\n"), inf->num);
+ switch_to_inferior_and_push_target (inf, no_connection, orginf);
if (exec != NULL)
{
- /* Switch over temporarily, while reading executable and
- symbols. */
- switch_to_inferior_no_thread (inf);
exec_file_attach (exec.get (), from_tty);
symbol_file_add_main (exec.get (), add_flags);
}
}
}
-/* clone-inferior [-copies N] [ID] */
+/* clone-inferior [-copies N] [ID] [-no-connection] */
static void
clone_inferior_command (const char *args, int from_tty)
{
int i, copies = 1;
struct inferior *orginf = NULL;
+ bool no_connection = false;
if (args)
{
@@ -781,6 +807,8 @@ clone_inferior_command (const char *args, int from_tty)
if (copies < 0)
error (_("Invalid copies number"));
}
+ else if (strcmp (*argv, "-no-connection") == 0)
+ no_connection = true;
}
else
{
@@ -826,15 +854,13 @@ clone_inferior_command (const char *args, int from_tty)
inf->aspace = pspace->aspace;
inf->gdbarch = orginf->gdbarch;
+ switch_to_inferior_and_push_target (inf, no_connection, orginf);
+
/* If the original inferior had a user specified target
description, make the clone use it too. */
if (target_desc_info_from_user_p (inf->tdesc_info))
copy_inferior_target_desc_info (inf, orginf);
- printf_filtered (_("Added inferior %d.\n"), inf->num);
-
- set_current_inferior (inf);
- switch_to_no_thread ();
clone_program_space (pspace, orginf->pspace);
}
}
@@ -895,10 +921,13 @@ By default all inferiors are displayed."));
c = add_com ("add-inferior", no_class, add_inferior_command, _("\
Add a new inferior.\n\
-Usage: add-inferior [-copies N] [-exec FILENAME]\n\
+Usage: add-inferior [-copies N] [-exec FILENAME] [-no-connection]\n\
N is the optional number of inferiors to add, default is 1.\n\
FILENAME is the file name of the executable to use\n\
-as main program."));
+as main program.\n\
+By default, the new inferior inherits the current inferior's connection.\n\
+If -no-connection is specified, the new inferior begins with\n\
+no target connection yet."));
set_cmd_completer (c, filename_completer);
add_com ("remove-inferiors", no_class, remove_inferior_command, _("\
@@ -907,11 +936,14 @@ Usage: remove-inferiors ID..."));
add_com ("clone-inferior", no_class, clone_inferior_command, _("\
Clone inferior ID.\n\
-Usage: clone-inferior [-copies N] [ID]\n\
-Add N copies of inferior ID. The new inferior has the same\n\
+Usage: clone-inferior [-copies N] [-no-connection] [ID]\n\
+Add N copies of inferior ID. The new inferiors have the same\n\
executable loaded as the copied inferior. If -copies is not specified,\n\
adds 1 copy. If ID is not specified, it is the current inferior\n\
-that is cloned."));
+that is cloned.\n\
+By default, the new inferiors inherit the copied inferior's connection.\n\
+If -no-connection is specified, the new inferiors begin with\n\
+no target connection yet."));
add_cmd ("inferiors", class_run, detach_inferior_command, _("\
Detach from inferior ID (or list of IDS).\n\
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 967d4fa8b7..3bcb6d6c60 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -56,6 +56,8 @@ struct thread_info;
#include "gdbsupport/common-inferior.h"
#include "gdbthread.h"
+#include "process-stratum-target.h"
+
struct infcall_suspend_state;
struct infcall_control_state;
@@ -208,7 +210,7 @@ extern void registers_info (const char *, int);
extern void continue_1 (int all_threads);
-extern void interrupt_target_1 (int all_threads);
+extern void interrupt_target_1 (bool all_threads);
using delete_longjmp_breakpoint_cleanup
= FORWARD_SCOPE_EXIT (delete_longjmp_breakpoint);
@@ -364,6 +366,35 @@ public:
/* Returns true if we can delete this inferior. */
bool deletable () const { return refcount () == 0; }
+ /* Push T in this inferior's target stack. */
+ void push_target (struct target_ops *t)
+ { m_target_stack.push (t); }
+
+ /* Unpush T from this inferior's target stack. */
+ int unpush_target (struct target_ops *t)
+ { return m_target_stack.unpush (t); }
+
+ /* Returns true if T is pushed in this inferior's target stack. */
+ bool target_is_pushed (target_ops *t)
+ { return m_target_stack.is_pushed (t); }
+
+ /* Find the target beneath T in this inferior's target stack. */
+ target_ops *find_target_beneath (const target_ops *t)
+ { return m_target_stack.find_beneath (t); }
+
+ /* Return the target at the top of this inferior's target stack. */
+ target_ops *top_target ()
+ { return m_target_stack.top (); }
+
+ /* Return the target at process_stratum level in this inferior's
+ target stack. */
+ struct process_stratum_target *process_target ()
+ { return (process_stratum_target *) m_target_stack.at (process_stratum); }
+
+ /* Return the target at STRATUM in this inferior's target stack. */
+ target_ops *target_at (enum strata stratum)
+ { return m_target_stack.at (stratum); }
+
bool has_execution ()
{ return target_has_execution_1 (this); }
@@ -528,6 +559,10 @@ public:
/* Per inferior data-pointers required by other GDB modules. */
REGISTRY_FIELDS;
+
+private:
+ /* The inferior's target stack. */
+ target_stack m_target_stack;
};
/* Keep a registry of per-inferior data-pointers required by other GDB
@@ -558,14 +593,14 @@ extern void exit_inferior_num_silent (int num);
extern void inferior_appeared (struct inferior *inf, int pid);
-/* Get rid of all inferiors. */
-extern void discard_all_inferiors (void);
+/* Search function to lookup an inferior of TARG by target 'pid'. */
+extern struct inferior *find_inferior_pid (process_stratum_target *targ,
+ int pid);
-/* Search function to lookup an inferior by target 'pid'. */
-extern struct inferior *find_inferior_pid (int pid);
-
-/* Search function to lookup an inferior whose pid is equal to 'ptid.pid'. */
-extern struct inferior *find_inferior_ptid (ptid_t ptid);
+/* Search function to lookup an inferior of TARG whose pid is equal to
+ 'ptid.pid'. */
+extern struct inferior *find_inferior_ptid (process_stratum_target *targ,
+ ptid_t ptid);
/* Search function to lookup an inferior by GDB 'num'. */
extern struct inferior *find_inferior_id (int num);
@@ -592,8 +627,9 @@ extern struct inferior *iterate_over_inferiors (int (*) (struct inferior *,
/* Returns true if the inferior list is not empty. */
extern int have_inferiors (void);
-/* Returns the number of live inferiors (real live processes). */
-extern int number_of_live_inferiors (void);
+/* Returns the number of live inferiors running on PROC_TARGET (real
+ live processes with execution). */
+extern int number_of_live_inferiors (process_stratum_target *proc_target);
/* Returns true if there are any live inferiors in the inferior list
(not cores, not executables, real live processes). */
@@ -650,18 +686,18 @@ all_inferiors_safe ()
*/
inline all_inferiors_range
-all_inferiors ()
+all_inferiors (process_stratum_target *proc_target = nullptr)
{
- return {};
+ return all_inferiors_range (proc_target);
}
/* Return a range that can be used to walk over all inferiors with PID
not zero, with range-for. */
inline all_non_exited_inferiors_range
-all_non_exited_inferiors ()
+all_non_exited_inferiors (process_stratum_target *proc_target = nullptr)
{
- return {};
+ return all_non_exited_inferiors_range (proc_target);
}
/* Prune away automatically added inferiors that aren't required
diff --git a/gdb/infrun.c b/gdb/infrun.c
index d27b47c6a8..33088a11e7 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -69,6 +69,7 @@
#include "arch-utils.h"
#include "gdbsupport/scope-exit.h"
#include "gdbsupport/forward-scope-exit.h"
+#include "gdb_select.h"
/* Prototypes for local functions */
@@ -94,6 +95,8 @@ static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
static void resume (gdb_signal sig);
+static void wait_for_inferior (inferior *inf);
+
/* Asynchronous signal handler registered as event loop source for
when we have pending events ready to be passed to the core. */
static struct async_event_handler *infrun_async_inferior_event_token;
@@ -378,9 +381,10 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty,
static int stop_print_frame;
-/* This is a cached copy of the pid/waitstatus of the last event
- returned by target_wait()/deprecated_target_wait_hook(). This
- information is returned by get_last_target_status(). */
+/* This is a cached copy of the target/ptid/waitstatus of the last
+ event returned by target_wait()/deprecated_target_wait_hook().
+ This information is returned by get_last_target_status(). */
+static process_stratum_target *target_last_proc_target;
static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus;
@@ -487,10 +491,12 @@ holding the child stopped. Try \"set detach-on-fork\" or \
scoped_restore_current_pspace_and_thread restore_pspace_thread;
- inferior_ptid = child_ptid;
- add_thread_silent (inferior_ptid);
set_current_inferior (child_inf);
+ switch_to_no_thread ();
child_inf->symfile_flags = SYMFILE_NO_READ;
+ push_target (parent_inf->process_target ());
+ add_thread_silent (child_inf->process_target (), child_ptid);
+ inferior_ptid = child_ptid;
/* If this is a vfork child, then the address-space is
shared with the parent. */
@@ -499,6 +505,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \
child_inf->pspace = parent_inf->pspace;
child_inf->aspace = parent_inf->aspace;
+ exec_on_vfork ();
+
/* The parent will be frozen until the child is done
with the shared region. Keep track of the
parent. */
@@ -574,52 +582,64 @@ holding the child stopped. Try \"set detach-on-fork\" or \
parent_pspace = parent_inf->pspace;
- /* If we're vforking, we want to hold on to the parent until the
- child exits or execs. At child exec or exit time we can
- remove the old breakpoints from the parent and detach or
- resume debugging it. Otherwise, detach the parent now; we'll
- want to reuse it's program/address spaces, but we can't set
- them to the child before removing breakpoints from the
- parent, otherwise, the breakpoints module could decide to
- remove breakpoints from the wrong process (since they'd be
- assigned to the same address space). */
+ process_stratum_target *target = parent_inf->process_target ();
- if (has_vforked)
- {
- gdb_assert (child_inf->vfork_parent == NULL);
- gdb_assert (parent_inf->vfork_child == NULL);
- child_inf->vfork_parent = parent_inf;
- child_inf->pending_detach = 0;
- parent_inf->vfork_child = child_inf;
- parent_inf->pending_detach = detach_fork;
- parent_inf->waiting_for_vfork_done = 0;
- }
- else if (detach_fork)
- {
- if (print_inferior_events)
- {
- /* Ensure that we have a process ptid. */
- ptid_t process_ptid = ptid_t (parent_ptid.pid ());
+ {
+ /* Hold a strong reference to the target while (maybe)
+ detaching the parent. Otherwise detaching could close the
+ target. */
+ auto target_ref = target_ops_ref::new_reference (target);
+
+ /* If we're vforking, we want to hold on to the parent until
+ the child exits or execs. At child exec or exit time we
+ can remove the old breakpoints from the parent and detach
+ or resume debugging it. Otherwise, detach the parent now;
+ we'll want to reuse it's program/address spaces, but we
+ can't set them to the child before removing breakpoints
+ from the parent, otherwise, the breakpoints module could
+ decide to remove breakpoints from the wrong process (since
+ they'd be assigned to the same address space). */
+
+ if (has_vforked)
+ {
+ gdb_assert (child_inf->vfork_parent == NULL);
+ gdb_assert (parent_inf->vfork_child == NULL);
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = detach_fork;
+ parent_inf->waiting_for_vfork_done = 0;
+ }
+ else if (detach_fork)
+ {
+ if (print_inferior_events)
+ {
+ /* Ensure that we have a process ptid. */
+ ptid_t process_ptid = ptid_t (parent_ptid.pid ());
+
+ target_terminal::ours_for_output ();
+ fprintf_filtered (gdb_stdlog,
+ _("[Detaching after fork from "
+ "parent %s]\n"),
+ target_pid_to_str (process_ptid).c_str ());
+ }
- target_terminal::ours_for_output ();
- fprintf_filtered (gdb_stdlog,
- _("[Detaching after fork from "
- "parent %s]\n"),
- target_pid_to_str (process_ptid).c_str ());
- }
+ target_detach (parent_inf, 0);
+ parent_inf = NULL;
+ }
- target_detach (parent_inf, 0);
- }
+ /* Note that the detach above makes PARENT_INF dangling. */
- /* Note that the detach above makes PARENT_INF dangling. */
+ /* Add the child thread to the appropriate lists, and switch
+ to this new thread, before cloning the program space, and
+ informing the solib layer about this new process. */
- /* Add the child thread to the appropriate lists, and switch to
- this new thread, before cloning the program space, and
- informing the solib layer about this new process. */
+ set_current_inferior (child_inf);
+ push_target (target);
+ }
+ add_thread_silent (target, child_ptid);
inferior_ptid = child_ptid;
- add_thread_silent (inferior_ptid);
- set_current_inferior (child_inf);
/* If this is a vfork child, then the address-space is shared
with the parent. If we detached from the parent, then we can
@@ -628,6 +648,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \
{
child_inf->pspace = parent_pspace;
child_inf->aspace = child_inf->pspace->aspace;
+
+ exec_on_vfork ();
}
else
{
@@ -674,11 +696,12 @@ follow_fork (void)
if (!non_stop)
{
+ process_stratum_target *wait_target;
ptid_t wait_ptid;
struct target_waitstatus wait_status;
/* Get the last target status returned by target_wait(). */
- get_last_target_status (&wait_ptid, &wait_status);
+ get_last_target_status (&wait_target, &wait_ptid, &wait_status);
/* If not stopped at a fork event, then there's nothing else to
do. */
@@ -689,14 +712,14 @@ follow_fork (void)
/* Check if we switched over from WAIT_PTID, since the event was
reported. */
if (wait_ptid != minus_one_ptid
- && inferior_ptid != wait_ptid)
+ && (current_inferior ()->process_target () != wait_target
+ || inferior_ptid != wait_ptid))
{
/* We did. Switch back to WAIT_PTID thread, to tell the
target to follow it (in either direction). We'll
afterwards refuse to resume, and inform the user what
happened. */
- thread_info *wait_thread
- = find_thread_ptid (wait_ptid);
+ thread_info *wait_thread = find_thread_ptid (wait_target, wait_ptid);
switch_to_thread (wait_thread);
should_resume = 0;
}
@@ -742,6 +765,7 @@ follow_fork (void)
parent = inferior_ptid;
child = tp->pending_follow.value.related_pid;
+ process_stratum_target *parent_targ = tp->inf->process_target ();
/* Set up inferior(s) as specified by the caller, and tell the
target to do whatever is necessary to follow either parent
or child. */
@@ -757,7 +781,7 @@ follow_fork (void)
or another. The previous selected thread may be gone
from the lists by now, but if it is still around, need
to clear the pending follow request. */
- tp = find_thread_ptid (parent);
+ tp = find_thread_ptid (parent_targ, parent);
if (tp)
tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
@@ -768,7 +792,7 @@ follow_fork (void)
/* If we followed the child, switch to it... */
if (follow_child)
{
- thread_info *child_thr = find_thread_ptid (child);
+ thread_info *child_thr = find_thread_ptid (parent_targ, child);
switch_to_thread (child_thr);
/* ... and preserve the stepping state, in case the
@@ -1197,9 +1221,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
inf->pid = pid;
target_follow_exec (inf, exec_file_target);
- set_current_inferior (inf);
- set_current_program_space (inf->pspace);
- add_thread (ptid);
+ inferior *org_inferior = current_inferior ();
+ switch_to_inferior_no_thread (inf);
+ push_target (org_inferior->process_target ());
+ thread_info *thr = add_thread (inf->process_target (), ptid);
+ switch_to_thread (thr);
}
else
{
@@ -1893,6 +1919,7 @@ displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal)
discarded between events. */
struct execution_control_state
{
+ process_stratum_target *target;
ptid_t ptid;
/* The thread that got the event, if this was a thread event; NULL
otherwise. */
@@ -2149,6 +2176,16 @@ user_visible_resume_ptid (int step)
return resume_ptid;
}
+/* See infrun.h. */
+
+process_stratum_target *
+user_visible_resume_target (ptid_t resume_ptid)
+{
+ return (resume_ptid == minus_one_ptid
+ ? NULL
+ : current_inferior ()->process_target ());
+}
+
/* Return a ptid representing the set of threads that we will resume,
in the perspective of the target, assuming run control handling
does not require leaving some threads stopped (e.g., stepping past
@@ -2256,6 +2293,7 @@ resume_1 (enum gdb_signal sig)
currently_stepping (tp));
}
+ tp->inf->process_target ()->threads_executing = true;
tp->resumed = 1;
/* FIXME: What should we do if we are supposed to resume this
@@ -2741,10 +2779,12 @@ clear_proceed_status (int step)
if (!non_stop && inferior_ptid != null_ptid)
{
ptid_t resume_ptid = user_visible_resume_ptid (step);
+ process_stratum_target *resume_target
+ = user_visible_resume_target (resume_ptid);
/* In all-stop mode, delete the per-thread status of all threads
we're about to resume, implicitly and explicitly. */
- for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid))
clear_proceed_status_thread (tp);
}
@@ -2821,6 +2861,21 @@ schedlock_applies (struct thread_info *tp)
execution_direction)));
}
+/* Calls target_commit_resume on all targets. */
+
+static void
+commit_resume_all_targets ()
+{
+ scoped_restore_current_thread restore_thread;
+
+ for (inferior *inf : all_non_exited_inferiors ())
+ if (inf->has_execution ())
+ {
+ switch_to_inferior_no_thread (inf);
+ target_commit_resume ();
+ }
+}
+
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
@@ -2835,7 +2890,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
struct regcache *regcache;
struct gdbarch *gdbarch;
CORE_ADDR pc;
- ptid_t resume_ptid;
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
int started;
@@ -2867,6 +2921,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
gdb_assert (!thread_is_in_step_over_chain (cur_thr));
+ ptid_t resume_ptid
+ = user_visible_resume_ptid (cur_thr->control.stepping_command);
+ process_stratum_target *resume_target
+ = user_visible_resume_target (resume_ptid);
+
if (addr == (CORE_ADDR) -1)
{
if (pc == cur_thr->suspend.stop_pc
@@ -2896,12 +2955,10 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
if (siggnal != GDB_SIGNAL_DEFAULT)
cur_thr->suspend.stop_signal = siggnal;
- resume_ptid = user_visible_resume_ptid (cur_thr->control.stepping_command);
-
/* If an exception is thrown from this point on, make sure to
propagate GDB's knowledge of the executing state to the
frontend/user running state. */
- scoped_finish_thread_state finish_state (resume_ptid);
+ scoped_finish_thread_state finish_state (resume_target, resume_ptid);
/* Even if RESUME_PTID is a wildcard, and we end up resuming fewer
threads (e.g., we might need to set threads stepping over
@@ -2910,7 +2967,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
inferior function, as in that case we pretend the inferior
doesn't run at all. */
if (!cur_thr->control.in_infcall)
- set_running (resume_ptid, 1);
+ set_running (resume_target, resume_ptid, 1);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -2945,7 +3002,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
threads. */
if (!non_stop && !schedlock_applies (cur_thr))
{
- for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ for (thread_info *tp : all_non_exited_threads (resume_target,
+ resume_ptid))
{
switch_to_thread_no_regs (tp);
@@ -3002,9 +3060,20 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
{
/* In all-stop, but the target is always in non-stop mode.
Start all other threads that are implicitly resumed too. */
- for (thread_info *tp : all_non_exited_threads (resume_ptid))
- {
- switch_to_thread_no_regs (tp);
+ for (thread_info *tp : all_non_exited_threads (resume_target,
+ resume_ptid))
+ {
+ switch_to_thread_no_regs (tp);
+
+ if (!tp->inf->has_execution ())
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: proceed: [%s] target has "
+ "no execution\n",
+ target_pid_to_str (tp->ptid).c_str ());
+ continue;
+ }
if (tp->resumed)
{
@@ -3048,7 +3117,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
}
}
- target_commit_resume ();
+ commit_resume_all_targets ();
finish_state.release ();
@@ -3070,10 +3139,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
void
start_remote (int from_tty)
{
- struct inferior *inferior;
-
- inferior = current_inferior ();
- inferior->control.stop_soon = STOP_QUIETLY_REMOTE;
+ inferior *inf = current_inferior ();
+ inf->control.stop_soon = STOP_QUIETLY_REMOTE;
/* Always go on waiting for the target, regardless of the mode. */
/* FIXME: cagney/1999-09-23: At present it isn't possible to
@@ -3089,7 +3156,7 @@ start_remote (int from_tty)
target_open() return to the caller an indication that the target
is currently running and GDB state should be set to the same as
for an async run. */
- wait_for_inferior ();
+ wait_for_inferior (inf);
/* Now that the inferior has stopped, do any bookkeeping like
loading shared libraries. We want to do this before normal_stop,
@@ -3140,11 +3207,13 @@ static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
static void
infrun_thread_stop_requested (ptid_t ptid)
{
+ process_stratum_target *curr_target = current_inferior ()->process_target ();
+
/* PTID was requested to stop. If the thread was already stopped,
but the user/frontend doesn't know about that yet (e.g., the
thread had been temporarily paused for some step-over), set up
for reporting the stop now. */
- for (thread_info *tp : all_threads (ptid))
+ for (thread_info *tp : all_threads (curr_target, ptid))
{
if (tp->state != THREAD_RUNNING)
continue;
@@ -3170,7 +3239,7 @@ infrun_thread_stop_requested (ptid_t ptid)
/* Clear the inline-frame state, since we're re-processing the
stop. */
- clear_inline_frame_state (tp->ptid);
+ clear_inline_frame_state (tp);
/* If this thread was paused because some other thread was
doing an inline-step over, let that finish first. Once
@@ -3189,7 +3258,8 @@ infrun_thread_stop_requested (ptid_t ptid)
static void
infrun_thread_thread_exit (struct thread_info *tp, int silent)
{
- if (target_last_wait_ptid == tp->ptid)
+ if (target_last_proc_target == tp->inf->process_target ()
+ && target_last_wait_ptid == tp->ptid)
nullify_last_target_wait_ptid ();
}
@@ -3285,19 +3355,20 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
had events. */
static struct thread_info *
-random_pending_event_thread (ptid_t waiton_ptid)
+random_pending_event_thread (inferior *inf, ptid_t waiton_ptid)
{
int num_events = 0;
- auto has_event = [] (thread_info *tp)
+ auto has_event = [&] (thread_info *tp)
{
- return (tp->resumed
+ return (tp->ptid.matches (waiton_ptid)
+ && tp->resumed
&& tp->suspend.waitstatus_pending_p);
};
/* First see how many events we have. Count only resumed threads
that have an event pending. */
- for (thread_info *tp : all_non_exited_threads (waiton_ptid))
+ for (thread_info *tp : inf->non_exited_threads ())
if (has_event (tp))
num_events++;
@@ -3314,7 +3385,7 @@ random_pending_event_thread (ptid_t waiton_ptid)
num_events, random_selector);
/* Select the Nth thread that has had an event. */
- for (thread_info *tp : all_non_exited_threads (waiton_ptid))
+ for (thread_info *tp : inf->non_exited_threads ())
if (has_event (tp))
if (random_selector-- == 0)
return tp;
@@ -3324,10 +3395,12 @@ random_pending_event_thread (ptid_t waiton_ptid)
/* Wrapper for target_wait that first checks whether threads have
pending statuses to report before actually asking the target for
- more events. */
+ more events. INF is the inferior we're using to call target_wait
+ on. */
static ptid_t
-do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
+do_target_wait_1 (inferior *inf, ptid_t ptid,
+ target_waitstatus *status, int options)
{
ptid_t event_ptid;
struct thread_info *tp;
@@ -3336,7 +3409,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
pending. */
if (ptid == minus_one_ptid || ptid.is_pid ())
{
- tp = random_pending_event_thread (ptid);
+ tp = random_pending_event_thread (inf, ptid);
}
else
{
@@ -3346,7 +3419,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
target_pid_to_str (ptid).c_str ());
/* We have a specific thread to check. */
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (inf, ptid);
gdb_assert (tp != NULL);
if (!tp->suspend.waitstatus_pending_p)
tp = NULL;
@@ -3453,6 +3526,109 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
return event_ptid;
}
+/* Returns true if INF has any resumed thread with a status
+ pending. */
+
+static bool
+threads_are_resumed_pending_p (inferior *inf)
+{
+ for (thread_info *tp : inf->non_exited_threads ())
+ if (tp->resumed
+ && tp->suspend.waitstatus_pending_p)
+ return true;
+
+ return false;
+}
+
+/* Wrapper for target_wait that first checks whether threads have
+ pending statuses to report before actually asking the target for
+ more events. Polls for events from all inferiors/targets. */
+
+static bool
+do_target_wait (ptid_t wait_ptid, execution_control_state *ecs, int options)
+{
+ int num_inferiors = 0;
+ int random_selector;
+
+ /* For fairness, we pick the first inferior/target to poll at
+ random, and then continue polling the rest of the inferior list
+ starting from that one in a circular fashion until the whole list
+ is polled once. */
+
+ auto inferior_matches = [&wait_ptid] (inferior *inf)
+ {
+ return (inf->process_target () != NULL
+ && (threads_are_executing (inf->process_target ())
+ || threads_are_resumed_pending_p (inf))
+ && ptid_t (inf->pid).matches (wait_ptid));
+ };
+
+ /* First see how many resumed inferiors we have. */
+ for (inferior *inf : all_inferiors ())
+ if (inferior_matches (inf))
+ num_inferiors++;
+
+ if (num_inferiors == 0)
+ {
+ ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+ return false;
+ }
+
+ /* Now randomly pick an inferior out of those that were resumed. */
+ random_selector = (int)
+ ((num_inferiors * (double) rand ()) / (RAND_MAX + 1.0));
+
+ if (debug_infrun && num_inferiors > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: Found %d inferiors, starting at #%d\n",
+ num_inferiors, random_selector);
+
+ /* Select the Nth inferior that was resumed. */
+
+ inferior *selected = nullptr;
+
+ for (inferior *inf : all_inferiors ())
+ if (inferior_matches (inf))
+ if (random_selector-- == 0)
+ {
+ selected = inf;
+ break;
+ }
+
+ /* Now poll for events out of each of the resumed inferior's
+ targets, starting from the selected one. */
+
+ auto do_wait = [&] (inferior *inf)
+ {
+ switch_to_inferior_no_thread (inf);
+
+ ecs->ptid = do_target_wait_1 (inf, wait_ptid, &ecs->ws, options);
+ ecs->target = inf->process_target ();
+ return (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+ };
+
+ /* Needed in all-stop+target-non-stop mode, because we end up here
+ spuriously after the target is all stopped and we've already
+ reported the stop to the user, polling for events. */
+ scoped_restore_current_thread restore_thread;
+
+ int inf_num = selected->num;
+ for (inferior *inf = selected; inf != NULL; inf = inf->next)
+ if (inferior_matches (inf))
+ if (do_wait (inf))
+ return true;
+
+ for (inferior *inf = inferior_list;
+ inf != NULL && inf->num < inf_num;
+ inf = inf->next)
+ if (inferior_matches (inf))
+ if (do_wait (inf))
+ return true;
+
+ ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+ return false;
+}
+
/* Prepare and stabilize the inferior for detaching it. E.g.,
detaching while a thread is displaced stepping is a recipe for
crashing it, as nothing would readjust the PC out of the scratch
@@ -3492,7 +3668,7 @@ prepare_for_detach (void)
don't get any event. */
target_dcache_invalidate ();
- ecs->ptid = do_target_wait (pid_ptid, &ecs->ws, 0);
+ do_target_wait (pid_ptid, ecs, 0);
if (debug_infrun)
print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws);
@@ -3500,7 +3676,8 @@ prepare_for_detach (void)
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
- scoped_finish_thread_state finish_state (minus_one_ptid);
+ scoped_finish_thread_state finish_state (inf->process_target (),
+ minus_one_ptid);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -3528,8 +3705,8 @@ prepare_for_detach (void)
When this function actually returns it means the inferior
should be left stopped and GDB should read more commands. */
-void
-wait_for_inferior (void)
+static void
+wait_for_inferior (inferior *inf)
{
if (debug_infrun)
fprintf_unfiltered
@@ -3540,13 +3717,13 @@ wait_for_inferior (void)
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
- scoped_finish_thread_state finish_state (minus_one_ptid);
+ scoped_finish_thread_state finish_state
+ (inf->process_target (), minus_one_ptid);
while (1)
{
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- ptid_t waiton_ptid = minus_one_ptid;
memset (ecs, 0, sizeof (*ecs));
@@ -3558,10 +3735,11 @@ wait_for_inferior (void)
don't get any event. */
target_dcache_invalidate ();
- ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, 0);
+ ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, 0);
+ ecs->target = inf->process_target ();
if (debug_infrun)
- print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
+ print_target_wait_results (minus_one_ptid, ecs->ptid, &ecs->ws);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -3687,7 +3865,6 @@ fetch_inferior_event (void *client_data)
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
int cmd_done = 0;
- ptid_t waiton_ptid = minus_one_ptid;
memset (ecs, 0, sizeof (*ecs));
@@ -3728,17 +3905,28 @@ fetch_inferior_event (void *client_data)
= make_scoped_restore (&execution_direction,
target_execution_direction ());
- ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
- target_can_async_p () ? TARGET_WNOHANG : 0);
+ if (!do_target_wait (minus_one_ptid, ecs, TARGET_WNOHANG))
+ return;
+
+ gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+
+ /* Switch to the target that generated the event, so we can do
+ target calls. Any inferior bound to the target will do, so we
+ just switch to the first we find. */
+ for (inferior *inf : all_inferiors (ecs->target))
+ {
+ switch_to_inferior_no_thread (inf);
+ break;
+ }
if (debug_infrun)
- print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
+ print_target_wait_results (minus_one_ptid, ecs->ptid, &ecs->ws);
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid;
- scoped_finish_thread_state finish_state (finish_ptid);
+ scoped_finish_thread_state finish_state (ecs->target, finish_ptid);
/* Get executed before scoped_restore_current_thread above to apply
still for the thread which has thrown the exception. */
@@ -3752,7 +3940,7 @@ fetch_inferior_event (void *client_data)
if (!ecs->wait_some_more)
{
- struct inferior *inf = find_inferior_ptid (ecs->ptid);
+ struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
int should_stop = 1;
struct thread_info *thr = ecs->event_thread;
@@ -3854,23 +4042,28 @@ init_thread_stepping_state (struct thread_info *tss)
tss->step_after_step_resume_breakpoint = 0;
}
-/* Set the cached copy of the last ptid/waitstatus. */
+/* Set the cached copy of the last target/ptid/waitstatus. */
void
-set_last_target_status (ptid_t ptid, struct target_waitstatus status)
+set_last_target_status (process_stratum_target *target, ptid_t ptid,
+ target_waitstatus status)
{
+ target_last_proc_target = target;
target_last_wait_ptid = ptid;
target_last_waitstatus = status;
}
-/* Return the cached copy of the last ptid/waitstatus returned
+/* Return the cached copy of the last target/ptid/waitstatus returned
by target_wait()/deprecated_target_wait_hook(). The data is
actually cached by handle_inferior_event(), which gets called
immediately after target_wait()/deprecated_target_wait_hook(). */
void
-get_last_target_status (ptid_t *ptid, struct target_waitstatus *status)
+get_last_target_status (process_stratum_target **target, ptid_t *ptid,
+ target_waitstatus *status)
{
+ if (target != nullptr)
+ *target = target_last_proc_target;
if (ptid != nullptr)
*ptid = target_last_wait_ptid;
if (status != nullptr)
@@ -3880,6 +4073,7 @@ get_last_target_status (ptid_t *ptid, struct target_waitstatus *status)
void
nullify_last_target_wait_ptid (void)
{
+ target_last_proc_target = nullptr;
target_last_wait_ptid = minus_one_ptid;
target_last_waitstatus = {};
}
@@ -3891,7 +4085,8 @@ context_switch (execution_control_state *ecs)
{
if (debug_infrun
&& ecs->ptid != inferior_ptid
- && ecs->event_thread != inferior_thread ())
+ && (inferior_ptid == null_ptid
+ || ecs->event_thread != inferior_thread ()))
{
fprintf_unfiltered (gdb_stdlog, "infrun: Switching context from %s ",
target_pid_to_str (inferior_ptid).c_str ());
@@ -4177,20 +4372,19 @@ fill_in_stop_func (struct gdbarch *gdbarch,
static enum stop_kind
get_inferior_stop_soon (execution_control_state *ecs)
{
- struct inferior *inf = find_inferior_ptid (ecs->ptid);
+ struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
gdb_assert (inf != NULL);
return inf->control.stop_soon;
}
-/* Wait for one event. Store the resulting waitstatus in WS, and
- return the event ptid. */
+/* Poll for one event out of the current target. Store the resulting
+ waitstatus in WS, and return the event ptid. Does not block. */
static ptid_t
-wait_one (struct target_waitstatus *ws)
+poll_one_curr_target (struct target_waitstatus *ws)
{
ptid_t event_ptid;
- ptid_t wait_ptid = minus_one_ptid;
overlay_cache_invalid = 1;
@@ -4201,16 +4395,101 @@ wait_one (struct target_waitstatus *ws)
target_dcache_invalidate ();
if (deprecated_target_wait_hook)
- event_ptid = deprecated_target_wait_hook (wait_ptid, ws, 0);
+ event_ptid = deprecated_target_wait_hook (minus_one_ptid, ws, TARGET_WNOHANG);
else
- event_ptid = target_wait (wait_ptid, ws, 0);
+ event_ptid = target_wait (minus_one_ptid, ws, TARGET_WNOHANG);
if (debug_infrun)
- print_target_wait_results (wait_ptid, event_ptid, ws);
+ print_target_wait_results (minus_one_ptid, event_ptid, ws);
return event_ptid;
}
+/* An event reported by wait_one. */
+
+struct wait_one_event
+{
+ /* The target the event came out of. */
+ process_stratum_target *target;
+
+ /* The PTID the event was for. */
+ ptid_t ptid;
+
+ /* The waitstatus. */
+ target_waitstatus ws;
+};
+
+/* Wait for one event out of any target. */
+
+static wait_one_event
+wait_one ()
+{
+ while (1)
+ {
+ for (inferior *inf : all_inferiors ())
+ {
+ process_stratum_target *target = inf->process_target ();
+ if (target == NULL
+ || !target->is_async_p ()
+ || !target->threads_executing)
+ continue;
+
+ switch_to_inferior_no_thread (inf);
+
+ wait_one_event event;
+ event.target = target;
+ event.ptid = poll_one_curr_target (&event.ws);
+
+ if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ {
+ /* If nothing is resumed, remove the target from the
+ event loop. */
+ target_async (0);
+ }
+ else if (event.ws.kind != TARGET_WAITKIND_IGNORE)
+ return event;
+ }
+
+ /* Block waiting for some event. */
+
+ fd_set readfds;
+ int nfds = 0;
+
+ FD_ZERO (&readfds);
+
+ for (inferior *inf : all_inferiors ())
+ {
+ process_stratum_target *target = inf->process_target ();
+ if (target == NULL
+ || !target->is_async_p ()
+ || !target->threads_executing)
+ continue;
+
+ int fd = target->async_wait_fd ();
+ FD_SET (fd, &readfds);
+ if (nfds <= fd)
+ nfds = fd + 1;
+ }
+
+ if (nfds == 0)
+ {
+ /* No waitable targets left. All must be stopped. */
+ return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}};
+ }
+
+ QUIT;
+
+ int numfds = interruptible_select (nfds, &readfds, 0, NULL, 0);
+ if (numfds < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ perror_with_name ("interruptible_select");
+ }
+ }
+}
+
/* Generate a wrapper for target_stopped_by_REASON that works on PTID
instead of the current thread. */
#define THREAD_STOPPED_BY(REASON) \
@@ -4333,8 +4612,6 @@ stop_all_threads (void)
"iterations=%d\n", pass, iterations);
while (1)
{
- ptid_t event_ptid;
- struct target_waitstatus ws;
int need_wait = 0;
update_thread_list ();
@@ -4392,7 +4669,10 @@ stop_all_threads (void)
if (pass > 0)
pass = -1;
- event_ptid = wait_one (&ws);
+ wait_one_event event = wait_one ();
+ target_waitstatus &ws = event.ws;
+ ptid_t &event_ptid = event.ptid;
+
if (debug_infrun)
{
fprintf_unfiltered (gdb_stdlog,
@@ -4411,9 +4691,9 @@ stop_all_threads (void)
}
else
{
- thread_info *t = find_thread_ptid (event_ptid);
+ thread_info *t = find_thread_ptid (event.target, event_ptid);
if (t == NULL)
- t = add_thread (event_ptid);
+ t = add_thread (event.target, event_ptid);
t->stop_requested = 0;
t->executing = 0;
@@ -4422,7 +4702,7 @@ stop_all_threads (void)
/* This may be the first time we see the inferior report
a stop. */
- inferior *inf = find_inferior_ptid (event_ptid);
+ inferior *inf = find_inferior_ptid (event.target, event_ptid);
if (inf->needs_setup)
{
switch_to_thread_no_regs (t);
@@ -4572,7 +4852,7 @@ handle_no_resumed (struct execution_control_state *ecs)
the synchronous command show "no unwaited-for " to the user. */
update_thread_list ();
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (ecs->target))
{
if (thread->executing
|| thread->suspend.waitstatus_pending_p)
@@ -4592,7 +4872,7 @@ handle_no_resumed (struct execution_control_state *ecs)
process exited meanwhile (thus updating the thread list results
in an empty thread list). In this case we know we'll be getting
a process exit event shortly. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (ecs->target))
{
thread_info *thread = any_live_thread_of_inferior (inf);
if (thread == NULL)
@@ -4662,8 +4942,8 @@ handle_inferior_event (struct execution_control_state *ecs)
&& handle_no_resumed (ecs))
return;
- /* Cache the last pid/waitstatus. */
- set_last_target_status (ecs->ptid, ecs->ws);
+ /* Cache the last target/ptid/waitstatus. */
+ set_last_target_status (ecs->target, ecs->ptid, ecs->ws);
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = STOP_NONE;
@@ -4680,10 +4960,10 @@ handle_inferior_event (struct execution_control_state *ecs)
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
{
- ecs->event_thread = find_thread_ptid (ecs->ptid);
+ ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
/* If it's a new thread, add it to the thread database. */
if (ecs->event_thread == NULL)
- ecs->event_thread = add_thread (ecs->ptid);
+ ecs->event_thread = add_thread (ecs->target, ecs->ptid);
/* Disable range stepping. If the next step request could use a
range, this will be end up re-enabled then. */
@@ -4755,10 +5035,10 @@ handle_inferior_event (struct execution_control_state *ecs)
else
mark_ptid = ecs->ptid;
- set_executing (mark_ptid, 0);
+ set_executing (ecs->target, mark_ptid, 0);
/* Likewise the resumed flag. */
- set_resumed (mark_ptid, 0);
+ set_resumed (ecs->target, mark_ptid, 0);
}
switch (ecs->ws.kind)
@@ -4859,7 +5139,7 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_EXITED:
case TARGET_WAITKIND_SIGNALLED:
inferior_ptid = ecs->ptid;
- set_current_inferior (find_inferior_ptid (ecs->ptid));
+ set_current_inferior (find_inferior_ptid (ecs->target, ecs->ptid));
set_current_program_space (current_inferior ()->pspace);
handle_vfork_child_exec_or_exit (0);
target_terminal::ours (); /* Must do this before mourn anyway. */
@@ -4932,7 +5212,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
if (displaced_step_in_progress_thread (ecs->event_thread))
{
struct inferior *parent_inf
- = find_inferior_ptid (ecs->ptid);
+ = find_inferior_ptid (ecs->target, ecs->ptid);
struct regcache *child_regcache;
CORE_ADDR parent_pc;
@@ -4963,7 +5243,8 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
list yet at this point. */
child_regcache
- = get_thread_arch_aspace_regcache (ecs->ws.value.related_pid,
+ = get_thread_arch_aspace_regcache (parent_inf->process_target (),
+ ecs->ws.value.related_pid,
gdbarch,
parent_inf->aspace);
/* Read PC value of parent process. */
@@ -5031,10 +5312,16 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+ process_stratum_target *targ
+ = ecs->event_thread->inf->process_target ();
+
should_resume = follow_fork ();
+ /* Note that one of these may be an invalid pointer,
+ depending on detach_fork. */
thread_info *parent = ecs->event_thread;
- thread_info *child = find_thread_ptid (ecs->ws.value.related_pid);
+ thread_info *child
+ = find_thread_ptid (targ, ecs->ws.value.related_pid);
/* At this point, the parent is marked running, and the
child is marked stopped. */
@@ -5847,7 +6134,7 @@ handle_signal_stop (struct execution_control_state *ecs)
if (random_signal)
{
/* Signal not for debugging purposes. */
- struct inferior *inf = find_inferior_ptid (ecs->ptid);
+ struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal;
if (debug_infrun)
@@ -6896,7 +7183,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
/* Ignore threads of processes the caller is not
resuming. */
if (!sched_multi
- && tp->ptid.pid () != ecs->ptid.pid ())
+ && (tp->inf->process_target () != ecs->target
+ || tp->inf->pid != ecs->ptid.pid ()))
continue;
/* When stepping over a breakpoint, we lock all threads
@@ -7842,7 +8130,7 @@ print_stop_event (struct ui_out *uiout, bool displays)
struct target_waitstatus last;
struct thread_info *tp;
- get_last_target_status (nullptr, &last);
+ get_last_target_status (nullptr, nullptr, &last);
{
scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout);
@@ -7962,7 +8250,7 @@ normal_stop (void)
{
struct target_waitstatus last;
- get_last_target_status (nullptr, &last);
+ get_last_target_status (nullptr, nullptr, &last);
new_stop_id ();
@@ -7971,10 +8259,10 @@ normal_stop (void)
frontend/user running state. A QUIT is an easy exception to see
here, so do this before any filtered output. */
- gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
+ ptid_t finish_ptid = null_ptid;
if (!non_stop)
- maybe_finish_thread_state.emplace (minus_one_ptid);
+ finish_ptid = minus_one_ptid;
else if (last.kind == TARGET_WAITKIND_SIGNALLED
|| last.kind == TARGET_WAITKIND_EXITED)
{
@@ -7984,10 +8272,17 @@ normal_stop (void)
linux-fork.c automatically switches to another fork from
within target_mourn_inferior. */
if (inferior_ptid != null_ptid)
- maybe_finish_thread_state.emplace (ptid_t (inferior_ptid.pid ()));
+ finish_ptid = ptid_t (inferior_ptid.pid ());
}
else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
- maybe_finish_thread_state.emplace (inferior_ptid);
+ finish_ptid = inferior_ptid;
+
+ gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
+ if (finish_ptid != null_ptid)
+ {
+ maybe_finish_thread_state.emplace
+ (user_visible_resume_target (finish_ptid), finish_ptid);
+ }
/* As we're presenting a stop, and potentially removing breakpoints,
update the thread list so we can tell whether there are threads
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 042edbbb66..2412d26123 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -25,6 +25,7 @@ struct target_waitstatus;
struct frame_info;
struct address_space;
struct return_value_info;
+struct process_stratum_target;
/* True if we are debugging run control. */
extern unsigned int debug_infrun;
@@ -93,7 +94,13 @@ extern void proceed (CORE_ADDR, enum gdb_signal);
resumed. */
extern ptid_t user_visible_resume_ptid (int step);
-extern void wait_for_inferior (void);
+/* Return the process_stratum target that we will proceed, in the
+ perspective of the user/frontend. If RESUME_PTID is
+ MINUS_ONE_PTID, then we'll resume all threads of all targets, so
+ the function returns NULL. Otherwise, we'll be resuming a process
+ or thread of the current process, so we return the current
+ inferior's process stratum target. */
+extern process_stratum_target *user_visible_resume_target (ptid_t resume_ptid);
/* Return control to GDB when the inferior stops for real. Print
appropriate messages, remove breakpoints, give terminal our modes,
@@ -101,10 +108,11 @@ extern void wait_for_inferior (void);
target, false otherwise. */
extern int normal_stop (void);
-extern void get_last_target_status (ptid_t *ptid,
+extern void get_last_target_status (process_stratum_target **target,
+ ptid_t *ptid,
struct target_waitstatus *status);
-extern void set_last_target_status (ptid_t ptid,
+extern void set_last_target_status (process_stratum_target *target, ptid_t ptid,
struct target_waitstatus status);
extern void nullify_last_target_wait_ptid ();
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index b039ab8fa2..c4958518e5 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -96,37 +96,54 @@ find_inline_frame_state (thread_info *thread)
return &state;
}
-/* Forget about any hidden inlined functions in PTID, which is new or
- about to be resumed. PTID may be minus_one_ptid (all processes)
- or a PID (all threads in this process). */
+/* See inline-frame.h. */
void
-clear_inline_frame_state (ptid_t ptid)
+clear_inline_frame_state (process_stratum_target *target, ptid_t filter_ptid)
{
- if (ptid == minus_one_ptid)
- {
- inline_states.clear ();
- return;
- }
+ gdb_assert (target != NULL);
- if (ptid.is_pid ())
+ if (filter_ptid == minus_one_ptid || filter_ptid.is_pid ())
{
- int pid = ptid.pid ();
+ auto matcher = [target, &filter_ptid] (const inline_state &state)
+ {
+ thread_info *t = state.thread;
+ return (t->inf->process_target () == target
+ && t->ptid.matches (filter_ptid));
+ };
+
auto it = std::remove_if (inline_states.begin (), inline_states.end (),
- [pid] (const inline_state &state)
- {
- return pid == state.thread->inf->pid;
- });
+ matcher);
inline_states.erase (it, inline_states.end ());
return;
}
+
+ auto matcher = [target, &filter_ptid] (const inline_state &state)
+ {
+ thread_info *t = state.thread;
+ return (t->inf->process_target () == target
+ && filter_ptid == t->ptid);
+ };
+
+ auto it = std::find_if (inline_states.begin (), inline_states.end (),
+ matcher);
+
+ if (it != inline_states.end ())
+ unordered_remove (inline_states, it);
+}
+
+/* See inline-frame.h. */
+
+void
+clear_inline_frame_state (thread_info *thread)
+{
auto it = std::find_if (inline_states.begin (), inline_states.end (),
- [&ptid] (const inline_state &state)
+ [thread] (const inline_state &state)
{
- return ptid == state.thread->ptid;
+ return thread == state.thread;
});
if (it != inline_states.end ())
diff --git a/gdb/inline-frame.h b/gdb/inline-frame.h
index e1d98f5ab5..6ba748ee22 100644
--- a/gdb/inline-frame.h
+++ b/gdb/inline-frame.h
@@ -23,6 +23,7 @@
struct frame_info;
struct frame_unwind;
struct bpstats;
+struct process_stratum_target;
/* The inline frame unwinder. */
@@ -39,10 +40,15 @@ extern const struct frame_unwind inline_frame_unwind;
void skip_inline_frames (thread_info *thread, struct bpstats *stop_chain);
/* Forget about any hidden inlined functions in PTID, which is new or
- about to be resumed. If PTID is minus_one_ptid, forget about all
- hidden inlined functions. */
+ about to be resumed. PTID may be minus_one_ptid (all processes of
+ TARGET) or a PID (all threads in this process of TARGET). */
-void clear_inline_frame_state (ptid_t ptid);
+void clear_inline_frame_state (process_stratum_target *target, ptid_t ptid);
+
+/* Forget about any hidden inlined functions in THREAD, which is new
+ or about to be resumed. */
+
+void clear_inline_frame_state (thread_info *thread);
/* Step into an inlined function by unhiding it. */
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index ab96be2f38..d3e094f530 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -519,7 +519,7 @@ Please switch to another checkpoint before deleting the current one"));
list, waitpid the ptid.
If fi->parent_ptid is a part of lwp and it is stopped, waitpid the
ptid. */
- thread_info *parent = find_thread_ptid (pptid);
+ thread_info *parent = find_thread_ptid (linux_target, pptid);
if ((parent == NULL && find_fork_ptid (pptid))
|| (parent != NULL && parent->state == THREAD_STOPPED))
{
@@ -679,7 +679,7 @@ checkpoint_command (const char *args, int from_tty)
error (_("checkpoint: call_function_by_hand returned null."));
retpid = value_as_long (ret);
- get_last_target_status (&last_target_ptid, &last_target_waitstatus);
+ get_last_target_status (nullptr, &last_target_ptid, &last_target_waitstatus);
fp = find_fork_pid (retpid);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 8f7d4b6eba..89a0b9378f 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -518,9 +518,12 @@ linux_nat_target::follow_fork (int follow_child, int detach_fork)
}
else
{
- scoped_restore save_inferior_ptid
- = make_scoped_restore (&inferior_ptid);
- inferior_ptid = child_ptid;
+ /* Switching inferior_ptid is not enough, because then
+ inferior_thread () would crash by not finding the thread
+ in the current inferior. */
+ scoped_restore_current_thread restore_current_thread;
+ thread_info *child = find_thread_ptid (this, child_ptid);
+ switch_to_thread (child);
/* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
@@ -992,7 +995,7 @@ linux_nat_switch_fork (ptid_t new_ptid)
/* This changes the thread's ptid while preserving the gdb thread
num. Also changes the inferior pid, while preserving the
inferior num. */
- thread_change_ptid (inferior_ptid, new_ptid);
+ thread_change_ptid (linux_target, inferior_ptid, new_ptid);
/* We've just told GDB core that the thread changed target id, but,
in fact, it really is a different thread, with different register
@@ -1005,7 +1008,7 @@ linux_nat_switch_fork (ptid_t new_ptid)
static void
exit_lwp (struct lwp_info *lp)
{
- struct thread_info *th = find_thread_ptid (lp->ptid);
+ struct thread_info *th = find_thread_ptid (linux_target, lp->ptid);
if (th)
{
@@ -1165,9 +1168,9 @@ attach_proc_task_lwp_callback (ptid_t ptid)
/* Also add the LWP to gdb's thread list, in case a
matching libthread_db is not found (or the process uses
raw clone). */
- add_thread (lp->ptid);
- set_running (lp->ptid, 1);
- set_executing (lp->ptid, 1);
+ add_thread (linux_target, lp->ptid);
+ set_running (linux_target, lp->ptid, 1);
+ set_executing (linux_target, lp->ptid, 1);
}
return 1;
@@ -1206,7 +1209,7 @@ linux_nat_target::attach (const char *args, int from_tty)
ptid = ptid_t (inferior_ptid.pid (),
inferior_ptid.pid (),
0);
- thread_change_ptid (inferior_ptid, ptid);
+ thread_change_ptid (linux_target, inferior_ptid, ptid);
/* Add the initial process as the first LWP to the list. */
lp = add_initial_lwp (ptid);
@@ -1307,7 +1310,7 @@ get_detach_signal (struct lwp_info *lp)
signo = gdb_signal_from_host (WSTOPSIG (lp->status));
else
{
- struct thread_info *tp = find_thread_ptid (lp->ptid);
+ struct thread_info *tp = find_thread_ptid (linux_target, lp->ptid);
if (target_is_non_stop_p () && !tp->executing)
{
@@ -1319,10 +1322,12 @@ get_detach_signal (struct lwp_info *lp)
else if (!target_is_non_stop_p ())
{
ptid_t last_ptid;
+ process_stratum_target *last_target;
- get_last_target_status (&last_ptid, nullptr);
+ get_last_target_status (&last_target, &last_ptid, nullptr);
- if (lp->ptid.lwp () == last_ptid.lwp ())
+ if (last_target == linux_target
+ && lp->ptid.lwp () == last_ptid.lwp ())
signo = tp->suspend.stop_signal;
}
}
@@ -1519,7 +1524,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
handle the case of stepping a breakpoint instruction). */
if (step)
{
- struct regcache *regcache = get_thread_regcache (lp->ptid);
+ struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
lp->stop_pc = regcache_read_pc (regcache);
}
@@ -1538,7 +1543,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
lp->stopped = 0;
lp->core = -1;
lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
- registers_changed_ptid (lp->ptid);
+ registers_changed_ptid (linux_target, lp->ptid);
}
/* Called when we try to resume a stopped LWP and that errors out. If
@@ -1597,7 +1602,7 @@ resume_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
{
if (lp->stopped)
{
- struct inferior *inf = find_inferior_ptid (lp->ptid);
+ struct inferior *inf = find_inferior_ptid (linux_target, lp->ptid);
if (inf->vfork_child != NULL)
{
@@ -1651,7 +1656,7 @@ linux_nat_resume_callback (struct lwp_info *lp, struct lwp_info *except)
{
struct thread_info *thread;
- thread = find_thread_ptid (lp->ptid);
+ thread = find_thread_ptid (linux_target, lp->ptid);
if (thread != NULL)
{
signo = thread->suspend.stop_signal;
@@ -1808,7 +1813,7 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
{
struct target_waitstatus *ourstatus = &lp->waitstatus;
struct gdbarch *gdbarch = target_thread_architecture (lp->ptid);
- thread_info *thread = find_thread_ptid (lp->ptid);
+ thread_info *thread = find_thread_ptid (linux_target, lp->ptid);
int syscall_number = (int) gdbarch_get_syscall_number (gdbarch, thread);
if (stopping)
@@ -2028,15 +2033,15 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
/* The process is not using thread_db. Add the LWP to
GDB's list. */
target_post_attach (new_lp->ptid.lwp ());
- add_thread (new_lp->ptid);
+ add_thread (linux_target, new_lp->ptid);
}
/* Even if we're stopping the thread for some reason
internal to this module, from the perspective of infrun
and the user/frontend, this new thread is running until
it next reports a stop. */
- set_running (new_lp->ptid, 1);
- set_executing (new_lp->ptid, 1);
+ set_running (linux_target, new_lp->ptid, 1);
+ set_executing (linux_target, new_lp->ptid, 1);
if (WSTOPSIG (status) != SIGSTOP)
{
@@ -2259,7 +2264,7 @@ wait_lwp (struct lwp_info *lp)
if (lp->must_set_ptrace_flags)
{
- struct inferior *inf = find_inferior_pid (lp->ptid.pid ());
+ inferior *inf = find_inferior_pid (linux_target, lp->ptid.pid ());
int options = linux_nat_ptrace_options (inf->attach_flag);
linux_enable_event_reporting (lp->ptid.lwp (), options);
@@ -2486,7 +2491,7 @@ linux_nat_target::low_status_is_event (int status)
static int
stop_wait_callback (struct lwp_info *lp)
{
- struct inferior *inf = find_inferior_ptid (lp->ptid);
+ inferior *inf = find_inferior_ptid (linux_target, lp->ptid);
/* If this is a vfork parent, bail out, it is not going to report
any SIGSTOP until the vfork is done with. */
@@ -2579,7 +2584,7 @@ status_callback (struct lwp_info *lp)
if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
|| lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
{
- struct regcache *regcache = get_thread_regcache (lp->ptid);
+ struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
CORE_ADDR pc;
int discard = 0;
@@ -2700,7 +2705,7 @@ save_stop_reason (struct lwp_info *lp)
if (!linux_target->low_status_is_event (lp->status))
return;
- regcache = get_thread_regcache (lp->ptid);
+ regcache = get_thread_regcache (linux_target, lp->ptid);
gdbarch = regcache->arch ();
pc = regcache_read_pc (regcache);
@@ -2962,7 +2967,7 @@ linux_nat_filter_event (int lwpid, int status)
lp = add_lwp (ptid_t (lwpid, lwpid, 0));
lp->stopped = 1;
lp->resumed = 1;
- add_thread (lp->ptid);
+ add_thread (linux_target, lp->ptid);
}
if (WIFSTOPPED (status) && !lp)
@@ -2988,7 +2993,7 @@ linux_nat_filter_event (int lwpid, int status)
if (WIFSTOPPED (status) && lp->must_set_ptrace_flags)
{
- struct inferior *inf = find_inferior_pid (lp->ptid.pid ());
+ inferior *inf = find_inferior_pid (linux_target, lp->ptid.pid ());
int options = linux_nat_ptrace_options (inf->attach_flag);
linux_enable_event_reporting (lp->ptid.lwp (), options);
@@ -3270,7 +3275,7 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
if (inferior_ptid.is_pid ())
{
/* Upgrade the main thread's ptid. */
- thread_change_ptid (inferior_ptid,
+ thread_change_ptid (linux_target, inferior_ptid,
ptid_t (inferior_ptid.pid (),
inferior_ptid.pid (), 0));
@@ -3415,7 +3420,7 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
&& !USE_SIGTRAP_SIGINFO)
{
- struct regcache *regcache = get_thread_regcache (lp->ptid);
+ struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
struct gdbarch *gdbarch = regcache->arch ();
int decr_pc = gdbarch_decr_pc_after_break (gdbarch);
@@ -3516,7 +3521,7 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, const ptid_t wait_ptid)
}
else
{
- struct regcache *regcache = get_thread_regcache (lp->ptid);
+ struct regcache *regcache = get_thread_regcache (linux_target, lp->ptid);
struct gdbarch *gdbarch = regcache->arch ();
try
@@ -4389,6 +4394,12 @@ linux_async_pipe (int enable)
return previous;
}
+int
+linux_nat_target::async_wait_fd ()
+{
+ return linux_nat_event_pipe[0];
+}
+
/* target_async implementation. */
void
@@ -4446,7 +4457,7 @@ linux_nat_stop_lwp (struct lwp_info *lwp)
if (debug_linux_nat)
{
- if (find_thread_ptid (lwp->ptid)->stop_requested)
+ if (find_thread_ptid (linux_target, lwp->ptid)->stop_requested)
fprintf_unfiltered (gdb_stdlog,
"LNSL: already stopped/stop_requested %s\n",
target_pid_to_str (lwp->ptid).c_str ());
@@ -4503,7 +4514,7 @@ linux_nat_target::thread_address_space (ptid_t ptid)
pid = ptid.pid ();
}
- inf = find_inferior_pid (pid);
+ inf = find_inferior_pid (this, pid);
gdb_assert (inf != NULL);
return inf->aspace;
}
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 0c1695ad10..3c1045f3a4 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -88,6 +88,7 @@ public:
bool supports_non_stop () override;
bool always_non_stop_p () override;
+ int async_wait_fd () override;
void async (int) override;
void close () override;
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 7d0c3e9fc9..025cdb470a 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1717,7 +1717,8 @@ linux_corefile_thread (struct thread_info *info,
{
struct regcache *regcache;
- regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
+ regcache = get_thread_arch_regcache (info->inf->process_target (),
+ info->ptid, args->gdbarch);
target_fetch_registers (regcache, -1);
gdb::byte_vector siginfo_data = linux_get_siginfo_data (info, args->gdbarch);
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index b2c9d6d77c..a3a71c742b 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -167,6 +167,9 @@ struct thread_db_info
{
struct thread_db_info *next;
+ /* The target this thread_db_info is bound to. */
+ process_stratum_target *process_target;
+
/* Process id this object refers to. */
int pid;
@@ -227,6 +230,7 @@ add_thread_db_info (void *handle)
{
struct thread_db_info *info = XCNEW (struct thread_db_info);
+ info->process_target = current_inferior ()->process_target ();
info->pid = inferior_ptid.pid ();
info->handle = handle;
@@ -245,12 +249,12 @@ add_thread_db_info (void *handle)
related to process PID, if any; NULL otherwise. */
static struct thread_db_info *
-get_thread_db_info (int pid)
+get_thread_db_info (process_stratum_target *targ, int pid)
{
struct thread_db_info *info;
for (info = thread_db_list; info; info = info->next)
- if (pid == info->pid)
+ if (targ == info->process_target && pid == info->pid)
return info;
return NULL;
@@ -264,14 +268,14 @@ static const char *thread_db_err_str (td_err_e err);
LIBTHREAD_DB_SO's dlopen'ed handle. */
static void
-delete_thread_db_info (int pid)
+delete_thread_db_info (process_stratum_target *targ, int pid)
{
struct thread_db_info *info, *info_prev;
info_prev = NULL;
for (info = thread_db_list; info; info_prev = info, info = info->next)
- if (pid == info->pid)
+ if (targ == info->process_target && pid == info->pid)
break;
if (info == NULL)
@@ -405,7 +409,7 @@ thread_from_lwp (thread_info *stopped, ptid_t ptid)
LWP. */
gdb_assert (ptid.lwp () != 0);
- info = get_thread_db_info (ptid.pid ());
+ info = get_thread_db_info (stopped->inf->process_target (), ptid.pid ());
/* Access an lwp we know is stopped. */
info->proc_handle.thread = stopped;
@@ -421,7 +425,7 @@ thread_from_lwp (thread_info *stopped, ptid_t ptid)
thread_db_err_str (err));
/* Fill the cache. */
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (stopped->inf->process_target (), ptid);
return record_thread (info, tp, ptid, &th, &ti);
}
\f
@@ -433,12 +437,12 @@ thread_db_notice_clone (ptid_t parent, ptid_t child)
{
struct thread_db_info *info;
- info = get_thread_db_info (child.pid ());
+ info = get_thread_db_info (linux_target, child.pid ());
if (info == NULL)
return 0;
- thread_info *stopped = find_thread_ptid (parent);
+ thread_info *stopped = find_thread_ptid (linux_target, parent);
thread_from_lwp (stopped, child);
@@ -683,13 +687,13 @@ check_thread_db_callback (const td_thrhandle_t *th, void *arg)
to how GDB accesses TLS could result in this passing
without exercising the calls it's supposed to. */
ptid_t ptid = ptid_t (tdb_testinfo->info->pid, ti.ti_lid, 0);
- struct thread_info *thread_info = find_thread_ptid (ptid);
+ thread_info *thread_info = find_thread_ptid (linux_target, ptid);
if (thread_info != NULL && thread_info->priv != NULL)
{
LOG ("; errno");
scoped_restore_current_thread restore_current_thread;
- switch_to_thread (ptid);
+ switch_to_thread (thread_info);
expression_up expr = parse_expression ("(int) errno");
struct value *val = evaluate_expression (expr.get ());
@@ -938,10 +942,8 @@ try_thread_db_load_1 (struct thread_db_info *info)
}
/* The thread library was detected. Activate the thread_db target
- if this is the first process using it. */
- if (thread_db_list->next == NULL)
- push_target (&the_thread_db_target);
-
+ for this process. */
+ push_target (&the_thread_db_target);
return true;
}
@@ -1011,7 +1013,8 @@ try_thread_db_load (const char *library, bool check_auto_load_safe)
return true;
/* This library "refused" to work on current inferior. */
- delete_thread_db_info (inferior_ptid.pid ());
+ delete_thread_db_info (current_inferior ()->process_target (),
+ inferior_ptid.pid ());
return false;
}
@@ -1179,7 +1182,8 @@ thread_db_load (void)
{
struct thread_db_info *info;
- info = get_thread_db_info (inferior_ptid.pid ());
+ info = get_thread_db_info (current_inferior ()->process_target (),
+ inferior_ptid.pid ());
if (info != NULL)
return true;
@@ -1346,7 +1350,7 @@ record_thread (struct thread_db_info *info,
thread with this PTID, but it's marked exited, then the kernel
reused the tid of an old thread. */
if (tp == NULL || tp->state == THREAD_EXITED)
- tp = add_thread_with_info (ptid, priv);
+ tp = add_thread_with_info (info->process_target, ptid, priv);
else
tp->priv.reset (priv);
@@ -1359,16 +1363,14 @@ record_thread (struct thread_db_info *info,
void
thread_db_target::detach (inferior *inf, int from_tty)
{
- delete_thread_db_info (inf->pid);
+ delete_thread_db_info (inf->process_target (), inf->pid);
beneath ()->detach (inf, from_tty);
/* NOTE: From this point on, inferior_ptid is null_ptid. */
- /* If there are no more processes using libpthread, detach the
- thread_db target ops. */
- if (!thread_db_list)
- unpush_target (this);
+ /* Detach the thread_db target from this inferior. */
+ unpush_target (this);
}
ptid_t
@@ -1377,7 +1379,10 @@ thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
{
struct thread_db_info *info;
- ptid = beneath ()->wait (ptid, ourstatus, options);
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
+
+ ptid = beneath->wait (ptid, ourstatus, options);
switch (ourstatus->kind)
{
@@ -1388,7 +1393,7 @@ thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
return ptid;
}
- info = get_thread_db_info (ptid.pid ());
+ info = get_thread_db_info (beneath, ptid.pid ());
/* If this process isn't using thread_db, we're done. */
if (info == NULL)
@@ -1398,15 +1403,14 @@ thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
{
/* New image, it may or may not end up using thread_db. Assume
not unless we find otherwise. */
- delete_thread_db_info (ptid.pid ());
- if (!thread_db_list)
- unpush_target (&the_thread_db_target);
+ delete_thread_db_info (beneath, ptid.pid ());
+ unpush_target (this);
return ptid;
}
/* Fill in the thread's user-level thread id and status. */
- thread_from_lwp (find_thread_ptid (ptid), ptid);
+ thread_from_lwp (find_thread_ptid (beneath, ptid), ptid);
return ptid;
}
@@ -1414,13 +1418,15 @@ thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
void
thread_db_target::mourn_inferior ()
{
- delete_thread_db_info (inferior_ptid.pid ());
+ process_stratum_target *target_beneath
+ = as_process_stratum_target (this->beneath ());
+
+ delete_thread_db_info (target_beneath, inferior_ptid.pid ());
- beneath ()->mourn_inferior ();
+ target_beneath->mourn_inferior ();
- /* Detach thread_db target ops. */
- if (!thread_db_list)
- unpush_target (&the_thread_db_target);
+ /* Detach the thread_db target from this inferior. */
+ unpush_target (this);
}
struct callback_data
@@ -1485,7 +1491,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
}
ptid_t ptid (info->pid, ti.ti_lid);
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (info->process_target, ptid);
if (tp == NULL || tp->priv == NULL)
record_thread (info, tp, ptid, th_p, &ti);
@@ -1552,7 +1558,8 @@ thread_db_find_new_threads_2 (thread_info *stopped, bool until_no_new)
struct thread_db_info *info;
int i, loop;
- info = get_thread_db_info (stopped->ptid.pid ());
+ info = get_thread_db_info (stopped->inf->process_target (),
+ stopped->ptid.pid ());
/* Access an lwp we know is stopped. */
info->proc_handle.thread = stopped;
@@ -1595,16 +1602,14 @@ thread_db_target::update_thread_list ()
for (inferior *inf : all_inferiors ())
{
- struct thread_info *thread;
-
if (inf->pid == 0)
continue;
- info = get_thread_db_info (inf->pid);
+ info = get_thread_db_info (inf->process_target (), inf->pid);
if (info == NULL)
continue;
- thread = any_live_thread_of_inferior (inf);
+ thread_info *thread = any_live_thread_of_inferior (inf);
if (thread == NULL || thread->executing)
continue;
@@ -1632,7 +1637,7 @@ thread_db_target::update_thread_list ()
std::string
thread_db_target::pid_to_str (ptid_t ptid)
{
- struct thread_info *thread_info = find_thread_ptid (ptid);
+ thread_info *thread_info = find_thread_ptid (current_inferior (), ptid);
if (thread_info != NULL && thread_info->priv != NULL)
{
@@ -1725,9 +1730,10 @@ thread_db_target::get_thread_local_address (ptid_t ptid,
CORE_ADDR offset)
{
struct thread_info *thread_info;
-
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
/* Find the matching thread. */
- thread_info = find_thread_ptid (ptid);
+ thread_info = find_thread_ptid (beneath, ptid);
/* We may not have discovered the thread yet. */
if (thread_info != NULL && thread_info->priv == NULL)
@@ -1737,7 +1743,7 @@ thread_db_target::get_thread_local_address (ptid_t ptid,
{
td_err_e err;
psaddr_t address;
- thread_db_info *info = get_thread_db_info (ptid.pid ());
+ thread_db_info *info = get_thread_db_info (beneath, ptid.pid ());
thread_db_thread_info *priv = get_thread_db_thread_info (thread_info);
/* Finally, get the address of the variable. */
@@ -1796,7 +1802,7 @@ thread_db_target::get_thread_local_address (ptid_t ptid,
: (CORE_ADDR) (uintptr_t) address);
}
- return beneath ()->get_thread_local_address (ptid, lm, offset);
+ return beneath->get_thread_local_address (ptid, lm, offset);
}
/* Implement the to_get_ada_task_ptid target method for this target. */
@@ -1811,12 +1817,13 @@ thread_db_target::get_ada_task_ptid (long lwp, long thread)
void
thread_db_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
{
- struct thread_db_info *info;
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
- if (ptid == minus_one_ptid)
- info = get_thread_db_info (inferior_ptid.pid ());
- else
- info = get_thread_db_info (ptid.pid ());
+ thread_db_info *info
+ = get_thread_db_info (beneath, (ptid == minus_one_ptid
+ ? inferior_ptid.pid ()
+ : ptid.pid ()));
/* This workaround is only needed for child fork lwps stopped in a
PTRACE_O_TRACEFORK event. When the inferior is resumed, the
@@ -1824,7 +1831,7 @@ thread_db_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
if (info)
info->need_stale_parent_threads_check = 0;
- beneath ()->resume (ptid, step, signo);
+ beneath->resume (ptid, step, signo);
}
/* std::sort helper function for info_auto_load_libthread_db, sort the
@@ -1950,7 +1957,8 @@ maintenance_check_libthread_db (const char *args, int from_tty)
if (inferior_pid == 0)
error (_("No inferior running"));
- info = get_thread_db_info (inferior_pid);
+ info = get_thread_db_info (current_inferior ()->process_target (),
+ inferior_pid);
if (info == NULL)
error (_("No libthread_db loaded"));
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 9033a61950..1a9c13c0dc 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -958,7 +958,8 @@ multiple_inferiors_p ()
}
static void
-mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
+mi_on_resume_1 (struct mi_interp *mi,
+ process_stratum_target *targ, ptid_t ptid)
{
/* To cater for older frontends, emit ^running, but do it only once
per each command. We do it here, since at this point we know
@@ -981,7 +982,7 @@ mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
&& !multiple_inferiors_p ())
fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
else
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
mi_output_running (tp);
if (!running_result_record_printed && mi_proceeded)
@@ -1001,10 +1002,11 @@ mi_on_resume (ptid_t ptid)
{
struct thread_info *tp = NULL;
+ process_stratum_target *target = current_inferior ()->process_target ();
if (ptid == minus_one_ptid || ptid.is_pid ())
tp = inferior_thread ();
else
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (target, ptid);
/* Suppress output while calling an inferior function. */
if (tp->control.in_infcall)
@@ -1020,7 +1022,7 @@ mi_on_resume (ptid_t ptid)
target_terminal::scoped_restore_terminal_state term_state;
target_terminal::ours_for_output ();
- mi_on_resume_1 (mi, ptid);
+ mi_on_resume_1 (mi, target, ptid);
}
}
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 355e9bef43..3d9f0881c0 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -450,7 +450,7 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
/* See nat/fork-inferior.h. */
ptid_t
-startup_inferior (pid_t pid, int ntraps,
+startup_inferior (process_stratum_target *proc_target, pid_t pid, int ntraps,
struct target_waitstatus *last_waitstatus,
ptid_t *last_ptid)
{
@@ -502,7 +502,7 @@ startup_inferior (pid_t pid, int ntraps,
case TARGET_WAITKIND_SYSCALL_ENTRY:
case TARGET_WAITKIND_SYSCALL_RETURN:
/* Ignore gracefully during startup of the inferior. */
- switch_to_thread (event_ptid);
+ switch_to_thread (proc_target, event_ptid);
break;
case TARGET_WAITKIND_SIGNALLED:
@@ -527,12 +527,12 @@ startup_inferior (pid_t pid, int ntraps,
/* Handle EXEC signals as if they were SIGTRAP signals. */
xfree (ws.value.execd_pathname);
resume_signal = GDB_SIGNAL_TRAP;
- switch_to_thread (event_ptid);
+ switch_to_thread (proc_target, event_ptid);
break;
case TARGET_WAITKIND_STOPPED:
resume_signal = ws.value.sig;
- switch_to_thread (event_ptid);
+ switch_to_thread (proc_target, event_ptid);
break;
}
diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
index 1d0519fb26..269d60502b 100644
--- a/gdb/nat/fork-inferior.h
+++ b/gdb/nat/fork-inferior.h
@@ -22,6 +22,8 @@
#include <string>
+struct process_stratum_target;
+
/* Number of traps that happen between exec'ing the shell to run an
inferior and when we finally get to the inferior code, not counting
the exec for the shell. This is 1 on all supported
@@ -50,7 +52,8 @@ extern pid_t fork_inferior (const char *exec_file_arg,
/* Accept NTRAPS traps from the inferior.
Return the ptid of the inferior being started. */
-extern ptid_t startup_inferior (pid_t pid, int ntraps,
+extern ptid_t startup_inferior (process_stratum_target *proc_target,
+ pid_t pid, int ntraps,
struct target_waitstatus *mystatus,
ptid_t *myptid);
diff --git a/gdb/ppc-fbsd-tdep.c b/gdb/ppc-fbsd-tdep.c
index 290bd1fd88..a3efd860a6 100644
--- a/gdb/ppc-fbsd-tdep.c
+++ b/gdb/ppc-fbsd-tdep.c
@@ -35,6 +35,7 @@
#include "ppc-fbsd-tdep.h"
#include "fbsd-tdep.h"
#include "solib-svr4.h"
+#include "inferior.h"
/* 32-bit regset descriptions. */
@@ -289,7 +290,8 @@ ppcfbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
struct regcache *regcache;
int tp_offset, tp_regnum;
- regcache = get_thread_arch_regcache (ptid, gdbarch);
+ regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, gdbarch);
if (tdep->wordsize == 4)
{
diff --git a/gdb/proc-service.c b/gdb/proc-service.c
index b0741318ad..954d150a5e 100644
--- a/gdb/proc-service.c
+++ b/gdb/proc-service.c
@@ -70,17 +70,22 @@ static ps_err_e
ps_xfer_memory (const struct ps_prochandle *ph, psaddr_t addr,
gdb_byte *buf, size_t len, int write)
{
- scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
- int ret;
- CORE_ADDR core_addr = ps_addr_to_core_addr (addr);
+ scoped_restore_current_inferior restore_inferior;
+ set_current_inferior (ph->thread->inf);
+ scoped_restore_current_program_space restore_current_progspace;
+ set_current_program_space (ph->thread->inf->pspace);
+
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
inferior_ptid = ph->thread->ptid;
+ CORE_ADDR core_addr = ps_addr_to_core_addr (addr);
+
+ int ret;
if (write)
ret = target_write_memory (core_addr, buf, len);
else
ret = target_read_memory (core_addr, buf, len);
-
return (ret == 0 ? PS_OK : PS_ERR);
}
\f
@@ -138,7 +143,9 @@ static struct regcache *
get_ps_regcache (struct ps_prochandle *ph, lwpid_t lwpid)
{
inferior *inf = ph->thread->inf;
- return get_thread_arch_regcache (ptid_t (inf->pid, lwpid), inf->gdbarch);
+ return get_thread_arch_regcache (inf->process_target (),
+ ptid_t (inf->pid, lwpid),
+ inf->gdbarch);
}
/* Get the general registers of LWP LWPID within the target process PH
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 1517088f0f..234a31378b 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -29,7 +29,7 @@ struct address_space *
process_stratum_target::thread_address_space (ptid_t ptid)
{
/* Fall-back to the "main" address space of the inferior. */
- inferior *inf = find_inferior_ptid (ptid);
+ inferior *inf = find_inferior_ptid (this, ptid);
if (inf == NULL || inf->aspace == NULL)
internal_error (__FILE__, __LINE__,
@@ -43,7 +43,7 @@ process_stratum_target::thread_address_space (ptid_t ptid)
struct gdbarch *
process_stratum_target::thread_architecture (ptid_t ptid)
{
- inferior *inf = find_inferior_ptid (ptid);
+ inferior *inf = find_inferior_ptid (this, ptid);
gdb_assert (inf != NULL);
return inf->gdbarch;
}
diff --git a/gdb/process-stratum-target.h b/gdb/process-stratum-target.h
index a14e4f3a72..6081c0a927 100644
--- a/gdb/process-stratum-target.h
+++ b/gdb/process-stratum-target.h
@@ -51,6 +51,22 @@ public:
bool has_stack () override;
bool has_registers () override;
bool has_execution (inferior *inf) override;
+
+ /* True if any thread is, or may be executing. We need to track
+ this separately because until we fully sync the thread list, we
+ won't know whether the target is fully stopped, even if we see
+ stop events for all known threads, because any of those threads
+ may have spawned new threads we haven't heard of yet. */
+ bool threads_executing = false;
};
+/* Downcast TARGET to process_stratum_target. */
+
+static inline process_stratum_target *
+as_process_stratum_target (target_ops *target)
+{
+ gdb_assert (target->stratum () == process_stratum);
+ return static_cast<process_stratum_target *> (target);
+}
+
#endif /* !defined (PROCESS_STRATUM_TARGET_H) */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
index c2af2fa3c1..9b2afc4802 100644
--- a/gdb/python/py-threadevent.c
+++ b/gdb/python/py-threadevent.c
@@ -27,7 +27,9 @@ py_get_event_thread (ptid_t ptid)
{
if (non_stop)
{
- thread_info *thread = find_thread_ptid (ptid);
+ thread_info *thread
+ = find_thread_ptid (current_inferior ()->process_target (),
+ ptid);
if (thread != nullptr)
return thread_to_thread_object (thread);
PyErr_SetString (PyExc_RuntimeError, "Could not find event thread");
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index f217d949f6..095504ecbf 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -219,6 +219,9 @@ get_base_thread_from_ravenscar_task (ptid_t ptid)
void
ravenscar_thread_target::update_inferior_ptid ()
{
+ process_stratum_target *proc_target
+ = as_process_stratum_target (this->beneath ());
+
int base_cpu;
m_base_ptid = inferior_ptid;
@@ -239,8 +242,8 @@ ravenscar_thread_target::update_inferior_ptid ()
/* The running thread may not have been added to
system.tasking.debug's list yet; so ravenscar_update_thread_list
may not always add it to the thread list. Add it here. */
- if (!find_thread_ptid (inferior_ptid))
- add_thread (inferior_ptid);
+ if (!find_thread_ptid (proc_target, inferior_ptid))
+ add_thread (proc_target, inferior_ptid);
}
/* The Ravenscar Runtime exports a symbol which contains the ID of
@@ -336,12 +339,14 @@ ravenscar_thread_target::wait (ptid_t ptid,
struct target_waitstatus *status,
int options)
{
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
ptid_t event_ptid;
inferior_ptid = m_base_ptid;
if (ptid != minus_one_ptid)
ptid = m_base_ptid;
- event_ptid = beneath ()->wait (ptid, status, 0);
+ event_ptid = beneath->wait (ptid, status, 0);
/* Find any new threads that might have been created, and update
inferior_ptid to the active thread.
@@ -367,8 +372,9 @@ ravenscar_thread_target::wait (ptid_t ptid,
static void
ravenscar_add_thread (struct ada_task_info *task)
{
- if (find_thread_ptid (task->ptid) == NULL)
- add_thread (task->ptid);
+ process_stratum_target *targ = current_inferior ()->process_target ();
+ if (find_thread_ptid (targ, task->ptid) == NULL)
+ add_thread (targ, task->ptid);
}
void
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 65d6a254ff..e31306e111 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -556,10 +556,11 @@ record_btrace_target::info_record ()
DEBUG ("info");
- tp = find_thread_ptid (inferior_ptid);
- if (tp == NULL)
+ if (inferior_ptid == null_ptid)
error (_("No thread."));
+ tp = inferior_thread ();
+
validate_registers_access ();
btinfo = &tp->btrace;
@@ -1373,7 +1374,8 @@ record_btrace_target::call_history_from (ULONGEST from, int size,
enum record_method
record_btrace_target::record_method (ptid_t ptid)
{
- struct thread_info * const tp = find_thread_ptid (ptid);
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+ thread_info *const tp = find_thread_ptid (proc_target, ptid);
if (tp == NULL)
error (_("No thread."));
@@ -1389,7 +1391,8 @@ record_btrace_target::record_method (ptid_t ptid)
bool
record_btrace_target::record_is_replaying (ptid_t ptid)
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+ for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
if (btrace_is_replaying (tp))
return true;
@@ -1520,13 +1523,10 @@ record_btrace_target::remove_breakpoint (struct gdbarch *gdbarch,
void
record_btrace_target::fetch_registers (struct regcache *regcache, int regno)
{
- struct btrace_insn_iterator *replay;
- struct thread_info *tp;
-
- tp = find_thread_ptid (regcache->ptid ());
+ thread_info *tp = find_thread_ptid (regcache->target (), regcache->ptid ());
gdb_assert (tp != NULL);
- replay = tp->btrace.replay;
+ btrace_insn_iterator *replay = tp->btrace.replay;
if (replay != NULL && !record_btrace_generating_corefile)
{
const struct btrace_insn *insn;
@@ -1967,6 +1967,8 @@ get_thread_current_frame_id (struct thread_info *tp)
switch_to_thread (tp);
+ process_stratum_target *proc_target = tp->inf->process_target ();
+
/* Clear the executing flag to allow changes to the current frame.
We are not actually running, yet. We just started a reverse execution
command or a record goto command.
@@ -1975,7 +1977,7 @@ get_thread_current_frame_id (struct thread_info *tp)
move the thread. Since we need to recompute the stack, we temporarily
set EXECUTING to flase. */
executing = tp->executing;
- set_executing (inferior_ptid, false);
+ set_executing (proc_target, inferior_ptid, false);
id = null_frame_id;
try
@@ -1985,13 +1987,13 @@ get_thread_current_frame_id (struct thread_info *tp)
catch (const gdb_exception &except)
{
/* Restore the previous execution state. */
- set_executing (inferior_ptid, executing);
+ set_executing (proc_target, inferior_ptid, executing);
throw;
}
/* Restore the previous execution state. */
- set_executing (inferior_ptid, executing);
+ set_executing (proc_target, inferior_ptid, executing);
return id;
}
@@ -2154,12 +2156,15 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
/* We just indicate the resume intent here. The actual stepping happens in
record_btrace_wait below.
- For all-stop targets, we only step INFERIOR_PTID and continue others. */
+ For all-stop targets, we only step INFERIOR_PTID and continue others. */
+
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+
if (!target_is_non_stop_p ())
{
gdb_assert (inferior_ptid.matches (ptid));
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
{
if (tp->ptid.matches (inferior_ptid))
record_btrace_resume_thread (tp, flag);
@@ -2169,7 +2174,7 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
}
else
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
record_btrace_resume_thread (tp, flag);
}
@@ -2527,7 +2532,8 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
}
/* Keep a work list of moving threads. */
- for (thread_info *tp : all_non_exited_threads (ptid))
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+ for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
if ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0)
moving.push_back (tp);
@@ -2647,7 +2653,10 @@ record_btrace_target::stop (ptid_t ptid)
}
else
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+
+ for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
{
tp->btrace.flags &= ~BTHR_MOVE;
tp->btrace.flags |= BTHR_STOP;
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 1b03301da4..3737ee8492 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1228,6 +1228,8 @@ record_full_wait_1 (struct target_ops *ops,
interested in the event. */
registers_changed ();
+ switch_to_thread (current_inferior ()->process_target (),
+ ret);
regcache = get_current_regcache ();
tmp_pc = regcache_read_pc (regcache);
const struct address_space *aspace = regcache->aspace ();
@@ -1260,14 +1262,17 @@ record_full_wait_1 (struct target_ops *ops,
if (gdbarch_software_single_step_p (gdbarch))
{
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+
/* Try to insert the software single step breakpoint.
If insert success, set step to 0. */
- set_executing (inferior_ptid, 0);
+ set_executing (proc_target, inferior_ptid, 0);
reinit_frame_cache ();
step = !insert_single_step_breakpoints (gdbarch);
- set_executing (inferior_ptid, 1);
+ set_executing (proc_target, inferior_ptid, 1);
}
if (record_debug)
@@ -1290,6 +1295,8 @@ record_full_wait_1 (struct target_ops *ops,
}
else
{
+ switch_to_thread (current_inferior ()->process_target (),
+ record_full_resume_ptid);
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = regcache->arch ();
const struct address_space *aspace = regcache->aspace ();
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 7184c74842..e0c0fd315e 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -196,10 +196,11 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo)
}
}
-regcache::regcache (gdbarch *gdbarch, const address_space *aspace_)
+regcache::regcache (process_stratum_target *target, gdbarch *gdbarch,
+ const address_space *aspace_)
/* The register buffers. A read/write register cache can only hold
[0 .. gdbarch_num_regs). */
- : detached_regcache (gdbarch, false), m_aspace (aspace_)
+ : detached_regcache (gdbarch, false), m_aspace (aspace_), m_target (target)
{
m_ptid = minus_one_ptid;
}
@@ -320,14 +321,19 @@ reg_buffer::assert_regnum (int regnum) const
std::forward_list<regcache *> regcache::current_regcache;
struct regcache *
-get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
+get_thread_arch_aspace_regcache (process_stratum_target *target,
+ ptid_t ptid, struct gdbarch *gdbarch,
struct address_space *aspace)
{
+ gdb_assert (target != nullptr);
+
for (const auto ®cache : regcache::current_regcache)
- if (regcache->ptid () == ptid && regcache->arch () == gdbarch)
+ if (regcache->target () == target
+ && regcache->ptid () == ptid
+ && regcache->arch () == gdbarch)
return regcache;
- regcache *new_regcache = new regcache (gdbarch, aspace);
+ regcache *new_regcache = new regcache (target, gdbarch, aspace);
regcache::current_regcache.push_front (new_regcache);
new_regcache->set_ptid (ptid);
@@ -336,26 +342,38 @@ get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
}
struct regcache *
-get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+get_thread_arch_regcache (process_stratum_target *target, ptid_t ptid,
+ struct gdbarch *gdbarch)
{
+ scoped_restore_current_inferior restore_current_inferior;
+ set_current_inferior (find_inferior_ptid (target, ptid));
address_space *aspace = target_thread_address_space (ptid);
- return get_thread_arch_aspace_regcache (ptid, gdbarch, aspace);
+ return get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace);
}
+static process_stratum_target *current_thread_target;
static ptid_t current_thread_ptid;
static struct gdbarch *current_thread_arch;
struct regcache *
-get_thread_regcache (ptid_t ptid)
+get_thread_regcache (process_stratum_target *target, ptid_t ptid)
{
- if (!current_thread_arch || current_thread_ptid != ptid)
+ if (!current_thread_arch
+ || target != current_thread_target
+ || current_thread_ptid != ptid)
{
+ gdb_assert (ptid != null_ptid);
+
current_thread_ptid = ptid;
+ current_thread_target = target;
+
+ scoped_restore_current_inferior restore_current_inferior;
+ set_current_inferior (find_inferior_ptid (target, ptid));
current_thread_arch = target_thread_architecture (ptid);
}
- return get_thread_arch_regcache (ptid, current_thread_arch);
+ return get_thread_arch_regcache (target, ptid, current_thread_arch);
}
/* See regcache.h. */
@@ -363,7 +381,8 @@ get_thread_regcache (ptid_t ptid)
struct regcache *
get_thread_regcache (thread_info *thread)
{
- return get_thread_regcache (thread->ptid);
+ return get_thread_regcache (thread->inf->process_target (),
+ thread->ptid);
}
struct regcache *
@@ -377,7 +396,11 @@ get_current_regcache (void)
struct regcache *
get_thread_regcache_for_ptid (ptid_t ptid)
{
- return get_thread_regcache (ptid);
+ /* This function doesn't take a process_stratum_target parameter
+ because it's a common/ routine implemented by both gdb and
+ gdbserver. It always refers to a ptid of the current target. */
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+ return get_thread_regcache (proc_target, ptid);
}
/* Observer for the target_changed event. */
@@ -412,29 +435,34 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
Indicate that registers may have changed, so invalidate the cache. */
void
-registers_changed_ptid (ptid_t ptid)
+registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
{
for (auto oit = regcache::current_regcache.before_begin (),
it = std::next (oit);
it != regcache::current_regcache.end ();
)
{
- if ((*it)->ptid ().matches (ptid))
+ struct regcache *regcache = *it;
+ if ((target == nullptr || regcache->target () == target)
+ && regcache->ptid ().matches (ptid))
{
- delete *it;
+ delete regcache;
it = regcache::current_regcache.erase_after (oit);
}
else
oit = it++;
}
- if (current_thread_ptid.matches (ptid))
+ if ((target == nullptr || current_thread_target == target)
+ && current_thread_ptid.matches (ptid))
{
+ current_thread_target = NULL;
current_thread_ptid = null_ptid;
current_thread_arch = NULL;
}
- if (inferior_ptid.matches (ptid))
+ if ((target == nullptr || current_inferior ()->process_target () == target)
+ && inferior_ptid.matches (ptid))
{
/* We just deleted the regcache of the current thread. Need to
forget about any frames we have cached, too. */
@@ -447,13 +475,13 @@ registers_changed_ptid (ptid_t ptid)
void
registers_changed_thread (thread_info *thread)
{
- registers_changed_ptid (thread->ptid);
+ registers_changed_ptid (thread->inf->process_target (), thread->ptid);
}
void
registers_changed (void)
{
- registers_changed_ptid (minus_one_ptid);
+ registers_changed_ptid (nullptr, minus_one_ptid);
}
void
@@ -1400,6 +1428,21 @@ public:
}
};
+/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
+
+static void
+test_get_thread_arch_aspace_regcache (process_stratum_target *target,
+ ptid_t ptid, struct gdbarch *gdbarch,
+ address_space *aspace)
+{
+ struct regcache *regcache
+ = get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace);
+ SELF_CHECK (regcache != NULL);
+ SELF_CHECK (regcache->target () == target);
+ SELF_CHECK (regcache->ptid () == ptid);
+ SELF_CHECK (regcache->aspace () == aspace);
+}
+
static void
current_regcache_test (void)
{
@@ -1408,47 +1451,61 @@ current_regcache_test (void)
ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
- /* Get regcache from ptid1, a new regcache is added to
- current_regcache. */
- regcache *regcache = get_thread_arch_aspace_regcache (ptid1,
- target_gdbarch (),
- NULL);
+ test_target_ops test_target1;
+ test_target_ops test_target2;
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid1);
+ /* Get regcache from (target1,ptid1), a new regcache is added to
+ current_regcache. */
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 1);
- /* Get regcache from ptid2, a new regcache is added to
+ /* Get regcache from (target1,ptid2), a new regcache is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid2);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 2);
- /* Get regcache from ptid3, a new regcache is added to
+ /* Get regcache from (target1,ptid3), a new regcache is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid3,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid3);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 3);
- /* Get regcache from ptid2 again, nothing is added to
+ /* Get regcache from (target1,ptid2) again, nothing is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid2);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 3);
- /* Mark ptid2 is changed, so regcache of ptid2 should be removed from
- current_regcache. */
- registers_changed_ptid (ptid2);
- SELF_CHECK (regcache_access::current_regcache_size () == 2);
+ /* Get regcache from (target2,ptid2), a new regcache is added to
+ current_regcache, since this time we're using a differen
+ target. */
+ test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
+ target_gdbarch (),
+ NULL);
+ SELF_CHECK (regcache_access::current_regcache_size () == 4);
+
+ /* Mark that (target1,ptid2) changed. The regcache of (target1,
+ ptid2) should be removed from current_regcache. */
+ registers_changed_ptid (&test_target1, ptid2);
+ SELF_CHECK (regcache_access::current_regcache_size () == 3);
+
+ /* Get the regcache from (target2,ptid2) again, confirming the
+ registers_changed_ptid call above did not delete it. */
+ test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
+ target_gdbarch (),
+ NULL);
+ SELF_CHECK (regcache_access::current_regcache_size () == 3);
+
+ /* Confirm that marking all regcaches of all targets as changed
+ clears current_regcache. */
+ registers_changed_ptid (nullptr, minus_one_ptid);
+ SELF_CHECK (regcache_access::current_regcache_size () == 0);
}
class target_ops_no_register : public test_target_ops
@@ -1509,8 +1566,9 @@ target_ops_no_register::xfer_partial (enum target_object object,
class readwrite_regcache : public regcache
{
public:
- readwrite_regcache (struct gdbarch *gdbarch)
- : regcache (gdbarch, nullptr)
+ readwrite_regcache (process_stratum_target *target,
+ struct gdbarch *gdbarch)
+ : regcache (target, gdbarch, nullptr)
{}
};
@@ -1576,7 +1634,7 @@ cooked_read_test (struct gdbarch *gdbarch)
break;
}
- readwrite_regcache readwrite (gdbarch);
+ readwrite_regcache readwrite (&mock_target, gdbarch);
gdb::def_vector<gdb_byte> buf (register_size (gdbarch, nonzero_regnum));
readwrite.raw_read (nonzero_regnum, buf.data ());
@@ -1712,7 +1770,7 @@ cooked_write_test (struct gdbarch *gdbarch)
}
} pop_targets;
- readwrite_regcache readwrite (gdbarch);
+ readwrite_regcache readwrite (&mock_target, gdbarch);
const int num_regs = gdbarch_num_cooked_regs (gdbarch);
diff --git a/gdb/regcache.h b/gdb/regcache.h
index f7d4bc60f6..0303a9334a 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -29,17 +29,20 @@ struct regset;
struct gdbarch;
struct address_space;
class thread_info;
+struct process_stratum_target;
extern struct regcache *get_current_regcache (void);
-extern struct regcache *get_thread_regcache (ptid_t ptid);
+extern struct regcache *get_thread_regcache (process_stratum_target *target,
+ ptid_t ptid);
/* Get the regcache of THREAD. */
extern struct regcache *get_thread_regcache (thread_info *thread);
-extern struct regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *);
-extern struct regcache *get_thread_arch_aspace_regcache (ptid_t,
- struct gdbarch *,
- struct address_space *);
+extern struct regcache *get_thread_arch_regcache
+ (process_stratum_target *targ, ptid_t, struct gdbarch *);
+extern struct regcache *get_thread_arch_aspace_regcache
+ (process_stratum_target *target, ptid_t,
+ struct gdbarch *, struct address_space *);
extern enum register_status
regcache_raw_read_signed (struct regcache *regcache,
@@ -385,13 +388,19 @@ public:
this->m_ptid = ptid;
}
+ process_stratum_target *target () const
+ {
+ return m_target;
+ }
+
/* Dump the contents of a register from the register cache to the target
debug. */
void debug_print_register (const char *func, int regno);
static void regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid);
protected:
- regcache (gdbarch *gdbarch, const address_space *aspace_);
+ regcache (process_stratum_target *target, gdbarch *gdbarch,
+ const address_space *aspace);
static std::forward_list<regcache *> current_regcache;
@@ -421,14 +430,16 @@ private:
/* If this is a read-write cache, which thread's registers is
it connected to? */
+ process_stratum_target *m_target;
ptid_t m_ptid;
friend struct regcache *
- get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
+ get_thread_arch_aspace_regcache (process_stratum_target *target, ptid_t ptid,
+ struct gdbarch *gdbarch,
struct address_space *aspace);
friend void
- registers_changed_ptid (ptid_t ptid);
+ registers_changed_ptid (process_stratum_target *target, ptid_t ptid);
};
class readonly_detached_regcache : public readable_regcache
@@ -451,7 +462,8 @@ public:
};
extern void registers_changed (void);
-extern void registers_changed_ptid (ptid_t);
+extern void registers_changed_ptid (process_stratum_target *target,
+ ptid_t ptid);
/* Indicate that registers of THREAD may have changed, so invalidate
the cache. */
diff --git a/gdb/remote.c b/gdb/remote.c
index ef6eb99999..168fff3047 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -277,6 +277,8 @@ public: /* data */
/* The status of the stub support for the various vCont actions. */
vCont_action_support supports_vCont;
+ /* Whether vCont support was probed already. */
+ bool supports_vCont_probed;
/* True if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
@@ -536,6 +538,8 @@ public:
void async (int) override;
+ int async_wait_fd () override;
+
void thread_events (int) override;
int can_do_single_step () override;
@@ -1025,7 +1029,7 @@ static void remote_console_output (const char *msg);
static void remote_btrace_reset (remote_state *rs);
-static void remote_unpush_and_throw (void);
+static void remote_unpush_and_throw (remote_target *target);
/* For "remote". */
@@ -1395,7 +1399,7 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch)
static remote_target *
get_current_remote_target ()
{
- target_ops *proc_target = find_target_at (process_stratum);
+ target_ops *proc_target = current_inferior ()->process_target ();
return dynamic_cast<remote_target *> (proc_target);
}
@@ -1676,6 +1680,7 @@ show_memory_packet_size (struct memory_packet_config *config)
}
}
+/* FIXME: needs to be per-remote-target. */
static struct memory_packet_config memory_write_packet_config =
{
"memory-write-packet-size",
@@ -1732,6 +1737,7 @@ remote_target::get_memory_write_packet_size ()
return get_memory_packet_size (&memory_write_packet_config);
}
+/* FIXME: needs to be per-remote-target. */
static struct memory_packet_config memory_read_packet_config =
{
"memory-read-packet-size",
@@ -2090,6 +2096,9 @@ enum {
PACKET_MAX
};
+/* FIXME: needs to be per-remote-target. Ignoring this for now,
+ assuming all remote targets are the same server (thus all support
+ the same packets). */
static struct packet_config remote_protocol_packets[PACKET_MAX];
/* Returns the packet's corresponding "set remote foo-packet" command
@@ -2391,6 +2400,7 @@ remote_target::remote_add_inferior (bool fake_pid_p, int pid, int attached,
inf = add_inferior_with_spaces ();
}
switch_to_inferior_no_thread (inf);
+ push_target (this);
inferior_appeared (inf, pid);
}
@@ -2406,7 +2416,8 @@ remote_target::remote_add_inferior (bool fake_pid_p, int pid, int attached,
}
static remote_thread_info *get_remote_thread_info (thread_info *thread);
-static remote_thread_info *get_remote_thread_info (ptid_t ptid);
+static remote_thread_info *get_remote_thread_info (remote_target *target,
+ ptid_t ptid);
/* Add thread PTID to GDB's thread list. Tag it as executing/running
according to RUNNING. */
@@ -2424,13 +2435,13 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing)
might be confusing to the user. Be silent then, preserving the
age old behavior. */
if (rs->starting_up)
- thread = add_thread_silent (ptid);
+ thread = add_thread_silent (this, ptid);
else
- thread = add_thread (ptid);
+ thread = add_thread (this, ptid);
get_remote_thread_info (thread)->vcont_resumed = executing;
- set_executing (ptid, executing);
- set_running (ptid, running);
+ set_executing (this, ptid, executing);
+ set_running (this, ptid, running);
return thread;
}
@@ -2453,7 +2464,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing)
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
- thread_info *tp = find_thread_ptid (currthread);
+ thread_info *tp = find_thread_ptid (this, currthread);
if (tp != NULL && tp->state == THREAD_EXITED)
{
/* We're seeing an event on a thread id we knew had exited.
@@ -2462,7 +2473,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing)
return;
}
- if (!in_thread_list (currthread))
+ if (!in_thread_list (this, currthread))
{
struct inferior *inf = NULL;
int pid = currthread.pid ();
@@ -2475,8 +2486,8 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing)
stub doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
- if (in_thread_list (ptid_t (pid)))
- thread_change_ptid (inferior_ptid, currthread);
+ if (in_thread_list (this, ptid_t (pid)))
+ thread_change_ptid (this, inferior_ptid, currthread);
else
{
remote_add_thread (currthread, running, executing);
@@ -2492,7 +2503,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing)
doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
- thread_change_ptid (inferior_ptid, currthread);
+ thread_change_ptid (this, inferior_ptid, currthread);
return;
}
@@ -2500,7 +2511,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, int executing)
extended-remote which already was debugging an inferior, we
may not know about it yet. Add it before adding its child
thread, so notifications are emitted in a sensible order. */
- if (find_inferior_pid (currthread.pid ()) == NULL)
+ if (find_inferior_pid (this, currthread.pid ()) == NULL)
{
struct remote_state *rs = get_remote_state ();
bool fake_pid_p = !remote_multi_process_p (rs);
@@ -2540,10 +2551,12 @@ get_remote_thread_info (thread_info *thread)
return static_cast<remote_thread_info *> (thread->priv.get ());
}
+/* Return PTID's private thread data, creating it if necessary. */
+
static remote_thread_info *
-get_remote_thread_info (ptid_t ptid)
+get_remote_thread_info (remote_target *target, ptid_t ptid)
{
- thread_info *thr = find_thread_ptid (ptid);
+ thread_info *thr = find_thread_ptid (target, ptid);
return get_remote_thread_info (thr);
}
@@ -3803,6 +3816,9 @@ remote_target::update_thread_list ()
target. */
for (thread_info *tp : all_threads_safe ())
{
+ if (tp->inf->process_target () != this)
+ continue;
+
if (!context.contains_thread (tp->ptid))
{
/* Not found. */
@@ -3828,7 +3844,7 @@ remote_target::update_thread_list ()
remote_notice_new_inferior (item.ptid, executing);
- thread_info *tp = find_thread_ptid (item.ptid);
+ thread_info *tp = find_thread_ptid (this, item.ptid);
remote_thread_info *info = get_remote_thread_info (tp);
info->core = item.core;
info->extra = std::move (item.extra);
@@ -4030,13 +4046,6 @@ remote_target::close ()
/* Make sure we leave stdin registered in the event loop. */
terminal_ours ();
- /* We don't have a connection to the remote stub anymore. Get rid
- of all the inferiors and their threads we were controlling.
- Reset inferior_ptid to null_ptid first, as otherwise has_stack_frame
- will be unable to find the thread corresponding to (pid, 0, 0). */
- inferior_ptid = null_ptid;
- discard_all_inferiors ();
-
trace_reset_local_state ();
delete this;
@@ -4346,7 +4355,7 @@ remote_target::add_current_inferior_and_thread (char *wait_status)
/* Add the main thread and switch to it. Don't try reading
registers yet, since we haven't fetched the target description
yet. */
- thread_info *tp = add_thread_silent (curr_ptid);
+ thread_info *tp = add_thread_silent (this, curr_ptid);
switch_to_thread_no_regs (tp);
}
@@ -4422,7 +4431,7 @@ remote_target::process_initial_stop_replies (int from_tty)
if (ignore_event)
continue;
- struct thread_info *evthread = find_thread_ptid (event_ptid);
+ thread_info *evthread = find_thread_ptid (this, event_ptid);
if (ws.kind == TARGET_WAITKIND_STOPPED)
{
@@ -4442,14 +4451,14 @@ remote_target::process_initial_stop_replies (int from_tty)
|| ws.value.sig != GDB_SIGNAL_0)
evthread->suspend.waitstatus_pending_p = 1;
- set_executing (event_ptid, 0);
- set_running (event_ptid, 0);
+ set_executing (this, event_ptid, 0);
+ set_running (this, event_ptid, 0);
get_remote_thread_info (evthread)->vcont_resumed = 0;
}
/* "Notice" the new inferiors before anything related to
registers/memory. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
inf->needs_setup = 1;
@@ -4470,7 +4479,7 @@ remote_target::process_initial_stop_replies (int from_tty)
/* If all threads of an inferior were already stopped, we
haven't setup the inferior yet. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (inf->needs_setup)
{
@@ -4484,7 +4493,7 @@ remote_target::process_initial_stop_replies (int from_tty)
/* Now go over all threads that are stopped, and print their current
frame. If all-stop, then if there's a signalled thread, pick
that as current. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
if (first == NULL)
first = thread;
@@ -4523,7 +4532,7 @@ remote_target::process_initial_stop_replies (int from_tty)
/* For "info program". */
thread_info *thread = inferior_thread ();
if (thread->state == THREAD_STOPPED)
- set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
+ set_last_target_status (this, inferior_ptid, thread->suspend.waitstatus);
}
/* Start the remote connection and sync state. */
@@ -4696,7 +4705,7 @@ remote_target::start_remote (int from_tty, int extended_p)
/* Let the stub know that we want it to return the thread. */
set_continue_thread (minus_one_ptid);
- if (thread_count () == 0)
+ if (thread_count (this) == 0)
{
/* Target has no concept of threads at all. GDB treats
non-threaded target as single-threaded; add a main
@@ -4722,14 +4731,15 @@ remote_target::start_remote (int from_tty, int extended_p)
"warning: couldn't determine remote "
"current thread; picking first in list.\n");
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this,
+ minus_one_ptid))
{
switch_to_thread (tp);
break;
}
}
else
- switch_to_thread (find_thread_ptid (curr_thread));
+ switch_to_thread (find_thread_ptid (this, curr_thread));
}
/* init_wait_for_inferior should be called before get_offsets in order
@@ -4788,7 +4798,7 @@ remote_target::start_remote (int from_tty, int extended_p)
remote_notif_get_pending_events (notif);
}
- if (thread_count () == 0)
+ if (thread_count (this) == 0)
{
if (!extended_p)
error (_("The target is not running (try extended-remote?)"));
@@ -5445,7 +5455,7 @@ remote_target::remote_serial_quit_handler ()
{
if (query (_("The target is not responding to GDB commands.\n"
"Stop debugging it? ")))
- remote_unpush_and_throw ();
+ remote_unpush_and_throw (this);
}
/* If ^C has already been sent once, offer to disconnect. */
else if (!target_terminal::is_ours () && rs->ctrlc_pending_p)
@@ -5469,19 +5479,29 @@ remote_serial_quit_handler ()
curr_quit_handler_target->remote_serial_quit_handler ();
}
-/* Remove any of the remote.c targets from target stack. Upper targets depend
- on it so remove them first. */
+/* Remove the remote target from the target stack of each inferior
+ that is using it. Upper targets depend on it so remove them
+ first. */
static void
-remote_unpush_target (void)
+remote_unpush_target (remote_target *target)
{
- pop_all_targets_at_and_above (process_stratum);
+ /* We have to unpush the target from all inferiors, even those that
+ aren't running. */
+ scoped_restore_current_inferior restore_current_inferior;
+
+ for (inferior *inf : all_inferiors (target))
+ {
+ switch_to_inferior_no_thread (inf);
+ pop_all_targets_at_and_above (process_stratum);
+ generic_mourn_inferior ();
+ }
}
static void
-remote_unpush_and_throw (void)
+remote_unpush_and_throw (remote_target *target)
{
- remote_unpush_target ();
+ remote_unpush_target (target);
throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target."));
}
@@ -5498,7 +5518,7 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p)
/* If we're connected to a running target, target_preopen will kill it.
Ask this question first, before target_preopen has a chance to kill
anything. */
- if (curr_remote != NULL && !have_inferiors ())
+ if (curr_remote != NULL && !target_has_execution)
{
if (from_tty
&& !query (_("Already connected to a remote target. Disconnect? ")))
@@ -5627,7 +5647,7 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p)
/* Pop the partially set up target - unless something else did
already before throwing the exception. */
if (ex.error != TARGET_CLOSE_ERROR)
- remote_unpush_target ();
+ remote_unpush_target (remote);
throw;
}
}
@@ -5691,10 +5711,10 @@ remote_target::remote_detach_1 (inferior *inf, int from_tty)
remote_detach_pid (pid);
/* Exit only if this is the only active inferior. */
- if (from_tty && !rs->extended && number_of_live_inferiors () == 1)
+ if (from_tty && !rs->extended && number_of_live_inferiors (this) == 1)
puts_filtered (_("Ending remote debugging.\n"));
- struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ thread_info *tp = find_thread_ptid (this, inferior_ptid);
/* Check to see if we are detaching a fork parent. Note that if we
are detaching a fork child, tp == NULL. */
@@ -5796,10 +5816,10 @@ remote_target::disconnect (const char *args, int from_tty)
error (_("Argument given to \"disconnect\" when remotely debugging."));
/* Make sure we unpush even the extended remote targets. Calling
- target_mourn_inferior won't unpush, and remote_mourn won't
- unpush if there is more than one inferior left. */
- unpush_target (this);
- generic_mourn_inferior ();
+ target_mourn_inferior won't unpush, and
+ remote_target::mourn_inferior won't unpush if there is more than
+ one inferior left. */
+ remote_unpush_target (this);
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
@@ -5887,10 +5907,10 @@ extended_remote_target::attach (const char *args, int from_tty)
inferior_ptid = remote_current_thread (inferior_ptid);
/* Add the main thread to the thread list. */
- thread_info *thr = add_thread_silent (inferior_ptid);
+ thread_info *thr = add_thread_silent (this, inferior_ptid);
/* Don't consider the thread stopped until we've processed the
saved stop reply. */
- set_executing (thr->ptid, true);
+ set_executing (this, thr->ptid, true);
}
/* Next, if the target can specify a description, read it. We do
@@ -5992,6 +6012,7 @@ remote_target::remote_vcont_probe ()
}
packet_ok (rs->buf, &remote_protocol_packets[PACKET_vCont]);
+ rs->supports_vCont_probed = true;
}
/* Helper function for building "vCont" resumptions. Write a
@@ -6029,10 +6050,10 @@ remote_target::append_resumption (char *p, char *endp,
{
/* If we don't know about the target thread's tid, then
we're resuming magic_null_ptid (see caller). */
- tp = find_thread_ptid (magic_null_ptid);
+ tp = find_thread_ptid (this, magic_null_ptid);
}
else
- tp = find_thread_ptid (ptid);
+ tp = find_thread_ptid (this, ptid);
gdb_assert (tp != NULL);
if (tp->control.may_range_step)
@@ -6095,7 +6116,7 @@ char *
remote_target::append_pending_thread_resumptions (char *p, char *endp,
ptid_t ptid)
{
- for (thread_info *thread : all_non_exited_threads (ptid))
+ for (thread_info *thread : all_non_exited_threads (this, ptid))
if (inferior_ptid != thread->ptid
&& thread->suspend.stop_signal != GDB_SIGNAL_0)
{
@@ -6128,7 +6149,7 @@ remote_target::remote_resume_with_hc (ptid_t ptid, int step,
else
set_continue_thread (ptid);
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
resume_clear_thread_private_info (thread);
buf = rs->buf.data ();
@@ -6265,9 +6286,9 @@ remote_target::resume (ptid_t ptid, int step, enum gdb_signal siggnal)
remote_thread_info *remote_thr;
if (minus_one_ptid == ptid || ptid.is_pid ())
- remote_thr = get_remote_thread_info (inferior_ptid);
+ remote_thr = get_remote_thread_info (this, inferior_ptid);
else
- remote_thr = get_remote_thread_info (ptid);
+ remote_thr = get_remote_thread_info (this, ptid);
remote_thr->last_resume_step = step;
remote_thr->last_resume_sig = siggnal;
@@ -6499,7 +6520,7 @@ remote_target::commit_resume ()
may_global_wildcard_vcont = 1;
/* And assume every process is individually wildcard-able too. */
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
remote_inferior *priv = get_remote_inferior (inf);
@@ -6510,7 +6531,7 @@ remote_target::commit_resume ()
disable process and global wildcard resumes appropriately. */
check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont);
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
/* If a thread of a process is not meant to be resumed, then we
can't wildcard that process. */
@@ -6539,7 +6560,7 @@ remote_target::commit_resume ()
struct vcont_builder vcont_builder (this);
/* Threads first. */
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
remote_thread_info *remote_thr = get_remote_thread_info (tp);
@@ -6568,7 +6589,7 @@ remote_target::commit_resume ()
supposed to be resumed. */
any_process_wildcard = 0;
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (get_remote_inferior (inf)->may_wildcard_vcont)
{
@@ -6589,7 +6610,7 @@ remote_target::commit_resume ()
}
else
{
- for (inferior *inf : all_non_exited_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors (this))
{
if (get_remote_inferior (inf)->may_wildcard_vcont)
{
@@ -6601,6 +6622,8 @@ remote_target::commit_resume ()
}
vcont_builder.flush ();
+
+ target_async (1);
}
\f
@@ -6616,7 +6639,10 @@ remote_target::remote_stop_ns (ptid_t ptid)
char *p = rs->buf.data ();
char *endp = p + get_remote_packet_size ();
- if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN)
+ /* FIXME: This supports_vCont_probed check is a workaround until
+ packet_support is per-connection. */
+ if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN
+ || !rs->supports_vCont_probed)
remote_vcont_probe ();
if (!rs->supports_vCont.t)
@@ -6773,7 +6799,7 @@ remote_target::interrupt_query ()
if (query (_("The target is not responding to interrupt requests.\n"
"Stop debugging it? ")))
{
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target."));
}
}
@@ -6980,7 +7006,7 @@ remote_target::remove_new_fork_children (threads_listing_context *context)
/* For any threads stopped at a fork event, remove the corresponding
fork child threads from the CONTEXT list. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
struct target_waitstatus *ws = thread_pending_fork_status (thread);
@@ -7022,7 +7048,7 @@ remote_target::check_pending_events_prevent_wildcard_vcont
|| event->ws.kind == TARGET_WAITKIND_VFORKED)
*may_global_wildcard = 0;
- struct inferior *inf = find_inferior_ptid (event->ptid);
+ struct inferior *inf = find_inferior_ptid (this, event->ptid);
/* This may be the first time we heard about this process.
Regardless, we must not do a global wildcard resume, otherwise
@@ -7388,9 +7414,10 @@ Packet: '%s'\n"),
if (rsa == NULL)
{
- inferior *inf = (event->ptid == null_ptid
- ? NULL
- : find_inferior_ptid (event->ptid));
+ inferior *inf
+ = (event->ptid == null_ptid
+ ? NULL
+ : find_inferior_ptid (this, event->ptid));
/* If this is the first time we learn anything
about this process, skip the registers
included in this packet, since we don't yet
@@ -7650,7 +7677,7 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
if (!stop_reply->regcache.empty ())
{
struct regcache *regcache
- = get_thread_arch_regcache (ptid, stop_reply->arch);
+ = get_thread_arch_regcache (this, ptid, stop_reply->arch);
for (cached_reg_t ® : stop_reply->regcache)
{
@@ -7662,7 +7689,7 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
}
remote_notice_new_inferior (ptid, 0);
- remote_thread_info *remote_thr = get_remote_thread_info (ptid);
+ remote_thread_info *remote_thr = get_remote_thread_info (this, ptid);
remote_thr->core = stop_reply->core;
remote_thr->stop_reason = stop_reply->stop_reason;
remote_thr->watch_data_address = stop_reply->watch_data_address;
@@ -7732,9 +7759,9 @@ remote_target::wait_ns (ptid_t ptid, struct target_waitstatus *status, int optio
/* Return the first resumed thread. */
static ptid_t
-first_remote_resumed_thread ()
+first_remote_resumed_thread (remote_target *target)
{
- for (thread_info *tp : all_non_exited_threads (minus_one_ptid))
+ for (thread_info *tp : all_non_exited_threads (target, minus_one_ptid))
if (tp->resumed)
return tp->ptid;
return null_ptid;
@@ -7876,7 +7903,7 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
if (event_ptid != null_ptid)
record_currthread (rs, event_ptid);
else
- event_ptid = first_remote_resumed_thread ();
+ event_ptid = first_remote_resumed_thread (this);
}
else
/* A process exit. Invalidate our notion of current thread. */
@@ -8993,11 +9020,11 @@ remote_target::files_info ()
for output compatibility with throw_perror_with_name. */
static void
-unpush_and_perror (const char *string)
+unpush_and_perror (remote_target *target, const char *string)
{
int saved_errno = errno;
- remote_unpush_target ();
+ remote_unpush_target (target);
throw_error (TARGET_CLOSE_ERROR, "%s: %s.", string,
safe_strerror (saved_errno));
}
@@ -9033,12 +9060,12 @@ remote_target::readchar (int timeout)
switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR, _("Remote connection closed"));
/* no return */
case SERIAL_ERROR:
- unpush_and_perror (_("Remote communication error. "
- "Target disconnected."));
+ unpush_and_perror (this, _("Remote communication error. "
+ "Target disconnected."));
/* no return */
case SERIAL_TIMEOUT:
break;
@@ -9066,8 +9093,8 @@ remote_target::remote_serial_write (const char *str, int len)
if (serial_write (rs->remote_desc, str, len))
{
- unpush_and_perror (_("Remote communication error. "
- "Target disconnected."));
+ unpush_and_perror (this, _("Remote communication error. "
+ "Target disconnected."));
}
if (rs->got_ctrlc_during_io)
@@ -9584,7 +9611,7 @@ remote_target::getpkt_or_notif_sane_1 (gdb::char_vector *buf,
if (forever) /* Watchdog went off? Kill the target. */
{
- remote_unpush_target ();
+ remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR,
_("Watchdog timeout has expired. "
"Target detached."));
@@ -9694,7 +9721,7 @@ remote_target::kill_new_fork_children (int pid)
/* Kill the fork child threads of any threads in process PID
that are stopped at a fork event. */
- for (thread_info *thread : all_non_exited_threads ())
+ for (thread_info *thread : all_non_exited_threads (this))
{
struct target_waitstatus *ws = &thread->pending_follow;
@@ -9754,7 +9781,7 @@ remote_target::kill ()
inferior, then we will tell gdbserver to exit and unpush the
target. */
if (res == -1 && !remote_multi_process_p (rs)
- && number_of_live_inferiors () == 1)
+ && number_of_live_inferiors (this) == 1)
{
remote_kill_k ();
@@ -9840,12 +9867,9 @@ remote_target::mourn_inferior ()
discard_pending_stop_replies (current_inferior ());
/* In 'target remote' mode with one inferior, we close the connection. */
- if (!rs->extended && number_of_live_inferiors () <= 1)
+ if (!rs->extended && number_of_live_inferiors (this) <= 1)
{
- unpush_target (this);
-
- /* remote_close takes care of doing most of the clean up. */
- generic_mourn_inferior ();
+ remote_unpush_target (this);
return;
}
@@ -13444,7 +13468,7 @@ remote_target::set_disconnected_tracing (int val)
int
remote_target::core_of_thread (ptid_t ptid)
{
- struct thread_info *info = find_thread_ptid (ptid);
+ thread_info *info = find_thread_ptid (this, ptid);
if (info != NULL && info->priv != NULL)
return get_remote_thread_info (info)->core;
@@ -13724,7 +13748,7 @@ remote_target::remote_btrace_maybe_reopen ()
scoped_restore_current_thread restore_thread;
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
set_general_thread (tp->ptid);
@@ -13940,13 +13964,12 @@ char *
remote_target::pid_to_exec_file (int pid)
{
static gdb::optional<gdb::char_vector> filename;
- struct inferior *inf;
char *annex = NULL;
if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
return NULL;
- inf = find_inferior_pid (pid);
+ inferior *inf = find_inferior_pid (this, pid);
if (inf == NULL)
internal_error (__FILE__, __LINE__,
_("not currently attached to process %d"), pid);
@@ -14007,7 +14030,7 @@ remote_target::thread_handle_to_thread_info (const gdb_byte *thread_handle,
int handle_len,
inferior *inf)
{
- for (thread_info *tp : all_non_exited_threads ())
+ for (thread_info *tp : all_non_exited_threads (this))
{
remote_thread_info *priv = get_remote_thread_info (tp);
@@ -14079,6 +14102,13 @@ remote_async_inferior_event_handler (gdb_client_data data)
inferior_event_handler (INF_REG_EVENT, data);
}
+int
+remote_target::async_wait_fd ()
+{
+ struct remote_state *rs = get_remote_state ();
+ return rs->remote_desc->fd;
+}
+
void
remote_target::async (int enable)
{
diff --git a/gdb/riscv-fbsd-tdep.c b/gdb/riscv-fbsd-tdep.c
index a17d55b08b..926fd6b6e6 100644
--- a/gdb/riscv-fbsd-tdep.c
+++ b/gdb/riscv-fbsd-tdep.c
@@ -26,6 +26,7 @@
#include "trad-frame.h"
#include "tramp-frame.h"
#include "gdbarch.h"
+#include "inferior.h"
/* Register maps. */
@@ -183,7 +184,8 @@ riscv_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
{
struct regcache *regcache;
- regcache = get_thread_arch_regcache (ptid, gdbarch);
+ regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, gdbarch);
target_fetch_registers (regcache, RISCV_TP_REGNUM);
diff --git a/gdb/sol2-tdep.c b/gdb/sol2-tdep.c
index 014b7d79a7..dd6f06ec95 100644
--- a/gdb/sol2-tdep.c
+++ b/gdb/sol2-tdep.c
@@ -58,7 +58,7 @@ sol2_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
/* GDB didn't use to put a NT_PSTATUS note in Solaris cores. If
that's missing, then we're dealing with a fake PID corelow.c made
up. */
- inf = find_inferior_ptid (ptid);
+ inf = find_inferior_ptid (current_inferior ()->process_target (), ptid);
if (inf == NULL || inf->fake_pid_p)
return "<core>";
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index 5b97b9bcf6..71942fd937 100644
--- a/gdb/solib-spu.c
+++ b/gdb/solib-spu.c
@@ -88,7 +88,8 @@ spu_skip_standalone_loader (void)
target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
target_wait (minus_one_ptid, &ws, 0);
- set_executing (minus_one_ptid, 0);
+ set_executing (current_inferior ()->process_target (),
+ minus_one_ptid, 0);
inferior_thread ()->control.in_infcall = 0;
}
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index ffae26bfc5..dc182f2480 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -2373,7 +2373,8 @@ enable_break (struct svr4_info *info, int from_tty)
if (!load_addr_found)
{
struct regcache *regcache
- = get_thread_arch_regcache (inferior_ptid, target_gdbarch ());
+ = get_thread_arch_regcache (current_inferior ()->process_target (),
+ inferior_ptid, target_gdbarch ());
load_addr = (regcache_read_pc (regcache)
- exec_entry_point (tmp_bfd.get (), tmp_bfd_target));
diff --git a/gdb/spu-multiarch.c b/gdb/spu-multiarch.c
index 88ad291dbd..c1b2afd808 100644
--- a/gdb/spu-multiarch.c
+++ b/gdb/spu-multiarch.c
@@ -100,13 +100,15 @@ parse_spufs_run (ptid_t ptid, int *fd, CORE_ADDR *addr)
if (gdbarch_bfd_arch_info (target_gdbarch ())->arch != bfd_arch_powerpc)
return 0;
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+
/* If we're called too early (e.g. after fork), we cannot
access the inferior yet. */
- if (find_inferior_ptid (ptid) == NULL)
+ if (find_inferior_ptid (proc_target, ptid) == NULL)
return 0;
/* Get PPU-side registers. */
- regcache = get_thread_arch_regcache (ptid, target_gdbarch ());
+ regcache = get_thread_arch_regcache (proc_target, ptid, target_gdbarch ());
tdep = gdbarch_tdep (target_gdbarch ());
/* Fetch instruction preceding current NIP. */
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index ddaee54b30..48d87cbcfa 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -1273,8 +1273,12 @@ spu2ppu_sniffer (const struct frame_unwind *self,
}
else
{
- struct regcache *regcache;
- regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch ());
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ struct regcache *regcache
+ = get_thread_arch_regcache (proc_target, inferior_ptid,
+ target_gdbarch ());
+
cache->regcache = new readonly_detached_regcache (*regcache);
*this_prologue_cache = cache;
return 1;
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 52034fe436..5c2142b63f 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -83,6 +83,7 @@ struct dummy_target : public target_ops
bool can_async_p () override;
bool is_async_p () override;
void async (int arg0) override;
+ int async_wait_fd () override;
void thread_events (int arg0) override;
bool supports_non_stop () override;
bool always_non_stop_p () override;
@@ -251,6 +252,7 @@ struct debug_target : public target_ops
bool can_async_p () override;
bool is_async_p () override;
void async (int arg0) override;
+ int async_wait_fd () override;
void thread_events (int arg0) override;
bool supports_non_stop () override;
bool always_non_stop_p () override;
@@ -2162,6 +2164,31 @@ debug_target::async (int arg0)
fputs_unfiltered (")\n", gdb_stdlog);
}
+int
+target_ops::async_wait_fd ()
+{
+ return this->beneath ()->async_wait_fd ();
+}
+
+int
+dummy_target::async_wait_fd ()
+{
+ noprocess ();
+}
+
+int
+debug_target::async_wait_fd ()
+{
+ int result;
+ fprintf_unfiltered (gdb_stdlog, "-> %s->async_wait_fd (...)\n", this->beneath ()->shortname ());
+ result = this->beneath ()->async_wait_fd ();
+ fprintf_unfiltered (gdb_stdlog, "<- %s->async_wait_fd (", this->beneath ()->shortname ());
+ fputs_unfiltered (") = ", gdb_stdlog);
+ target_debug_print_int (result);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ return result;
+}
+
void
target_ops::thread_events (int arg0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 68f874bf4b..541b95bc10 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -110,10 +110,6 @@ static std::unordered_map<const target_info *, target_open_ftype *>
static struct target_ops *the_debug_target;
-/* The target stack. */
-
-static target_stack g_target_stack;
-
/* Top of target stack. */
/* The target structure we are currently using to talk to a process
or file or whatever "inferior" we have. */
@@ -121,7 +117,7 @@ static target_stack g_target_stack;
target_ops *
current_top_target ()
{
- return g_target_stack.top ();
+ return current_inferior ()->top_target ();
}
/* Command list for target. */
@@ -226,7 +222,9 @@ target_has_registers_1 (void)
bool
target_has_execution_1 (inferior *inf)
{
- for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
+ for (target_ops *t = inf->top_target ();
+ t != nullptr;
+ t = inf->find_target_beneath (t))
if (t->has_execution (inf))
return true;
@@ -501,13 +499,16 @@ target_terminal::info (const char *arg, int from_tty)
bool
target_supports_terminal_ours (void)
{
- /* This can be called before there is any target, so we must check
- for nullptr here. */
- target_ops *top = current_top_target ();
+ /* The current top target is the target at the top of the target
+ stack of the current inferior. While normally there's always an
+ inferior, we must check for nullptr here because we can get here
+ very early during startup, before the initial inferior is first
+ created. */
+ inferior *inf = current_inferior ();
- if (top == nullptr)
+ if (inf == nullptr)
return false;
- return top->supports_terminal_ours ();
+ return inf->top_target ()->supports_terminal_ours ();
}
static void
@@ -553,19 +554,32 @@ default_execution_direction (struct target_ops *self)
to_execution_direction must be implemented for reverse async");
}
+/* Decref a target and close if, if there are no references left. */
+
+static void
+decref_target (target_ops *t)
+{
+ t->decref ();
+ if (t->refcount () == 0)
+ target_close (t);
+}
+
/* See target.h. */
void
target_stack::push (target_ops *t)
{
- /* If there's already a target at this stratum, remove it. */
+ t->incref ();
+
strata stratum = t->stratum ();
+ /* If there's already a target at this stratum, remove it. */
+
if (m_stack[stratum] != NULL)
{
target_ops *prev = m_stack[stratum];
m_stack[stratum] = NULL;
- target_close (prev);
+ decref_target (prev);
}
/* Now add the new one. */
@@ -580,15 +594,15 @@ target_stack::push (target_ops *t)
void
push_target (struct target_ops *t)
{
- g_target_stack.push (t);
+ current_inferior ()->push_target (t);
}
-/* See target.h */
+/* See target.h. */
void
push_target (target_ops_up &&t)
{
- g_target_stack.push (t.get ());
+ current_inferior ()->push_target (t.get ());
t.release ();
}
@@ -597,7 +611,7 @@ push_target (target_ops_up &&t)
int
unpush_target (struct target_ops *t)
{
- return g_target_stack.unpush (t);
+ return current_inferior ()->unpush_target (t);
}
/* See target.h. */
@@ -629,10 +643,13 @@ target_stack::unpush (target_ops *t)
if (m_top == stratum)
m_top = t->beneath ()->stratum ();
- /* Finally close the target. Note we do this after unchaining, so
- any target method calls from within the target_close
- implementation don't end up in T anymore. */
- target_close (t);
+ /* Finally close the target, if there are no inferiors
+ referencing this target still. Note we do this after unchaining,
+ so any target method calls from within the target_close
+ implementation don't end up in T anymore. Do leave the target
+ open if we have are other inferiors referencing this target
+ still. */
+ decref_target (t);
return true;
}
@@ -674,12 +691,13 @@ pop_all_targets (void)
pop_all_targets_above (dummy_stratum);
}
-/* Return 1 if T is now pushed in the target stack. Return 0 otherwise. */
+/* Return true if T is now pushed in the current inferior's target
+ stack. Return false otherwise. */
-int
-target_is_pushed (struct target_ops *t)
+bool
+target_is_pushed (target_ops *t)
{
- return g_target_stack.is_pushed (t);
+ return current_inferior ()->target_is_pushed (t);
}
/* Default implementation of to_get_thread_local_address. */
@@ -1956,14 +1974,14 @@ target_pre_inferior (int from_tty)
/* Callback for iterate_over_inferiors. Gets rid of the given
inferior. */
-static int
-dispose_inferior (struct inferior *inf, void *args)
+static void
+dispose_inferior (inferior *inf)
{
/* Not all killed inferiors can, or will ever be, removed from the
inferior list. Killed inferiors clearly don't need to be killed
again, so, we're done. */
if (inf->pid == 0)
- return 0;
+ return;
thread_info *thread = any_thread_of_inferior (inf);
if (thread != NULL)
@@ -1976,8 +1994,6 @@ dispose_inferior (struct inferior *inf, void *args)
else
target_detach (inf, 0);
}
-
- return 0;
}
/* This is to be called by the open routine before it does
@@ -1988,12 +2004,12 @@ target_preopen (int from_tty)
{
dont_repeat ();
- if (have_inferiors ())
+ if (current_inferior ()->pid != 0)
{
if (!from_tty
- || !have_live_inferiors ()
+ || !target_has_execution
|| query (_("A program is being debugged already. Kill it? ")))
- iterate_over_inferiors (dispose_inferior, NULL);
+ dispose_inferior (current_inferior ());
else
error (_("Program not killed."));
}
@@ -2035,9 +2051,16 @@ target_detach (inferior *inf, int from_tty)
prepare_for_detach ();
+ /* Hold a strong reference because detaching may unpush the
+ target. */
+ auto proc_target_ref = target_ops_ref::new_reference (inf->process_target ());
+
current_top_target ()->detach (inf, from_tty);
- registers_changed_ptid (save_pid_ptid);
+ process_stratum_target *proc_target
+ = as_process_stratum_target (proc_target_ref.get ());
+
+ registers_changed_ptid (proc_target, save_pid_ptid);
/* We have to ensure we have no frame cache left. Normally,
registers_changed_ptid (save_pid_ptid) calls reinit_frame_cache when
@@ -2085,6 +2108,8 @@ target_pid_to_str (ptid_t ptid)
const char *
target_thread_name (struct thread_info *info)
{
+ gdb_assert (info->inf == current_inferior ());
+
return current_top_target ()->thread_name (info);
}
@@ -2108,16 +2133,18 @@ target_thread_info_to_thread_handle (struct thread_info *tip)
void
target_resume (ptid_t ptid, int step, enum gdb_signal signal)
{
+ process_stratum_target *curr_target = current_inferior ()->process_target ();
+
target_dcache_invalidate ();
current_top_target ()->resume (ptid, step, signal);
- registers_changed_ptid (ptid);
+ registers_changed_ptid (curr_target, ptid);
/* We only set the internal executing state here. The user/frontend
running state is set at a higher level. This also clears the
thread's stop_pc as side effect. */
- set_executing (ptid, 1);
- clear_inline_frame_state (ptid);
+ set_executing (curr_target, ptid, 1);
+ clear_inline_frame_state (curr_target, ptid);
}
/* If true, target_commit_resume is a nop. */
@@ -2542,7 +2569,6 @@ target_get_osdata (const char *type)
return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
}
-
/* Determine the current address space of thread PTID. */
struct address_space *
@@ -2561,7 +2587,7 @@ target_thread_address_space (ptid_t ptid)
target_ops *
target_ops::beneath () const
{
- return g_target_stack.find_beneath (this);
+ return current_inferior ()->find_target_beneath (this);
}
void
@@ -3157,7 +3183,7 @@ target_stack::find_beneath (const target_ops *t) const
struct target_ops *
find_target_at (enum strata stratum)
{
- return g_target_stack.at (stratum);
+ return current_inferior ()->target_at (stratum);
}
\f
@@ -3253,6 +3279,14 @@ dummy_make_corefile_notes (struct target_ops *self,
static dummy_target the_dummy_target;
+/* See target.h. */
+
+target_ops *
+get_dummy_target ()
+{
+ return &the_dummy_target;
+}
+
static const target_info dummy_target_info = {
"None",
N_("None"),
@@ -3339,7 +3373,33 @@ target_interrupt ()
void
target_pass_ctrlc (void)
{
- current_top_target ()->pass_ctrlc ();
+ /* Pass the Ctrl-C to the first inferior that has a thread
+ running. */
+ for (inferior *inf : all_inferiors ())
+ {
+ target_ops *proc_target = inf->process_target ();
+ if (proc_target == NULL)
+ continue;
+
+ for (thread_info *thr : inf->threads ())
+ {
+ /* A thread can be THREAD_STOPPED and executing, while
+ running an infcall. */
+ if (thr->state == THREAD_RUNNING || thr->executing)
+ {
+ /* We can get here quite deep in target layers. Avoid
+ switching thread context or anything that would
+ communicate with the target (e.g., to fetch
+ registers), or flushing e.g., the frame cache. We
+ just switch inferior in order to be able to call
+ through the target_stack. */
+ scoped_restore_current_inferior restore_inferior;
+ set_current_inferior (inf);
+ current_top_target ()->pass_ctrlc ();
+ return;
+ }
+ }
+ }
}
/* See target.h. */
@@ -3987,10 +4047,8 @@ set_write_memory_permission (const char *args, int from_tty,
}
void
-initialize_targets (void)
+_initialize_target (void)
{
- push_target (&the_dummy_target);
-
the_debug_target = new debug_target ();
add_info ("target", info_target_command, targ_desc);
diff --git a/gdb/target.h b/gdb/target.h
index 9a94227953..9ceea7e06a 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -43,6 +43,7 @@ struct inferior;
#include "infrun.h" /* For enum exec_direction_kind. */
#include "breakpoint.h" /* For enum bptype. */
#include "gdbsupport/scoped_restore.h"
+#include "gdbsupport/refcounted-object.h"
/* This include file defines the interface between the main part
of the debugger, and the part which is target-specific, or
@@ -430,6 +431,7 @@ struct target_info
};
struct target_ops
+ : public refcounted_object
{
/* Return this target's stratum. */
virtual strata stratum () const = 0;
@@ -448,10 +450,10 @@ struct target_ops
virtual const target_info &info () const = 0;
/* Name this target type. */
- const char *shortname ()
+ const char *shortname () const
{ return info ().shortname; }
- const char *longname ()
+ const char *longname () const
{ return info ().longname; }
/* Close the target. This is where the target can handle
@@ -697,6 +699,8 @@ struct target_ops
TARGET_DEFAULT_RETURN (false);
virtual void async (int)
TARGET_DEFAULT_NORETURN (tcomplain ());
+ virtual int async_wait_fd ()
+ TARGET_DEFAULT_NORETURN (noprocess ());
virtual void thread_events (int)
TARGET_DEFAULT_IGNORE ();
/* This method must be implemented in some situations. See the
@@ -1261,6 +1265,9 @@ struct target_ops_deleter
/* A unique pointer for target_ops. */
typedef std::unique_ptr<target_ops, target_ops_deleter> target_ops_up;
+/* A gdb::ref_ptr pointer to a target_ops. */
+typedef gdb::ref_ptr<target_ops, refcounted_object_ref_policy> target_ops_ref;
+
/* Native target backends call this once at initialization time to
inform the core about which is the target that can respond to "run"
or "attach". Note: native targets are always singletons. */
@@ -1315,6 +1322,9 @@ private:
extern target_ops *current_top_target ();
+/* Return the dummy target. */
+extern target_ops *get_dummy_target ();
+
/* Define easy words for doing these operations on our current target. */
#define target_shortname (current_top_target ()->shortname ())
@@ -2363,7 +2373,7 @@ extern void pop_all_targets_at_and_above (enum strata stratum);
strictly above ABOVE_STRATUM. */
extern void pop_all_targets_above (enum strata above_stratum);
-extern int target_is_pushed (struct target_ops *t);
+extern bool target_is_pushed (target_ops *t);
extern CORE_ADDR target_translate_tls_address (struct objfile *objfile,
CORE_ADDR offset);
diff --git a/gdb/thread-iter.c b/gdb/thread-iter.c
index 9a41a46aa6..a41f894325 100644
--- a/gdb/thread-iter.c
+++ b/gdb/thread-iter.c
@@ -58,16 +58,22 @@ all_threads_iterator::advance ()
bool
all_matching_threads_iterator::m_inf_matches ()
{
- return (m_filter_ptid == minus_one_ptid
- || m_filter_ptid.pid () == m_inf->pid);
+ return ((m_filter_target == nullptr
+ || m_filter_target == m_inf->process_target ())
+ && (m_filter_ptid == minus_one_ptid
+ || m_filter_ptid.pid () == m_inf->pid));
}
/* See thread-iter.h. */
all_matching_threads_iterator::all_matching_threads_iterator
- (ptid_t filter_ptid)
- : m_filter_ptid (filter_ptid)
+ (process_stratum_target *filter_target, ptid_t filter_ptid)
+ : m_filter_target (filter_target),
+ m_filter_ptid (filter_ptid)
{
+ gdb_assert ((filter_target == nullptr && filter_ptid == minus_one_ptid)
+ || filter_target->stratum () == process_stratum);
+
m_thr = nullptr;
for (m_inf = inferior_list; m_inf != NULL; m_inf = m_inf->next)
if (m_inf_matches ())
diff --git a/gdb/thread-iter.h b/gdb/thread-iter.h
index 72ee9ddcb8..8586653df2 100644
--- a/gdb/thread-iter.h
+++ b/gdb/thread-iter.h
@@ -92,12 +92,14 @@ public:
/* Creates an iterator that iterates over all threads that match
FILTER_PTID. */
- explicit all_matching_threads_iterator (ptid_t filter_ptid);
+ explicit all_matching_threads_iterator (process_stratum_target *filter_target,
+ ptid_t filter_ptid);
/* Create a one-past-end iterator. */
all_matching_threads_iterator ()
: m_inf (nullptr),
m_thr (nullptr),
+ m_filter_target (nullptr),
m_filter_ptid (minus_one_ptid)
{}
@@ -131,6 +133,7 @@ private:
thread_info *m_thr;
/* The filter. */
+ process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
@@ -211,20 +214,22 @@ struct all_threads_safe_range
struct all_matching_threads_range
{
public:
- explicit all_matching_threads_range (ptid_t filter_ptid)
- : m_filter_ptid (filter_ptid)
+ explicit all_matching_threads_range (process_stratum_target *filter_target,
+ ptid_t filter_ptid)
+ : m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
all_matching_threads_range ()
- : m_filter_ptid (minus_one_ptid)
+ : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid)
{}
all_matching_threads_iterator begin () const
- { return all_matching_threads_iterator (m_filter_ptid); }
+ { return all_matching_threads_iterator (m_filter_target, m_filter_ptid); }
all_matching_threads_iterator end () const
{ return all_matching_threads_iterator (); }
private:
/* The filter. */
+ process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
@@ -236,20 +241,22 @@ private:
class all_non_exited_threads_range
{
public:
- explicit all_non_exited_threads_range (ptid_t filter_ptid)
- : m_filter_ptid (filter_ptid)
+ explicit all_non_exited_threads_range (process_stratum_target *filter_target,
+ ptid_t filter_ptid)
+ : m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
all_non_exited_threads_range ()
- : m_filter_ptid (minus_one_ptid)
+ : m_filter_target (nullptr), m_filter_ptid (minus_one_ptid)
{}
all_non_exited_threads_iterator begin () const
- { return all_non_exited_threads_iterator (m_filter_ptid); }
+ { return all_non_exited_threads_iterator (m_filter_target, m_filter_ptid); }
all_non_exited_threads_iterator end () const
{ return all_non_exited_threads_iterator (); }
private:
+ process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
diff --git a/gdb/thread.c b/gdb/thread.c
index 9a5867306b..9dafca57bf 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -55,13 +55,6 @@
static int highest_thread_num;
-/* True if any thread is, or may be executing. We need to track this
- separately because until we fully sync the thread list, we won't
- know whether the target is fully stopped, even if we see stop
- events for all known threads, because any of those threads may have
- spawned new threads we haven't heard of yet. */
-static int threads_executing;
-
/* RAII type used to increase / decrease the refcount of each thread
in a given list of threads. */
@@ -89,7 +82,7 @@ private:
struct thread_info*
inferior_thread (void)
{
- struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ struct thread_info *tp = find_thread_ptid (current_inferior (), inferior_ptid);
gdb_assert (tp);
return tp;
}
@@ -195,7 +188,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
thread_cancel_execution_command (tp);
- clear_inline_frame_state (tp->ptid);
+ clear_inline_frame_state (tp);
}
/* Set the TP's state as exited. */
@@ -260,12 +253,11 @@ new_thread (struct inferior *inf, ptid_t ptid)
}
struct thread_info *
-add_thread_silent (ptid_t ptid)
+add_thread_silent (process_stratum_target *targ, ptid_t ptid)
{
- struct inferior *inf = find_inferior_ptid (ptid);
- gdb_assert (inf != NULL);
+ inferior *inf;
- thread_info *tp = find_thread_ptid (inf, ptid);
+ thread_info *tp = find_thread_ptid (targ, ptid);
if (tp)
/* Found an old thread with the same id. It has to be dead,
otherwise we wouldn't be adding a new thread with the same id.
@@ -281,7 +273,7 @@ add_thread_silent (ptid_t ptid)
if (inferior_ptid == ptid)
{
- thread_info *new_thr = new_thread (inf, null_ptid);
+ thread_info *new_thr = new_thread (tp->inf, null_ptid);
/* Make switch_to_thread not read from the thread. */
new_thr->state = THREAD_EXITED;
@@ -300,10 +292,14 @@ add_thread_silent (ptid_t ptid)
/* All done. */
return new_thr;
}
- else
- /* Just go ahead and delete it. */
- delete_thread (tp);
+
+ inf = tp->inf;
+
+ /* Just go ahead and delete it. */
+ delete_thread (tp);
}
+ else
+ inf = find_inferior_ptid (targ, ptid);
tp = new_thread (inf, ptid);
gdb::observers::new_thread.notify (tp);
@@ -312,9 +308,10 @@ add_thread_silent (ptid_t ptid)
}
struct thread_info *
-add_thread_with_info (ptid_t ptid, private_thread_info *priv)
+add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
+ private_thread_info *priv)
{
- struct thread_info *result = add_thread_silent (ptid);
+ thread_info *result = add_thread_silent (targ, ptid);
result->priv.reset (priv);
@@ -326,9 +323,9 @@ add_thread_with_info (ptid_t ptid, private_thread_info *priv)
}
struct thread_info *
-add_thread (ptid_t ptid)
+add_thread (process_stratum_target *targ, ptid_t ptid)
{
- return add_thread_with_info (ptid, NULL);
+ return add_thread_with_info (targ, ptid, NULL);
}
private_thread_info::~private_thread_info () = default;
@@ -352,6 +349,14 @@ thread_info::~thread_info ()
xfree (this->name);
}
+/* Returns true if THR is the current thread. */
+
+static bool
+is_current_thread (const thread_info *thr)
+{
+ return thr->inf == current_inferior () && thr->ptid == inferior_ptid;
+}
+
/* See gdbthread.h. */
bool
@@ -359,7 +364,7 @@ thread_info::deletable () const
{
/* If this is the current thread, or there's code out there that
relies on it existing (refcount > 0) we can't delete yet. */
- return refcount () == 0 && ptid != inferior_ptid;
+ return refcount () == 0 && !is_current_thread (this);
}
/* Add TP to the end of the step-over chain LIST_P. */
@@ -514,12 +519,12 @@ find_thread_id (struct inferior *inf, int thr_num)
return NULL;
}
-/* Find a thread_info by matching PTID. */
+/* See gdbthread.h. */
struct thread_info *
-find_thread_ptid (ptid_t ptid)
+find_thread_ptid (process_stratum_target *targ, ptid_t ptid)
{
- inferior *inf = find_inferior_ptid (ptid);
+ inferior *inf = find_inferior_ptid (targ, ptid);
if (inf == NULL)
return NULL;
return find_thread_ptid (inf, ptid);
@@ -584,9 +589,9 @@ any_thread_p ()
}
int
-thread_count (void)
+thread_count (process_stratum_target *proc_target)
{
- auto rng = all_threads ();
+ auto rng = all_threads (proc_target);
return std::distance (rng.begin (), rng.end ());
}
@@ -609,10 +614,10 @@ valid_global_thread_id (int global_id)
return 0;
}
-int
-in_thread_list (ptid_t ptid)
+bool
+in_thread_list (process_stratum_target *targ, ptid_t ptid)
{
- return find_thread_ptid (ptid) != nullptr;
+ return find_thread_ptid (targ, ptid) != nullptr;
}
/* Finds the first thread of the inferior. */
@@ -788,7 +793,8 @@ get_last_thread_stack_temporary (thread_info *tp)
}
void
-thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
+thread_change_ptid (process_stratum_target *targ,
+ ptid_t old_ptid, ptid_t new_ptid)
{
struct inferior *inf;
struct thread_info *tp;
@@ -796,7 +802,7 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
/* It can happen that what we knew as the target inferior id
changes. E.g, target remote may only discover the remote process
pid after adding the inferior to GDB's list. */
- inf = find_inferior_ptid (old_ptid);
+ inf = find_inferior_ptid (targ, old_ptid);
inf->pid = new_ptid.pid ();
tp = find_thread_ptid (inf, old_ptid);
@@ -808,9 +814,9 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
/* See gdbthread.h. */
void
-set_resumed (ptid_t ptid, int resumed)
+set_resumed (process_stratum_target *targ, ptid_t ptid, bool resumed)
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
tp->resumed = resumed;
}
@@ -848,7 +854,7 @@ thread_info::set_running (bool running)
}
void
-set_running (ptid_t ptid, int running)
+set_running (process_stratum_target *targ, ptid_t ptid, bool running)
{
/* We try not to notify the observer if no thread has actually
changed the running state -- merely to reduce the number of
@@ -856,7 +862,7 @@ set_running (ptid_t ptid, int running)
multiple *running notifications just fine. */
bool any_started = false;
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
if (set_running_thread (tp, running))
any_started = true;
@@ -878,32 +884,32 @@ set_executing_thread (thread_info *thr, bool executing)
}
void
-set_executing (ptid_t ptid, int executing)
+set_executing (process_stratum_target *targ, ptid_t ptid, bool executing)
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
set_executing_thread (tp, executing);
/* It only takes one running thread to spawn more threads. */
if (executing)
- threads_executing = 1;
+ targ->threads_executing = true;
/* Only clear the flag if the caller is telling us everything is
stopped. */
else if (minus_one_ptid == ptid)
- threads_executing = 0;
+ targ->threads_executing = false;
}
/* See gdbthread.h. */
-int
-threads_are_executing (void)
+bool
+threads_are_executing (process_stratum_target *target)
{
- return threads_executing;
+ return target->threads_executing;
}
void
-set_stop_requested (ptid_t ptid, int stop)
+set_stop_requested (process_stratum_target *targ, ptid_t ptid, bool stop)
{
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
tp->stop_requested = stop;
/* Call the stop requested observer so other components of GDB can
@@ -913,11 +919,11 @@ set_stop_requested (ptid_t ptid, int stop)
}
void
-finish_thread_state (ptid_t ptid)
+finish_thread_state (process_stratum_target *targ, ptid_t ptid)
{
bool any_started = false;
- for (thread_info *tp : all_non_exited_threads (ptid))
+ for (thread_info *tp : all_non_exited_threads (targ, ptid))
if (set_running_thread (tp, tp->executing))
any_started = true;
@@ -1333,7 +1339,7 @@ switch_to_thread (thread_info *thr)
{
gdb_assert (thr != NULL);
- if (inferior_ptid == thr->ptid)
+ if (is_current_thread (thr))
return;
switch_to_thread_no_regs (thr);
@@ -1344,9 +1350,9 @@ switch_to_thread (thread_info *thr)
/* See gdbsupport/common-gdbthread.h. */
void
-switch_to_thread (ptid_t ptid)
+switch_to_thread (process_stratum_target *proc_target, ptid_t ptid)
{
- thread_info *thr = find_thread_ptid (ptid);
+ thread_info *thr = find_thread_ptid (proc_target, ptid);
switch_to_thread (thr);
}
@@ -2069,18 +2075,39 @@ print_selected_thread_frame (struct ui_out *uiout,
}
/* Update the 'threads_executing' global based on the threads we know
- about right now. */
+ about right now. This is used by infrun to tell whether we should
+ pull events out of the current target. */
static void
update_threads_executing (void)
{
- threads_executing = 0;
- for (thread_info *tp : all_non_exited_threads ())
+ process_stratum_target *targ = current_inferior ()->process_target ();
+
+ if (targ == NULL)
+ return;
+
+ targ->threads_executing = false;
+
+ for (inferior *inf : all_non_exited_inferiors (targ))
{
- if (tp->executing)
+ if (!inf->has_execution ())
+ continue;
+
+ /* If the process has no threads, then it must be we have a
+ process-exit event pending. */
+ if (inf->thread_list == NULL)
+ {
+ targ->threads_executing = true;
+ return;
+ }
+
+ for (thread_info *tp : inf->non_exited_threads ())
{
- threads_executing = 1;
- break;
+ if (tp->executing)
+ {
+ targ->threads_executing = true;
+ return;
+ }
}
}
}
diff --git a/gdb/top.c b/gdb/top.c
index 9d4ce1fa3b..6af8c1629e 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1681,13 +1681,17 @@ quit_force (int *exit_arg, int from_tty)
/* Give all pushed targets a chance to do minimal cleanup, and pop
them all out. */
- try
+ for (inferior *inf : all_inferiors ())
{
- pop_all_targets ();
- }
- catch (const gdb_exception &ex)
- {
- exception_print (gdb_stderr, ex);
+ switch_to_inferior_no_thread (inf);
+ try
+ {
+ pop_all_targets ();
+ }
+ catch (const gdb_exception &ex)
+ {
+ exception_print (gdb_stderr, ex);
+ }
}
/* Save the history information if it is appropriate to do so. */
@@ -2233,7 +2237,6 @@ gdb_init (char *argv0)
#endif
init_cmd_lists (); /* This needs to be done first. */
- initialize_targets (); /* Setup target_terminal macros for utils.c. */
initialize_utils (); /* Make errors and warnings possible. */
init_page_info ();
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index c5063e66b0..f6ff71104f 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -557,7 +557,7 @@ tfile_target_open (const char *arg, int from_tty)
inferior_appeared (current_inferior (), TFILE_PID);
inferior_ptid = ptid_t (TFILE_PID);
- add_thread_silent (inferior_ptid);
+ add_thread_silent (&tfile_ops, inferior_ptid);
if (ts->traceframe_count <= 0)
warning (_("No traceframes present in this file."));
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (4 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 01/23] Preserve selected thread in all-stop w/ background execution Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2020-07-31 3:17 ` Tom Tromey
2019-09-06 23:28 ` [PATCH 10/23] Some get_last_target_status tweaks Pedro Alves
` (19 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
The multi-target patch sets inferior_ptid to null_ptid before handling
a target event, and thus before calling target_wait, in order to catch
places in target_ops::wait implementations that are incorrectly
relying on inferior_ptid (which could otherwise be a ptid of a
different target, for example). That caught this instance in
record-full.c.
Fix it by saving the last resumed ptid, and then using it in
record_full_wait_1, just like how the last "step" argument passed to
record_full_target::resume is handled too.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* record-full.c (record_full_resume_ptid): New global.
(record_full_target::resume): Set it.
(record_full_wait_1): Use record_full_resume_ptid instead of
inferior_ptid.
---
gdb/record-full.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gdb/record-full.c b/gdb/record-full.c
index e83ce01b71..8ed973ad12 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1036,6 +1036,9 @@ record_full_base_target::async (int enable)
beneath ()->async (enable);
}
+/* The PTID and STEP arguments last passed to
+ record_full_target::resume. */
+static ptid_t record_full_resume_ptid = null_ptid;
static int record_full_resume_step = 0;
/* True if we've been resumed, and so each record_full_wait call should
@@ -1064,6 +1067,7 @@ static enum exec_direction_kind record_full_execution_dir = EXEC_FORWARD;
void
record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
{
+ record_full_resume_ptid = inferior_ptid;
record_full_resume_step = step;
record_full_resumed = 1;
record_full_execution_dir = ::execution_direction;
@@ -1190,7 +1194,8 @@ record_full_wait_1 (struct target_ops *ops,
/* This is not a single step. */
ptid_t ret;
CORE_ADDR tmp_pc;
- struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid);
+ struct gdbarch *gdbarch
+ = target_thread_architecture (record_full_resume_ptid);
while (1)
{
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 16/23] Fix reconnecting to a gdbserver already debugging multiple processes, II
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (13 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 18/23] Add multi-target tests Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:33 ` [PATCH 23/23] Multi-target: NEWS and user manual Pedro Alves
` (10 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
Another bug exposed by gdb.server/extended-remote-restart.exp in the
multi-target work is that remote_target::start_remote can leave
inferior_ptid and current_inferior() out of sync:
(top-gdb) p current_inferior_->pid
$1 = 29541
(top-gdb) p inferior_ptid
$2 = {m_pid = 29540, m_lwp = 29540, m_tid = 0}
This is caused by writing to inferior_ptid directly instead of using
switch_to_thread. Also, "inferior_list->thread_list->ptid" assumes
that we want the first thread of the first inferior, but that inferior
may not have threads, or with multi-target, that target may be
connected to some other target.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (remote_target::start_remote): Don't set inferior_ptid
directly. Instead find the first thread in the thread list and
use switch_to_thread.
---
gdb/remote.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/gdb/remote.c b/gdb/remote.c
index 16ef9dbdfd..ef6eb99999 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4709,8 +4709,8 @@ remote_target::start_remote (int from_tty, int extended_p)
says should be current. If we're reconnecting to a
multi-threaded program, this will ideally be the thread
that last reported an event before GDB disconnected. */
- inferior_ptid = get_current_thread (wait_status);
- if (inferior_ptid == null_ptid)
+ ptid_t curr_thread = get_current_thread (wait_status);
+ if (curr_thread == null_ptid)
{
/* Odd... The target was able to list threads, but not
tell us which thread was current (no "thread"
@@ -4722,8 +4722,14 @@ remote_target::start_remote (int from_tty, int extended_p)
"warning: couldn't determine remote "
"current thread; picking first in list.\n");
- inferior_ptid = inferior_list->thread_list->ptid;
+ for (thread_info *tp : all_non_exited_threads ())
+ {
+ switch_to_thread (tp);
+ break;
+ }
}
+ else
+ switch_to_thread (find_thread_ptid (curr_thread));
}
/* init_wait_for_inferior should be called before get_offsets in order
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 10/23] Some get_last_target_status tweaks
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (5 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-09 18:53 ` Tom Tromey
2019-09-06 23:28 ` [PATCH 08/23] Introduce switch_to_inferior_no_thread Pedro Alves
` (18 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
- Make get_last_target_status arguments optional. A following patch
will add another argument to get_last_target_status (the event's
target), and passing nullptr when we don't care for some piece of
info is handier than creating dummy local variables.
- Declare nullify_last_target_wait_ptid in a header, and remove the
local extern declaration from linux-fork.c.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* break-catch-sig.c (signal_catchpoint_print_it): Don't pass a
ptid to get_last_target_status.
* break-catch-syscall.c (print_it_catch_syscall): Don't pass a
ptid to get_last_target_status.
* infcmd.c (continue_command): Don't pass a target_waitstatus to
get_last_target_status.
(info_program_command): Don't pass a target_waitstatus to
get_last_target_status.
* infrun.c (init_wait_for_inferior): Use
nullify_last_target_wait_ptid.
(get_last_target_status): Handle nullptr arguments.
(nullify_last_target_wait_ptid): Clear target_last_waitstatus.
(print_stop_event): Don't pass a ptid to get_last_target_status.
(normal_stop): Don't pass a ptid to get_last_target_status.
* infrun.h (nullify_last_target_wait_ptid): Declare.
* linux-fork.c (fork_load_infrun_state): Remove local extern
declaration of nullify_last_target_wait_ptid.
* linux-nat.c (get_detach_signal): Don't pass a target_waitstatus
to get_last_target_status.
---
gdb/break-catch-sig.c | 3 +--
gdb/break-catch-syscall.c | 3 +--
gdb/infcmd.c | 9 ++-------
gdb/infrun.c | 27 +++++++++++++--------------
gdb/infrun.h | 2 ++
gdb/linux-fork.c | 1 -
gdb/linux-nat.c | 3 +--
7 files changed, 20 insertions(+), 28 deletions(-)
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
index 53540ee832..76f6db60ab 100644
--- a/gdb/break-catch-sig.c
+++ b/gdb/break-catch-sig.c
@@ -180,12 +180,11 @@ static enum print_stop_action
signal_catchpoint_print_it (bpstat bs)
{
struct breakpoint *b = bs->breakpoint_at;
- ptid_t ptid;
struct target_waitstatus last;
const char *signal_name;
struct ui_out *uiout = current_uiout;
- get_last_target_status (&ptid, &last);
+ get_last_target_status (nullptr, &last);
signal_name = signal_to_name_or_int (last.value.sig);
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index a165be62be..0fce15d81b 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -181,12 +181,11 @@ print_it_catch_syscall (bpstat bs)
syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
must print "called syscall" or "returned from syscall". */
- ptid_t ptid;
struct target_waitstatus last;
struct syscall s;
struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
- get_last_target_status (&ptid, &last);
+ get_last_target_status (nullptr, &last);
get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index a12dba23aa..879f33bbc2 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -859,9 +859,8 @@ continue_command (const char *args, int from_tty)
else
{
ptid_t last_ptid;
- struct target_waitstatus ws;
- get_last_target_status (&last_ptid, &ws);
+ get_last_target_status (&last_ptid, nullptr);
tp = find_thread_ptid (last_ptid);
}
if (tp != NULL)
@@ -1985,11 +1984,7 @@ info_program_command (const char *args, int from_tty)
if (non_stop)
ptid = inferior_ptid;
else
- {
- struct target_waitstatus ws;
-
- get_last_target_status (&ptid, &ws);
- }
+ get_last_target_status (&ptid, nullptr);
if (ptid == null_ptid || ptid == minus_one_ptid)
error (_("No selected thread."));
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 61c99e36c4..f25cbcd5e8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -84,8 +84,6 @@ static void follow_inferior_reset_breakpoints (void);
static int currently_stepping (struct thread_info *tp);
-void nullify_last_target_wait_ptid (void);
-
static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *);
static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
@@ -3112,7 +3110,7 @@ init_wait_for_inferior (void)
clear_proceed_status (0);
- target_last_wait_ptid = minus_one_ptid;
+ nullify_last_target_wait_ptid ();
previous_inferior_ptid = inferior_ptid;
}
@@ -3865,22 +3863,25 @@ set_last_target_status (ptid_t ptid, struct target_waitstatus status)
target_last_waitstatus = status;
}
-/* Return the cached copy of the last pid/waitstatus returned by
- target_wait()/deprecated_target_wait_hook(). The data is actually
- cached by handle_inferior_event(), which gets called immediately
- after target_wait()/deprecated_target_wait_hook(). */
+/* Return the cached copy of the last ptid/waitstatus returned
+ by target_wait()/deprecated_target_wait_hook(). The data is
+ actually cached by handle_inferior_event(), which gets called
+ immediately after target_wait()/deprecated_target_wait_hook(). */
void
-get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status)
+get_last_target_status (ptid_t *ptid, struct target_waitstatus *status)
{
- *ptidp = target_last_wait_ptid;
- *status = target_last_waitstatus;
+ if (ptid != nullptr)
+ *ptid = target_last_wait_ptid;
+ if (status != nullptr)
+ *status = target_last_waitstatus;
}
void
nullify_last_target_wait_ptid (void)
{
target_last_wait_ptid = minus_one_ptid;
+ target_last_waitstatus = {};
}
/* Switch thread contexts. */
@@ -7842,10 +7843,9 @@ void
print_stop_event (struct ui_out *uiout, bool displays)
{
struct target_waitstatus last;
- ptid_t last_ptid;
struct thread_info *tp;
- get_last_target_status (&last_ptid, &last);
+ get_last_target_status (nullptr, &last);
{
scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout);
@@ -7964,9 +7964,8 @@ int
normal_stop (void)
{
struct target_waitstatus last;
- ptid_t last_ptid;
- get_last_target_status (&last_ptid, &last);
+ get_last_target_status (nullptr, &last);
new_stop_id ();
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 30374ee51c..042edbbb66 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -107,6 +107,8 @@ extern void get_last_target_status (ptid_t *ptid,
extern void set_last_target_status (ptid_t ptid,
struct target_waitstatus status);
+extern void nullify_last_target_wait_ptid ();
+
/* Stop all threads. Only returns after everything is halted. */
extern void stop_all_threads (void);
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 87cfacc8e8..ab96be2f38 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -215,7 +215,6 @@ call_lseek (int fd, off_t offset, int whence)
static void
fork_load_infrun_state (struct fork_info *fp)
{
- extern void nullify_last_target_wait_ptid ();
int i;
linux_nat_switch_fork (fp->ptid);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 945c19f666..8f7d4b6eba 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1318,10 +1318,9 @@ get_detach_signal (struct lwp_info *lp)
}
else if (!target_is_non_stop_p ())
{
- struct target_waitstatus last;
ptid_t last_ptid;
- get_last_target_status (&last_ptid, &last);
+ get_last_target_status (&last_ptid, nullptr);
if (lp->ptid.lwp () == last_ptid.lwp ())
signo = tp->suspend.stop_signal;
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 18/23] Add multi-target tests
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (12 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 17/23] Multi-target support Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-10-09 16:01 ` Aktemur, Tankut Baris
2019-09-06 23:28 ` [PATCH 16/23] Fix reconnecting to a gdbserver already debugging multiple processes, II Pedro Alves
` (11 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
This adds a testcase exercising multi-target features. It spawns 6
inferiors, like this:
inferior 1 -> native
inferior 2 -> extended-remote 1
inferior 3 -> core
inferior 4 -> native
inferior 5 -> extended-remote 2
inferior 6 -> core
and then tests various details, including:
- running to breakpoints
- interrupting with Ctrl-C and "interrupt -a"
- "next" bouncing between two breakpoints in two threads running in
different targets.
- since we have cores and live inferiors mixed in the same session,
this makes sure that gdb doesn't try to remove a core dump's
threads.
- all-stop and non-stop modes.
This testcase caught a _lot_ of bugs in development.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.multi/multi-target.c: New file.
* gdb.multi/multi-target.exp: New file.
* lib/gdbserver-support.exp (gdb_target_cmd): Handle "Non-stop
mode requested, but remote does not support non-stop".
---
gdb/testsuite/gdb.multi/multi-target.c | 100 +++++++++
gdb/testsuite/gdb.multi/multi-target.exp | 361 +++++++++++++++++++++++++++++++
gdb/testsuite/lib/gdbserver-support.exp | 4 +
3 files changed, 465 insertions(+)
create mode 100644 gdb/testsuite/gdb.multi/multi-target.c
create mode 100644 gdb/testsuite/gdb.multi/multi-target.exp
diff --git a/gdb/testsuite/gdb.multi/multi-target.c b/gdb/testsuite/gdb.multi/multi-target.c
new file mode 100644
index 0000000000..856226e6b9
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/multi-target.c
@@ -0,0 +1,100 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017-2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NUM_THREADS 1
+
+static pthread_barrier_t barrier;
+
+static void *
+thread_start (void *arg)
+{
+ pthread_barrier_wait (&barrier);
+
+ while (1)
+ sleep (1);
+ return NULL;
+}
+
+static void
+all_started (void)
+{
+}
+
+int wait_for_gdb;
+
+static void
+function1 (void)
+{
+ while (wait_for_gdb)
+ sleep (1);
+}
+
+static void
+function2 (void)
+{
+ while (wait_for_gdb)
+ sleep (1);
+}
+
+static void
+function3 (void)
+{
+}
+
+static void
+function4 (void)
+{
+}
+
+static void
+function5 (void)
+{
+}
+
+int
+main (int argc, char ** argv)
+{
+ pthread_t thread;
+ int len;
+
+ alarm (360);
+
+ pthread_barrier_init (&barrier, NULL, NUM_THREADS + 1);
+ pthread_create (&thread, NULL, thread_start, NULL);
+
+ pthread_barrier_wait (&barrier);
+ all_started ();
+
+ while (1)
+ {
+ function1 (); /* set break 1 here */
+ function2 (); /* set break 2 here */
+ function3 ();
+ function4 ();
+ function5 ();
+ sleep (1);
+ }
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.multi/multi-target.exp b/gdb/testsuite/gdb.multi/multi-target.exp
new file mode 100644
index 0000000000..3b71e7446b
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/multi-target.exp
@@ -0,0 +1,361 @@
+# Copyright 2017-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test multi-target features.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+# The plain remote target can't do multiple inferiors.
+if {[target_info gdb_protocol] != ""} {
+ return
+}
+
+if { [prepare_for_testing "failed to prepare" ${binfile} "${srcfile}" \
+ {debug pthreads}] } {
+ return
+}
+
+proc connect_target_extended_remote {binfile} {
+ set res [gdbserver_start "--multi" ""]
+ set gdbserver_gdbport [lindex $res 1]
+ return [gdb_target_cmd "extended-remote" $gdbserver_gdbport]
+}
+
+# Add and start inferior number NUM. Returns true on success, false
+# otherwise.
+proc add_inferior {num target binfile {gcorefile ""}} {
+ # Start another inferior.
+ gdb_test "add-inferior -no-connection" "Added inferior $num" \
+ "add empty inferior $num"
+ gdb_test "inferior $num" "Switching to inferior $num.*" \
+ "switch to inferior $num"
+ gdb_test "file ${binfile}" ".*" "load file in inferior $num"
+ gdb_test_no_output "set remote exec-file ${binfile}" \
+ "set remote-exec file in inferior $num"
+
+ if {$target == "core"} {
+ gdb_test "core $gcorefile" "Core was generated by.*" \
+ "core [file tail $gcorefile]"
+ return 1
+ }
+
+ if {$target == "extended-remote"} {
+ if {[connect_target_extended_remote $binfile]} {
+ return 0
+ }
+ }
+ if ![runto "all_started"] then {
+ return 0
+ }
+ delete_breakpoints
+
+ return 1
+}
+
+proc prepare_core {} {
+ global gcorefile gcore_created
+ global binfile
+
+ clean_restart ${binfile}
+
+ if ![runto all_started] then {
+ return -1
+ }
+
+ global testfile
+ set gcorefile [standard_output_file $testfile.gcore]
+ set gcore_created [gdb_gcore_cmd $gcorefile "save a core file"]
+}
+
+proc next_live_inferior {inf} {
+ incr inf
+ if {$inf == 3} {
+ # 3 is a core.
+ return 4
+ }
+ if {$inf > 5} {
+ # 6 is a core.
+ return 1
+ }
+
+ return $inf
+}
+
+# Return true on success, false otherwise.
+
+proc setup {non-stop} {
+ global gcorefile gcore_created
+ global binfile
+
+ clean_restart ${binfile}
+
+ # multi-target depends on target running in non-stop mode. Force
+ # it on for remote targets, until this is the default.
+ gdb_test_no_output "maint set target-non-stop on"
+
+ gdb_test_no_output "set non-stop ${non-stop}"
+
+ if ![runto all_started] then {
+ return 0
+ }
+
+ delete_breakpoints
+
+ # inferior 1 -> native
+ # inferior 2 -> extended-remote
+ # inferior 3 -> core
+ # inferior 4 -> native
+ # inferior 5 -> extended-remote
+ # inferior 6 -> core
+ if {![add_inferior 2 "extended-remote" $binfile]} {
+ return 0
+ }
+ if {![add_inferior 3 "core" $binfile $gcorefile]} {
+ return 0
+ }
+ if {![add_inferior 4 "native" $binfile]} {
+ return 0
+ }
+ if {![add_inferior 5 "extended-remote" $binfile]} {
+ return 0
+ }
+ if {![add_inferior 6 "core" $binfile $gcorefile]} {
+ return 0
+ }
+
+ # For debugging.
+ gdb_test "info inferiors" ".*"
+ gdb_test "info threads" ".*"
+
+ # Make "continue" resume all inferiors.
+ if {${non-stop} == "off"} {
+ gdb_test_no_output "set schedule-multiple on"
+ }
+
+ return 1
+}
+
+# Test "continue" to breakpoints in different targets. In non-stop
+# mode, also tests "interrupt -a".
+proc test_continue {non-stop} {
+ if {![setup ${non-stop}]} {
+ untested "setup failed"
+ return
+ }
+
+ proc set_break {inf} {
+ gdb_test "break function${inf} thread ${inf}.1" \
+ "Breakpoint .* function${inf}\\..*"
+ }
+
+ # Select inferior INF, and then run to a breakpoint on inferior
+ # INF+1.
+ proc test_continue_inf {inf} {
+ upvar 1 non-stop non-stop
+
+ global gdb_prompt
+ delete_breakpoints
+
+ set next_inf [next_live_inferior $inf]
+
+ gdb_test "inferior $inf" "Switching to inferior $inf.*"
+ set_break $next_inf
+
+ if {${non-stop} == "off"} {
+ gdb_test "continue" "hit Breakpoint .* function${next_inf}.*"
+ } else {
+ set msg "continue"
+ gdb_test_multiple "continue -a&" $msg {
+ -re "Continuing.*$gdb_prompt " {
+ pass $msg
+ }
+ }
+
+ set msg "hit bp"
+ gdb_test_multiple "" $msg {
+ -re "hit Breakpoint .* function${next_inf}" {
+ pass $msg
+ }
+ }
+
+ set msg "stop all threads"
+ gdb_test_multiple "interrupt -a" $msg {
+ -re "$gdb_prompt " {
+ for {set i 0} {$i < 7} {incr i} {
+ set ok 0
+ gdb_test_multiple "" $msg {
+ -re "Thread\[^\r\n\]*stopped\\." {
+ set ok 1
+ }
+ }
+ if {!$ok} {
+ break
+ }
+ }
+ gdb_assert $ok $msg
+ }
+ }
+ }
+ }
+
+ for {set i 1} {$i <= 5} {incr i} {
+ if {$i == 3} {
+ # This is a core inferior.
+ continue
+ }
+
+ with_test_prefix "inf$i" {
+ test_continue_inf $i
+ }
+ }
+}
+
+# Test interrupting multiple targets with Ctrl-C.
+
+proc test_ctrlc {} {
+ if {![setup "off"]} {
+ untested "setup failed"
+ return
+ }
+
+ delete_breakpoints
+
+ # Select inferior INF, continue all inferiors, and then Ctrl-C.
+ proc test_ctrlc_inf {inf} {
+ global gdb_prompt
+
+ gdb_test "inferior $inf" "Switching to inferior $inf.*"
+
+ set msg "continue"
+ gdb_test_multiple "continue" $msg {
+ -re "Continuing" {
+ pass $msg
+ }
+ }
+
+ after 200 { send_gdb "\003" }
+
+ set msg "send_gdb control C"
+ gdb_test_multiple "" $msg {
+ -re "received signal SIGINT.*$gdb_prompt $" {
+ pass $msg
+ }
+ }
+
+ set msg "all threads stopped"
+ gdb_test_multiple "info threads" "$msg" {
+ -re "\\\(running\\\).*$gdb_prompt $" {
+ fail $msg
+ }
+ -re "$gdb_prompt $" {
+ pass $msg
+ }
+ }
+ }
+
+ for {set i 1} {$i <= 5} {incr i} {
+ if {$i == 3} {
+ # This is a core inferior.
+ continue
+ }
+
+ with_test_prefix "inf$i" {
+ test_ctrlc_inf $i
+ }
+ }
+}
+
+# Test "next" bouncing between two breakpoints in two threads running
+# in different targets.
+proc test_ping_pong_next {} {
+ global srcfile
+
+ if {![setup "off"]} {
+ untested "setup failed"
+ return
+ }
+
+ # block/unblock inferiors 1 and 2 according to INF1 and INF2.
+ proc block {inf1 inf2} {
+ gdb_test "thread apply 1.1 p wait_for_gdb = $inf1" " = $inf1"
+ gdb_test "thread apply 2.1 p wait_for_gdb = $inf2" " = $inf2"
+ }
+
+ # We're use inferiors 1 and 2. Make sure they're really connected
+ # to different targets.
+ gdb_test "thread apply 1.1 maint print target-stack" \
+ "- native.*"
+ gdb_test "thread apply 2.1 maint print target-stack" \
+ "- extended-remote.*"
+
+ # Set two breakpoints, one for each of inferior 1 and 2. Inferior
+ # 1 is running on the native target, and inferior 2 is running on
+ # extended-gdbserver. Run to breakpoint 1 to gets things started.
+ set line1 [gdb_get_line_number "set break 1 here"]
+ set line2 [gdb_get_line_number "set break 2 here"]
+
+ gdb_test "thread 1.1" "Switching to thread 1.1 .*"
+
+ gdb_test "break $srcfile:$line1 thread 1.1" \
+ "Breakpoint .*$srcfile:$line1\\..*"
+
+ gdb_test "continue" "hit Breakpoint .*"
+
+ gdb_test "break $srcfile:$line2 thread 2.1" \
+ "Breakpoint .*$srcfile:$line2\\..*"
+
+ # Now block inferior 1 and issue "next". We should stop at the
+ # breakpoint for inferior 2, given schedlock off.
+ with_test_prefix "next inf 1" {
+ block 1 0
+ gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*"
+ }
+
+ # Now unblock inferior 2 and block inferior 1. "next" should run
+ # into the breakpoint in inferior 1.
+ with_test_prefix "next inf 2" {
+ block 0 1
+ gdb_test "next" "Thread 1.1 .*hit Breakpoint .*$srcfile:$line1.*"
+ }
+
+ # Try nexting inferior 1 again.
+ with_test_prefix "next inf 1 again" {
+ block 1 0
+ gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*"
+ }
+}
+
+# Make a core file with two threads upfront. Several tests load the
+# same core file.
+prepare_core
+
+# Some basic "continue" + breakpoints tests.
+with_test_prefix "continue" {
+ foreach_with_prefix non-stop {"off" "on"} {
+ test_continue ${non-stop}
+ }
+}
+
+# Some basic all-stop Ctrl-C tests.
+with_test_prefix "interrupt" {
+ test_ctrlc
+}
+
+# Test ping-ponging between two targets with "next".
+with_test_prefix "ping-pong" {
+ test_ping_pong_next
+}
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index ade99c0ea1..4ec0ed66ab 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -63,6 +63,10 @@ proc gdb_target_cmd { targetname serialport {additional_text ""} } {
-re "Couldn't establish connection to remote.*$gdb_prompt $" {
verbose "Connection failed"
}
+ -re "Non-stop mode requested, but remote does not support non-stop.*$gdb_prompt $" {
+ verbose "remote does not support non-stop"
+ return 1
+ }
-re "Remote MIPS debugging.*$additional_text.*$gdb_prompt" {
verbose "Set target to $targetname"
return 0
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 19/23] gdbarch-selftests.c: No longer error out if debugging something
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (9 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 20/23] Revert 'Remove unused struct serial::name field' Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 03/23] Make "show remote exec-file" inferior-aware Pedro Alves
` (14 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
Since each inferior has its own target stack, the stratum condition
for the "error out if debugging something" check is always false.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdbarch-selftests.c (register_to_value_test): Remove "target
already pushed" check.
---
gdb/gdbarch-selftests.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c
index 0942050479..7fd56b0343 100644
--- a/gdb/gdbarch-selftests.c
+++ b/gdb/gdbarch-selftests.c
@@ -71,11 +71,6 @@ register_to_value_test (struct gdbarch *gdbarch)
builtin->builtin_char32,
};
- /* Error out if debugging something, because we're going to push the
- test target, which would pop any existing target. */
- if (current_top_target ()->stratum () >= process_stratum)
- error (_("target already pushed"));
-
/* Create a mock environment. An inferior with a thread, with a
process_stratum target pushed. */
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 11/23] tfile_target::close: trace_fd can't be -1
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 15/23] Fix reconnecting to a gdbserver already debugging multiple processes, I Pedro Alves
` (24 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
It's not possible to open a tfile target with an invalid trace_fd, and
it's not possible to close a closed target, so this early return is dead.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* tracefile-tfile.c (tfile_target::close): Assert that trace_fd is
not -1.
---
gdb/tracefile-tfile.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index 5c3837ec5b..c5063e66b0 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -616,8 +616,7 @@ tfile_interp_line (char *line, struct uploaded_tp **utpp,
void
tfile_target::close ()
{
- if (trace_fd < 0)
- return;
+ gdb_assert (trace_fd != -1);
inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */
exit_inferior_silent (current_inferior ());
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 08/23] Introduce switch_to_inferior_no_thread
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (6 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 10/23] Some get_last_target_status tweaks Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-09 18:42 ` Tom Tromey
2019-09-06 23:28 ` [PATCH 06/23] Don't check target is running in remote_target::mourn_inferior Pedro Alves
` (17 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
Several places want to switch context to an inferior and its pspace,
while at the same time switch to "no thread selected". This commit
adds a function that does that, and uses it in a few places. The
function is made extern because many more uses will be added in follow
up commits.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* inferior.c (switch_to_inferior_no_thread): New function,
factored out from ...
(inferior_command): ... here.
* inferior.h (switch_to_inferior_no_thread): Declare.
---
gdb/inferior.c | 21 +++++++++++++--------
gdb/inferior.h | 4 ++++
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 994938d564..18f6f805cc 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -584,6 +584,16 @@ kill_inferior_command (const char *args, int from_tty)
bfd_cache_close_all ();
}
+/* See inferior.h. */
+
+void
+switch_to_inferior_no_thread (inferior *inf)
+{
+ set_current_inferior (inf);
+ switch_to_no_thread ();
+ set_current_program_space (inf->pspace);
+}
+
static void
inferior_command (const char *args, int from_tty)
{
@@ -614,9 +624,7 @@ inferior_command (const char *args, int from_tty)
}
else
{
- set_current_inferior (inf);
- switch_to_no_thread ();
- set_current_program_space (inf->pspace);
+ switch_to_inferior_no_thread (inf);
gdb::observers::user_selected_context_changed.notify
(USER_SELECTED_INFERIOR);
@@ -746,11 +754,8 @@ add_inferior_command (const char *args, int from_tty)
if (exec != NULL)
{
/* Switch over temporarily, while reading executable and
- symbols.q. */
- set_current_program_space (inf->pspace);
- set_current_inferior (inf);
- switch_to_no_thread ();
-
+ symbols. */
+ switch_to_inferior_no_thread (inf);
exec_file_attach (exec.get (), from_tty);
symbol_file_add_main (exec.get (), add_flags);
}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index ce9bcbf122..967d4fa8b7 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -329,6 +329,10 @@ extern inferior *current_inferior ();
extern void set_current_inferior (inferior *);
+/* Switch inferior (and program space) to INF, and switch to no thread
+ selected. */
+extern void switch_to_inferior_no_thread (inferior *inf);
+
/* GDB represents the state of each program execution with an object
called an inferior. An inferior typically corresponds to a process
but is more general and applies also to targets that do not have a
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 03/23] Make "show remote exec-file" inferior-aware
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (10 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 19/23] gdbarch-selftests.c: No longer error out if debugging something Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 17/23] Multi-target support Pedro Alves
` (13 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
The "set remote exec-file" setting is per-inferior, but the "show
remote exec-file" command always shows the last set exec-file,
irrespective of the current inferior. E.g.:
# Set inferior 1's exec-file:
(gdb) set remote exec-file prog1
# Add inferior 2, switch to it, and set its exec-file:
(gdb) add-inferior
Added inferior 2
(gdb) inferior 2
(gdb) set remote exec-file prog2
# Switch back to inferior 1, and show its exec-file:
(gdb) inferior 1
(gdb) show remote exec-file
prog2
^^^^^ should show "prog1" instead here.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (show_remote_exec_file): Show the current inferior's
exec-file instead of the command variable's value.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.base/remote-exec-file.exp: New file.
---
gdb/remote.c | 2 +-
gdb/testsuite/gdb.base/remote-exec-file.exp | 46 +++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.base/remote-exec-file.exp
diff --git a/gdb/remote.c b/gdb/remote.c
index ae06c4ba79..db6f1a0e59 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1272,7 +1272,7 @@ static void
show_remote_exec_file (struct ui_file *file, int from_tty,
struct cmd_list_element *cmd, const char *value)
{
- fprintf_filtered (file, "%s\n", remote_exec_file_var);
+ fprintf_filtered (file, "%s\n", get_remote_exec_file ());
}
static int
diff --git a/gdb/testsuite/gdb.base/remote-exec-file.exp b/gdb/testsuite/gdb.base/remote-exec-file.exp
new file mode 100644
index 0000000000..3db009b830
--- /dev/null
+++ b/gdb/testsuite/gdb.base/remote-exec-file.exp
@@ -0,0 +1,46 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Check that "show remote exec-file" displays each inferior's
+# exec-file. Regression test for a bug where "show remote exec-file"
+# would show the last exec-file set, irrespective of the current
+# inferior.
+
+clean_restart
+
+# Set remote exec-file in inferior 1.
+with_test_prefix "set inf 1" {
+ gdb_test_no_output "set remote exec-file prog1"
+}
+
+# Set remote exec-file in inferior 2.
+with_test_prefix "set inf 2" {
+ gdb_test "add-inferior" "Added inferior 2" "add inferior 2"
+ gdb_test "inferior 2" "Switching to inferior 2.*"
+ gdb_test_no_output "set remote exec-file prog2"
+}
+
+# Check that "show remote exec-file" diplays each inferior's
+# exec-file.
+
+with_test_prefix "show inf 1" {
+ gdb_test "inferior 1" "Switching to inferior 1.*"
+ gdb_test "show remote exec-file" "prog1"
+}
+
+with_test_prefix "show inf 2" {
+ gdb_test "inferior 2" "Switching to inferior 2.*"
+ gdb_test "show remote exec-file" "prog2"
+}
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 09/23] switch inferior/thread before calling target methods
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
2019-09-06 23:28 ` [PATCH 11/23] tfile_target::close: trace_fd can't be -1 Pedro Alves
2019-09-06 23:28 ` [PATCH 15/23] Fix reconnecting to a gdbserver already debugging multiple processes, I Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 13/23] Delete exit_inferior_silent(int pid) Pedro Alves
` (22 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
Once each inferior has its own target stack, we'll need to make sure
that the right inferior is selected before we call into target
methods.
It kind of sounds worse than it is in practice. Not that many places
need to be concerned.
In thread.c, we add a new switch_to_thread_if_alive function that
centralizes the switching before calls to target_thread_alive. Other
cases are handled with explicit switching.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdbthread.h (scoped_restore_current_thread)
<dont_restore, restore, m_dont_restore>: Declare.
* thread.c (thread_alive): Add assertion. Return bool.
(switch_to_thread_if_alive): New.
(prune_threads): Switch inferior/thread.
(print_thread_info_1): Switch thread before calling target methods.
(scoped_restore_current_thread::restore): New, factored out from
...
(scoped_restore_current_thread::~scoped_restore_current_thread):
... this.
(scoped_restore_current_thread::scoped_restore_current_thread):
Add assertion.
(thread_apply_all_command, thread_select): Use
switch_to_thread_if_alive.
* infrun.c (proceed, restart_threads, handle_signal_stop)
(switch_back_to_stepped_thread): Switch current thread before
calling target methods.
---
gdb/infrun.c | 16 ++++++++++++--
gdb/thread.c | 72 +++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 66 insertions(+), 22 deletions(-)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9c888aa72f..61c99e36c4 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2949,6 +2949,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
{
for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
+ switch_to_thread_no_regs (tp);
+
/* Ignore the current thread here. It's handled
afterwards. */
if (tp == cur_thr)
@@ -2966,6 +2968,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
thread_step_over_chain_enqueue (tp);
}
+
+ switch_to_thread (cur_thr);
}
/* Enqueue the current thread last, so that we move all other
@@ -3002,6 +3006,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
Start all other threads that are implicitly resumed too. */
for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
+ switch_to_thread_no_regs (tp);
+
if (tp->resumed)
{
if (debug_infrun)
@@ -4347,6 +4353,7 @@ stop_all_threads (void)
"infrun: %s executing, "
"need stop\n",
target_pid_to_str (t->ptid).c_str ());
+ switch_to_thread_no_regs (t);
target_stop (t->ptid);
t->stop_requested = 1;
}
@@ -5191,6 +5198,8 @@ restart_threads (struct thread_info *event_thread)
for (thread_info *tp : all_non_exited_threads ())
{
+ switch_to_thread_no_regs (tp);
+
if (tp == event_thread)
{
if (debug_infrun)
@@ -5449,9 +5458,8 @@ handle_signal_stop (struct execution_control_state *ecs)
{
struct regcache *regcache = get_thread_regcache (ecs->event_thread);
struct gdbarch *reg_gdbarch = regcache->arch ();
- scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
- inferior_ptid = ecs->ptid;
+ switch_to_thread (ecs->event_thread);
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n",
paddress (reg_gdbarch,
@@ -6885,6 +6893,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
for (thread_info *tp : all_non_exited_threads ())
{
+ switch_to_thread_no_regs (tp);
+
/* Ignore threads of processes the caller is not
resuming. */
if (!sched_multi
@@ -6936,6 +6946,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
return 1;
}
}
+
+ switch_to_thread (ecs->event_thread);
}
return 0;
diff --git a/gdb/thread.c b/gdb/thread.c
index f79507716b..9a5867306b 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -62,8 +62,6 @@ static int highest_thread_num;
spawned new threads we haven't heard of yet. */
static int threads_executing;
-static int thread_alive (struct thread_info *);
-
/* RAII type used to increase / decrease the refcount of each thread
in a given list of threads. */
@@ -679,14 +677,38 @@ any_live_thread_of_inferior (inferior *inf)
}
/* Return true if TP is an active thread. */
-static int
-thread_alive (struct thread_info *tp)
+static bool
+thread_alive (thread_info *tp)
{
if (tp->state == THREAD_EXITED)
- return 0;
- if (!target_thread_alive (tp->ptid))
- return 0;
- return 1;
+ return false;
+
+ /* Ensure we're looking at the right target stack. */
+ gdb_assert (tp->inf == current_inferior ());
+
+ return target_thread_alive (tp->ptid);
+}
+
+/* Switch to thread TP if it is alive. Returns true if successfully
+ switched, false otherwise. */
+
+static bool
+switch_to_thread_if_alive (thread_info *thr)
+{
+ scoped_restore_current_thread restore_thread;
+
+ /* Switch inferior first, so that we're looking at the right target
+ stack. */
+ switch_to_inferior_no_thread (thr->inf);
+
+ if (thread_alive (thr))
+ {
+ switch_to_thread (thr);
+ restore_thread.dont_restore ();
+ return true;
+ }
+
+ return false;
}
/* See gdbthreads.h. */
@@ -694,9 +716,15 @@ thread_alive (struct thread_info *tp)
void
prune_threads (void)
{
+ scoped_restore_current_thread restore_thread;
+
for (thread_info *tp : all_threads_safe ())
- if (!thread_alive (tp))
- delete_thread (tp);
+ {
+ switch_to_inferior_no_thread (tp->inf);
+
+ if (!thread_alive (tp))
+ delete_thread (tp);
+ }
}
/* See gdbthreads.h. */
@@ -1037,6 +1065,9 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
gdb::optional<ui_out_emit_list> list_emitter;
gdb::optional<ui_out_emit_table> table_emitter;
+ /* We'll be switching threads temporarily below. */
+ scoped_restore_current_thread restore_thread;
+
if (uiout->is_mi_like_p ())
list_emitter.emplace (uiout, "threads");
else
@@ -1054,6 +1085,10 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
if (!uiout->is_mi_like_p ())
{
+ /* Switch inferiors so we're looking at the right
+ target stack. */
+ switch_to_inferior_no_thread (tp->inf);
+
target_id_col_width
= std::max (target_id_col_width,
thread_target_id_str (tp).size ());
@@ -1085,9 +1120,6 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
uiout->table_body ();
}
- /* We'll be switching threads temporarily. */
- scoped_restore_current_thread restore_thread;
-
for (inferior *inf : all_inferiors ())
for (thread_info *tp : inf->threads ())
{
@@ -1116,6 +1148,9 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
if (show_global_ids || uiout->is_mi_like_p ())
uiout->field_signed ("id", tp->global_num);
+ /* Switch to the thread (and inferior / target). */
+ switch_to_thread (tp);
+
/* For the CLI, we stuff everything into the target-id field.
This is a gross hack to make the output come out looking
correct. The underlying problem here is that ui-out has no
@@ -1147,9 +1182,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
uiout->text ("(running)\n");
else
{
- /* The switch below puts us at the top of the stack (leaf
+ /* The switch above put us at the top of the stack (leaf
frame). */
- switch_to_thread (tp);
print_stack_frame (get_selected_frame (NULL),
/* For MI output, print frame level. */
uiout->is_mi_like_p (),
@@ -1662,7 +1696,7 @@ thread_apply_all_command (const char *cmd, int from_tty)
scoped_restore_current_thread restore_thread;
for (thread_info *thr : thr_list_cpy)
- if (thread_alive (thr))
+ if (switch_to_thread_if_alive (thr))
thr_try_catch_cmd (thr, cmd, from_tty, flags);
}
}
@@ -1819,7 +1853,7 @@ thread_apply_command (const char *tidlist, int from_tty)
continue;
}
- if (!thread_alive (tp))
+ if (!switch_to_thread_if_alive (tp))
{
warning (_("Thread %s has terminated."), print_thread_id (tp));
continue;
@@ -1983,11 +2017,9 @@ show_print_thread_events (struct ui_file *file, int from_tty,
void
thread_select (const char *tidstr, thread_info *tp)
{
- if (!thread_alive (tp))
+ if (!switch_to_thread_if_alive (tp))
error (_("Thread ID %s has terminated."), tidstr);
- switch_to_thread (tp);
-
annotate_thread_changed ();
/* Since the current thread may have changed, see if there is any
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 01/23] Preserve selected thread in all-stop w/ background execution
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (3 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 13/23] Delete exit_inferior_silent(int pid) Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-10-09 9:36 ` Aktemur, Tankut Baris
2019-09-06 23:28 ` [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait Pedro Alves
` (20 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
In non-stop mode, if you resume the program in the background (with
"continue&", for example), then gdb makes sure to not switch the
current thread behind your back. That means that you can be sure that
the commands you type apply to the thread you selected, even if some
other thread that was running in the background hits some event just
while you're typing.
In all-stop mode, however, if you resume the program in the
background, gdb let's the current thread switch behind your back.
This is bogus, of course. All-stop and non-stop background
resumptions should behave the same.
This patch fixes that, and adds a testcase that exposes the bad
behavior in current master.
The fork-running-state.exp changes are necessary because that
preexisting testcase was expecting the old behavior:
Before:
continue &
Continuing.
(gdb)
[Attaching after process 8199 fork to child process 8203]
[New inferior 2 (process 8203)]
info threads
Id Target Id Frame
1.1 process 8199 "fork-running-st" (running)
* 2.1 process 8203 "fork-running-st" (running)
(gdb)
After:
continue &
Continuing.
(gdb)
[Attaching after process 24660 fork to child process 24664]
[New inferior 2 (process 24664)]
info threads
Id Target Id Frame
* 1.1 process 24660 "fork-running-st" (running)
2.1 process 24664 "fork-running-st" (running)
(gdb)
Here we see that before this patch GDB switches current inferior to
the new inferior behind the user's back, as a side effect of handling
the fork.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdbthread.h (scoped_restore_current_thread)
<dont_restore, restore, m_dont_restore>: Declare.
* thread.c (thread_alive): Add assertion. Return bool.
(switch_to_thread_if_alive): New.
(prune_threads): Switch inferior/thread.
(print_thread_info_1): Switch thread before calling target methods.
(scoped_restore_current_thread::restore): New, factored out from
...
(scoped_restore_current_thread::~scoped_restore_current_thread):
... this.
(scoped_restore_current_thread::scoped_restore_current_thread):
Add assertion.
(thread_apply_all_command, thread_select): Use
switch_to_thread_if_alive.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.base/fork-running-state.exp (do_test): Adjust expected
output.
* gdb.threads/async.c: New.
* gdb.threads/async.exp: New.
---
gdb/gdbthread.h | 6 ++
gdb/infrun.c | 31 ++++++---
gdb/testsuite/gdb.base/fork-running-state.exp | 17 +----
gdb/testsuite/gdb.threads/async.c | 70 +++++++++++++++++++
gdb/testsuite/gdb.threads/async.exp | 98 +++++++++++++++++++++++++++
gdb/thread.c | 19 +++++-
6 files changed, 218 insertions(+), 23 deletions(-)
create mode 100644 gdb/testsuite/gdb.threads/async.c
create mode 100644 gdb/testsuite/gdb.threads/async.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 04230d3c17..bb7a71af0b 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -646,7 +646,13 @@ public:
DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread);
+ /* Cancel restoring on scope exit. */
+ void dont_restore () { m_dont_restore = true; }
+
private:
+ void restore ();
+
+ bool m_dont_restore = false;
/* Use the "class" keyword here, because of a clash with a "thread_info"
function in the Darwin API. */
class thread_info *m_thread;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a9588f896a..9c888aa72f 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3048,6 +3048,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
finish_state.release ();
+ /* If we've switched threads above, switch back to the previously
+ current thread. We don't want the user to see a different
+ selected thread. */
+ switch_to_thread (cur_thr);
+
/* Tell the event loop to wait for it to stop. If the target
supports asynchronous execution, it'll do this from within
target_resume. */
@@ -3702,14 +3707,11 @@ fetch_inferior_event (void *client_data)
set_current_traceframe (-1);
}
- gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
-
- if (non_stop)
- /* In non-stop mode, the user/frontend should not notice a thread
- switch due to internal events. Make sure we reverse to the
- user selected thread and frame after handling the event and
- running any breakpoint commands. */
- maybe_restore_thread.emplace ();
+ /* The user/frontend should not notice a thread switch due to
+ internal events. Make sure we revert to the user selected
+ thread and frame after handling the event and running any
+ breakpoint commands. */
+ scoped_restore_current_thread restore_thread;
overlay_cache_invalid = 1;
/* Flush target cache before starting to handle each event. Target
@@ -3786,6 +3788,19 @@ fetch_inferior_event (void *client_data)
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
cmd_done = 1;
}
+
+ /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
+ previously selected thread is gone. We have two
+ choices - switch to no thread selected, or restore the
+ previously selected thread (now exited). We chose the
+ later, just because that's what GDB used to do. After
+ this, "info threads" says "The current thread <Thread
+ ID 2> has terminated." instead of "No thread
+ selected.". */
+ if (!non_stop
+ && cmd_done
+ && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+ restore_thread.dont_restore ();
}
}
diff --git a/gdb/testsuite/gdb.base/fork-running-state.exp b/gdb/testsuite/gdb.base/fork-running-state.exp
index 98733a6cc1..143b5ce714 100644
--- a/gdb/testsuite/gdb.base/fork-running-state.exp
+++ b/gdb/testsuite/gdb.base/fork-running-state.exp
@@ -98,30 +98,19 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
set not_nl "\[^\r\n\]*"
- if {$detach_on_fork == "on" && $non_stop == "on" && $follow_fork == "child"} {
+ if {$detach_on_fork == "on" && $follow_fork == "child"} {
gdb_test "info threads" \
" 2.1 ${not_nl}\\\(running\\\).*No selected thread.*"
- } elseif {$detach_on_fork == "on" && $follow_fork == "child"} {
- gdb_test "info threads" \
- "\\\* 2.1 ${not_nl}\\\(running\\\)"
} elseif {$detach_on_fork == "on"} {
gdb_test "info threads" \
"\\\* 1 ${not_nl}\\\(running\\\)"
- } elseif {$non_stop == "on"
- || ($schedule_multiple == "on" && $follow_fork == "parent")} {
+ } elseif {$non_stop == "on" || $schedule_multiple == "on"} {
# Both parent and child should be marked running, and the
# parent should be selected.
gdb_test "info threads" \
[multi_line \
"\\\* 1.1 ${not_nl} \\\(running\\\)${not_nl}" \
" 2.1 ${not_nl} \\\(running\\\)"]
- } elseif {$schedule_multiple == "on" && $follow_fork == "child"} {
- # Both parent and child should be marked running, and the
- # child should be selected.
- gdb_test "info threads" \
- [multi_line \
- " 1.1 ${not_nl} \\\(running\\\)${not_nl}" \
- "\\\* 2.1 ${not_nl} \\\(running\\\)"]
} else {
set test "only $follow_fork marked running"
gdb_test_multiple "info threads" $test {
@@ -131,7 +120,7 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
-re "\\\* 1.1 ${not_nl}\\\(running\\\)\r\n 2.1 ${not_nl}\r\n$gdb_prompt $" {
gdb_assert [string eq $follow_fork "parent"] $test
}
- -re "1.1 ${not_nl}\r\n\\\* 2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
+ -re "\\\* 1.1 ${not_nl}\r\n 2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
gdb_assert [string eq $follow_fork "child"] $test
}
}
diff --git a/gdb/testsuite/gdb.threads/async.c b/gdb/testsuite/gdb.threads/async.c
new file mode 100644
index 0000000000..6bffca9c8d
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define NUM 2
+
+static pthread_barrier_t threads_started_barrier;
+
+static void *
+thread_function (void *arg)
+{
+ pthread_barrier_wait (&threads_started_barrier);
+
+ while (1)
+ {
+ /* Sleep a bit to give the other threads a chance to run. */
+ usleep (1); /* set breakpoint here */
+ }
+
+ pthread_exit (NULL);
+}
+
+static void
+all_started (void)
+{
+}
+
+int
+main ()
+{
+ pthread_t threads[NUM];
+ long i;
+
+ pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
+
+ for (i = 1; i <= NUM; i++)
+ {
+ int res;
+
+ res = pthread_create (&threads[i - 1],
+ NULL,
+ thread_function, NULL);
+ }
+
+ pthread_barrier_wait (&threads_started_barrier);
+
+ all_started ();
+
+ sleep (180);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.threads/async.exp b/gdb/testsuite/gdb.threads/async.exp
new file mode 100644
index 0000000000..7047bef2bd
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.exp
@@ -0,0 +1,98 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
+ return -1
+}
+
+# At this point GDB will be busy handling the breakpoint hits and
+# re-resuming the program. Even if GDB internally switches thread
+# context, the user should not notice it. The following part of the
+# testcase ensures that.
+
+# Switch to thread EXPECTED_THR, and then confirm that the thread
+# stays selected.
+
+proc test_current_thread {expected_thr} {
+ global decimal
+ global gdb_prompt
+ global binfile
+
+ clean_restart $binfile
+
+ if {![runto "all_started"]} {
+ fail "could not run to all_started"
+ return
+ }
+
+ # Set a breakpoint that continuously fires but doeesn't cause a stop.
+ gdb_breakpoint [concat [gdb_get_line_number "set breakpoint here"] " if 0"]
+
+ gdb_test "thread $expected_thr" "Switching to thread $expected_thr .*" \
+ "switch to thread $expected_thr"
+
+ # Continue the program in the background.
+ set test "continue&"
+ gdb_test_multiple "continue&" $test {
+ -re "Continuing\\.\r\n$gdb_prompt " {
+ pass $test
+ }
+ }
+
+ set test "current thread is $expected_thr"
+ set fails 0
+ for {set i 0} {$i < 10} {incr i} {
+ after 200
+
+ set cur_thread 0
+ gdb_test_multiple "thread" $test {
+ -re "Current thread is ($decimal) .*$gdb_prompt " {
+ set cur_thread $expect_out(1,string)
+ }
+ }
+
+ if {$cur_thread != $expected_thr} {
+ incr fails
+ }
+ }
+
+ gdb_assert {$fails == 0} $test
+
+ # Explicitly interrupt the target, because in all-stop/remote,
+ # that's all we can do when the target is running. If we don't do
+ # this, we'd time out trying to kill the target, while bringing
+ # down gdb & gdbserver.
+ set test "interrupt"
+ gdb_test_multiple $test $test {
+ -re "^interrupt\r\n$gdb_prompt " {
+ gdb_test_multiple "" $test {
+ -re "Thread .* received signal SIGINT, Interrupt\\." {
+ pass $test
+ }
+ }
+ }
+ }
+}
+
+# Try once with each thread as current, to avoid missing a bug just
+# because some part of GDB manages to switch to the right thread by
+# chance.
+for {set thr 1} {$thr <= 3} {incr thr} {
+ with_test_prefix "thread $thr" {
+ test_current_thread $thr
+ }
+}
diff --git a/gdb/thread.c b/gdb/thread.c
index 4a7fe689db..f79507716b 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1375,7 +1375,8 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
}
}
-scoped_restore_current_thread::~scoped_restore_current_thread ()
+void
+scoped_restore_current_thread::restore ()
{
/* If an entry of thread_info was previously selected, it won't be
deleted because we've increased its refcount. The thread represented
@@ -1402,6 +1403,22 @@ scoped_restore_current_thread::~scoped_restore_current_thread ()
&& target_has_stack
&& target_has_memory)
restore_selected_frame (m_selected_frame_id, m_selected_frame_level);
+}
+
+scoped_restore_current_thread::~scoped_restore_current_thread ()
+{
+ if (!m_dont_restore)
+ {
+ try
+ {
+ restore ();
+ }
+ catch (const gdb_exception &ex)
+ {
+ /* We're in a dtor, there's really nothing else we can do
+ but swallow the exception. */
+ }
+ }
if (m_thread != NULL)
m_thread->decref ();
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 13/23] Delete exit_inferior_silent(int pid)
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (2 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 09/23] switch inferior/thread before calling target methods Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 01/23] Preserve selected thread in all-stop w/ background execution Pedro Alves
` (21 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
In commit 00431a78b28f ("Use thread_info and inferior pointers more
throughout"), I introduced 'exit_inferior_silent(inferior *)' and left
'exit_inferior_silent(int)' behind by mistake. This overload isn't
used anywhere. It's not declared in inferior.h either, that commit
deleted its declaration in favor of the new
'exit_inferior_silent(inferior *)'.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* inferior.c (exit_inferior_silent(int)): Delete.
---
gdb/inferior.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 18f6f805cc..97cecbe78b 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -220,14 +220,6 @@ exit_inferior (inferior *inf)
exit_inferior_1 (inf, 0);
}
-void
-exit_inferior_silent (int pid)
-{
- struct inferior *inf = find_inferior_pid (pid);
-
- exit_inferior_1 (inf, 1);
-}
-
void
exit_inferior_silent (inferior *inf)
{
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 00/23] Multi-target support
@ 2019-09-06 23:28 Pedro Alves
2019-09-06 23:28 ` [PATCH 11/23] tfile_target::close: trace_fd can't be -1 Pedro Alves
` (25 more replies)
0 siblings, 26 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
This commit adds multi-target support to GDB. What this means is that
with this commit, GDB can now be connected to different targets at the
same time. E.g., you can debug a live native process and a core dump
at the same time, connect to multiple gdbservers, etc.
Patches 1 to 16 are preparatory patches.
Patch 17 is the actual multi-target patch. This is the largest patch
in the series. It does a number of things at the same time, but
they're all intertwined, so I gave up on splitting it further.
Patch 18 adds tests. Split out because patch 17 is already too big as
is.
Patch 21 does some user-visible changes, including a new command to
list open target connections. This is just the bare minimum I could
think of that is necessary for multi-target work. I'm sure we'll find
other tweaks to other commands necessary.
Documentation is in patch 23.
This surely breaks the build on non-Linux ports as is. I have not
tried to adjust the host-specific nat files to function API changes,
but I don't envision any serious trouble. The fixes they'll need will
be quite mechanical, mostly usually to pass
'current_inferior()->process_target ()' to functions that gained a new
'process_stratum_target *' parameter, similar to the changes to tdep
files in the multi-target patch, need for which was caught with
--enable-targets=all.
I've pushed this to users/palves/multi-target-v1 on sourceware for
review and testing convenience.
Pedro Alves (23):
Preserve selected thread in all-stop w/ background execution
Don't rely on inferior_ptid in record_full_wait
Make "show remote exec-file" inferior-aware
exceptions.c:print_flush: Remove obsolete check
Make target_ops::has_execution take an 'inferior *' instead of a
ptid_t
Don't check target is running in remote_target::mourn_inferior
Delete unnecessary code from kill_command
Introduce switch_to_inferior_no_thread
switch inferior/thread before calling target methods
Some get_last_target_status tweaks
tfile_target::close: trace_fd can't be -1
Use all_non_exited_inferiors in infrun.c
Delete exit_inferior_silent(int pid)
Tweak handling of remote errors in response to resumption packet
Fix reconnecting to a gdbserver already debugging multiple processes,
I
Fix reconnecting to a gdbserver already debugging multiple processes,
II
Multi-target support
Add multi-target tests
gdbarch-selftests.c: No longer error out if debugging something
Revert 'Remove unused struct serial::name field'
Add "info connections" command, "info inferiors" connection
number/string
Require always-non-stop for multi-target resumptions
Multi-target: NEWS and user manual
gdb/doc/gdb.texinfo | 140 +++--
gdb/doc/guile.texi | 4 +-
gdb/doc/python.texi | 6 +-
gdb/NEWS | 29 +
gdb/Makefile.in | 1 +
gdb/ada-tasks.c | 4 +-
gdb/amd64-fbsd-tdep.c | 4 +-
gdb/amd64-linux-nat.c | 2 +-
gdb/break-catch-sig.c | 3 +-
gdb/break-catch-syscall.c | 3 +-
gdb/breakpoint.c | 25 +-
gdb/bsd-uthread.c | 20 +-
gdb/btrace.c | 2 +-
gdb/corelow.c | 10 +-
gdb/ctf.c | 2 +-
gdb/event-top.c | 14 +-
gdb/exceptions.c | 6 +-
gdb/exec.c | 51 +-
gdb/exec.h | 7 +
gdb/fbsd-tdep.c | 3 +-
gdb/fork-child.c | 7 +-
gdb/gdbarch-selftests.c | 5 -
gdb/gdbserver/fork-child.c | 3 +-
gdb/gdbserver/inferiors.c | 2 +-
gdb/gdbserver/linux-low.c | 2 +-
gdb/gdbserver/remote-utils.c | 2 +-
gdb/gdbserver/target.c | 8 +-
gdb/gdbserver/target.h | 9 +-
gdb/gdbsupport/common-gdbthread.h | 5 +-
gdb/gdbthread.h | 133 ++--
gdb/i386-fbsd-tdep.c | 4 +-
gdb/inf-child.c | 2 +-
gdb/inf-ptrace.c | 6 +-
gdb/infcall.c | 3 +-
gdb/infcmd.c | 129 ++--
gdb/inferior-iter.h | 77 ++-
gdb/inferior.c | 155 +++--
gdb/inferior.h | 71 ++-
gdb/infrun.c | 683 ++++++++++++++++-----
gdb/infrun.h | 16 +-
gdb/inline-frame.c | 51 +-
gdb/inline-frame.h | 12 +-
gdb/linux-fork.c | 5 +-
gdb/linux-nat.c | 74 ++-
gdb/linux-nat.h | 1 +
gdb/linux-tdep.c | 3 +-
gdb/linux-thread-db.c | 112 ++--
gdb/mi/mi-interp.c | 10 +-
gdb/nat/fork-inferior.c | 8 +-
gdb/nat/fork-inferior.h | 5 +-
gdb/ppc-fbsd-tdep.c | 4 +-
gdb/proc-service.c | 17 +-
gdb/process-stratum-target.c | 12 +-
gdb/process-stratum-target.h | 31 +-
gdb/python/py-threadevent.c | 4 +-
gdb/ravenscar-thread.c | 16 +-
gdb/record-btrace.c | 43 +-
gdb/record-full.c | 22 +-
gdb/regcache.c | 162 +++--
gdb/regcache.h | 30 +-
gdb/remote.c | 290 +++++----
gdb/riscv-fbsd-tdep.c | 4 +-
gdb/serial.c | 4 +
gdb/serial.h | 1 +
gdb/sol2-tdep.c | 2 +-
gdb/solib-spu.c | 3 +-
gdb/solib-svr4.c | 3 +-
gdb/spu-multiarch.c | 6 +-
gdb/spu-tdep.c | 8 +-
gdb/target-connection.c | 153 +++++
gdb/target-connection.h | 40 ++
gdb/target-delegates.c | 27 +
gdb/target.c | 166 +++--
gdb/target.h | 23 +-
gdb/testsuite/gdb.base/fork-running-state.exp | 17 +-
.../gdb.base/kill-detach-inferiors-cmd.exp | 4 +-
gdb/testsuite/gdb.base/quit-live.exp | 2 +-
gdb/testsuite/gdb.base/remote-exec-file.exp | 46 ++
gdb/testsuite/gdb.guile/scm-progspace.exp | 2 +-
gdb/testsuite/gdb.linespec/linespec.exp | 2 +-
gdb/testsuite/gdb.mi/new-ui-mi-sync.exp | 2 +-
.../gdb.mi/user-selected-context-sync.exp | 2 +-
gdb/testsuite/gdb.multi/multi-target.c | 100 +++
gdb/testsuite/gdb.multi/multi-target.exp | 387 ++++++++++++
gdb/testsuite/gdb.multi/remove-inferiors.exp | 2 +-
gdb/testsuite/gdb.multi/watchpoint-multi.exp | 2 +-
gdb/testsuite/gdb.python/py-inferior.exp | 4 +-
.../gdb.server/extended-remote-restart.exp | 22 +-
gdb/testsuite/gdb.threads/async.c | 70 +++
gdb/testsuite/gdb.threads/async.exp | 98 +++
gdb/testsuite/gdb.threads/fork-plus-threads.exp | 2 +-
.../forking-threads-plus-breakpoint.exp | 2 +-
gdb/testsuite/gdb.trace/report.exp | 2 +-
gdb/testsuite/lib/gdbserver-support.exp | 4 +
gdb/thread-iter.c | 14 +-
gdb/thread-iter.h | 25 +-
gdb/thread.c | 230 ++++---
gdb/top.c | 17 +-
gdb/tracefile-tfile.c | 5 +-
gdb/tracefile.h | 2 +-
100 files changed, 3098 insertions(+), 977 deletions(-)
create mode 100644 gdb/target-connection.c
create mode 100644 gdb/target-connection.h
create mode 100644 gdb/testsuite/gdb.base/remote-exec-file.exp
create mode 100644 gdb/testsuite/gdb.multi/multi-target.c
create mode 100644 gdb/testsuite/gdb.multi/multi-target.exp
create mode 100644 gdb/testsuite/gdb.threads/async.c
create mode 100644 gdb/testsuite/gdb.threads/async.exp
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 06/23] Don't check target is running in remote_target::mourn_inferior
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (7 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 08/23] Introduce switch_to_inferior_no_thread Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 20/23] Revert 'Remove unused struct serial::name field' Pedro Alves
` (16 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
I believe the tail end of remote_target::mourn_inferior is broken, and
it's been broken for too long to even bother trying to fix. Most
probably nobody needs it. If the code is reached and we find the
target is running, we'd need to resync the thread list, at least,
since generic_mourn_inferior got rid of all the threads in the
inferior, otherwise, we'd hit an assertion on the next call to
inferior_thread(), for example. A "correct" fix would probably
involve restarting the whole remote_target::start_remote requence,
exactly as if we had completely disconnected and reconnected from
scratch.
Note that regular stub debugging usually uses plain target remote, but
this code is only reachable in target extended-mode:
- The !remote_multi_process_p check means that it's only reacheable if
the stub does not support multi-process. I.e., there can only ever
be one live process.
- remote_target::mourn_inferior has this at the top:
/* In 'target remote' mode with one inferior, we close the connection. */
if (!rs->extended && number_of_live_inferiors () <= 1)
{
unpush_target (this);
/* remote_close takes care of doing most of the clean up. */
generic_mourn_inferior ();
return;
}
Which means that if we only had one live inferior (which for our
case, must be true), we'll have closed the connection already,
unless we're in extended-remote mode.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (remote_target::mourn_inferior): No longer check
whether the target is running.
---
gdb/remote.c | 20 --------------------
1 file changed, 20 deletions(-)
diff --git a/gdb/remote.c b/gdb/remote.c
index db6f1a0e59..bed861c65d 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9843,26 +9843,6 @@ remote_target::mourn_inferior ()
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
-
- if (!have_inferiors ())
- {
- if (!remote_multi_process_p (rs))
- {
- /* Check whether the target is running now - some remote stubs
- automatically restart after kill. */
- putpkt ("?");
- getpkt (&rs->buf, 0);
-
- if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
- {
- /* Assume that the target has been restarted. Set
- inferior_ptid so that bits of core GDB realizes
- there's something here, e.g., so that the user can
- say "kill" again. */
- inferior_ptid = magic_null_ptid;
- }
- }
- }
}
bool
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 20/23] Revert 'Remove unused struct serial::name field'
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (8 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 06/23] Don't check target is running in remote_target::mourn_inferior Pedro Alves
@ 2019-09-06 23:28 ` Pedro Alves
2019-09-06 23:47 ` Christian Biesinger via gdb-patches
2019-09-06 23:28 ` [PATCH 19/23] gdbarch-selftests.c: No longer error out if debugging something Pedro Alves
` (15 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:28 UTC (permalink / raw)
To: gdb-patches
This commit reverts:
commit 5f5219fc34f7557296272230123a3837960a6f09
Author: Pedro Alves <palves@redhat.com>
AuthorDate: Tue Apr 12 16:49:30 2016 +0100
Remove unused struct serial::name field
The following patches will add uses for the field.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
Revert:
2016-04-12 Pedro Alves <palves@redhat.com>
* serial.c (serial_open, serial_fdopen_ops, do_serial_close):
Remove references to name.
* serial.h (struct serial) <name>: Delete.
---
gdb/serial.c | 4 ++++
gdb/serial.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/gdb/serial.c b/gdb/serial.c
index a881bbc97c..0ed3d37406 100644
--- a/gdb/serial.c
+++ b/gdb/serial.c
@@ -247,6 +247,7 @@ serial_open_ops_1 (const struct serial_ops *ops, const char *open_name)
return NULL;
}
+ scb->name = open_name != NULL ? xstrdup (open_name) : NULL;
scb->next = scb_base;
scb_base = scb;
@@ -291,6 +292,7 @@ serial_fdopen_ops (const int fd, const struct serial_ops *ops)
scb = new_serial (ops);
+ scb->name = NULL;
scb->next = scb_base;
scb_base = scb;
@@ -330,6 +332,8 @@ do_serial_close (struct serial *scb, int really_close)
if (really_close)
scb->ops->close (scb);
+ xfree (scb->name);
+
/* For serial_is_open. */
scb->bufp = NULL;
diff --git a/gdb/serial.h b/gdb/serial.h
index b75b3666e7..d58ab660e9 100644
--- a/gdb/serial.h
+++ b/gdb/serial.h
@@ -240,6 +240,7 @@ struct serial
buffer. -ve for sticky errors. */
unsigned char *bufp; /* Current byte */
unsigned char buf[BUFSIZ]; /* Da buffer itself */
+ char *name; /* The name of the device or host */
struct serial *next; /* Pointer to the next `struct serial *' */
int debug_p; /* Trace this serial devices operation. */
int async_state; /* Async internal state. */
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 23/23] Multi-target: NEWS and user manual
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (14 preceding siblings ...)
2019-09-06 23:28 ` [PATCH 16/23] Fix reconnecting to a gdbserver already debugging multiple processes, II Pedro Alves
@ 2019-09-06 23:33 ` Pedro Alves
2019-09-07 6:33 ` Eli Zaretskii
2019-09-06 23:34 ` [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check Pedro Alves
` (9 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:33 UTC (permalink / raw)
To: gdb-patches
This commit documents the new multi-target features in both NEWS and
user manual.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* NEWS: Mention multi-target debugging, "info connections", and
"add-inferior -no-connection".
gdb/doc/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.texinfo (Starting): Say "current inferior not connected"
instead of "GDB not connected".
(Inferiors and Programs): Rename node to ...
(Inferiors Connections and Programs): ... this. Update all
references. Talk about multiple target connections. Update "info
inferiors" info to mention the connections column. Describe "info
connections". Document "add-inferior -no-connection".
* guile.texi, python.texi: Update cross references.
---
gdb/doc/gdb.texinfo | 140 +++++++++++++++++++++++++++++++++++++---------------
gdb/doc/guile.texi | 4 +-
gdb/doc/python.texi | 6 +--
gdb/NEWS | 29 +++++++++++
4 files changed, 135 insertions(+), 44 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 53b7de91e4..37537a1dfe 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2237,8 +2237,7 @@ kill a child process.
* Input/Output:: Your program's input and output
* Attach:: Debugging an already-running process
* Kill Process:: Killing the child process
-
-* Inferiors and Programs:: Debugging multiple inferiors and programs
+* Inferiors Connections and Programs:: Debugging multiple inferiors connections and programs
* Threads:: Debugging programs with multiple threads
* Forks:: Debugging forks
* Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@@ -2493,27 +2492,28 @@ $@file{.zshenv} for the Z shell, or the file specified in the
@itemx set auto-connect-native-target off
@itemx show auto-connect-native-target
-By default, if not connected to any target yet (e.g., with
-@code{target remote}), the @code{run} command starts your program as a
-native process under @value{GDBN}, on your local machine. If you're
-sure you don't want to debug programs on your local machine, you can
-tell @value{GDBN} to not connect to the native target automatically
-with the @code{set auto-connect-native-target off} command.
+By default, if the current inferior is not connected to any target yet
+(e.g., with @code{target remote}), the @code{run} command starts your
+program as a native process under @value{GDBN}, on your local machine.
+If you're sure you don't want to debug programs on your local machine,
+you can tell @value{GDBN} to not connect to the native target
+automatically with the @code{set auto-connect-native-target off}
+command.
-If @code{on}, which is the default, and if @value{GDBN} is not
+If @code{on}, which is the default, and if the current inferior is not
connected to a target already, the @code{run} command automaticaly
connects to the native target, if one is available.
-If @code{off}, and if @value{GDBN} is not connected to a target
-already, the @code{run} command fails with an error:
+If @code{off}, and if the current inferior is not connected to a
+target already, the @code{run} command fails with an error:
@smallexample
(@value{GDBP}) run
Don't know how to run. Try "help target".
@end smallexample
-If @value{GDBN} is already connected to a target, @value{GDBN} always
-uses it with the @code{run} command.
+If the current inferior is already connected to a target, @value{GDBN}
+always uses it with the @code{run} command.
In any case, you can explicitly connect to the native target with the
@code{target native} command. For example,
@@ -2943,15 +2943,17 @@ next type @code{run}, @value{GDBN} notices that the file has changed, and
reads the symbol table again (while trying to preserve your current
breakpoint settings).
-@node Inferiors and Programs
-@section Debugging Multiple Inferiors and Programs
+@node Inferiors Connections and Programs
+@section Debugging Multiple Inferiors Connections and Programs
@value{GDBN} lets you run and debug multiple programs in a single
session. In addition, @value{GDBN} on some systems may let you run
several programs simultaneously (otherwise you have to exit from one
-before starting another). In the most general case, you can have
-multiple threads of execution in each of multiple processes, launched
-from multiple executables.
+before starting another). On some systems @value{GDBN} may even let
+you debug several programs simultaneously on different remote systems.
+In the most general case, you can have multiple threads of execution
+in each of multiple processes, launched from multiple executables,
+running on different machines.
@cindex inferior
@value{GDBN} represents the state of each program execution with an
@@ -2985,6 +2987,11 @@ the inferior number assigned by @value{GDBN}
@item
the target system's inferior identifier
+@item
+the target connection the inferior is bound to. This includes the
+unique connection number assigned by @value{GDBN}, and the name of the
+protocol used by the connection.
+
@item
the name of the executable the inferior is running.
@@ -3000,11 +3007,57 @@ For example,
@smallexample
(@value{GDBP}) info inferiors
- Num Description Executable
- 2 process 2307 hello
-* 1 process 3401 goodbye
+ Num Description Connection Executable
+* 1 process 3401 1 (native) goodbye
+ 2 process 2307 2 (extended-remote host:10000) hello
+@end smallexample
+
+To find out what open target connections exist at any moment, use
+@w{@code{info connections}}:
+
+@table @code
+@kindex info connections [ @var{id}@dots{} ]
+@item info connections
+Print a list of all open target connections currently being managed by
+@value{GDBN}. By default all connections are printed, but the
+argument @var{id}@dots{} -- a space separated list of connections
+numbers -- can be used to limit the display to just the requested
+connections.
+
+@value{GDBN} displays for each connection (in this order):
+
+@enumerate
+@item
+the connection number assigned by @value{GDBN}
+
+@item
+the connection name, derived from the protocol used by the connection.
+
+@item
+a textual description of the protocol used by the connection.
+
+@end enumerate
+
+@noindent
+An asterisk @samp{*} preceding the @value{GDBN} connection number
+indicates the connection of the current inferior.
+
+For example,
+@end table
+@c end table here to get a little more width for example
+
+@smallexample
+(@value{GDBP}) info connections
+ Num Name Description
+* 1 extended-remote host:10000 Extended remote serial target in gdb-specific protocol
+ 2 native Native process
+ 3 core Local core dump file
@end smallexample
+There's no explicit way to switch focus between connections. Instead,
+you switch focus between inferiors, which implicitly switches the
+focus to the selected inferior's connection.
+
To switch focus between inferiors, use the @code{inferior} command:
@table @code
@@ -3031,13 +3084,22 @@ remove inferiors from the debugging session use the
@table @code
@kindex add-inferior
-@item add-inferior [ -copies @var{n} ] [ -exec @var{executable} ]
+@item add-inferior [ -copies @var{n} ] [ -exec @var{executable} ] [-no-connection ]
Adds @var{n} inferiors to be run using @var{executable} as the
executable; @var{n} defaults to 1. If no executable is specified,
the inferiors begins empty, with no program. You can still assign or
change the program assigned to the inferior at any time by using the
@code{file} command with the executable name as its argument.
+By default, the new inferior begins connected to the same target
+connection as the current inferior. For example, if the current
+inferior was connected to @code{gdbserver} with @code{target remote},
+then the new inferior will be connected to the same @code{gdbserver}
+instance. The @samp{-no-connection} option starts the new inferior
+with no connection yet. You can then for example use the @code{target
+remote} command to connect to some other @code{gdbserver} instance,
+use @code{run} to spawn a local program, etc.
+
@kindex clone-inferior
@item clone-inferior [ -copies @var{n} ] [ @var{infno} ]
Adds @var{n} inferiors ready to execute the same program as inferior
@@ -3047,15 +3109,15 @@ want to run another instance of the inferior you are debugging.
@smallexample
(@value{GDBP}) info inferiors
- Num Description Executable
-* 1 process 29964 helloworld
+ Num Description Connection Executable
+* 1 process 29964 1 (native) helloworld
(@value{GDBP}) clone-inferior
Added inferior 2.
1 inferiors added.
(@value{GDBP}) info inferiors
- Num Description Executable
- 2 <null> helloworld
-* 1 process 29964 helloworld
+ Num Description Connection Executable
+* 1 process 29964 1 (native) helloworld
+ 2 <null> 1 (native) helloworld
@end smallexample
You can now simply switch focus to inferior 2 and run it.
@@ -3708,14 +3770,14 @@ If you choose to set @samp{detach-on-fork} mode off, then @value{GDBN}
will retain control of all forked processes (including nested forks).
You can list the forked processes under the control of @value{GDBN} by
using the @w{@code{info inferiors}} command, and switch from one fork
-to another by using the @code{inferior} command (@pxref{Inferiors and
-Programs, ,Debugging Multiple Inferiors and Programs}).
+to another by using the @code{inferior} command (@pxref{Inferiors Connections and
+Programs, ,Debugging Multiple Inferiors Connections and Programs}).
To quit debugging one of the forked processes, you can either detach
from it by using the @w{@code{detach inferiors}} command (allowing it
to run independently), or kill it using the @w{@code{kill inferiors}}
-command. @xref{Inferiors and Programs, ,Debugging Multiple Inferiors
-and Programs}.
+command. @xref{Inferiors Connections and Programs, ,Debugging
+Multiple Inferiors Connections and Programs}.
If you ask to debug a child process and a @code{vfork} is followed by an
@code{exec}, @value{GDBN} executes the new target up to the first
@@ -11769,8 +11831,8 @@ gdbserver that supports the @code{qGetTIBAddr} request.
This variable contains the address of the thread information block.
@item $_inferior
-The number of the current inferior. @xref{Inferiors and
-Programs, ,Debugging Multiple Inferiors and Programs}.
+The number of the current inferior. @xref{Inferiors Connections and
+Programs, ,Debugging Multiple Inferiors Connections and Programs}.
@item $_thread
The thread number of the current thread. @xref{thread numbers}.
@@ -12877,7 +12939,7 @@ character.
@value{GDBN} caches data exchanged between the debugger and a target.
Each cache is associated with the address space of the inferior.
-@xref{Inferiors and Programs}, about inferior and address space.
+@xref{Inferiors Connections and Programs}, about inferior and address space.
Such caching generally improves performance in remote debugging
(@pxref{Remote Debugging}), because it reduces the overhead of the
remote protocol by bundling memory reads and writes into large chunks.
@@ -28219,7 +28281,7 @@ groups can be obtained using @samp{-list-thread-groups --available}.
In general, the content of a thread group may be only retrieved only
after attaching to that thread group.
-Thread groups are related to inferiors (@pxref{Inferiors and
+Thread groups are related to inferiors (@pxref{Inferiors Connections and
Programs}). Each inferior corresponds to a thread group of a special
type @samp{process}, and some additional operations are permitted on
such thread groups.
@@ -35119,7 +35181,7 @@ popup menu, but is needless clutter on the command line, and
-add-inferior
@end smallexample
-Creates a new inferior (@pxref{Inferiors and Programs}). The created
+Creates a new inferior (@pxref{Inferiors Connections and Programs}). The created
inferior is not associated with any executable. Such association may
be established with the @samp{-file-exec-and-symbols} command
(@pxref{GDB/MI File Commands}). The command response has a single
@@ -45398,11 +45460,11 @@ command, otherwise you may get an error that looks something like
@command{gdbserver} can also debug multiple inferiors at once,
described in
@ifset man
-the @value{GDBN} manual in node @code{Inferiors and Programs}
--- shell command @code{info -f gdb -n 'Inferiors and Programs'}.
+the @value{GDBN} manual in node @code{Inferiors Connections and Programs}
+-- shell command @code{info -f gdb -n 'Inferiors Connections and Programs'}.
@end ifset
@ifclear man
-@ref{Inferiors and Programs}.
+@ref{Inferiors Connections and Programs}.
@end ifclear
In such case use the @code{extended-remote} @value{GDBN} command variant:
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index f4c29dc3df..aa21e79a48 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -2155,7 +2155,7 @@ A program space, or @dfn{progspace}, represents a symbolic view
of an address space.
It consists of all of the objfiles of the program.
@xref{Objfiles In Guile}.
-@xref{Inferiors and Programs, program spaces}, for more details
+@xref{Inferiors Connections and Programs, program spaces}, for more details
about program spaces.
Each progspace is represented by an instance of the @code{<gdb:progspace>}
@@ -2178,7 +2178,7 @@ if the program it refers to is not loaded in @value{GDBN} any longer.
@deffn {Scheme Procedure} current-progspace
This function returns the program space of the currently selected inferior.
There is always a current progspace, this never returns @code{#f}.
-@xref{Inferiors and Programs}.
+@xref{Inferiors Connections and Programs}.
@end deffn
@deffn {Scheme Procedure} progspaces
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 832283dede..2d39d9eb64 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -2928,7 +2928,7 @@ itself.
@findex gdb.Inferior
Programs which are being run under @value{GDBN} are called inferiors
-(@pxref{Inferiors and Programs}). Python scripts can access
+(@pxref{Inferiors Connections and Programs}). Python scripts can access
information about and manipulate inferiors controlled by @value{GDBN}
via objects of the @code{gdb.Inferior} class.
@@ -4158,7 +4158,7 @@ A program space, or @dfn{progspace}, represents a symbolic view
of an address space.
It consists of all of the objfiles of the program.
@xref{Objfiles In Python}.
-@xref{Inferiors and Programs, program spaces}, for more details
+@xref{Inferiors Connections and Programs, program spaces}, for more details
about program spaces.
The following progspace-related functions are available in the
@@ -4167,7 +4167,7 @@ The following progspace-related functions are available in the
@findex gdb.current_progspace
@defun gdb.current_progspace ()
This function returns the program space of the currently selected inferior.
-@xref{Inferiors and Programs}. This is identical to
+@xref{Inferiors Connections and Programs}. This is identical to
@code{gdb.selected_inferior().progspace} (@pxref{Inferiors In Python}) and is
included for historical compatibility.
@end defun
diff --git a/gdb/NEWS b/gdb/NEWS
index f382e887c0..20aad73aa5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -29,6 +29,21 @@
* The RX port now supports XML target descriptions.
+* Multi-target debugging support
+
+ GDB now supports debugging multiple target connections
+ simultaneously. For example, you can now have each inferior
+ connected to different remote servers running in different machines,
+ or have one inferior debugging a local native process, an inferior
+ debugging a core dump, etc.
+
+ This support is experimental and comes with some limitations -- you
+ can only resume multiple targets simultaneously if all targets
+ support non-stop mode, and all remote stubs or servers must support
+ the same set of remote protocol features exactly. See also "info
+ connections" and "add-inferior -no-connection" below, and "maint set
+ target-non-stop" in the user manual.
+
* Python API
** The gdb.Value type has a new method 'format_string' which returns a
@@ -130,6 +145,9 @@ show print frame-info
'frame', 'stepi'. The python frame filtering also respect this setting.
The 'backtrace' '-frame-info' option can override this global setting.
+info connections
+ Lists the target connections currently in use.
+
* Changed commands
help
@@ -174,6 +192,17 @@ show print raw-frame-arguments
old commands are now deprecated and may be removed in a future
release.
+add-inferior [-no-connection]
+ The add-inferior command now supports a "-no-connection" flag that
+ makes the new inferior start with no target connection associated.
+ By default, the new inferior inherits the target connection of the
+ current inferior. See also "info connections".
+
+info inferior
+ This command's output now includes a new "Connection" column
+ indicating which target connection an inferior is bound to. See
+ "info connections" above.
+
maint test-options require-delimiter
maint test-options unknown-is-error
maint test-options unknown-is-operand
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (15 preceding siblings ...)
2019-09-06 23:33 ` [PATCH 23/23] Multi-target: NEWS and user manual Pedro Alves
@ 2019-09-06 23:34 ` Pedro Alves
2019-09-09 18:07 ` Tom Tromey
2019-09-06 23:35 ` [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t Pedro Alves
` (8 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:34 UTC (permalink / raw)
To: gdb-patches
Commit 20f0d60db4fb ("Avoid crash when calling warning too early"),
added a "current_top_target () != NULL" check to
target_supports_terminal_ours, so this check in exceptions.c is now
obsolete.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* exceptions.c (print_flush): Remove current_top_target() check.
---
gdb/exceptions.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/gdb/exceptions.c b/gdb/exceptions.c
index a405947257..3dccda78e2 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -39,11 +39,7 @@ print_flush (void)
deprecated_error_begin_hook ();
gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
- /* While normally there's always something pushed on the target
- stack, the NULL check is needed here because we can get here very
- early during startup, before the target stack is first
- initialized. */
- if (current_top_target () != NULL && target_supports_terminal_ours ())
+ if (target_supports_terminal_ours ())
{
term_state.emplace ();
target_terminal::ours_for_output ();
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (16 preceding siblings ...)
2019-09-06 23:34 ` [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check Pedro Alves
@ 2019-09-06 23:35 ` Pedro Alves
2019-09-09 18:12 ` Tom Tromey
2019-09-06 23:36 ` [PATCH 07/23] Delete unnecessary code from kill_command Pedro Alves
` (7 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:35 UTC (permalink / raw)
To: gdb-patches
With the multi-target work, each inferior will have its own target
stack, so to call a target method, we'll need to make sure that the
inferior in question is the current one, otherwise target->beneath()
calls will find the target beneath in the wrong inferior.
In some places, it's much more convenient to be able to check whether
an inferior has execution without having to switch to it in order to
call target_has_execution on the right inferior/target stack, to avoid
side effects with switching inferior/thread/program space.
The current target_ops::has_execution method takes a ptid_t as
parameter, which, in a multi-target world, isn't sufficient to
identify the target. This patch prepares to address that, by changing
the parameter to an inferior pointer instead. From the inferior,
we'll be able to query its target stack to tell which target is
beneath.
Also adds a new inferior::has_execution() method to make callers a bit
more natural to read.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* corelow.c (core_target::has_execution): Change parameter type to
inferior pointer.
* inferior.c (number_of_live_inferiors): Use
inferior::has_execution instead of target_has_execution_1.
* inferior.h (inferior::has_execution): New.
* linux-thread-db.c (thread_db_target::update_thread_list): Use
inferior::has_execution instead of target_has_execution_1.
* process-stratum-target.c
(process_stratum_target::has_execution): Change parameter type to
inferior pointer. Check the inferior's PID instead of
inferior_ptid.
* process-stratum-target.h
(process_stratum_target::has_execution): Change parameter type to
inferior pointer.
* record-full.c (record_full_core_target::has_execution): Change
parameter type to inferior pointer.
* target.c (target_has_execution_1): Change parameter type to
inferior pointer.
(target_has_execution_current): Adjust.
* target.h (target_ops::has_execution): Change parameter type to
inferior pointer.
(target_has_execution_1): Change parameter type to inferior
pointer. Change return type to bool.
* tracefile.h (tracefile_target::has_execution): Change parameter
type to inferior pointer.
---
gdb/corelow.c | 2 +-
gdb/inferior.c | 2 +-
gdb/inferior.h | 3 +++
gdb/linux-thread-db.c | 2 +-
gdb/process-stratum-target.c | 8 ++++----
gdb/process-stratum-target.h | 2 +-
gdb/record-full.c | 4 ++--
gdb/target.c | 12 ++++++------
gdb/target.h | 7 ++++---
gdb/tracefile.h | 2 +-
10 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 5e9634e9d7..0fba93f802 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -92,7 +92,7 @@ public:
bool has_memory () override;
bool has_stack () override;
bool has_registers () override;
- bool has_execution (ptid_t) override { return false; }
+ bool has_execution (inferior *inf) override { return false; }
bool info_proc (const char *, enum info_proc_what) override;
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 2d58a11ba8..994938d564 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -352,7 +352,7 @@ number_of_live_inferiors (void)
int num_inf = 0;
for (inferior *inf : all_non_exited_inferiors ())
- if (target_has_execution_1 (ptid_t (inf->pid)))
+ if (inf->has_execution ())
for (thread_info *tp ATTRIBUTE_UNUSED : inf->non_exited_threads ())
{
/* Found a live thread in this inferior, go to the next
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 9cfb03cdbb..ce9bcbf122 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -360,6 +360,9 @@ public:
/* Returns true if we can delete this inferior. */
bool deletable () const { return refcount () == 0; }
+ bool has_execution ()
+ { return target_has_execution_1 (this); }
+
/* Pointer to next inferior in singly-linked list of inferiors. */
struct inferior *next = NULL;
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 1d32e9195c..b2c9d6d77c 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1619,7 +1619,7 @@ thread_db_target::update_thread_list ()
stop. That uses thread_db entry points that do not walk
libpthread's thread list, so should be safe, as well as more
efficient. */
- if (target_has_execution_1 (thread->ptid))
+ if (thread->inf->has_execution ())
continue;
thread_db_find_new_threads_1 (thread);
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 2c4b812f86..1517088f0f 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -77,9 +77,9 @@ process_stratum_target::has_registers ()
}
bool
-process_stratum_target::has_execution (ptid_t the_ptid)
+process_stratum_target::has_execution (inferior *inf)
{
- /* If there's no thread selected, then we can't make it run through
- hoops. */
- return the_ptid != null_ptid;
+ /* If there's a process running already, we can't make it run
+ through hoops. */
+ return inf->pid != 0;
}
diff --git a/gdb/process-stratum-target.h b/gdb/process-stratum-target.h
index 2e620f82e8..a14e4f3a72 100644
--- a/gdb/process-stratum-target.h
+++ b/gdb/process-stratum-target.h
@@ -50,7 +50,7 @@ public:
bool has_memory () override;
bool has_stack () override;
bool has_registers () override;
- bool has_execution (ptid_t the_ptid) override;
+ bool has_execution (inferior *inf) override;
};
#endif /* !defined (PROCESS_STRATUM_TARGET_H) */
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 8ed973ad12..1b03301da4 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -319,7 +319,7 @@ public:
struct bp_target_info *,
enum remove_bp_reason) override;
- bool has_execution (ptid_t) override;
+ bool has_execution (inferior *inf) override;
};
static record_full_target record_full_ops;
@@ -2244,7 +2244,7 @@ record_full_core_target::remove_breakpoint (struct gdbarch *gdbarch,
/* "has_execution" method for prec over corefile. */
bool
-record_full_core_target::has_execution (ptid_t the_ptid)
+record_full_core_target::has_execution (inferior *inf)
{
return true;
}
diff --git a/gdb/target.c b/gdb/target.c
index a19a9bce13..68f874bf4b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -223,20 +223,20 @@ target_has_registers_1 (void)
return 0;
}
-int
-target_has_execution_1 (ptid_t the_ptid)
+bool
+target_has_execution_1 (inferior *inf)
{
for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
- if (t->has_execution (the_ptid))
- return 1;
+ if (t->has_execution (inf))
+ return true;
- return 0;
+ return false;
}
int
target_has_execution_current (void)
{
- return target_has_execution_1 (inferior_ptid);
+ return target_has_execution_1 (current_inferior ());
}
/* This is used to implement the various target commands. */
diff --git a/gdb/target.h b/gdb/target.h
index 4e2e75cb80..9a94227953 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -682,7 +682,7 @@ struct target_ops
virtual bool has_memory () { return false; }
virtual bool has_stack () { return false; }
virtual bool has_registers () { return false; }
- virtual bool has_execution (ptid_t) { return false; }
+ virtual bool has_execution (inferior *inf) { return false; }
/* Control thread execution. */
virtual thread_control_capabilities get_thread_control_capabilities ()
@@ -1787,9 +1787,10 @@ extern int target_has_registers_1 (void);
case this will become true after to_create_inferior or
to_attach. */
-extern int target_has_execution_1 (ptid_t);
+extern bool target_has_execution_1 (inferior *inf);
-/* Like target_has_execution_1, but always passes inferior_ptid. */
+/* Like target_has_execution_1, but always passes
+ current_inferior(). */
extern int target_has_execution_current (void);
diff --git a/gdb/tracefile.h b/gdb/tracefile.h
index 8f9dc0e06d..9c7fdea729 100644
--- a/gdb/tracefile.h
+++ b/gdb/tracefile.h
@@ -127,7 +127,7 @@ public:
bool has_memory () override;
bool has_stack () override;
bool has_registers () override;
- bool has_execution (ptid_t) override { return false; }
+ bool has_execution (inferior *inf) override { return false; }
bool thread_alive (ptid_t ptid) override;
};
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 14/23] Tweak handling of remote errors in response to resumption packet
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (19 preceding siblings ...)
2019-09-06 23:36 ` [PATCH 12/23] Use all_non_exited_inferiors in infrun.c Pedro Alves
@ 2019-09-06 23:36 ` Pedro Alves
2019-10-09 13:35 ` Aktemur, Tankut Baris
2019-09-06 23:37 ` [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string Pedro Alves
` (4 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:36 UTC (permalink / raw)
To: gdb-patches
With current master, on a Fedora 27 machine with a kernel with buggy
watchpoint support, I see:
(gdb) PASS: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: hardware breakpoints work
continue
Continuing.
warning: Remote failure reply: E01
Remote communication error. Target disconnected.: Connection reset by peer.
(gdb) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: watchpoints work
continue
The program is not being run.
(gdb) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: breakpoint after the first fork (the program is no longer running)
The FAILs themselves aren't what's interesting here. What is
interesting is that with the main multi-target patch applied, I was getting this:
(gdb) PASS: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: hardware breakpoints work
continue
Continuing.
warning: Remote failure reply: E01
/home/pedro/brno/pedro/gdb/binutils-gdb-2/build/../src/gdb/inferior.c:285: internal-error: inferior* find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: watchpoints work (GDB internal error)
The problem is that in remote_target::wait_as, we're hitting this:
switch (buf[0])
{
case 'E': /* Error of some sort. */
/* We're out of sync with the target now. Did it continue or
not? Not is more likely, so report a stop. */
rs->waiting_for_stop_reply = 0;
warning (_("Remote failure reply: %s"), buf);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = GDB_SIGNAL_0;
break;
which leaves event_ptid as null_ptid. At the end of the function, we then reach:
else if (status->kind != TARGET_WAITKIND_EXITED
&& status->kind != TARGET_WAITKIND_SIGNALLED)
{
if (event_ptid != null_ptid)
record_currthread (rs, event_ptid);
else
event_ptid = inferior_ptid; <<<<< here
}
and the trouble is that with the multi-target patch, we'll get here
with inferior_ptid as null_ptid too. That is done exactly to find
these implicit assumptions that inferior_ptid is a good choice for
default thread, which isn't generaly true.
I first thought of fixing this in the "case 'E'" path, but, given that
this "event_ptid = inferior_ptid" path is also taken when the remote
target does not support threads at all, no thread-related packets or
extensions, it's better to fix it in latter path, to handle all
scenarios that miss reporting a thread.
That's what this patch does.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (first_remote_resumed_thread): New.
(remote_target::wait_as): Use it as default event_ptid instead of
inferior_ptid.
---
gdb/remote.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/gdb/remote.c b/gdb/remote.c
index bed861c65d..eacaf11976 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7703,6 +7703,17 @@ remote_target::wait_ns (ptid_t ptid, struct target_waitstatus *status, int optio
}
}
+/* Return the first resumed thread. */
+
+static ptid_t
+first_remote_resumed_thread ()
+{
+ for (thread_info *tp : all_non_exited_threads (minus_one_ptid))
+ if (tp->resumed)
+ return tp->ptid;
+ return null_ptid;
+}
+
/* Wait until the remote machine stops, then return, storing status in
STATUS just as `wait' would. */
@@ -7839,7 +7850,7 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
if (event_ptid != null_ptid)
record_currthread (rs, event_ptid);
else
- event_ptid = inferior_ptid;
+ event_ptid = first_remote_resumed_thread ();
}
else
/* A process exit. Invalidate our notion of current thread. */
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 12/23] Use all_non_exited_inferiors in infrun.c
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (18 preceding siblings ...)
2019-09-06 23:36 ` [PATCH 07/23] Delete unnecessary code from kill_command Pedro Alves
@ 2019-09-06 23:36 ` Pedro Alves
2019-09-06 23:36 ` [PATCH 14/23] Tweak handling of remote errors in response to resumption packet Pedro Alves
` (5 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:36 UTC (permalink / raw)
To: gdb-patches
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* infrun.c (handle_no_resumed): Use all_non_exited_inferiors.
---
gdb/infrun.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index f25cbcd5e8..d27b47c6a8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4592,11 +4592,8 @@ handle_no_resumed (struct execution_control_state *ecs)
process exited meanwhile (thus updating the thread list results
in an empty thread list). In this case we know we'll be getting
a process exit event shortly. */
- for (inferior *inf : all_inferiors ())
+ for (inferior *inf : all_non_exited_inferiors ())
{
- if (inf->pid == 0)
- continue;
-
thread_info *thread = any_live_thread_of_inferior (inf);
if (thread == NULL)
{
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 07/23] Delete unnecessary code from kill_command
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (17 preceding siblings ...)
2019-09-06 23:35 ` [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t Pedro Alves
@ 2019-09-06 23:36 ` Pedro Alves
2019-10-01 10:19 ` Aktemur, Tankut Baris
2019-09-06 23:36 ` [PATCH 12/23] Use all_non_exited_inferiors in infrun.c Pedro Alves
` (6 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:36 UTC (permalink / raw)
To: gdb-patches
I believe this comment:
/* Killing off the inferior can leave us with a core file. If
so, print the state we are left in. */
Referred to the fact that a decade ago, by design, GDB would let you
type "run" when debugging a core dump, keeping the core open. That
"run" would push a process_stratum target on the target stack for the
live process, and, the core would remain open -- we used to have a
core_stratum. When the live process was killed/detached or exited,
GDB would go back to debugging the core, since the core_stratum target
was now at the top of the stack. That design had a number of
problems, see here for example:
https://sourceware.org/ml/gdb-patches/2008-08/msg00290.html
In 2010, core_stratum was finaly eliminated and cores now have
process_stratum too, with commit c0edd9edadfe ("Make core files the
process_stratum."). Pushing a live process on the stack while you're
debugging a core discards the core completely.
I also thought that this might be in use with checkpoints, but it does
not -- "kill" when you have multiple checkpoints kills all the
checkpoints.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* infcmd.c (kill_command): Remove dead code.
---
gdb/infcmd.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d7a7e6f933..a12dba23aa 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2503,20 +2503,6 @@ kill_command (const char *arg, int from_tty)
printf_unfiltered (_("[Inferior %d (%s) killed]\n"),
infnum, pid_str.c_str ());
- /* If we still have other inferiors to debug, then don't mess with
- with their threads. */
- if (!have_inferiors ())
- {
- init_thread_list (); /* Destroy thread info. */
-
- /* Killing off the inferior can leave us with a core file. If
- so, print the state we are left in. */
- if (target_has_stack)
- {
- printf_filtered (_("In %s,\n"), target_longname);
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
- }
- }
bfd_cache_close_all ();
}
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 22/23] Require always-non-stop for multi-target resumptions
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (21 preceding siblings ...)
2019-09-06 23:37 ` [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string Pedro Alves
@ 2019-09-06 23:37 ` Pedro Alves
2019-09-07 11:19 ` [PATCH 00/23] Multi-target support Philippe Waroquiers
` (2 subsequent siblings)
25 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:37 UTC (permalink / raw)
To: gdb-patches
Currently, we can only support resuming multiple targets at the same
time if all targets are in non-stop mode (or user-visible all-stop
mode with target backend in non-stop mode).
This patch makes GDB error out if the user tries to resume more than
one target at the same time and one of the resumed targets isn't in
non-stop mode:
(gdb) info inferiors
Num Description Connection Executable
1 process 15303 1 (native) a.out
* 2 process 15286 2 (extended-remote :9999) a.out
(gdb) set schedule-multiple on
(gdb) c
Continuing.
Connection 2 (extended-remote :9999) does not support multi-target resumption.
This is here later in the series instead of in the main multi-target
patch because it depends the previous patch, which added
process_stratum_target::connection_string().
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* infrun.c: Include "target-connection.h".
(check_multi_target_resumption): New.
(proceed): Call it.
* target-connection.c (make_target_connection_string): Make
static.
* target-connection.h (make_target_connection_string): Declare.
---
gdb/infrun.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/target-connection.c | 7 ++-----
gdb/target-connection.h | 8 ++++++++
3 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 33088a11e7..dc84e002f6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -30,6 +30,7 @@
#include "gdbcmd.h"
#include "cli/cli-script.h"
#include "target.h"
+#include "target-connection.h"
#include "gdbthread.h"
#include "annotate.h"
#include "symfile.h"
@@ -2876,6 +2877,56 @@ commit_resume_all_targets ()
}
}
+/* Check that all the targets we're about to resume are in non-stop
+ mode, since that's the only way we support handling events from
+ multiple targets simultaneously. */
+
+static void
+check_multi_target_resumption (process_stratum_target *resume_target)
+{
+ if (!non_stop && resume_target == nullptr)
+ {
+ scoped_restore_current_thread restore_thread;
+
+ /* This is used to track whether we're resuming more than one
+ target. */
+ process_stratum_target *first_connection = nullptr;
+
+ /* The first inferior we see with a target that does not work in
+ always-non-stop mode. */
+ inferior *first_not_non_stop = nullptr;
+
+ for (inferior *inf : all_non_exited_inferiors (resume_target))
+ {
+ switch_to_inferior_no_thread (inf);
+
+ if (!target_has_execution)
+ continue;
+
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target();
+
+ if (!target_is_non_stop_p ())
+ first_not_non_stop = inf;
+
+ if (first_connection == nullptr)
+ first_connection = proc_target;
+ else if (first_connection != proc_target
+ && first_not_non_stop != nullptr)
+ {
+ switch_to_inferior_no_thread (first_not_non_stop);
+
+ proc_target = current_inferior ()->process_target();
+
+ error (_("Connection %d (%s) does not support "
+ "multi-target resumption."),
+ proc_target->connection_number,
+ make_target_connection_string (proc_target).c_str ());
+ }
+ }
+ }
+}
+
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
@@ -2926,6 +2977,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
process_stratum_target *resume_target
= user_visible_resume_target (resume_ptid);
+ check_multi_target_resumption (resume_target);
+
if (addr == (CORE_ADDR) -1)
{
if (pc == cur_thr->suspend.stop_pc
diff --git a/gdb/target-connection.c b/gdb/target-connection.c
index f13e649977..c6e1e3f600 100644
--- a/gdb/target-connection.c
+++ b/gdb/target-connection.c
@@ -53,12 +53,9 @@ connection_list_remove (process_stratum_target *t)
t->connection_number = 0;
}
-/* Make a target connection string for T. This is usually T's
- shortname, but it includes the result of
- process_stratum_target::connection_string() too if T supports
- it. */
+/* See target-connection.h. */
-static std::string
+std::string
make_target_connection_string (process_stratum_target *t)
{
if (t->connection_string () != NULL)
diff --git a/gdb/target-connection.h b/gdb/target-connection.h
index 0e2dc128d8..0b31924b99 100644
--- a/gdb/target-connection.h
+++ b/gdb/target-connection.h
@@ -20,6 +20,8 @@
#ifndef TARGET_CONNECTION_H
#define TARGET_CONNECTION_H
+#include <string>
+
struct process_stratum_target;
/* Add a process target to the connection list, if not already
@@ -29,4 +31,10 @@ void connection_list_add (process_stratum_target *t);
/* Remove a process target from the connection list. */
void connection_list_remove (process_stratum_target *t);
+/* Make a target connection string for T. This is usually T's
+ shortname, but it includes the result of
+ process_stratum_target::connection_string() too if T supports
+ it. */
+std::string make_target_connection_string (process_stratum_target *t);
+
#endif /* TARGET_CONNECTION_H */
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (20 preceding siblings ...)
2019-09-06 23:36 ` [PATCH 14/23] Tweak handling of remote errors in response to resumption packet Pedro Alves
@ 2019-09-06 23:37 ` Pedro Alves
2019-09-09 20:18 ` Tom Tromey
2019-09-06 23:37 ` [PATCH 22/23] Require always-non-stop for multi-target resumptions Pedro Alves
` (3 subsequent siblings)
25 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-06 23:37 UTC (permalink / raw)
To: gdb-patches
This commit extends the CLI a bit for multi-target, in three ways.
#1 - New "info connections" command.
This is a new command that lists the open connections (process_stratum
targets). For example, if you're debugging two remote connections, a
couple local/native processes, and a core dump, all at the same time,
you might see something like this:
(gdb) info connections
Num Name Description
1 remote 192.168.0.1:9999 Remote serial target in gdb-specific protocol
2 remote 192.168.0.2:9998 Remote serial target in gdb-specific protocol
* 3 native Native process
4 core Local core dump file
#2 - New "info inferiors" "Connection" column
You'll also see a new matching "Connection" column in "info
inferiors", showing you which connection an inferior is bound to:
(gdb) info inferiors
Num Description Connection Executable
1 process 18526 1 (remote 192.168.0.1:9999) target:/tmp/a.out
2 process 18531 2 (remote 192.168.0.2:9998) target:/tmp/a.out
3 process 19115 3 (native) /tmp/prog1
4 process 6286 4 (core) myprogram
* 5 process 19122 3 (native) /bin/hello
#3 - Makes "add-inferior" show the inferior's target connection
"add-inferior" now shows you the connection you've just bound the
inferior to, which is the current process_stratum target:
(gdb) add-inferior
[New inferior 2]
Added inferior 2 on connection 1 (extended-remote localhost:2346)
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* Makefile.in (COMMON_SFILES): Add target-connection.c.
* inferior.c (uiout_field_connection): New function.
(print_inferior): Add new "connection-id" column.
(add_inferior_command): Show connection number/string of added
inferior.
* process-stratum-target.h
(process_stratum_target::connection_string): New virtual method.
(process_stratum_target::connection_number): New field.
* remote.c (remote_target::connection_string): New override.
* target-connection.c: New file.
* target-connection.h: New file.
* target.c (decref_target): Remove process_stratum targets from
the connection list.
(target_stack::push): Add process_stratum targets to the
connection list.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.base/kill-detach-inferiors-cmd.exp: Adjust expected output
of "add-inferior".
* gdb.base/quit-live.exp: Likewise.
* gdb.base/remote-exec-file.exp: Likewise.
* gdb.guile/scm-progspace.exp: Likewise.
* gdb.linespec/linespec.exp: Likewise.
* gdb.mi/new-ui-mi-sync.exp: Likewise.
* gdb.mi/user-selected-context-sync.exp: Likewise.
* gdb.multi/multi-target.exp (setup): Add "info connection" and
"info inferiors" tests.
* gdb.multi/remove-inferiors.exp: Adjust expected output of
"add-inferior".
* gdb.multi/watchpoint-multi.exp: Likewise.
* gdb.python/py-inferior.exp: Likewise.
* gdb.server/extended-remote-restart.exp: Likewise.
* gdb.threads/fork-plus-threads.exp: Adjust expected output of
"info inferiors".
* gdb.threads/forking-threads-plus-breakpoint.exp: Likewise.
* gdb.trace/report.exp: Likewise.
---
gdb/Makefile.in | 1 +
gdb/inferior.c | 56 +++++++-
gdb/process-stratum-target.h | 13 ++
gdb/remote.c | 13 ++
gdb/target-connection.c | 156 +++++++++++++++++++++
gdb/target-connection.h | 32 +++++
gdb/target.c | 10 +-
.../gdb.base/kill-detach-inferiors-cmd.exp | 4 +-
gdb/testsuite/gdb.base/quit-live.exp | 2 +-
gdb/testsuite/gdb.base/remote-exec-file.exp | 2 +-
gdb/testsuite/gdb.guile/scm-progspace.exp | 2 +-
gdb/testsuite/gdb.linespec/linespec.exp | 2 +-
gdb/testsuite/gdb.mi/new-ui-mi-sync.exp | 2 +-
.../gdb.mi/user-selected-context-sync.exp | 2 +-
gdb/testsuite/gdb.multi/multi-target.exp | 28 +++-
gdb/testsuite/gdb.multi/remove-inferiors.exp | 2 +-
gdb/testsuite/gdb.multi/watchpoint-multi.exp | 2 +-
gdb/testsuite/gdb.python/py-inferior.exp | 4 +-
.../gdb.server/extended-remote-restart.exp | 18 ++-
gdb/testsuite/gdb.threads/fork-plus-threads.exp | 2 +-
.../forking-threads-plus-breakpoint.exp | 2 +-
gdb/testsuite/gdb.trace/report.exp | 2 +-
22 files changed, 329 insertions(+), 28 deletions(-)
create mode 100644 gdb/target-connection.c
create mode 100644 gdb/target-connection.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e7e26a44a0..4fa84fa16c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1119,6 +1119,7 @@ COMMON_SFILES = \
symmisc.c \
symtab.c \
target.c \
+ target-connection.c \
target-dcache.c \
target-descriptions.c \
target-memory.c \
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 6f4f396453..96d38f865d 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -429,6 +429,31 @@ print_selected_inferior (struct ui_out *uiout)
inf->num, inferior_pid_to_str (inf->pid).c_str (), filename);
}
+/* Helper for print_inferior. Returns the 'connection-id' string for
+ PROC_TARGET. */
+
+static std::string
+uiout_field_connection (process_stratum_target *proc_target)
+{
+ if (proc_target == NULL)
+ {
+ return {};
+ }
+ else if (proc_target->connection_string () != NULL)
+ {
+ return string_printf ("%d (%s %s)",
+ proc_target->connection_number,
+ proc_target->shortname (),
+ proc_target->connection_string ());
+ }
+ else
+ {
+ return string_printf ("%d (%s)",
+ proc_target->connection_number,
+ proc_target->shortname ());
+ }
+}
+
/* Prints the list of inferiors and their details on UIOUT. This is a
version of 'info_inferior_command' suitable for use from MI.
@@ -440,6 +465,7 @@ static void
print_inferior (struct ui_out *uiout, const char *requested_inferiors)
{
int inf_count = 0;
+ size_t connection_id_len = 20;
/* Compute number of inferiors we will print. */
for (inferior *inf : all_inferiors ())
@@ -447,6 +473,10 @@ print_inferior (struct ui_out *uiout, const char *requested_inferiors)
if (!number_is_in_list (requested_inferiors, inf->num))
continue;
+ std::string conn = uiout_field_connection (inf->process_target ());
+ if (connection_id_len < conn.size ())
+ connection_id_len = conn.size ();
+
++inf_count;
}
@@ -456,10 +486,12 @@ print_inferior (struct ui_out *uiout, const char *requested_inferiors)
return;
}
- ui_out_emit_table table_emitter (uiout, 4, inf_count, "inferiors");
+ ui_out_emit_table table_emitter (uiout, 5, inf_count, "inferiors");
uiout->table_header (1, ui_left, "current", "");
uiout->table_header (4, ui_left, "number", "Num");
uiout->table_header (17, ui_left, "target-id", "Description");
+ uiout->table_header (connection_id_len, ui_left,
+ "connection-id", "Connection");
uiout->table_header (17, ui_left, "exec", "Executable");
uiout->table_body ();
@@ -479,6 +511,9 @@ print_inferior (struct ui_out *uiout, const char *requested_inferiors)
uiout->field_string ("target-id", inferior_pid_to_str (inf->pid));
+ std::string conn = uiout_field_connection (inf->process_target ());
+ uiout->field_string ("connection-id", conn.c_str ());
+
if (inf->pspace->pspace_exec_filename != NULL)
uiout->field_string ("exec", inf->pspace->pspace_exec_filename);
else
@@ -713,9 +748,22 @@ switch_to_inferior_and_push_target (inferior *new_inf,
/* Reuse the target for new inferior. */
if (!no_connection && proc_target != NULL)
- push_target (proc_target);
-
- printf_filtered (_("Added inferior %d\n"), new_inf->num);
+ {
+ push_target (proc_target);
+ if (proc_target->connection_string () != NULL)
+ printf_filtered (_("Added inferior %d on connection %d (%s %s)\n"),
+ new_inf->num,
+ proc_target->connection_number,
+ proc_target->shortname (),
+ proc_target->connection_string ());
+ else
+ printf_filtered (_("Added inferior %d on connection %d (%s)\n"),
+ new_inf->num,
+ proc_target->connection_number,
+ proc_target->shortname ());
+ }
+ else
+ printf_filtered (_("Added inferior %d\n"), new_inf->num);
}
/* add-inferior [-copies N] [-exec FILENAME] [-no-connection] */
diff --git a/gdb/process-stratum-target.h b/gdb/process-stratum-target.h
index 6081c0a927..53e1c6a618 100644
--- a/gdb/process-stratum-target.h
+++ b/gdb/process-stratum-target.h
@@ -31,6 +31,16 @@ public:
strata stratum () const final override { return process_stratum; }
+ /* Return a string representation of this target's open connection.
+ This string is used to distinguish different instances of a given
+ target type. For example, when remote debugging, the target is
+ called "remote", but since we may have more than one remote
+ target open, connection_string() returns the connection serial
+ connection name, e.g., "localhost:10001", "192.168.0.1:20000",
+ etc. This string is shown in several places, e.g., in "info
+ connections" and "info inferiors". */
+ virtual const char *connection_string () { return nullptr; }
+
/* We must default these because they must be implemented by any
target that can run. */
bool can_async_p () override { return false; }
@@ -58,6 +68,9 @@ public:
stop events for all known threads, because any of those threads
may have spawned new threads we haven't heard of yet. */
bool threads_executing = false;
+
+ /* The connection number. Visible in "info connections". */
+ int connection_number = 0;
};
/* Downcast TARGET to process_stratum_target. */
diff --git a/gdb/remote.c b/gdb/remote.c
index 168fff3047..ff75204ee8 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -404,6 +404,8 @@ public:
const target_info &info () const override
{ return remote_target_info; }
+ const char *connection_string () override;
+
thread_control_capabilities get_thread_control_capabilities () override
{ return tc_schedlock; }
@@ -4860,6 +4862,17 @@ remote_target::start_remote (int from_tty, int extended_p)
insert_breakpoints ();
}
+const char *
+remote_target::connection_string ()
+{
+ remote_state *rs = get_remote_state ();
+
+ if (rs->remote_desc->name != NULL)
+ return rs->remote_desc->name;
+ else
+ return NULL;
+}
+
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
diff --git a/gdb/target-connection.c b/gdb/target-connection.c
new file mode 100644
index 0000000000..f13e649977
--- /dev/null
+++ b/gdb/target-connection.c
@@ -0,0 +1,156 @@
+/* List of target connections for GDB.
+
+ Copyright (C) 2017-2019 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "target-connection.h"
+
+#include <map>
+
+#include "inferior.h"
+#include "target.h"
+
+/* A map between connection number and representative process_stratum
+ target. */
+static std::map<int, process_stratum_target *> process_targets;
+
+/* The highest connection number ever given to a target. */
+static int highest_target_connection_num;
+
+/* See target-connection.h. */
+
+void
+connection_list_add (process_stratum_target *t)
+{
+ if (t->connection_number == 0)
+ {
+ t->connection_number = ++highest_target_connection_num;
+ process_targets[t->connection_number] = t;
+ }
+}
+
+/* See target-connection.h. */
+
+void
+connection_list_remove (process_stratum_target *t)
+{
+ process_targets.erase (t->connection_number);
+ t->connection_number = 0;
+}
+
+/* Make a target connection string for T. This is usually T's
+ shortname, but it includes the result of
+ process_stratum_target::connection_string() too if T supports
+ it. */
+
+static std::string
+make_target_connection_string (process_stratum_target *t)
+{
+ if (t->connection_string () != NULL)
+ return string_printf ("%s %s", t->shortname (),
+ t->connection_string ());
+ else
+ return t->shortname ();
+}
+
+/* Prints the list of target connections and their details on UIOUT.
+
+ If REQUESTED_CONNECTIONS is not NULL, it's a list of GDB ids of the
+ target connections that should be printed. Otherwise, all target
+ connections are printed. */
+
+static void
+print_connection (struct ui_out *uiout, const char *requested_connections)
+{
+ int count = 0;
+ size_t name_len = 0;
+
+ /* Compute number of lines we will print. */
+ for (const auto &it : process_targets)
+ {
+ if (!number_is_in_list (requested_connections, it.first))
+ continue;
+
+ ++count;
+
+ process_stratum_target *t = it.second;
+
+ size_t l = strlen (t->shortname ());
+ if (t->connection_string () != NULL)
+ l += 1 + strlen (t->connection_string ());
+
+ if (l > name_len)
+ name_len = l;
+ }
+
+ if (count == 0)
+ {
+ uiout->message (_("No connections.\n"));
+ return;
+ }
+
+ ui_out_emit_table table_emitter (uiout, 4, process_targets.size (),
+ "connections");
+
+ uiout->table_header (1, ui_left, "current", "");
+ uiout->table_header (4, ui_left, "number", "Num");
+ uiout->table_header (name_len + 1, ui_left, "name", "Name");
+ uiout->table_header (17, ui_left, "description", "Description");
+
+ uiout->table_body ();
+
+ for (const auto &it : process_targets)
+ {
+ process_stratum_target *t = it.second;
+
+ if (!number_is_in_list (requested_connections, t->connection_number))
+ continue;
+
+ ui_out_emit_tuple tuple_emitter (uiout, NULL);
+
+ if (current_inferior ()->process_target () == t)
+ uiout->field_string ("current", "*");
+ else
+ uiout->field_skip ("current");
+
+ uiout->field_signed ("number", t->connection_number);
+
+ uiout->field_string ("name", make_target_connection_string (t).c_str ());
+
+ uiout->field_string ("description", t->longname ());
+
+ uiout->text ("\n");
+ }
+}
+
+/* The "info connections" command. */
+
+static void
+info_connections_command (const char *args, int from_tty)
+{
+ print_connection (current_uiout, args);
+}
+
+void
+_initialize_target_connection ()
+{
+ add_info ("connections", info_connections_command,
+ _("\
+Names of target connections being debugged.\n\
+Shows the list of targets currently in use as well as their description."));
+}
diff --git a/gdb/target-connection.h b/gdb/target-connection.h
new file mode 100644
index 0000000000..0e2dc128d8
--- /dev/null
+++ b/gdb/target-connection.h
@@ -0,0 +1,32 @@
+/* List of target connections for GDB.
+
+ Copyright (C) 2017-2019 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef TARGET_CONNECTION_H
+#define TARGET_CONNECTION_H
+
+struct process_stratum_target;
+
+/* Add a process target to the connection list, if not already
+ added. */
+void connection_list_add (process_stratum_target *t);
+
+/* Remove a process target from the connection list. */
+void connection_list_remove (process_stratum_target *t);
+
+#endif /* TARGET_CONNECTION_H */
diff --git a/gdb/target.c b/gdb/target.c
index 541b95bc10..ba01148d7a 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -49,6 +49,7 @@
#include "gdbsupport/byte-vector.h"
#include "terminal.h"
#include <unordered_map>
+#include "target-connection.h"
static void generic_tls_error (void) ATTRIBUTE_NORETURN;
@@ -561,7 +562,11 @@ decref_target (target_ops *t)
{
t->decref ();
if (t->refcount () == 0)
- target_close (t);
+ {
+ if (t->stratum () == process_stratum)
+ connection_list_remove (as_process_stratum_target (t));
+ target_close (t);
+ }
}
/* See target.h. */
@@ -573,6 +578,9 @@ target_stack::push (target_ops *t)
strata stratum = t->stratum ();
+ if (stratum == process_stratum)
+ connection_list_add (as_process_stratum_target (t));
+
/* If there's already a target at this stratum, remove it. */
if (m_stack[stratum] != NULL)
diff --git a/gdb/testsuite/gdb.base/kill-detach-inferiors-cmd.exp b/gdb/testsuite/gdb.base/kill-detach-inferiors-cmd.exp
index 63045cb504..bd50a60c7f 100644
--- a/gdb/testsuite/gdb.base/kill-detach-inferiors-cmd.exp
+++ b/gdb/testsuite/gdb.base/kill-detach-inferiors-cmd.exp
@@ -32,7 +32,7 @@ if [prepare_for_testing "failed to prepare" $executable] {
runto_main
# Add another forked inferior process.
-gdb_test "add-inferior" "Added inferior 2" "add inferior 2"
+gdb_test "add-inferior" "Added inferior 2 on target .*" "add inferior 2"
gdb_test "inferior 2" "Switching to inferior 2.*"
gdb_test "file $binfile" "Reading symbols from .*" "load binary"
gdb_test "start" "Temporary breakpoint.*Starting program.*"
@@ -40,7 +40,7 @@ gdb_test "start" "Temporary breakpoint.*Starting program.*"
# Add an attached inferior process.
set test_spawn_id [spawn_wait_for_attach $binfile]
set test_pid [spawn_id_get_pid $test_spawn_id]
-gdb_test "add-inferior" "Added inferior 3" "add inferior 3"
+gdb_test "add-inferior" "Added inferior 3 on connection .*" "add inferior 3"
gdb_test "inferior 3" "Switching to inferior 3.*"
gdb_test "attach $test_pid" "Attaching to process.*" "attach to pid"
diff --git a/gdb/testsuite/gdb.base/quit-live.exp b/gdb/testsuite/gdb.base/quit-live.exp
index c0eba44d43..7b23a9c013 100644
--- a/gdb/testsuite/gdb.base/quit-live.exp
+++ b/gdb/testsuite/gdb.base/quit-live.exp
@@ -120,7 +120,7 @@ proc quit_with_live_inferior {appear_how extra_inferior quit_how} {
}
if {$extra_inferior} {
- gdb_test "add-inferior" "Added inferior 2*" \
+ gdb_test "add-inferior" "Added inferior 2 on connection .*" \
"add empty inferior 2"
gdb_test "inferior 2" "Switching to inferior 2.*" \
"switch to inferior 2"
diff --git a/gdb/testsuite/gdb.base/remote-exec-file.exp b/gdb/testsuite/gdb.base/remote-exec-file.exp
index 3db009b830..6af8afcc5a 100644
--- a/gdb/testsuite/gdb.base/remote-exec-file.exp
+++ b/gdb/testsuite/gdb.base/remote-exec-file.exp
@@ -27,7 +27,7 @@ with_test_prefix "set inf 1" {
# Set remote exec-file in inferior 2.
with_test_prefix "set inf 2" {
- gdb_test "add-inferior" "Added inferior 2" "add inferior 2"
+ gdb_test "add-inferior" "Added inferior 2.*" "add inferior 2"
gdb_test "inferior 2" "Switching to inferior 2.*"
gdb_test_no_output "set remote exec-file prog2"
}
diff --git a/gdb/testsuite/gdb.guile/scm-progspace.exp b/gdb/testsuite/gdb.guile/scm-progspace.exp
index cb8384f83d..19520943c0 100644
--- a/gdb/testsuite/gdb.guile/scm-progspace.exp
+++ b/gdb/testsuite/gdb.guile/scm-progspace.exp
@@ -73,7 +73,7 @@ with_test_prefix "program unloaded" {
# deleted. We need to, for example, delete an inferior to get the progspace
# to go away.
-gdb_test "add-inferior" "Added inferior 2" "create new inferior"
+gdb_test "add-inferior" "Added inferior 2.*" "create new inferior"
gdb_test "inferior 2" ".*" "switch to new inferior"
gdb_test_no_output "remove-inferiors 1" "remove first inferior"
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
index 45982ddeff..08be8f606f 100644
--- a/gdb/testsuite/gdb.linespec/linespec.exp
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -201,7 +201,7 @@ gdb_test "break lspec.h:$line" \
# Multi-inferior tests.
#
-gdb_test "add-inferior" "Added inferior 2" \
+gdb_test "add-inferior" "Added inferior 2.*" \
"add inferior for linespec tests"
gdb_test "inferior 2" "Switching to inferior 2 .*" \
diff --git a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
index 5560a8be96..7eb4fb3716 100644
--- a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
+++ b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
@@ -83,7 +83,7 @@ proc do_test {sync_command} {
# in the separate MI UI. Note the "run" variant usually triggers
# =thread-group-started/=thread-created/=library-loaded as well.
with_spawn_id $gdb_main_spawn_id {
- gdb_test "add-inferior" "Added inferior 2"
+ gdb_test "add-inferior" "Added inferior 2 on connection .*"
}
# Interrupt the program.
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 621b4c5163..19dd4c9493 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -415,7 +415,7 @@ proc_with_prefix test_setup { mode } {
# Add the second inferior now. While this is not mandatory, it allows
# us to assume that per-inferior thread numbering will be used,
# simplifying test_continue_to_start a bit (Thread 1.2 and not Thread 2).
- gdb_test "add-inferior" "Added inferior 2" "add inferior 2"
+ gdb_test "add-inferior" "Added inferior 2 on connection .*" "add inferior 2"
# Prepare the first inferior for the test.
test_continue_to_start $mode 1
diff --git a/gdb/testsuite/gdb.multi/multi-target.exp b/gdb/testsuite/gdb.multi/multi-target.exp
index 3b71e7446b..78a43d8c2e 100644
--- a/gdb/testsuite/gdb.multi/multi-target.exp
+++ b/gdb/testsuite/gdb.multi/multi-target.exp
@@ -137,8 +137,34 @@ proc setup {non-stop} {
return 0
}
+ set ws "\[ \t\]+"
+ global decimal
+
+ # Test "info connections" and "info inferior"'s "Connection"
+ # column, while at it.
+
+ gdb_test "info connections" \
+ [multi_line \
+ "Num${ws}Name${ws}Description${ws}" \
+ " 1${ws}native${ws}Native process${ws}" \
+ " 2${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \
+ " 3${ws}core${ws}Local core dump file${ws}" \
+ " 4${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \
+ "\\* 5${ws}core${ws}Local core dump file${ws}" \
+ ]
+
+ gdb_test "info inferiors" \
+ [multi_line \
+ "Num${ws}Description${ws}Connection${ws}Executable${ws}" \
+ " 1${ws}process ${decimal}${ws}1 \\(native\\)${ws}${binfile}${ws}" \
+ " 2${ws}process ${decimal}${ws}2 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \
+ " 3${ws}process ${decimal}${ws}3 \\(core\\)${ws}${binfile}${ws}" \
+ " 4${ws}process ${decimal}${ws}1 \\(native\\)${ws}${binfile}${ws}" \
+ " 5${ws}process ${decimal}${ws}4 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \
+ "\\* 6${ws}process ${decimal}${ws}5 \\(core\\)${ws}${binfile}${ws}" \
+ ]
+
# For debugging.
- gdb_test "info inferiors" ".*"
gdb_test "info threads" ".*"
# Make "continue" resume all inferiors.
diff --git a/gdb/testsuite/gdb.multi/remove-inferiors.exp b/gdb/testsuite/gdb.multi/remove-inferiors.exp
index 18f6c90225..ef3def7b5b 100644
--- a/gdb/testsuite/gdb.multi/remove-inferiors.exp
+++ b/gdb/testsuite/gdb.multi/remove-inferiors.exp
@@ -26,7 +26,7 @@ proc switch_to_inferior { num message } {
}
proc add_inferior { expected_num message } {
- gdb_test "add-inferior" "Added inferior ${expected_num}" "${message}"
+ gdb_test "add-inferior" "Added inferior ${expected_num}( on connection .*)?" "${message}"
}
proc test_remove_inferiors { } {
diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
index b0f47db374..f3f9ca58fc 100644
--- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
+++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
@@ -53,7 +53,7 @@ if [support_displaced_stepping] {
gdb_breakpoint main {temporary}
gdb_test "run" "Temporary breakpoint.* main .*" "start to main inferior 1"
-gdb_test "add-inferior" "Added inferior 2" "add inferior 2"
+gdb_test "add-inferior" "Added inferior 2 on connection .*" "add inferior 2"
gdb_test "inferior 2" "witching to inferior 2 .*" "switch to inferior 2, first time"
gdb_load $binfile
diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp
index 72ec1f2186..a4839c83d6 100644
--- a/gdb/testsuite/gdb.python/py-inferior.exp
+++ b/gdb/testsuite/gdb.python/py-inferior.exp
@@ -279,7 +279,7 @@ with_test_prefix "selected_inferior" {
gdb_test "inferior 1" ".*" "switch to first inferior"
gdb_test "py print (gdb.selected_inferior().num)" "1" "first inferior selected"
- gdb_test "add-inferior" "Added inferior 3" "create new inferior"
+ gdb_test "add-inferior" "Added inferior 3 on connection .*" "create new inferior"
gdb_test "inferior 3" ".*" "switch to third inferior"
gdb_test "py print (gdb.selected_inferior().num)" "3" "third inferior selected"
gdb_test "inferior 1" ".*" "switch back to first inferior"
@@ -288,7 +288,7 @@ with_test_prefix "selected_inferior" {
# Test repr()/str()
with_test_prefix "__repr__" {
- gdb_test "add-inferior" "Added inferior 4" "add inferior 4"
+ gdb_test "add-inferior" "Added inferior 4 on connection .*" "add inferior 4"
gdb_py_test_silent_cmd "python infs = gdb.inferiors()" "get inferior list" 1
gdb_test "python print (infs\[0\])" "<gdb.Inferior num=1, pid=$decimal>"
gdb_test "python print (infs)" \
diff --git a/gdb/testsuite/gdb.server/extended-remote-restart.exp b/gdb/testsuite/gdb.server/extended-remote-restart.exp
index c78342c010..c1010a9358 100644
--- a/gdb/testsuite/gdb.server/extended-remote-restart.exp
+++ b/gdb/testsuite/gdb.server/extended-remote-restart.exp
@@ -88,12 +88,16 @@ proc test_reload { do_kill_p follow_child_p } {
gdb_breakpoint "breakpt"
gdb_continue_to_breakpoint "breakpt"
- # Check we have the expected inferiors.
+ set ws "\[ \t\]+"
+ set any_re "\[^\r\n\]+"
+ set connection_re $any_re
+ set executable_re $any_re
+
gdb_test "info inferiors" \
[multi_line \
- " Num Description Executable.*" \
- "${parent_prefix} 1 +${live_inf_ptn} \[^\r\n\]+" \
- "${child_prefix} 2 +${live_inf_ptn} \[^\r\n\]+" ] \
+ " Num${ws}Description${ws}Connection${ws}Executable${ws}" \
+ "${parent_prefix} 1${ws}${live_inf_ptn}${ws}${connection_re}${executable_re}" \
+ "${child_prefix} 2${ws}${live_inf_ptn}${ws}${connection_re}${executable_re}" ] \
"Check inferiors at breakpoint"
if { $do_kill_p } {
@@ -107,9 +111,9 @@ proc test_reload { do_kill_p follow_child_p } {
# Check the first inferior really did die.
gdb_test "info inferiors" \
[multi_line \
- " Num Description Executable.*" \
- "${parent_prefix} 1 +${parent_inf_after_kill_ptn} \[^\r\n\]+" \
- "${child_prefix} 2 +${child_inf_after_kill_ptn} \[^\r\n\]+" ] \
+ " Num${ws}Description${ws}Connection${ws}Executable${ws}" \
+ "${parent_prefix} 1${ws}${parent_inf_after_kill_ptn}${ws}${connection_re}${executable_re}" \
+ "${child_prefix} 2${ws}${child_inf_after_kill_ptn}${ws}${connection_re}${executable_re}" ] \
"Check inferior was killed"
}
diff --git a/gdb/testsuite/gdb.threads/fork-plus-threads.exp b/gdb/testsuite/gdb.threads/fork-plus-threads.exp
index 340a8df266..d488bb9d39 100644
--- a/gdb/testsuite/gdb.threads/fork-plus-threads.exp
+++ b/gdb/testsuite/gdb.threads/fork-plus-threads.exp
@@ -109,7 +109,7 @@ proc do_test { detach_on_fork } {
"no threads left"
gdb_test "info inferiors" \
- "Num\[ \t\]+Description\[ \t\]+Executable\[ \t\]+\r\n\\* 1 \[^\r\n\]+" \
+ "Num\[ \t\]+Description\[ \t\]+Connection\[ \t\]+Executable\[ \t\]+\r\n\\* 1 \[^\r\n\]+" \
"only inferior 1 left"
}
diff --git a/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.exp b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.exp
index 1d1378234e..6d24af401b 100644
--- a/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.exp
+++ b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.exp
@@ -142,7 +142,7 @@ proc do_test { cond_bp_target detach_on_fork displaced } {
"no threads left"
gdb_test "info inferiors" \
- "Num\[ \t\]+Description\[ \t\]+Executable\[ \t\]+\r\n\\* 1 \[^\r\n\]+" \
+ "Num\[ \t\]+Description\[ \t\]+Connection\[ \t\]+Executable\[ \t\]+\r\n\\* 1 \[^\r\n\]+" \
"only inferior 1 left"
}
diff --git a/gdb/testsuite/gdb.trace/report.exp b/gdb/testsuite/gdb.trace/report.exp
index c847ab0c5b..2949f1bb0d 100644
--- a/gdb/testsuite/gdb.trace/report.exp
+++ b/gdb/testsuite/gdb.trace/report.exp
@@ -391,7 +391,7 @@ proc use_collected_data { data_source } {
# There is always a thread of an inferior, either a live one or
# a faked one.
gdb_test "info threads" "\\* ${decimal} (process|Thread) \[0-9\.\]+\[ \t\].*"
- gdb_test "info inferiors" "\\* 1 process ${decimal} \[ \t\]+${binfile}.*"
+ gdb_test "info inferiors" "\\* 1 process ${decimal} \[ \t\]+\[^\r\n\]*\[ \t\]+${binfile}.*"
}
}
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 20/23] Revert 'Remove unused struct serial::name field'
2019-09-06 23:28 ` [PATCH 20/23] Revert 'Remove unused struct serial::name field' Pedro Alves
@ 2019-09-06 23:47 ` Christian Biesinger via gdb-patches
2019-09-08 19:30 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Christian Biesinger via gdb-patches @ 2019-09-06 23:47 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
Have you considered making this an std::string to avoid needing the manual
xfree?
On Fri, Sep 6, 2019, 18:29 Pedro Alves <palves@redhat.com> wrote:
> This commit reverts:
>
> commit 5f5219fc34f7557296272230123a3837960a6f09
> Author: Pedro Alves <palves@redhat.com>
> AuthorDate: Tue Apr 12 16:49:30 2016 +0100
>
> Remove unused struct serial::name field
>
> The following patches will add uses for the field.
>
> gdb/ChangeLog:
> yyyy-mm-dd Pedro Alves <palves@redhat.com>
>
> Revert:
> 2016-04-12 Pedro Alves <palves@redhat.com>
> * serial.c (serial_open, serial_fdopen_ops, do_serial_close):
> Remove references to name.
> * serial.h (struct serial) <name>: Delete.
> ---
> gdb/serial.c | 4 ++++
> gdb/serial.h | 1 +
> 2 files changed, 5 insertions(+)
>
> diff --git a/gdb/serial.c b/gdb/serial.c
> index a881bbc97c..0ed3d37406 100644
> --- a/gdb/serial.c
> +++ b/gdb/serial.c
> @@ -247,6 +247,7 @@ serial_open_ops_1 (const struct serial_ops *ops, const
> char *open_name)
> return NULL;
> }
>
> + scb->name = open_name != NULL ? xstrdup (open_name) : NULL;
> scb->next = scb_base;
> scb_base = scb;
>
> @@ -291,6 +292,7 @@ serial_fdopen_ops (const int fd, const struct
> serial_ops *ops)
>
> scb = new_serial (ops);
>
> + scb->name = NULL;
> scb->next = scb_base;
> scb_base = scb;
>
> @@ -330,6 +332,8 @@ do_serial_close (struct serial *scb, int really_close)
> if (really_close)
> scb->ops->close (scb);
>
> + xfree (scb->name);
> +
> /* For serial_is_open. */
> scb->bufp = NULL;
>
> diff --git a/gdb/serial.h b/gdb/serial.h
> index b75b3666e7..d58ab660e9 100644
> --- a/gdb/serial.h
> +++ b/gdb/serial.h
> @@ -240,6 +240,7 @@ struct serial
> buffer. -ve for sticky errors. */
> unsigned char *bufp; /* Current byte */
> unsigned char buf[BUFSIZ]; /* Da buffer itself */
> + char *name; /* The name of the device or host
> */
> struct serial *next; /* Pointer to the next `struct serial *' */
> int debug_p; /* Trace this serial devices operation. */
> int async_state; /* Async internal state. */
> --
> 2.14.5
>
>
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-09-06 23:33 ` [PATCH 23/23] Multi-target: NEWS and user manual Pedro Alves
@ 2019-09-07 6:33 ` Eli Zaretskii
2019-10-17 2:08 ` Pedro Alves
2019-10-17 2:42 ` Pedro Alves
0 siblings, 2 replies; 68+ messages in thread
From: Eli Zaretskii @ 2019-09-07 6:33 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> From: Pedro Alves <palves@redhat.com>
> Date: Sat, 7 Sep 2019 00:28:07 +0100
>
> -
> -* Inferiors and Programs:: Debugging multiple inferiors and programs
> +* Inferiors Connections and Programs:: Debugging multiple inferiors connections and programs
The new line is too long, please break it in two.
> +@item
> +the target connection the inferior is bound to. This includes the
> +unique connection number assigned by @value{GDBN}, and the name of the
> +protocol used by the connection.
Having this @item start with a lowercase letter, and then having
another sentence in it looks awkward, English-wise. How about making
this a single sentence, as in "... is bound to, including the unique
connection number ..."?
> +@enumerate
> +@item
> +the connection number assigned by @value{GDBN}
This should end in a period, as the other items do.
> +@item
> +the connection name, derived from the protocol used by the connection.
"Name" sounds ... inaccurate, when it can be something like
"extended-remote host:10000", doesn't it? How about "Type"? Or maybe
call that "Description" and the last field "Details"?
> +There's no explicit way to switch focus between connections. Instead,
> +you switch focus between inferiors, which implicitly switches the
> +focus to the selected inferior's connection.
> +
> To switch focus between inferiors, use the @code{inferior} command:
What does "focus" mean in this context? Either we should explain that
here, or have a cross-reference where that is already explained.
> diff --git a/gdb/NEWS b/gdb/NEWS
> index f382e887c0..20aad73aa5 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
This part is OK.
Thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (22 preceding siblings ...)
2019-09-06 23:37 ` [PATCH 22/23] Require always-non-stop for multi-target resumptions Pedro Alves
@ 2019-09-07 11:19 ` Philippe Waroquiers
2019-09-08 20:06 ` Pedro Alves
2019-09-09 19:09 ` [PATCH 00/23] Multi-target support Tom Tromey
2019-09-09 20:22 ` Tom Tromey
25 siblings, 1 reply; 68+ messages in thread
From: Philippe Waroquiers @ 2019-09-07 11:19 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
Patch is a nice target :).
This can be useful e.g. with the valgrind gdbserver, that only
supports to debug a single process (i.e. the valgrind process that
runs its embedded gdbserver).
First, a minor suggestion about the terminology (as introduced in patch 17, and used
in command names): the rational is that 'target' being already overloaded,
the wording 'target connection' is used (leading to e.g. the command
'info connections').
I am wondering if the word "connection" is not also too overloaded,
and too much interpreted as meaning 'a real connection', which might lead to
some user confusion.
Maybe other wording could be used instead (such as 'target channel'
and 'info channels') ? Or maybe another synonym of channel or similar ?
Otherwise, I did a minimal test to see how GDB could connect to 2 different
valgrind gdbservers (a 64 bits and a 32 bits), but I could not make it work.
The 2 valgrind I have launched are (in the top of a valgrind build):
./path to/bin/valgrind --vgdb-error=0 ./memcheck/tests/trivialleak
./path to/bin/valgrind --vgdb-error=0 ./memcheck/tests/x86-linux/scalar_exit_group
(gdb) tar rem|lvgdb
Remote debugging using |lvgdb
...
(gdb) add-inferior -no-connection
[New inferior 2]
Added inferior 2
(gdb) tar rem |lvgdb --pid=16727
Remote debugging using |lvgdb --pid=16727
...
(gdb) info connection
Num Name Description
1 remote lvgdb Remote serial target in gdb-specific protocol
* 2 remote lvgdb --pid=16727 Remote serial target in gdb-specific protocol
(gdb) b main
Breakpoint 1 at 0x109168: main. (2 locations)
????? this has put a break at 2 locations in 2 different inferiors, reporting
only one address. Wondering if that is the expected
behaviour. In any case, that behaviour does not look to be a big deal.
(gdb) infer 1
[Switching to inferior 1 [Remote target]
(/home/philippe/valgrind/git/trunk_untouched/memcheck/tests/trivialleak)]
[Switching to thread 1.1 (Thread 10050)]
#0 0x0000000004001090 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) c
Continuing.
Connection 2 (remote lvgdb --pid=16727) does not support multi-target resumption.
(gdb)
So, the continue command is refused both in inferior 1 and inferior 2.
Then when stopping this gdb (which automatically continues the valgrind executables
till valgrind reports the next error), launching a new gdb, and only connecting to the 32
bits valgrind gdbserver, here is what I see.
(gdb) tar rem|lvgdb --pid=16727
Remote debugging using |lvgdb
...
0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
(gdb) bt
#0 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0x0495fd27 in syscall () at ../sysdeps/unix/sysv/linux/i386/syscall.S:29
#2 0x0010922c in main () at scalar_exit_group.c:14
(gdb) c
Continuing.
../../multi-target-v1/gdb/inferior.c:285: internal-error: inferior*
find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
So, that looks to be a regression with the valgrind gdbserver.
I did another trial using an abbreviation for -no-connection, but then
that does not work:
(gdb) add-inferior -no-connection
[New inferior 2]
Added inferior 2
(gdb) add-inferior -no-conn
[New inferior 3]
Added inferior 3 on connection 1 (remote lvgdb --pid=17046)
(gdb)
Maybe add-inferior should better be converted to the option framework ?
Thanks
Philippe
On Sat, 2019-09-07 at 00:27 +0100, Pedro Alves wrote:
> This commit adds multi-target support to GDB. What this means is that
> with this commit, GDB can now be connected to different targets at the
> same time. E.g., you can debug a live native process and a core dump
> at the same time, connect to multiple gdbservers, etc.
>
> Patches 1 to 16 are preparatory patches.
>
> Patch 17 is the actual multi-target patch. This is the largest patch
> in the series. It does a number of things at the same time, but
> they're all intertwined, so I gave up on splitting it further.
>
> Patch 18 adds tests. Split out because patch 17 is already too big as
> is.
>
> Patch 21 does some user-visible changes, including a new command to
> list open target connections. This is just the bare minimum I could
> think of that is necessary for multi-target work. I'm sure we'll find
> other tweaks to other commands necessary.
>
> Documentation is in patch 23.
>
> This surely breaks the build on non-Linux ports as is. I have not
> tried to adjust the host-specific nat files to function API changes,
> but I don't envision any serious trouble. The fixes they'll need will
> be quite mechanical, mostly usually to pass
> 'current_inferior()->process_target ()' to functions that gained a new
> 'process_stratum_target *' parameter, similar to the changes to tdep
> files in the multi-target patch, need for which was caught with
> --enable-targets=all.
>
> I've pushed this to users/palves/multi-target-v1 on sourceware for
> review and testing convenience.
>
> Pedro Alves (23):
> Preserve selected thread in all-stop w/ background execution
> Don't rely on inferior_ptid in record_full_wait
> Make "show remote exec-file" inferior-aware
> exceptions.c:print_flush: Remove obsolete check
> Make target_ops::has_execution take an 'inferior *' instead of a
> ptid_t
> Don't check target is running in remote_target::mourn_inferior
> Delete unnecessary code from kill_command
> Introduce switch_to_inferior_no_thread
> switch inferior/thread before calling target methods
> Some get_last_target_status tweaks
> tfile_target::close: trace_fd can't be -1
> Use all_non_exited_inferiors in infrun.c
> Delete exit_inferior_silent(int pid)
> Tweak handling of remote errors in response to resumption packet
> Fix reconnecting to a gdbserver already debugging multiple processes,
> I
> Fix reconnecting to a gdbserver already debugging multiple processes,
> II
> Multi-target support
> Add multi-target tests
> gdbarch-selftests.c: No longer error out if debugging something
> Revert 'Remove unused struct serial::name field'
> Add "info connections" command, "info inferiors" connection
> number/string
> Require always-non-stop for multi-target resumptions
> Multi-target: NEWS and user manual
>
> gdb/doc/gdb.texinfo | 140 +++--
> gdb/doc/guile.texi | 4 +-
> gdb/doc/python.texi | 6 +-
> gdb/NEWS | 29 +
> gdb/Makefile.in | 1 +
> gdb/ada-tasks.c | 4 +-
> gdb/amd64-fbsd-tdep.c | 4 +-
> gdb/amd64-linux-nat.c | 2 +-
> gdb/break-catch-sig.c | 3 +-
> gdb/break-catch-syscall.c | 3 +-
> gdb/breakpoint.c | 25 +-
> gdb/bsd-uthread.c | 20 +-
> gdb/btrace.c | 2 +-
> gdb/corelow.c | 10 +-
> gdb/ctf.c | 2 +-
> gdb/event-top.c | 14 +-
> gdb/exceptions.c | 6 +-
> gdb/exec.c | 51 +-
> gdb/exec.h | 7 +
> gdb/fbsd-tdep.c | 3 +-
> gdb/fork-child.c | 7 +-
> gdb/gdbarch-selftests.c | 5 -
> gdb/gdbserver/fork-child.c | 3 +-
> gdb/gdbserver/inferiors.c | 2 +-
> gdb/gdbserver/linux-low.c | 2 +-
> gdb/gdbserver/remote-utils.c | 2 +-
> gdb/gdbserver/target.c | 8 +-
> gdb/gdbserver/target.h | 9 +-
> gdb/gdbsupport/common-gdbthread.h | 5 +-
> gdb/gdbthread.h | 133 ++--
> gdb/i386-fbsd-tdep.c | 4 +-
> gdb/inf-child.c | 2 +-
> gdb/inf-ptrace.c | 6 +-
> gdb/infcall.c | 3 +-
> gdb/infcmd.c | 129 ++--
> gdb/inferior-iter.h | 77 ++-
> gdb/inferior.c | 155 +++--
> gdb/inferior.h | 71 ++-
> gdb/infrun.c | 683 ++++++++++++++++-----
> gdb/infrun.h | 16 +-
> gdb/inline-frame.c | 51 +-
> gdb/inline-frame.h | 12 +-
> gdb/linux-fork.c | 5 +-
> gdb/linux-nat.c | 74 ++-
> gdb/linux-nat.h | 1 +
> gdb/linux-tdep.c | 3 +-
> gdb/linux-thread-db.c | 112 ++--
> gdb/mi/mi-interp.c | 10 +-
> gdb/nat/fork-inferior.c | 8 +-
> gdb/nat/fork-inferior.h | 5 +-
> gdb/ppc-fbsd-tdep.c | 4 +-
> gdb/proc-service.c | 17 +-
> gdb/process-stratum-target.c | 12 +-
> gdb/process-stratum-target.h | 31 +-
> gdb/python/py-threadevent.c | 4 +-
> gdb/ravenscar-thread.c | 16 +-
> gdb/record-btrace.c | 43 +-
> gdb/record-full.c | 22 +-
> gdb/regcache.c | 162 +++--
> gdb/regcache.h | 30 +-
> gdb/remote.c | 290 +++++----
> gdb/riscv-fbsd-tdep.c | 4 +-
> gdb/serial.c | 4 +
> gdb/serial.h | 1 +
> gdb/sol2-tdep.c | 2 +-
> gdb/solib-spu.c | 3 +-
> gdb/solib-svr4.c | 3 +-
> gdb/spu-multiarch.c | 6 +-
> gdb/spu-tdep.c | 8 +-
> gdb/target-connection.c | 153 +++++
> gdb/target-connection.h | 40 ++
> gdb/target-delegates.c | 27 +
> gdb/target.c | 166 +++--
> gdb/target.h | 23 +-
> gdb/testsuite/gdb.base/fork-running-state.exp | 17 +-
> .../gdb.base/kill-detach-inferiors-cmd.exp | 4 +-
> gdb/testsuite/gdb.base/quit-live.exp | 2 +-
> gdb/testsuite/gdb.base/remote-exec-file.exp | 46 ++
> gdb/testsuite/gdb.guile/scm-progspace.exp | 2 +-
> gdb/testsuite/gdb.linespec/linespec.exp | 2 +-
> gdb/testsuite/gdb.mi/new-ui-mi-sync.exp | 2 +-
> .../gdb.mi/user-selected-context-sync.exp | 2 +-
> gdb/testsuite/gdb.multi/multi-target.c | 100 +++
> gdb/testsuite/gdb.multi/multi-target.exp | 387 ++++++++++++
> gdb/testsuite/gdb.multi/remove-inferiors.exp | 2 +-
> gdb/testsuite/gdb.multi/watchpoint-multi.exp | 2 +-
> gdb/testsuite/gdb.python/py-inferior.exp | 4 +-
> .../gdb.server/extended-remote-restart.exp | 22 +-
> gdb/testsuite/gdb.threads/async.c | 70 +++
> gdb/testsuite/gdb.threads/async.exp | 98 +++
> gdb/testsuite/gdb.threads/fork-plus-threads.exp | 2 +-
> .../forking-threads-plus-breakpoint.exp | 2 +-
> gdb/testsuite/gdb.trace/report.exp | 2 +-
> gdb/testsuite/lib/gdbserver-support.exp | 4 +
> gdb/thread-iter.c | 14 +-
> gdb/thread-iter.h | 25 +-
> gdb/thread.c | 230 ++++---
> gdb/top.c | 17 +-
> gdb/tracefile-tfile.c | 5 +-
> gdb/tracefile.h | 2 +-
> 100 files changed, 3098 insertions(+), 977 deletions(-)
> create mode 100644 gdb/target-connection.c
> create mode 100644 gdb/target-connection.h
> create mode 100644 gdb/testsuite/gdb.base/remote-exec-file.exp
> create mode 100644 gdb/testsuite/gdb.multi/multi-target.c
> create mode 100644 gdb/testsuite/gdb.multi/multi-target.exp
> create mode 100644 gdb/testsuite/gdb.threads/async.c
> create mode 100644 gdb/testsuite/gdb.threads/async.exp
>
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 20/23] Revert 'Remove unused struct serial::name field'
2019-09-06 23:47 ` Christian Biesinger via gdb-patches
@ 2019-09-08 19:30 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-09-08 19:30 UTC (permalink / raw)
To: Christian Biesinger; +Cc: gdb-patches
On 9/7/19 12:47 AM, Christian Biesinger via gdb-patches wrote:
> Have you considered making this an std::string to avoid needing the manual
> xfree?
>
struct serial hasn't been C++fied yet, it is still allocated with
malloc (XCNEW), so we can't use std::string without further changes.
So I stuck with just reverting the original patch as is, thinking that
a change to use std::string or something like that could be done along
other C++ification changes.
Thanks,
Pedro Alves
> On Fri, Sep 6, 2019, 18:29 Pedro Alves <palves@redhat.com> wrote:
>
>> This commit reverts:
>>
>> commit 5f5219fc34f7557296272230123a3837960a6f09
>> Author: Pedro Alves <palves@redhat.com>
>> AuthorDate: Tue Apr 12 16:49:30 2016 +0100
>>
>> Remove unused struct serial::name field
>>
>> The following patches will add uses for the field.
>>
>> gdb/ChangeLog:
>> yyyy-mm-dd Pedro Alves <palves@redhat.com>
>>
>> Revert:
>> 2016-04-12 Pedro Alves <palves@redhat.com>
>> * serial.c (serial_open, serial_fdopen_ops, do_serial_close):
>> Remove references to name.
>> * serial.h (struct serial) <name>: Delete.
>> ---
>> gdb/serial.c | 4 ++++
>> gdb/serial.h | 1 +
>> 2 files changed, 5 insertions(+)
>>
>> diff --git a/gdb/serial.c b/gdb/serial.c
>> index a881bbc97c..0ed3d37406 100644
>> --- a/gdb/serial.c
>> +++ b/gdb/serial.c
>> @@ -247,6 +247,7 @@ serial_open_ops_1 (const struct serial_ops *ops, const
>> char *open_name)
>> return NULL;
>> }
>>
>> + scb->name = open_name != NULL ? xstrdup (open_name) : NULL;
>> scb->next = scb_base;
>> scb_base = scb;
>>
>> @@ -291,6 +292,7 @@ serial_fdopen_ops (const int fd, const struct
>> serial_ops *ops)
>>
>> scb = new_serial (ops);
>>
>> + scb->name = NULL;
>> scb->next = scb_base;
>> scb_base = scb;
>>
>> @@ -330,6 +332,8 @@ do_serial_close (struct serial *scb, int really_close)
>> if (really_close)
>> scb->ops->close (scb);
>>
>> + xfree (scb->name);
>> +
>> /* For serial_is_open. */
>> scb->bufp = NULL;
>>
>> diff --git a/gdb/serial.h b/gdb/serial.h
>> index b75b3666e7..d58ab660e9 100644
>> --- a/gdb/serial.h
>> +++ b/gdb/serial.h
>> @@ -240,6 +240,7 @@ struct serial
>> buffer. -ve for sticky errors. */
>> unsigned char *bufp; /* Current byte */
>> unsigned char buf[BUFSIZ]; /* Da buffer itself */
>> + char *name; /* The name of the device or host
>> */
>> struct serial *next; /* Pointer to the next `struct serial *' */
>> int debug_p; /* Trace this serial devices operation. */
>> int async_state; /* Async internal state. */
>> --
>> 2.14.5
>>
>>
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-07 11:19 ` [PATCH 00/23] Multi-target support Philippe Waroquiers
@ 2019-09-08 20:06 ` Pedro Alves
2019-09-08 20:50 ` Philippe Waroquiers
0 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-09-08 20:06 UTC (permalink / raw)
To: Philippe Waroquiers, gdb-patches
On 9/7/19 12:19 PM, Philippe Waroquiers wrote:
> Patch is a nice target :).
> This can be useful e.g. with the valgrind gdbserver, that only
> supports to debug a single process (i.e. the valgrind process that
> runs its embedded gdbserver).
Ahah, yeah, this was one of potential use cases for the multi-target work
that I talked about in last year's cauldron (in the multicore bof).
https://gcc.gnu.org/wiki/cauldron2018?action=AttachFile&do=get&target=palves-TheMulticoreGDBBoF%282018%29.pdf
>
> First, a minor suggestion about the terminology (as introduced in patch 17, and used
> in command names): the rational is that 'target' being already overloaded,
> the wording 'target connection' is used (leading to e.g. the command
> 'info connections').
> I am wondering if the word "connection" is not also too overloaded,
> and too much interpreted as meaning 'a real connection', which might lead to
> some user confusion.
> Maybe other wording could be used instead (such as 'target channel'
> and 'info channels') ? Or maybe another synonym of channel or similar ?
Hmm, I'm not seeing how those would be an improvement over connection,
to be honest.
I'm already used to saying / hearing "open a connection to some target",
so I thought it was natural. E.g., we have this command already:
(gdb) help set auto-connect-native-target
Set whether GDB may automatically connect to the native target.
When on, and GDB is not connected to a target yet, GDB
attempts "run" and other commands with the native target.
Granted, I was the one who invented/added that command and
wrote that text.
But see the much older "target" command:
(gdb) help target
Connect to a target machine or process.
^^^^^^^
The first argument is the type or protocol of the target machine.
Remaining arguments are interpreted by the target protocol. For more
information on the arguments for a particular protocol, type
`help target ' followed by the protocol name.
Also, we have the "disconnect" command, with "disconnect" obviously
being the opposite of "connect", meaning close a connection:
(gdb) target native
Done. Use the "run" command to start a process.
(gdb) maintenance print target-stack
The current target stack is:
- native (Native process)
- None (None)
(gdb) disconnect
(gdb) maintenance print target-stack
The current target stack is:
- None (None)
I'm thinking that it would be natural to use that
command to stop debugging a core dump too, for example,
I think this should be made to work:
(gdb) core core.10872
...
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f176838d3e7 in ?? ()
[Current thread is 1 (LWP 10872)]
(gdb) maint print target-stack
The current target stack is:
- core (Local core dump file)
- None (None)
(gdb) disconnect
You can't do that when your target is `core'
(gdb)
>
> Otherwise, I did a minimal test to see how GDB could connect to 2 different
> valgrind gdbservers (a 64 bits and a 32 bits), but I could not make it work.
> The 2 valgrind I have launched are (in the top of a valgrind build):
>
> ./path to/bin/valgrind --vgdb-error=0 ./memcheck/tests/trivialleak
> ./path to/bin/valgrind --vgdb-error=0 ./memcheck/tests/x86-linux/scalar_exit_group
>
> (gdb) tar rem|lvgdb
> Remote debugging using |lvgdb
> ...
> (gdb) add-inferior -no-connection
> [New inferior 2]
> Added inferior 2
> (gdb) tar rem |lvgdb --pid=16727
> Remote debugging using |lvgdb --pid=16727
> ...
> (gdb) info connection
> Num Name Description
> 1 remote lvgdb Remote serial target in gdb-specific protocol
> * 2 remote lvgdb --pid=16727 Remote serial target in gdb-specific protocol
> (gdb) b main
> Breakpoint 1 at 0x109168: main. (2 locations)
> ????? this has put a break at 2 locations in 2 different inferiors, reporting
> only one address. Wondering if that is the expected
> behaviour. In any case, that behaviour does not look to be a big deal.
Yeah, this behavior shouldn't have changed with this patchset. You should
see the exact same if you were debugging the two inferiors under the
same target. Does it differ for you? You have two locations, because
we create one location per inferior. I don't recall offhand why we only
show one address -- maybe the address is the same for all locations?
> (gdb) infer 1
> [Switching to inferior 1 [Remote target]
> (/home/philippe/valgrind/git/trunk_untouched/memcheck/tests/trivialleak)]
> [Switching to thread 1.1 (Thread 10050)]
> #0 0x0000000004001090 in _start () from /lib64/ld-linux-x86-64.so.2
> (gdb) c
> Continuing.
> Connection 2 (remote lvgdb --pid=16727) does not support multi-target resumption.
> (gdb)
>
> So, the continue command is refused both in inferior 1 and inferior 2.
Does valgrind's gdbserver support non-stop mode? I thought it didn't,
but if it does, then you need to do "maint set target-non-stop on"
before connecting. This is one of the limitations that I described
in patch #17.
Was this with "set schedule-multiple" set to "on", or "off", BTW?
>
> Then when stopping this gdb (which automatically continues the valgrind executables
> till valgrind reports the next error), launching a new gdb, and only connecting to the 32
> bits valgrind gdbserver, here is what I see.
>
> (gdb) tar rem|lvgdb --pid=16727
> Remote debugging using |lvgdb
> ...
> 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
> (gdb) bt
> #0 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
> #1 0x0495fd27 in syscall () at ../sysdeps/unix/sysv/linux/i386/syscall.S:29
> #2 0x0010922c in main () at scalar_exit_group.c:14
> (gdb) c
> Continuing.
> ../../multi-target-v1/gdb/inferior.c:285: internal-error: inferior*
> find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
> Quit this debugging session? (y or n)
>
> So, that looks to be a regression with the valgrind gdbserver.
Thanks. I'll have to try reproducing this.
>
> I did another trial using an abbreviation for -no-connection, but then
> that does not work:
> (gdb) add-inferior -no-connection
> [New inferior 2]
> Added inferior 2
> (gdb) add-inferior -no-conn
> [New inferior 3]
> Added inferior 3 on connection 1 (remote lvgdb --pid=17046)
> (gdb)
>
> Maybe add-inferior should better be converted to the option framework ?
Right, here's what I said in patch #17 about this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I tried converting "add-inferior" to the gdb::option framework, as a
preparatory patch, but that stumbled on the fact that gdb::option does
not support file options yet, for "add-inferior -exec". I have a WIP
patchset that adds that, but it's not a trivial patch, mainly due to
need to integrate readline's filename completion, so I deferred that
to some other time.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here's that WIP patchset in question:
https://github.com/palves/gdb/commits/palves/filename-options
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-08 20:06 ` Pedro Alves
@ 2019-09-08 20:50 ` Philippe Waroquiers
2019-10-16 19:08 ` Pedro Alves
2019-10-16 19:14 ` [PATCH] Avoid inferior_ptid reference in gdb/remote.c (Re: [PATCH 00/23] Multi-target support) Pedro Alves
0 siblings, 2 replies; 68+ messages in thread
From: Philippe Waroquiers @ 2019-09-08 20:50 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
On Sun, 2019-09-08 at 21:06 +0100, Pedro Alves wrote:
> Maybe other wording could be used instead (such as 'target channel'
> > and 'info channels') ? Or maybe another synonym of channel or similar ?
>
> Hmm, I'm not seeing how those would be an improvement over connection,
> to be honest.
Ok, the rational to use connection is convincing.
> (gdb) b main
> > Breakpoint 1 at 0x109168: main. (2 locations)
> > ????? this has put a break at 2 locations in 2 different inferiors, reporting
> > only one address. Wondering if that is the expected
> > behaviour. In any case, that behaviour does not look to be a big deal.
>
> Yeah, this behavior shouldn't have changed with this patchset. You should
> see the exact same if you were debugging the two inferiors under the
> same target. Does it differ for you? You have two locations, because
> we create one location per inferior. I don't recall offhand why we only
> show one address -- maybe the address is the same for all locations?
When using 2 native inferiors, one 64 bit and one 32 bits, origin/master gives:
(gdb) b main
Breakpoint 1 at 0x1168: main. (2 locations)
(gdb) info bre
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x0000000000001168 in main at trivialleak.c:12 inf 1
1.2 y 0x000011d6 in main at scalar_exit_group.c:6 inf 2
(gdb)
But I did some other tests with Ada generics and c++ templates,
and this all shows only one address, while multiple breakpoints have
been set at different addresses.
So, the behaviour with multi-target is normal.
>
> > (gdb) infer 1
> > [Switching to inferior 1 [Remote target]
> > (/home/philippe/valgrind/git/trunk_untouched/memcheck/tests/trivialleak)]
> > [Switching to thread 1.1 (Thread 10050)]
> > #0 0x0000000004001090 in _start () from /lib64/ld-linux-x86-64.so.2
> > (gdb) c
> > Continuing.
> > Connection 2 (remote lvgdb --pid=16727) does not support multi-target resumption.
> > (gdb)
> >
> > So, the continue command is refused both in inferior 1 and inferior 2.
>
> Does valgrind's gdbserver support non-stop mode? I thought it didn't,
> but if it does, then you need to do "maint set target-non-stop on"
> before connecting. This is one of the limitations that I described
> in patch #17.
valgrind gdbserver does not support non-stop mode.
>
> Was this with "set schedule-multiple" set to "on", or "off", BTW?
I just tried with both values, and neither of them allow to continue.
So, with multiple valgrind gdbserver targets, I have not seen how to continue
execution.
>
> > Then when stopping this gdb (which automatically continues the valgrind executables
> > till valgrind reports the next error), launching a new gdb, and only connecting to the 32
> > bits valgrind gdbserver, here is what I see.
> >
> > (gdb) tar rem|lvgdb --pid=16727
> > Remote debugging using |lvgdb
> > ...
> > 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
> > (gdb) bt
> > #0 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
> > #1 0x0495fd27 in syscall () at ../sysdeps/unix/sysv/linux/i386/syscall.S:29
> > #2 0x0010922c in main () at scalar_exit_group.c:14
> > (gdb) c
> > Continuing.
> > ../../multi-target-v1/gdb/inferior.c:285: internal-error: inferior*
> > find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
> > A problem internal to GDB has been detected,
> > further debugging may prove unreliable.
> > Quit this debugging session? (y or n)
> >
> > So, that looks to be a regression with the valgrind gdbserver.
>
> Thanks. I'll have to try reproducing this.
>
> > I did another trial using an abbreviation for -no-connection, but then
> > that does not work:
> > (gdb) add-inferior -no-connection
> > [New inferior 2]
> > Added inferior 2
> > (gdb) add-inferior -no-conn
> > [New inferior 3]
> > Added inferior 3 on connection 1 (remote lvgdb --pid=17046)
> > (gdb)
> >
> > Maybe add-inferior should better be converted to the option framework ?
>
> Right, here's what I said in patch #17 about this:
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> I tried converting "add-inferior" to the gdb::option framework, as a
> preparatory patch, but that stumbled on the fact that gdb::option does
> not support file options yet, for "add-inferior -exec". I have a WIP
> patchset that adds that, but it's not a trivial patch, mainly due to
> need to integrate readline's filename completion, so I deferred that
> to some other time.
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ouch, missed that.
What created the surprise is that add-inferior does not use
something like:
strncmp (opt.get (), "-someoption", strlen (opt.get ())
Thanks
Philippe
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check
2019-09-06 23:34 ` [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check Pedro Alves
@ 2019-09-09 18:07 ` Tom Tromey
0 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 18:07 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> Commit 20f0d60db4fb ("Avoid crash when calling warning too early"),
Pedro> added a "current_top_target () != NULL" check to
Pedro> target_supports_terminal_ours, so this check in exceptions.c is now
Pedro> obsolete.
Nice find. This looks good to me.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t
2019-09-06 23:35 ` [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t Pedro Alves
@ 2019-09-09 18:12 ` Tom Tromey
0 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 18:12 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> The current target_ops::has_execution method takes a ptid_t as
Pedro> parameter, which, in a multi-target world, isn't sufficient to
Pedro> identify the target. This patch prepares to address that, by changing
Pedro> the parameter to an inferior pointer instead. From the inferior,
Pedro> we'll be able to query its target stack to tell which target is
Pedro> beneath.
This looks good to me.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 08/23] Introduce switch_to_inferior_no_thread
2019-09-06 23:28 ` [PATCH 08/23] Introduce switch_to_inferior_no_thread Pedro Alves
@ 2019-09-09 18:42 ` Tom Tromey
2019-10-17 1:07 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 18:42 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> Several places want to switch context to an inferior and its pspace,
Pedro> while at the same time switch to "no thread selected". This commit
Pedro> adds a function that does that, and uses it in a few places. The
Pedro> function is made extern because many more uses will be added in follow
Pedro> up commits.
mi-main.c:run_one_inferior could also be converted.
This isn't directly related to this patch, but I wonder why
set_current_inferior doesn't set the current program space as well. It
seems possibly dangerous to have these globals that can get out of sync.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 10/23] Some get_last_target_status tweaks
2019-09-06 23:28 ` [PATCH 10/23] Some get_last_target_status tweaks Pedro Alves
@ 2019-09-09 18:53 ` Tom Tromey
2019-10-17 1:14 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 18:53 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> - Declare nullify_last_target_wait_ptid in a header, and remove the
Pedro> local extern declaration from linux-fork.c.
Pedro> diff --git a/gdb/infrun.h b/gdb/infrun.h
Pedro> index 30374ee51c..042edbbb66 100644
Pedro> --- a/gdb/infrun.h
Pedro> +++ b/gdb/infrun.h
Pedro> @@ -107,6 +107,8 @@ extern void get_last_target_status (ptid_t *ptid,
Pedro> extern void set_last_target_status (ptid_t ptid,
Pedro> struct target_waitstatus status);
Pedro> +extern void nullify_last_target_wait_ptid ();
This could use an intro comment.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (23 preceding siblings ...)
2019-09-07 11:19 ` [PATCH 00/23] Multi-target support Philippe Waroquiers
@ 2019-09-09 19:09 ` Tom Tromey
2019-09-09 20:22 ` Tom Tromey
25 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 19:09 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> This commit adds multi-target support to GDB. What this means is that
Pedro> with this commit, GDB can now be connected to different targets at the
Pedro> same time. E.g., you can debug a live native process and a core dump
Pedro> at the same time, connect to multiple gdbservers, etc.
Awesome news!
Pedro> Patches 1 to 16 are preparatory patches.
I read these and sent comments where needed. The rest looked ok to me.
I haven't read the remaining patches yet.
Pedro> This surely breaks the build on non-Linux ports as is. I have
Pedro> not tried to adjust the host-specific nat files to function API
Pedro> changes, but I don't envision any serious trouble.
The buildbot should at least exercise a few of these.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string
2019-09-06 23:37 ` [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string Pedro Alves
@ 2019-09-09 20:18 ` Tom Tromey
2019-10-17 2:21 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 20:18 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> This commit extends the CLI a bit for multi-target, in three ways.
Pedro> #1 - New "info connections" command.
This looks good to me. Just one question below.
FWIW I'm fine with the names you chose.
Pedro> + uiout->table_header (name_len + 1, ui_left, "name", "Name");
Why the "+ 1" here?
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
` (24 preceding siblings ...)
2019-09-09 19:09 ` [PATCH 00/23] Multi-target support Tom Tromey
@ 2019-09-09 20:22 ` Tom Tromey
25 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2019-09-09 20:22 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
Pedro> Patch 17 is the actual multi-target patch.
I've looked at all the patches except this one, now.
I don't have time to look at it today.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 17/23] Multi-target support
2019-09-06 23:28 ` [PATCH 17/23] Multi-target support Pedro Alves
@ 2019-09-11 17:11 ` Tom Tromey
2019-10-17 1:54 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2019-09-11 17:11 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> This commit adds multi-target support to GDB. What this means is that
Pedro> with this commit, GDB can now be connected to different targets at the
Pedro> same time. E.g., you can debug a live native process and a core dump
Pedro> at the same time, connect to multiple gdbservers, etc.
Awesome!
I read through the patch, but I can't really claim to understand how all
the parts interrelate. However your overview made sense to me, and I
don't have any conceptual concerns; just the usual sort of thing that
there are lurking bugs. I guess my main fear is that this will
introduce regressions... but on the other hand, I think it's important
direction for gdb, so I'd rather err on the side of moving forward with
it.
Pedro> To fix this,
Pedro> this commit renames gdbserver's target_ops to process_stratum_target.
Pedro> I think this makes sense. There's no concept of target stack in
Pedro> gdbserver, and gdbserver's target_ops really implements a
Pedro> process_stratum-like target.
Makes sense. Sometimes I dream about re-merging the target stacks,
further shrinking the size of the gdbserver fork.
Pedro> - you can only resume more that one target at the same time if all
Pedro> targets support asynchronous debugging, and support non-stop mode.
Pedro> It should be possible to support mixed all-stop + non-stop
Pedro> backends, but that is left for another time. This means that
Pedro> currently in order to do multi-target with gdbserver you need to
Pedro> issue "maint set target-non-stop on". I would like to make that
Pedro> mode be the default, but we're not there yet. Note that I'm
Pedro> talking about how the target backend works, only. User-visible
Pedro> all-stop mode works just fine.
Pedro> - as explained above, connecting to different remote servers at the
Pedro> same time is likely to produce bad results if they don't support the
Pedro> exact set of RSP features.
Are these limitations something that can be noticed when making the
remote connection, or do they require the user to be careful? What
happens if the user forgets or just doesn't know?
Pedro> - thread_info *tp = find_thread_ptid (task_info->ptid);
Pedro> + thread_info *tp = find_thread_ptid (inf->process_target (), task_info->ptid);
There are a few spots in the patch that could use the overload that
accepts an inferior, but instead call the process_target method
directly.
Pedro> +/* Calls target_commit_resume on all targets. */
Pedro> +
Pedro> +static void
Pedro> +commit_resume_all_targets ()
Pedro> +{
Pedro> + scoped_restore_current_thread restore_thread;
Pedro> +
Pedro> + for (inferior *inf : all_non_exited_inferiors ())
Pedro> + if (inf->has_execution ())
Pedro> + {
Pedro> + switch_to_inferior_no_thread (inf);
Pedro> + target_commit_resume ();
Pedro> + }
IIUC this can cause multiple calls to a given target's commit_resume
method. That seems fine (assuming you audited these implementations)
but I suppose it would be good to document this somewhere.
Alternatively I guess gdb would need some kind of iterator that ensures
it only visits each target once.
Pedro> - event_ptid = wait_one (&ws);
Pedro> + wait_one_event event = wait_one ();
Pedro> + target_waitstatus &ws = event.ws;
Pedro> + ptid_t &event_ptid = event.ptid;
I was wondering if these need to be references. It seemed like maybe
they could be const references but I couldn't immediately tell.
Pedro> - For all-stop targets, we only step INFERIOR_PTID and continue others. */
Pedro> + For all-stop targets, we only step INFERIOR_PTID and continue others. */
This looks like extra indentation was added.
Pedro> struct regcache *
Pedro> get_thread_regcache_for_ptid (ptid_t ptid)
Pedro> {
Pedro> - return get_thread_regcache (ptid);
Pedro> + /* This function doesn't take a process_stratum_target parameter
Pedro> + because it's a common/ routine implemented by both gdb and
Pedro> + gdbserver. It always refers to a ptid of the current target. */
It's "gdbsupport/" now.
Pedro> /* The status of the stub support for the various vCont actions. */
Pedro> vCont_action_support supports_vCont;
Pedro> + /* Whether vCont support was probed already. */
Pedro> + bool supports_vCont_probed;
If it's the case that this is only a temporary measure, then I think
this comment should mention that.
Pedro> @@ -6601,6 +6622,8 @@ remote_target::commit_resume ()
Pedro> }
Pedro> vcont_builder.flush ();
Pedro> +
Pedro> + target_async (1);
Pedro> }
I didn't understand this. Like, is it always ok to do this?
Pedro> /* Callback for iterate_over_inferiors. Gets rid of the given
Pedro> inferior. */
Pedro> -static int
Pedro> -dispose_inferior (struct inferior *inf, void *args)
Pedro> +static void
Pedro> +dispose_inferior (inferior *inf)
Pedro> {
Pedro> /* Not all killed inferiors can, or will ever be, removed from the
Pedro> inferior list. Killed inferiors clearly don't need to be killed
Pedro> again, so, we're done. */
Pedro> if (inf->pid == 0)
Pedro> - return 0;
Pedro> + return;
I think the comments here (both the intro comment and the one in the
function) need to be updated, since it seems that just a single inferior
is handled here now, and this is no longer a callback for
iterate_over_inferiors.
I didn't understand this change. Why did it used to iterate but now
does not?
Pedro> target_pass_ctrlc (void)
Pedro> {
Pedro> - current_top_target ()->pass_ctrlc ();
Pedro> + /* Pass the Ctrl-C to the first inferior that has a thread
Pedro> + running. */
Pedro> + for (inferior *inf : all_inferiors ())
Pedro> + {
[...]
Pedro> + return;
I didn't understand this. It seemed to me that a C-c should maybe be
sent to all running inferiors?
I don't actually know this area. Maybe that's obvious now :)
Pedro> /* See target.h. */
Pedro> @@ -3987,10 +4047,8 @@ set_write_memory_permission (const char *args, int from_tty,
Pedro> }
Pedro> void
Pedro> -initialize_targets (void)
Pedro> +_initialize_target (void)
You might as well remove the 'void' when touching the line.
Pedro> - explicit all_matching_threads_iterator (ptid_t filter_ptid);
Pedro> + explicit all_matching_threads_iterator (process_stratum_target *filter_target,
Pedro> + ptid_t filter_ptid);
I guess this could drop the "explicit".
Pedro> - explicit all_matching_threads_range (ptid_t filter_ptid)
Pedro> - : m_filter_ptid (filter_ptid)
Pedro> + explicit all_matching_threads_range (process_stratum_target *filter_target,
Pedro> + ptid_t filter_ptid)
Here too.
Pedro> - explicit all_non_exited_threads_range (ptid_t filter_ptid)
Pedro> - : m_filter_ptid (filter_ptid)
Pedro> + explicit all_non_exited_threads_range (process_stratum_target *filter_target,
Pedro> + ptid_t filter_ptid)
Pedro> + : m_filter_target (filter_target), m_filter_ptid (filter_ptid)
And here.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 07/23] Delete unnecessary code from kill_command
2019-09-06 23:36 ` [PATCH 07/23] Delete unnecessary code from kill_command Pedro Alves
@ 2019-10-01 10:19 ` Aktemur, Tankut Baris
2019-10-01 13:28 ` Aktemur, Tankut Baris
0 siblings, 1 reply; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-01 10:19 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
Hi,
* On September 7, 2019 1:28 AM, Pedro Alves wrote:
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index d7a7e6f933..a12dba23aa 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -2503,20 +2503,6 @@ kill_command (const char *arg, int from_tty)
> printf_unfiltered (_("[Inferior %d (%s) killed]\n"),
> infnum, pid_str.c_str ());
>
> - /* If we still have other inferiors to debug, then don't mess with
> - with their threads. */
> - if (!have_inferiors ())
> - {
> - init_thread_list (); /* Destroy thread info. */
Removing 'init_thread_list' skips re-initialization of the
'highest_thread_num' global back to zero. In turn, this causes the
following failure:
FAIL: gdb.arch/i386-mpx-simple_segv.exp: print nopass stop: display
because the output becomes
Thread 1 "i386-mpx-simple" received signal SIGSEGV
instead of
Program received signal SIGSEGV
Regards,
-Baris
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 07/23] Delete unnecessary code from kill_command
2019-10-01 10:19 ` Aktemur, Tankut Baris
@ 2019-10-01 13:28 ` Aktemur, Tankut Baris
0 siblings, 0 replies; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-01 13:28 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
* On October 1, 2019 12:19 PM, Aktemur, Tankut Baris wrote:
>
> Hi,
>
> * On September 7, 2019 1:28 AM, Pedro Alves wrote:
> >
> > diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> > index d7a7e6f933..a12dba23aa 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -2503,20 +2503,6 @@ kill_command (const char *arg, int from_tty)
> > printf_unfiltered (_("[Inferior %d (%s) killed]\n"),
> > infnum, pid_str.c_str ());
> >
> > - /* If we still have other inferiors to debug, then don't mess with
> > - with their threads. */
> > - if (!have_inferiors ())
> > - {
> > - init_thread_list (); /* Destroy thread info. */
>
> Removing 'init_thread_list' skips re-initialization of the
> 'highest_thread_num' global back to zero. In turn, this causes the
> following failure:
>
> FAIL: gdb.arch/i386-mpx-simple_segv.exp: print nopass stop: display
>
Please ignore this. The failure is caused by another patch, not this one.
Regards,
-Baris
> because the output becomes
>
> Thread 1 "i386-mpx-simple" received signal SIGSEGV
>
> instead of
>
> Program received signal SIGSEGV
>
> Regards,
> -Baris
>
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 68+ messages in thread
* RE: [PATCH 01/23] Preserve selected thread in all-stop w/ background execution
2019-09-06 23:28 ` [PATCH 01/23] Preserve selected thread in all-stop w/ background execution Pedro Alves
@ 2019-10-09 9:36 ` Aktemur, Tankut Baris
2019-10-16 23:54 ` [PATCH v1.1 " Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-09 9:36 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3872 bytes --]
* On September 7, 2019 1:28 AM, Pedro Alves wrote:
>
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index a9588f896a..9c888aa72f 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -3048,6 +3048,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
>
> finish_state.release ();
>
> + /* If we've switched threads above, switch back to the previously
> + current thread. We don't want the user to see a different
> + selected thread. */
> + switch_to_thread (cur_thr);
> +
> /* Tell the event loop to wait for it to stop. If the target
> supports asynchronous execution, it'll do this from within
> target_resume. */
> @@ -3702,14 +3707,11 @@ fetch_inferior_event (void *client_data)
> set_current_traceframe (-1);
> }
>
> - gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
> -
> - if (non_stop)
> - /* In non-stop mode, the user/frontend should not notice a thread
> - switch due to internal events. Make sure we reverse to the
> - user selected thread and frame after handling the event and
> - running any breakpoint commands. */
> - maybe_restore_thread.emplace ();
> + /* The user/frontend should not notice a thread switch due to
> + internal events. Make sure we revert to the user selected
> + thread and frame after handling the event and running any
> + breakpoint commands. */
> + scoped_restore_current_thread restore_thread;
>
Because this increases the refcount of the current thread, in case the
fetched inferior event denotes a thread exit, the thread will not be deleted
right away. A non-deleted but exited thread stays in the inferior's thread
list. This, in turn, causes the "init_thread_list" call in inferior.c to
be skipped. As a side effect, a regression is observed in
gdb.arch/i386-mpx-simple_segv.exp
IMHO, the 'any_thread_p' predicate should be updated. This predicate is used
in two places (one in 'inferior.c' and the other in 'mi/mi-main.c'). Both
uses, I believe, are in fact interested in whether there are any non-exited
threads. I'd suggest updating 'any_thread_p' to 'any_non_exited_thread_p'.
I'm attaching a patch that can be used to test.
> overlay_cache_invalid = 1;
> /* Flush target cache before starting to handle each event. Target
> @@ -3786,6 +3788,19 @@ fetch_inferior_event (void *client_data)
> inferior_event_handler (INF_EXEC_COMPLETE, NULL);
> cmd_done = 1;
> }
> +
> + /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
> + previously selected thread is gone. We have two
> + choices - switch to no thread selected, or restore the
> + previously selected thread (now exited). We chose the
> + later, just because that's what GDB used to do. After
> + this, "info threads" says "The current thread <Thread
> + ID 2> has terminated." instead of "No thread
> + selected.". */
> + if (!non_stop
> + && cmd_done
> + && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
> + restore_thread.dont_restore ();
> }
> }
>
The comment and the code seem to contradict each other. The comment says
"if we got a TARGET_WAITKIND_NO_RESUMED" whereas the condition is
ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED
Should TARGET_WAITKIND_THREAD_EXITED, TARGET_WAITKIND_EXITED, and
TARGET_WAITKIND_SIGNALLED be also included in the condition? They also mean
that the thread is gone, right?
Regards,
-Baris
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
[-- Attachment #2: any_thread_p.patch --]
[-- Type: application/octet-stream, Size: 1974 bytes --]
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index d00cc3fb8f..ce04fa6e42 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -579,8 +579,8 @@ all_threads_safe ()
extern int thread_count (process_stratum_target *proc_target);
-/* Return true if we have any thread in any inferior. */
-extern bool any_thread_p ();
+/* Return true if we have any non-exited thread in any inferior. */
+extern bool any_non_exited_thread_p ();
/* Switch context to thread THR. Also sets the STOP_PC global. */
extern void switch_to_thread (struct thread_info *thr);
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 96d38f865d..9e254a96af 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -249,7 +249,7 @@ inferior_appeared (struct inferior *inf, int pid)
{
/* If this is the first inferior with threads, reset the global
thread id. */
- if (!any_thread_p ())
+ if (!any_non_exited_thread_p ())
init_thread_list ();
inf->pid = pid;
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 5dc436bfd8..ee690e6daf 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -1991,7 +1991,7 @@ mi_execute_command (const char *cmd, int from_tty)
top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ()
/* Don't try report anything if there are no threads --
the program is dead. */
- && any_thread_p ()
+ && any_non_exited_thread_p ()
/* If the command already reports the thread change, no need to do it
again. */
&& !command_notifies_uscc_observer (command.get ()))
diff --git a/gdb/thread.c b/gdb/thread.c
index 9dafca57bf..37e007d9c5 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -581,9 +581,9 @@ iterate_over_threads (int (*callback) (struct thread_info *, void *),
/* See gdbthread.h. */
bool
-any_thread_p ()
+any_non_exited_thread_p ()
{
- for (thread_info *tp ATTRIBUTE_UNUSED : all_threads ())
+ for (thread_info *tp ATTRIBUTE_UNUSED : all_non_exited_threads ())
return true;
return false;
}
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet
2019-09-06 23:36 ` [PATCH 14/23] Tweak handling of remote errors in response to resumption packet Pedro Alves
@ 2019-10-09 13:35 ` Aktemur, Tankut Baris
2019-10-17 0:54 ` [PATCH 14.5/23] Avoid another inferior_ptid reference in gdb/remote.c (Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet) Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-09 13:35 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 5748 bytes --]
* On September 7, 2019 1:28 AM, Pedro Alves wrote:
>
> With current master, on a Fedora 27 machine with a kernel with buggy
> watchpoint support, I see:
>
> (gdb) PASS: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: hardware breakpoints work
> continue
> Continuing.
> warning: Remote failure reply: E01
> Remote communication error. Target disconnected.: Connection reset by peer.
> (gdb) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: watchpoints work
> continue
> The program is not being run.
> (gdb) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: breakpoint after the first fork (the program
> is no longer running)
>
> The FAILs themselves aren't what's interesting here. What is
> interesting is that with the main multi-target patch applied, I was getting this:
>
> (gdb) PASS: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: hardware breakpoints work
> continue
> Continuing.
> warning: Remote failure reply: E01
> /home/pedro/brno/pedro/gdb/binutils-gdb-2/build/../src/gdb/inferior.c:285: internal-error: inferior*
> find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
> Quit this debugging session? (y or n) FAIL: gdb.threads/watchpoint-fork.exp: parent: singlethreaded: watchpoints
> work (GDB internal error)
>
> The problem is that in remote_target::wait_as, we're hitting this:
>
> switch (buf[0])
> {
> case 'E': /* Error of some sort. */
> /* We're out of sync with the target now. Did it continue or
> not? Not is more likely, so report a stop. */
> rs->waiting_for_stop_reply = 0;
>
> warning (_("Remote failure reply: %s"), buf);
> status->kind = TARGET_WAITKIND_STOPPED;
> status->value.sig = GDB_SIGNAL_0;
> break;
>
> which leaves event_ptid as null_ptid. At the end of the function, we then reach:
>
> else if (status->kind != TARGET_WAITKIND_EXITED
> && status->kind != TARGET_WAITKIND_SIGNALLED)
> {
> if (event_ptid != null_ptid)
> record_currthread (rs, event_ptid);
> else
> event_ptid = inferior_ptid; <<<<< here
> }
>
> and the trouble is that with the multi-target patch, we'll get here
> with inferior_ptid as null_ptid too. That is done exactly to find
> these implicit assumptions that inferior_ptid is a good choice for
> default thread, which isn't generaly true.
>
> I first thought of fixing this in the "case 'E'" path, but, given that
> this "event_ptid = inferior_ptid" path is also taken when the remote
> target does not support threads at all, no thread-related packets or
> extensions, it's better to fix it in latter path, to handle all
> scenarios that miss reporting a thread.
>
> That's what this patch does.
>
A similar problem could occur in case of an exit event, too -- for instance,
if the remote target does not support the multi-process packet or if the
packet is disabled.
This can be checked by modifying the test
testsuite/gdb.server/connect-without-multi-process.exp
to continue the inferior to termination.
To also catch the process exit case, the coverage of the patch can be
expanded. Instead of
else
/* A process exit. Invalidate our notion of current thread. */
record_currthread (rs, minus_one_ptid);
the following can be done:
else
{
/* A process exit. Invalidate our notion of current thread. */
record_currthread (rs, minus_one_ptid);
/* It's possible that the packet did not include a pid. */
if (event_ptid == null_ptid)
event_ptid = first_remote_resumed_thread (this);
/* EVENT_PTID could still be NULL_PTID. Double-check. */
if (event_ptid == null_ptid)
event_ptid = magic_null_ptid;
}
I'm attaching these as a patch in case one wants to test. It should be applied
after the main multi-target patch.
Regards,
-Baris
> gdb/ChangeLog:
> yyyy-mm-dd Pedro Alves <palves@redhat.com>
>
> * remote.c (first_remote_resumed_thread): New.
> (remote_target::wait_as): Use it as default event_ptid instead of
> inferior_ptid.
> ---
> gdb/remote.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/remote.c b/gdb/remote.c
> index bed861c65d..eacaf11976 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -7703,6 +7703,17 @@ remote_target::wait_ns (ptid_t ptid, struct target_waitstatus *status, int optio
> }
> }
>
> +/* Return the first resumed thread. */
> +
> +static ptid_t
> +first_remote_resumed_thread ()
> +{
> + for (thread_info *tp : all_non_exited_threads (minus_one_ptid))
> + if (tp->resumed)
> + return tp->ptid;
> + return null_ptid;
> +}
> +
> /* Wait until the remote machine stops, then return, storing status in
> STATUS just as `wait' would. */
>
> @@ -7839,7 +7850,7 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
> if (event_ptid != null_ptid)
> record_currthread (rs, event_ptid);
> else
> - event_ptid = inferior_ptid;
> + event_ptid = first_remote_resumed_thread ();
> }
> else
> /* A process exit. Invalidate our notion of current thread. */
> --
> 2.14.5
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
[-- Attachment #2: remote_event_ptid.patch --]
[-- Type: application/octet-stream, Size: 1763 bytes --]
diff --git a/gdb/remote.c b/gdb/remote.c
index ff75204ee8..d036dcf9cf 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7919,8 +7919,16 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
event_ptid = first_remote_resumed_thread (this);
}
else
- /* A process exit. Invalidate our notion of current thread. */
- record_currthread (rs, minus_one_ptid);
+ {
+ /* A process exit. Invalidate our notion of current thread. */
+ record_currthread (rs, minus_one_ptid);
+ /* It's possible that the packet did not include a pid. */
+ if (event_ptid == null_ptid)
+ event_ptid = first_remote_resumed_thread (this);
+ /* EVENT_PTID could still be NULL_PTID. Double-check. */
+ if (event_ptid == null_ptid)
+ event_ptid = magic_null_ptid;
+ }
return event_ptid;
}
diff --git a/gdb/testsuite/gdb.server/connect-without-multi-process.exp b/gdb/testsuite/gdb.server/connect-without-multi-process.exp
index fba20a6a0b..36b42207e2 100644
--- a/gdb/testsuite/gdb.server/connect-without-multi-process.exp
+++ b/gdb/testsuite/gdb.server/connect-without-multi-process.exp
@@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. */
# Check that we can connect to GDBserver with the multiprocess
-# extensions disabled, and run to main.
+# extensions disabled, run to main, and finish the process.
load_lib gdbserver-support.exp
@@ -52,6 +52,9 @@ proc do_test {multiprocess} {
"target $gdbserver_protocol"
gdb_test "continue" "main .*" "continue to main"
+
+ # Also test the termination because the 'W' packet differs
+ gdb_test "continue" ".* exited normally.*" "continue to termination"
}
foreach multiprocess { "off" "auto" } {
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 18/23] Add multi-target tests
2019-09-06 23:28 ` [PATCH 18/23] Add multi-target tests Pedro Alves
@ 2019-10-09 16:01 ` Aktemur, Tankut Baris
2019-10-17 0:55 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-09 16:01 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
* On September 7, 2019 1:28 AM, Pedro Alves wrote:
>
> This adds a testcase exercising multi-target features. It spawns 6
> inferiors, like this:
>
> inferior 1 -> native
> inferior 2 -> extended-remote 1
> inferior 3 -> core
> inferior 4 -> native
> inferior 5 -> extended-remote 2
> inferior 6 -> core
>
> and then tests various details, including:
>
> - running to breakpoints
>
> - interrupting with Ctrl-C and "interrupt -a"
>
> - "next" bouncing between two breakpoints in two threads running in
> different targets.
>
> - since we have cores and live inferiors mixed in the same session,
> this makes sure that gdb doesn't try to remove a core dump's
> threads.
>
> - all-stop and non-stop modes.
>
> This testcase caught a _lot_ of bugs in development.
>
> diff --git a/gdb/testsuite/gdb.multi/multi-target.c b/gdb/testsuite/gdb.multi/multi-target.c
> new file mode 100644
> index 0000000000..856226e6b9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.multi/multi-target.c
> @@ -0,0 +1,100 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2017-2019 Free Software Foundation, Inc.
> +
The year should be just 2019. Right?
> diff --git a/gdb/testsuite/gdb.multi/multi-target.exp b/gdb/testsuite/gdb.multi/multi-target.exp
> new file mode 100644
> index 0000000000..3b71e7446b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.multi/multi-target.exp
> @@ -0,0 +1,361 @@
> +# Copyright 2017-2019 Free Software Foundation, Inc.
> +
Same here.
Regards,
-Baris
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/23] Multi-target support
2019-09-08 20:50 ` Philippe Waroquiers
@ 2019-10-16 19:08 ` Pedro Alves
2019-10-16 19:14 ` [PATCH] Avoid inferior_ptid reference in gdb/remote.c (Re: [PATCH 00/23] Multi-target support) Pedro Alves
1 sibling, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-16 19:08 UTC (permalink / raw)
To: Philippe Waroquiers, gdb-patches
On 9/8/19 9:50 PM, Philippe Waroquiers wrote:
>>> (gdb) infer 1
>>> [Switching to inferior 1 [Remote target]
>>> (/home/philippe/valgrind/git/trunk_untouched/memcheck/tests/trivialleak)]
>>> [Switching to thread 1.1 (Thread 10050)]
>>> #0 0x0000000004001090 in _start () from /lib64/ld-linux-x86-64.so.2
>>> (gdb) c
>>> Continuing.
>>> Connection 2 (remote lvgdb --pid=16727) does not support multi-target resumption.
>>> (gdb)
>>>
>>> So, the continue command is refused both in inferior 1 and inferior 2.
I've finally debugged this, it was a simple bug in target.c. We need this:
@@ -2181,7 +2181,7 @@ user_visible_resume_ptid (int step)
process_stratum_target *
user_visible_resume_target (ptid_t resume_ptid)
{
- return (resume_ptid == minus_one_ptid
+ return (resume_ptid == minus_one_ptid && sched_multi
? NULL
: current_inferior ()->process_target ());
I'm folding that into the main multi-target patch, which introduces
that function.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH] Avoid inferior_ptid reference in gdb/remote.c (Re: [PATCH 00/23] Multi-target support)
2019-09-08 20:50 ` Philippe Waroquiers
2019-10-16 19:08 ` Pedro Alves
@ 2019-10-16 19:14 ` Pedro Alves
1 sibling, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-16 19:14 UTC (permalink / raw)
To: Philippe Waroquiers, gdb-patches
Pedro Alves wrote:
On 9/8/19 9:50 PM, Philippe Waroquiers wrote:
>> Then when stopping this gdb (which automatically continues the valgrind executables
>> till valgrind reports the next error), launching a new gdb, and only connecting to the 32
>> bits valgrind gdbserver, here is what I see.
>>
>> (gdb) tar rem|lvgdb --pid=16727
>> Remote debugging using |lvgdb
>> ...
>> 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
>> (gdb) bt
>> #0 0x04001092 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
>> #1 0x0495fd27 in syscall () at ../sysdeps/unix/sysv/linux/i386/syscall.S:29
>> #2 0x0010922c in main () at scalar_exit_group.c:14
>> (gdb) c
>> Continuing.
>> ../../multi-target-v1/gdb/inferior.c:285: internal-error: inferior*
>> find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.
>> A problem internal to GDB has been detected,
>> further debugging may prove unreliable.
>> Quit this debugging session? (y or n)
>>
>> So, that looks to be a regression with the valgrind gdbserver.
> Thanks. I'll have to try reproducing this.
Thanks for spotting this. It was a regression against any remote target
that does not support the remote protocol multi-process extensions.
This patch fixes it.
From cd7e386563fcdb43d647ce499c5e05b85d44ba68 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Tue, 15 Oct 2019 20:01:55 +0100
Subject: [PATCH] Avoid inferior_ptid reference in gdb/remote.c
The multi-target patch makes inferior_ptid point to null_ptid before
calling into target_wait, which catches bad uses of inferior_ptid,
since the current selected thread in gdb shouldn't have much relation
to the thread that reports an event.
One such bad use is found in remote_target::remote_parse_stop_reply,
where we handle the 'W' or 'X' packets (process exit), and the remote
target does not support the multi-process extensions, i.e., it does
not report the PID of the process that exited.
With the multi-target patch, that would result in a failed assertion,
trying to find the inferior for process pid 0.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* remote.c (remote_target::remote_parse_stop_reply) <W/X packets>:
If no process is specified, assume remote's current process
instead of inferior_ptid.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.server/no-multi-process.exp: New file.
---
gdb/remote.c | 6 ++--
gdb/testsuite/gdb.server/no-multi-process.exp | 40 +++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 3 deletions(-)
create mode 100644 gdb/testsuite/gdb.server/no-multi-process.exp
diff --git a/gdb/remote.c b/gdb/remote.c
index b6d7bb0a6d..05c8b336f2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7511,7 +7511,6 @@ Packet: '%s'\n"),
case 'W': /* Target exited. */
case 'X':
{
- int pid;
ULONGEST value;
/* GDB used to accept only 2 hex chars here. Stubs should
@@ -7535,8 +7534,9 @@ Packet: '%s'\n"),
event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
}
- /* If no process is specified, assume inferior_ptid. */
- pid = inferior_ptid.pid ();
+ /* If no process is specified, assume the remote's current
+ process. */
+ int pid = get_remote_state ()->general_thread.pid ();
if (*p == '\0')
;
else if (*p == ';')
diff --git a/gdb/testsuite/gdb.server/no-multi-process.exp b/gdb/testsuite/gdb.server/no-multi-process.exp
new file mode 100644
index 0000000000..0e946dba6f
--- /dev/null
+++ b/gdb/testsuite/gdb.server/no-multi-process.exp
@@ -0,0 +1,40 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Smoke tests for debugging against a remote target with no
+# multi-process extensions support.
+
+load_lib gdbserver-support.exp
+
+if {[skip_gdbserver_tests]} {
+ return
+}
+
+standard_testfile server.c
+if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] {
+ return -1
+}
+
+# Make sure we're disconnected, in case we're testing with an
+# extended-remote board, therefore already connected.
+gdb_test "disconnect" ".*"
+
+gdb_test_no_output "set remote multiprocess-feature-packet off"
+gdbserver_run ""
+
+# The W/X packets do not include the PID of the exiting process
+# without the multi-process extensions. Check that we handle process
+# exit correctly in that case.
+gdb_continue_to_end "" continue 1
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v1.1 01/23] Preserve selected thread in all-stop w/ background execution
2019-10-09 9:36 ` Aktemur, Tankut Baris
@ 2019-10-16 23:54 ` Pedro Alves
2019-10-17 10:21 ` Aktemur, Tankut Baris
0 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-10-16 23:54 UTC (permalink / raw)
To: Aktemur, Tankut Baris, gdb-patches
On 10/9/19 10:36 AM, Aktemur, Tankut Baris wrote:
> * On September 7, 2019 1:28 AM, Pedro Alves wrote:
>>
>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>> index a9588f896a..9c888aa72f 100644
>> --- a/gdb/infrun.c
>> +++ b/gdb/infrun.c
>> @@ -3048,6 +3048,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
>>
>> finish_state.release ();
>>
>> + /* If we've switched threads above, switch back to the previously
>> + current thread. We don't want the user to see a different
>> + selected thread. */
>> + switch_to_thread (cur_thr);
>> +
>> /* Tell the event loop to wait for it to stop. If the target
>> supports asynchronous execution, it'll do this from within
>> target_resume. */
>> @@ -3702,14 +3707,11 @@ fetch_inferior_event (void *client_data)
>> set_current_traceframe (-1);
>> }
>>
>> - gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
>> -
>> - if (non_stop)
>> - /* In non-stop mode, the user/frontend should not notice a thread
>> - switch due to internal events. Make sure we reverse to the
>> - user selected thread and frame after handling the event and
>> - running any breakpoint commands. */
>> - maybe_restore_thread.emplace ();
>> + /* The user/frontend should not notice a thread switch due to
>> + internal events. Make sure we revert to the user selected
>> + thread and frame after handling the event and running any
>> + breakpoint commands. */
>> + scoped_restore_current_thread restore_thread;
>>
>
> Because this increases the refcount of the current thread, in case the
> fetched inferior event denotes a thread exit, the thread will not be deleted
> right away. A non-deleted but exited thread stays in the inferior's thread
> list. This, in turn, causes the "init_thread_list" call in inferior.c to
> be skipped. As a side effect, a regression is observed in
>
> gdb.arch/i386-mpx-simple_segv.exp
Thanks for spotting this. I don't have MPX on my machine, so I'm not
exactly sure the sequence of events that lead to a failure in that test,
but I found a way to reproduce a related problem without MPX, and wrote
a test based on it.
>
> IMHO, the 'any_thread_p' predicate should be updated. This predicate is used
> in two places (one in 'inferior.c' and the other in 'mi/mi-main.c'). Both
> uses, I believe, are in fact interested in whether there are any non-exited
> threads. I'd suggest updating 'any_thread_p' to 'any_non_exited_thread_p'.
>
I'm really not sure about that. Exited threads have a thread number still,
as long as they're on the list. Calling init_thread_list resets the
global thread counter, meaning that you could end up with multiple threads
with the same number, until the exited threads are purged.
I think instead a delete_exited_threads call in inferior_appeared
is better.
>> overlay_cache_invalid = 1;
>> /* Flush target cache before starting to handle each event. Target
>> @@ -3786,6 +3788,19 @@ fetch_inferior_event (void *client_data)
>> inferior_event_handler (INF_EXEC_COMPLETE, NULL);
>> cmd_done = 1;
>> }
>> +
>> + /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
>> + previously selected thread is gone. We have two
>> + choices - switch to no thread selected, or restore the
>> + previously selected thread (now exited). We chose the
>> + later, just because that's what GDB used to do. After
>> + this, "info threads" says "The current thread <Thread
>> + ID 2> has terminated." instead of "No thread
>> + selected.". */
>> + if (!non_stop
>> + && cmd_done
>> + && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
>> + restore_thread.dont_restore ();
>> }
>> }
>>
>
> The comment and the code seem to contradict each other. The comment says
> "if we got a TARGET_WAITKIND_NO_RESUMED" whereas the condition is
>
> ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED
I don't think they're contradicting, actually.
When the 'if' condition is true, we won't restore the selected thread.
So we if we got a TARGET_WAITKIND_NO_RESUMED, we restore the previous
selected thread. For all other event kinds, we won't restore.
>
> Should TARGET_WAITKIND_THREAD_EXITED, TARGET_WAITKIND_EXITED, and
> TARGET_WAITKIND_SIGNALLED be also included in the condition? They also mean
> that the thread is gone, right?
Not necessarily. With checkpoint, gdb automatically switches to
another checkpoint on TARGET_WAITKIND_EXITED/TARGET_WAITKIND_SIGNALLED:
(gdb) checkpoint
checkpoint 1: fork returned pid 10741.
(gdb) c
Continuing.
[Inferior 1 (process 10737) exited normally]
[Switching to process 10741]
(gdb) info threads
Id Target Id Frame
* 1 process 10741 "main" main () at main.cc:21
(gdb)
Here's an updated patch. I believe it should fix the MPX issue too.
From 3de0c8d9df4f0979062718c745226e493206a305 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 17 Oct 2019 00:37:02 +0100
Subject: [PATCH] Preserve selected thread in all-stop w/ background execution
In non-stop mode, if you resume the program in the background (with
"continue&", for example), then gdb makes sure to not switch the
current thread behind your back. That means that you can be sure that
the commands you type apply to the thread you selected, even if some
other thread that was running in the background hits some event just
while you're typing.
In all-stop mode, however, if you resume the program in the
background, gdb let's the current thread switch behind your back.
This is bogus, of course. All-stop and non-stop background
resumptions should behave the same.
This patch fixes that, and adds a testcase that exposes the bad
behavior in current master.
The fork-running-state.exp changes are necessary because that
preexisting testcase was expecting the old behavior:
Before:
continue &
Continuing.
(gdb)
[Attaching after process 8199 fork to child process 8203]
[New inferior 2 (process 8203)]
info threads
Id Target Id Frame
1.1 process 8199 "fork-running-st" (running)
* 2.1 process 8203 "fork-running-st" (running)
(gdb)
After:
continue &
Continuing.
(gdb)
[Attaching after process 24660 fork to child process 24664]
[New inferior 2 (process 24664)]
info threads
Id Target Id Frame
* 1.1 process 24660 "fork-running-st" (running)
2.1 process 24664 "fork-running-st" (running)
(gdb)
Here we see that before this patch GDB switches current inferior to
the new inferior behind the user's back, as a side effect of handling
the fork.
The delete_exited_threads call in inferior_appeared is there to fix an
issue that Baris found in a previous version of this patch. The
fetch_inferior_event change increases the refcount of the current
thread, and in case the fetched inferior event denotes a thread exit,
the thread will not be deleted right away. A non-deleted but exited
thread stays in the inferior's thread list. This, in turn, causes the
"init_thread_list" call in inferior.c to be skipped. A consequence is
that the global thread ID counter is not restarted if the current
thread exits, and then the inferior is restarted:
(gdb) start
Temporary breakpoint 1 at 0x4004d6: file main.c, line 21.
Starting program: /tmp/main
Temporary breakpoint 1, main () at main.c:21
21 foo ();
(gdb) info threads -gid
Id GId Target Id Frame
* 1 1 process 16106 "main" main () at main.c:21
(gdb) c
Continuing.
[Inferior 1 (process 16106) exited normally]
(gdb) start
Temporary breakpoint 2 at 0x4004d6: file main.c, line 21.
Starting program: /tmp/main
Temporary breakpoint 2, main () at main.c:21
21 foo ();
(gdb) info threads -gid
Id GId Target Id Frame
* 1 2 process 16138 "main" main () at main.c:21
^^^
Notice that GId == 2 above. It should have been "1" instead.
The new tids-git-reset.exp testcase exercises the problem above.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdbthread.h (scoped_restore_current_thread)
<dont_restore, restore, m_dont_restore>: Declare.
* thread.c (thread_alive): Add assertion. Return bool.
(switch_to_thread_if_alive): New.
(prune_threads): Switch inferior/thread.
(print_thread_info_1): Switch thread before calling target methods.
(scoped_restore_current_thread::restore): New, factored out from
...
(scoped_restore_current_thread::~scoped_restore_current_thread):
... this.
(scoped_restore_current_thread::scoped_restore_current_thread):
Add assertion.
(thread_apply_all_command, thread_select): Use
switch_to_thread_if_alive.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.base/fork-running-state.exp (do_test): Adjust expected
output.
* gdb.threads/async.c: New.
* gdb.threads/async.exp: New.
* gdb.multi/tids-gid-reset.c: New.
* gdb.multi/tids-gid-reset.exp: New.
---
gdb/gdbthread.h | 6 ++
gdb/inferior.c | 1 +
gdb/infrun.c | 31 ++++++---
gdb/testsuite/gdb.base/fork-running-state.exp | 17 +----
gdb/testsuite/gdb.multi/tids-gid-reset.c | 22 ++++++
gdb/testsuite/gdb.multi/tids-gid-reset.exp | 96 ++++++++++++++++++++++++++
gdb/testsuite/gdb.threads/async.c | 70 +++++++++++++++++++
gdb/testsuite/gdb.threads/async.exp | 98 +++++++++++++++++++++++++++
gdb/thread.c | 19 +++++-
9 files changed, 337 insertions(+), 23 deletions(-)
create mode 100644 gdb/testsuite/gdb.multi/tids-gid-reset.c
create mode 100644 gdb/testsuite/gdb.multi/tids-gid-reset.exp
create mode 100644 gdb/testsuite/gdb.threads/async.c
create mode 100644 gdb/testsuite/gdb.threads/async.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 370141e688..62b73fb83b 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -645,7 +645,13 @@ public:
DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread);
+ /* Cancel restoring on scope exit. */
+ void dont_restore () { m_dont_restore = true; }
+
private:
+ void restore ();
+
+ bool m_dont_restore = false;
/* Use the "class" keyword here, because of a clash with a "thread_info"
function in the Darwin API. */
class thread_info *m_thread;
diff --git a/gdb/inferior.c b/gdb/inferior.c
index cf2175494d..fa1fd3fc10 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -255,6 +255,7 @@ inferior_appeared (struct inferior *inf, int pid)
{
/* If this is the first inferior with threads, reset the global
thread id. */
+ delete_exited_threads ();
if (!any_thread_p ())
init_thread_list ();
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 07aebfa678..6da95e0584 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3046,6 +3046,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
finish_state.release ();
+ /* If we've switched threads above, switch back to the previously
+ current thread. We don't want the user to see a different
+ selected thread. */
+ switch_to_thread (cur_thr);
+
/* Tell the event loop to wait for it to stop. If the target
supports asynchronous execution, it'll do this from within
target_resume. */
@@ -3700,14 +3705,11 @@ fetch_inferior_event (void *client_data)
set_current_traceframe (-1);
}
- gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
-
- if (non_stop)
- /* In non-stop mode, the user/frontend should not notice a thread
- switch due to internal events. Make sure we reverse to the
- user selected thread and frame after handling the event and
- running any breakpoint commands. */
- maybe_restore_thread.emplace ();
+ /* The user/frontend should not notice a thread switch due to
+ internal events. Make sure we revert to the user selected
+ thread and frame after handling the event and running any
+ breakpoint commands. */
+ scoped_restore_current_thread restore_thread;
overlay_cache_invalid = 1;
/* Flush target cache before starting to handle each event. Target
@@ -3784,6 +3786,19 @@ fetch_inferior_event (void *client_data)
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
cmd_done = 1;
}
+
+ /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
+ previously selected thread is gone. We have two
+ choices - switch to no thread selected, or restore the
+ previously selected thread (now exited). We chose the
+ later, just because that's what GDB used to do. After
+ this, "info threads" says "The current thread <Thread
+ ID 2> has terminated." instead of "No thread
+ selected.". */
+ if (!non_stop
+ && cmd_done
+ && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+ restore_thread.dont_restore ();
}
}
diff --git a/gdb/testsuite/gdb.base/fork-running-state.exp b/gdb/testsuite/gdb.base/fork-running-state.exp
index 98733a6cc1..143b5ce714 100644
--- a/gdb/testsuite/gdb.base/fork-running-state.exp
+++ b/gdb/testsuite/gdb.base/fork-running-state.exp
@@ -98,30 +98,19 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
set not_nl "\[^\r\n\]*"
- if {$detach_on_fork == "on" && $non_stop == "on" && $follow_fork == "child"} {
+ if {$detach_on_fork == "on" && $follow_fork == "child"} {
gdb_test "info threads" \
" 2.1 ${not_nl}\\\(running\\\).*No selected thread.*"
- } elseif {$detach_on_fork == "on" && $follow_fork == "child"} {
- gdb_test "info threads" \
- "\\\* 2.1 ${not_nl}\\\(running\\\)"
} elseif {$detach_on_fork == "on"} {
gdb_test "info threads" \
"\\\* 1 ${not_nl}\\\(running\\\)"
- } elseif {$non_stop == "on"
- || ($schedule_multiple == "on" && $follow_fork == "parent")} {
+ } elseif {$non_stop == "on" || $schedule_multiple == "on"} {
# Both parent and child should be marked running, and the
# parent should be selected.
gdb_test "info threads" \
[multi_line \
"\\\* 1.1 ${not_nl} \\\(running\\\)${not_nl}" \
" 2.1 ${not_nl} \\\(running\\\)"]
- } elseif {$schedule_multiple == "on" && $follow_fork == "child"} {
- # Both parent and child should be marked running, and the
- # child should be selected.
- gdb_test "info threads" \
- [multi_line \
- " 1.1 ${not_nl} \\\(running\\\)${not_nl}" \
- "\\\* 2.1 ${not_nl} \\\(running\\\)"]
} else {
set test "only $follow_fork marked running"
gdb_test_multiple "info threads" $test {
@@ -131,7 +120,7 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
-re "\\\* 1.1 ${not_nl}\\\(running\\\)\r\n 2.1 ${not_nl}\r\n$gdb_prompt $" {
gdb_assert [string eq $follow_fork "parent"] $test
}
- -re "1.1 ${not_nl}\r\n\\\* 2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
+ -re "\\\* 1.1 ${not_nl}\r\n 2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
gdb_assert [string eq $follow_fork "child"] $test
}
}
diff --git a/gdb/testsuite/gdb.multi/tids-gid-reset.c b/gdb/testsuite/gdb.multi/tids-gid-reset.c
new file mode 100644
index 0000000000..4d3d67b8e4
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/tids-gid-reset.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.multi/tids-gid-reset.exp b/gdb/testsuite/gdb.multi/tids-gid-reset.exp
new file mode 100644
index 0000000000..e15049bfad
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/tids-gid-reset.exp
@@ -0,0 +1,96 @@
+# Copyright 2015-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Check that letting the inferior exit and restarting it again resets
+# the global TID counter, and thus the new thread 1.1 should end up
+# with global TID == 1.
+#
+# Also, check the same but with another inferior still running, in
+# which case the new thread 1.1 should end up with global TID == 3.
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } {
+ return -1
+}
+
+with_test_prefix "single-inferior" {
+ with_test_prefix "before restart" {
+ clean_restart ${testfile}
+
+ if { ![runto_main] } then {
+ return -1
+ }
+
+ gdb_test "info threads -gid" "\\* 1 +1 +.*"
+ }
+
+ with_test_prefix "restart" {
+ gdb_continue_to_end
+ if { ![runto_main] } then {
+ return -1
+ }
+ }
+
+ with_test_prefix "after restart" {
+ gdb_test "info threads -gid" "\\* 1 +1 +.*"
+ }
+}
+
+# For the following tests, multiple inferiors are needed, therefore
+# non-extended gdbserver is not supported.
+if [use_gdb_stub] {
+ untested "using gdb stub"
+ return
+}
+
+# Test with multiple inferiors. This time, since we restart inferior
+# 1 while inferior 2 still has threads, then the new thread 1.1 should
+# end up with GID == 3, since we won't be able to reset the global
+# thread ID counter.
+with_test_prefix "multi-inferior" {
+ gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
+ gdb_test "inferior 2" "Switching to inferior 2 .*" "switch to inferior 2"
+ gdb_load ${binfile}
+
+ if ![runto_main] then {
+ fail "starting inferior 2"
+ return
+ }
+
+ gdb_test "inferior 1" "Switching to inferior 1 .*" \
+ "switch back to inferior 1"
+
+ with_test_prefix "before restart" {
+ gdb_test "info threads -gid" \
+ [multi_line \
+ "\\* 1\.1 +1 +.*" \
+ " 2\.1 +2 +.*"]
+ }
+
+ with_test_prefix "restart" {
+ gdb_continue_to_end
+ if { ![runto_main] } then {
+ return -1
+ }
+ }
+
+ with_test_prefix "after restart" {
+ gdb_test "info threads -gid" \
+ [multi_line \
+ "\\* 1\.1 +3 +.*" \
+ " 2\.1 +2 +.*"]
+ }
+}
diff --git a/gdb/testsuite/gdb.threads/async.c b/gdb/testsuite/gdb.threads/async.c
new file mode 100644
index 0000000000..6bffca9c8d
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define NUM 2
+
+static pthread_barrier_t threads_started_barrier;
+
+static void *
+thread_function (void *arg)
+{
+ pthread_barrier_wait (&threads_started_barrier);
+
+ while (1)
+ {
+ /* Sleep a bit to give the other threads a chance to run. */
+ usleep (1); /* set breakpoint here */
+ }
+
+ pthread_exit (NULL);
+}
+
+static void
+all_started (void)
+{
+}
+
+int
+main ()
+{
+ pthread_t threads[NUM];
+ long i;
+
+ pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
+
+ for (i = 1; i <= NUM; i++)
+ {
+ int res;
+
+ res = pthread_create (&threads[i - 1],
+ NULL,
+ thread_function, NULL);
+ }
+
+ pthread_barrier_wait (&threads_started_barrier);
+
+ all_started ();
+
+ sleep (180);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.threads/async.exp b/gdb/testsuite/gdb.threads/async.exp
new file mode 100644
index 0000000000..7047bef2bd
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.exp
@@ -0,0 +1,98 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
+ return -1
+}
+
+# At this point GDB will be busy handling the breakpoint hits and
+# re-resuming the program. Even if GDB internally switches thread
+# context, the user should not notice it. The following part of the
+# testcase ensures that.
+
+# Switch to thread EXPECTED_THR, and then confirm that the thread
+# stays selected.
+
+proc test_current_thread {expected_thr} {
+ global decimal
+ global gdb_prompt
+ global binfile
+
+ clean_restart $binfile
+
+ if {![runto "all_started"]} {
+ fail "could not run to all_started"
+ return
+ }
+
+ # Set a breakpoint that continuously fires but doeesn't cause a stop.
+ gdb_breakpoint [concat [gdb_get_line_number "set breakpoint here"] " if 0"]
+
+ gdb_test "thread $expected_thr" "Switching to thread $expected_thr .*" \
+ "switch to thread $expected_thr"
+
+ # Continue the program in the background.
+ set test "continue&"
+ gdb_test_multiple "continue&" $test {
+ -re "Continuing\\.\r\n$gdb_prompt " {
+ pass $test
+ }
+ }
+
+ set test "current thread is $expected_thr"
+ set fails 0
+ for {set i 0} {$i < 10} {incr i} {
+ after 200
+
+ set cur_thread 0
+ gdb_test_multiple "thread" $test {
+ -re "Current thread is ($decimal) .*$gdb_prompt " {
+ set cur_thread $expect_out(1,string)
+ }
+ }
+
+ if {$cur_thread != $expected_thr} {
+ incr fails
+ }
+ }
+
+ gdb_assert {$fails == 0} $test
+
+ # Explicitly interrupt the target, because in all-stop/remote,
+ # that's all we can do when the target is running. If we don't do
+ # this, we'd time out trying to kill the target, while bringing
+ # down gdb & gdbserver.
+ set test "interrupt"
+ gdb_test_multiple $test $test {
+ -re "^interrupt\r\n$gdb_prompt " {
+ gdb_test_multiple "" $test {
+ -re "Thread .* received signal SIGINT, Interrupt\\." {
+ pass $test
+ }
+ }
+ }
+ }
+}
+
+# Try once with each thread as current, to avoid missing a bug just
+# because some part of GDB manages to switch to the right thread by
+# chance.
+for {set thr 1} {$thr <= 3} {incr thr} {
+ with_test_prefix "thread $thr" {
+ test_current_thread $thr
+ }
+}
diff --git a/gdb/thread.c b/gdb/thread.c
index 17bc642b84..2f9cd87ac8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1375,7 +1375,8 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
}
}
-scoped_restore_current_thread::~scoped_restore_current_thread ()
+void
+scoped_restore_current_thread::restore ()
{
/* If an entry of thread_info was previously selected, it won't be
deleted because we've increased its refcount. The thread represented
@@ -1402,6 +1403,22 @@ scoped_restore_current_thread::~scoped_restore_current_thread ()
&& target_has_stack
&& target_has_memory)
restore_selected_frame (m_selected_frame_id, m_selected_frame_level);
+}
+
+scoped_restore_current_thread::~scoped_restore_current_thread ()
+{
+ if (!m_dont_restore)
+ {
+ try
+ {
+ restore ();
+ }
+ catch (const gdb_exception &ex)
+ {
+ /* We're in a dtor, there's really nothing else we can do
+ but swallow the exception. */
+ }
+ }
if (m_thread != NULL)
m_thread->decref ();
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 14.5/23] Avoid another inferior_ptid reference in gdb/remote.c (Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet)
2019-10-09 13:35 ` Aktemur, Tankut Baris
@ 2019-10-17 0:54 ` Pedro Alves
2019-10-17 10:45 ` Aktemur, Tankut Baris
0 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 0:54 UTC (permalink / raw)
To: Aktemur, Tankut Baris; +Cc: gdb-patches
On 10/9/19 2:34 PM, Aktemur, Tankut Baris wrote:
> * On September 7, 2019 1:28 AM, Pedro Alves wrote:
> A similar problem could occur in case of an exit event, too -- for instance,
> if the remote target does not support the multi-process packet or if the
> packet is disabled.
>
> This can be checked by modifying the test
>
> testsuite/gdb.server/connect-without-multi-process.exp
>
> to continue the inferior to termination.
Oh, excellent, this is the same issue that Philippe discovered with
Valgrind, for which I sent a patch earlier:
https://sourceware.org/ml/gdb-patches/2019-10/msg00512.html
I did not realize you had already analyzed it. I was having second
thoughts on whether we can use general_thread, and for that I like
your patch better than mine. In haste, had completely forgot that
patch #14 added first_remote_resumed_thread. Also, I wrote a new test
from scratch, not realizing we already had connect-without-multi-process.exp.
Sigh. Well, I actually originally wrote that one too, so I just
completely forgot it. :-D Thanks for finding it.
> I'm attaching these as a patch in case one wants to test. It should be applied
> after the main multi-target patch.
I tweaked it a bit further, reused the commit log from my version of
the patch, and rebased it on top of patch #14. Here it is:
From 25f279aa79a9860c64d228a9eb7fc974c2367c64 Mon Sep 17 00:00:00 2001
From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Date: Thu, 17 Oct 2019 01:34:19 +0100
Subject: [PATCH] Avoid another inferior_ptid reference in gdb/remote.c
The multi-target patch makes inferior_ptid point to null_ptid before
calling into target_wait, which catches bad uses of inferior_ptid,
since the current selected thread in gdb shouldn't have much relation
to the thread that reports an event.
One such bad use is found in remote_target::remote_parse_stop_reply,
where we handle the 'W' or 'X' packets (process exit), and the remote
target does not support the multi-process extensions, i.e., it does
not report the PID of the process that exited.
With the multi-target patch, that would result in a failed assertion,
trying to find the inferior for process pid 0.
gdb/ChangeLog:
yyyy-mm-dd Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Pedro Alves <palves@redhat.com>
* remote.c (remote_target::remote_parse_stop_reply) <W/X packets>:
If no process is specified, return null_ptid instead of
inferior_ptid.
(remote_target::wait_as): Handle TARGET_WAITKIND_EXITED /
TARGET_WAITKIND_SIGNALLED with no pid.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Pedro Alves <palves@redhat.com>
* gdb.server/connect-without-multi-process.exp: Also test
continuing to end.
---
gdb/remote.c | 18 +++++++++++++-----
.../gdb.server/connect-without-multi-process.exp | 7 ++++++-
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/gdb/remote.c b/gdb/remote.c
index 8f3fdf098d..ad8a14d80b 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7446,7 +7446,6 @@ Packet: '%s'\n"),
case 'W': /* Target exited. */
case 'X':
{
- int pid;
ULONGEST value;
/* GDB used to accept only 2 hex chars here. Stubs should
@@ -7470,8 +7469,9 @@ Packet: '%s'\n"),
event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
}
- /* If no process is specified, assume inferior_ptid. */
- pid = inferior_ptid.pid ();
+ /* If no process is specified, return null_ptid, and let the
+ caller figure out the right process to use. */
+ int pid = 0;
if (*p == '\0')
;
else if (*p == ';')
@@ -7847,8 +7847,16 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
event_ptid = first_remote_resumed_thread ();
}
else
- /* A process exit. Invalidate our notion of current thread. */
- record_currthread (rs, minus_one_ptid);
+ {
+ /* A process exit. Invalidate our notion of current thread. */
+ record_currthread (rs, minus_one_ptid);
+ /* It's possible that the packet did not include a pid. */
+ if (event_ptid == null_ptid)
+ event_ptid = first_remote_resumed_thread ();
+ /* EVENT_PTID could still be NULL_PTID. Double-check. */
+ if (event_ptid == null_ptid)
+ event_ptid = magic_null_ptid;
+ }
return event_ptid;
}
diff --git a/gdb/testsuite/gdb.server/connect-without-multi-process.exp b/gdb/testsuite/gdb.server/connect-without-multi-process.exp
index fba20a6a0b..6ba35bf508 100644
--- a/gdb/testsuite/gdb.server/connect-without-multi-process.exp
+++ b/gdb/testsuite/gdb.server/connect-without-multi-process.exp
@@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. */
# Check that we can connect to GDBserver with the multiprocess
-# extensions disabled, and run to main.
+# extensions disabled, run to main, and finish the process.
load_lib gdbserver-support.exp
@@ -52,6 +52,11 @@ proc do_test {multiprocess} {
"target $gdbserver_protocol"
gdb_test "continue" "main .*" "continue to main"
+
+ # The W/X packets do not include the PID of the exiting process
+ # without the multi-process extensions. Check that we handle
+ # process exit correctly in that case.
+ gdb_continue_to_end
}
foreach multiprocess { "off" "auto" } {
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 18/23] Add multi-target tests
2019-10-09 16:01 ` Aktemur, Tankut Baris
@ 2019-10-17 0:55 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 0:55 UTC (permalink / raw)
To: Aktemur, Tankut Baris; +Cc: gdb-patches
On 10/9/19 5:01 PM, Aktemur, Tankut Baris wrote:
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.multi/multi-target.c
>> @@ -0,0 +1,100 @@
>> +/* This testcase is part of GDB, the GNU debugger.
>> +
>> + Copyright 2017-2019 Free Software Foundation, Inc.
>> +
>
> The year should be just 2019. Right?
Nope, these files were really originally written in 2017,
and have been published in my github since.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 08/23] Introduce switch_to_inferior_no_thread
2019-09-09 18:42 ` Tom Tromey
@ 2019-10-17 1:07 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 1:07 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 9/9/19 7:42 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> Several places want to switch context to an inferior and its pspace,
> Pedro> while at the same time switch to "no thread selected". This commit
> Pedro> adds a function that does that, and uses it in a few places. The
> Pedro> function is made extern because many more uses will be added in follow
> Pedro> up commits.
>
> mi-main.c:run_one_inferior could also be converted.
Indeed, I did that.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 10/23] Some get_last_target_status tweaks
2019-09-09 18:53 ` Tom Tromey
@ 2019-10-17 1:14 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 1:14 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 9/9/19 7:53 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> - Declare nullify_last_target_wait_ptid in a header, and remove the
> Pedro> local extern declaration from linux-fork.c.
>
> Pedro> diff --git a/gdb/infrun.h b/gdb/infrun.h
> Pedro> index 30374ee51c..042edbbb66 100644
> Pedro> --- a/gdb/infrun.h
> Pedro> +++ b/gdb/infrun.h
> Pedro> @@ -107,6 +107,8 @@ extern void get_last_target_status (ptid_t *ptid,
> Pedro> extern void set_last_target_status (ptid_t ptid,
> Pedro> struct target_waitstatus status);
>
> Pedro> +extern void nullify_last_target_wait_ptid ();
>
> This could use an intro comment.
>
I've added:
+/* Clear the cached copy of the last ptid/waitstatus returned by
+ target_wait(). */
Also moved the intro comments of get_last_target_status / set_last_target_status
to the header file.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 17/23] Multi-target support
2019-09-11 17:11 ` Tom Tromey
@ 2019-10-17 1:54 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 1:54 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 9/11/19 6:11 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> This commit adds multi-target support to GDB. What this means is that
> Pedro> with this commit, GDB can now be connected to different targets at the
> Pedro> same time. E.g., you can debug a live native process and a core dump
> Pedro> at the same time, connect to multiple gdbservers, etc.
>
> Awesome!
>
> I read through the patch, but I can't really claim to understand how all
> the parts interrelate. However your overview made sense to me, and I
> don't have any conceptual concerns; just the usual sort of thing that
> there are lurking bugs. I guess my main fear is that this will
> introduce regressions... but on the other hand, I think it's important
> direction for gdb, so I'd rather err on the side of moving forward with
> it.
>
> Pedro> To fix this,
> Pedro> this commit renames gdbserver's target_ops to process_stratum_target.
> Pedro> I think this makes sense. There's no concept of target stack in
> Pedro> gdbserver, and gdbserver's target_ops really implements a
> Pedro> process_stratum-like target.
>
> Makes sense. Sometimes I dream about re-merging the target stacks,
> further shrinking the size of the gdbserver fork.
Yeah, that's been a long term goal of mine too.
>
> Pedro> - you can only resume more that one target at the same time if all
> Pedro> targets support asynchronous debugging, and support non-stop mode.
> Pedro> It should be possible to support mixed all-stop + non-stop
> Pedro> backends, but that is left for another time. This means that
> Pedro> currently in order to do multi-target with gdbserver you need to
> Pedro> issue "maint set target-non-stop on". I would like to make that
> Pedro> mode be the default, but we're not there yet. Note that I'm
> Pedro> talking about how the target backend works, only. User-visible
> Pedro> all-stop mode works just fine.
>
> Pedro> - as explained above, connecting to different remote servers at the
> Pedro> same time is likely to produce bad results if they don't support the
> Pedro> exact set of RSP features.
>
> Are these limitations something that can be noticed when making the
> remote connection, or do they require the user to be careful? What
> happens if the user forgets or just doesn't know?
I'm not seeing how to detect that easily&gracefully, unfortunately. If the
user forgets, gdb might misbehave. I'm hoping that the limitation
will be temporary, though.
> Pedro> - thread_info *tp = find_thread_ptid (task_info->ptid);
> Pedro> + thread_info *tp = find_thread_ptid (inf->process_target (), task_info->ptid);
>
> There are a few spots in the patch that could use the overload that
> accepts an inferior, but instead call the process_target method
> directly.
Thanks. I fixed that one. I skimmed other calls and didn't
see any that was obvious it could be changed.
>
> Pedro> +/* Calls target_commit_resume on all targets. */
> Pedro> +
> Pedro> +static void
> Pedro> +commit_resume_all_targets ()
> Pedro> +{
> Pedro> + scoped_restore_current_thread restore_thread;
> Pedro> +
> Pedro> + for (inferior *inf : all_non_exited_inferiors ())
> Pedro> + if (inf->has_execution ())
> Pedro> + {
> Pedro> + switch_to_inferior_no_thread (inf);
> Pedro> + target_commit_resume ();
> Pedro> + }
>
> IIUC this can cause multiple calls to a given target's commit_resume
> method. That seems fine (assuming you audited these implementations)
> but I suppose it would be good to document this somewhere.
>
> Alternatively I guess gdb would need some kind of iterator that ensures
> it only visits each target once.
You're right. I didn't worry about it because resumptions are
supposed to be idempotent, but, reducing number of redundant
vCont packets can only be a good thing. I did not add an iterator,
instead fixed it locally. Thinking that we may end up changing
the data inferior/process_stratum_target structures to include
>
> Pedro> - event_ptid = wait_one (&ws);
> Pedro> + wait_one_event event = wait_one ();
> Pedro> + target_waitstatus &ws = event.ws;
> Pedro> + ptid_t &event_ptid = event.ptid;
>
> I was wondering if these need to be references. It seemed like maybe
> they could be const references but I couldn't immediately tell.
>
Good point. They can, if I constify save_waitstatus as well:
static void
-save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws)
+save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
But I decided to just get rid of them and adjust the code to refer
to event.ws / event.ptid directly.
> Pedro> - For all-stop targets, we only step INFERIOR_PTID and continue others. */
> Pedro> + For all-stop targets, we only step INFERIOR_PTID and continue others. */
>
> This looks like extra indentation was added.
Thanks.
>
> Pedro> struct regcache *
> Pedro> get_thread_regcache_for_ptid (ptid_t ptid)
> Pedro> {
> Pedro> - return get_thread_regcache (ptid);
> Pedro> + /* This function doesn't take a process_stratum_target parameter
> Pedro> + because it's a common/ routine implemented by both gdb and
> Pedro> + gdbserver. It always refers to a ptid of the current target. */
>
> It's "gdbsupport/" now.
Indeed. :-) Fixed, and also fixed double space at the end.
>
> Pedro> /* The status of the stub support for the various vCont actions. */
> Pedro> vCont_action_support supports_vCont;
> Pedro> + /* Whether vCont support was probed already. */
> Pedro> + bool supports_vCont_probed;
>
> If it's the case that this is only a temporary measure, then I think
> this comment should mention that.
Fixed.
>
> Pedro> @@ -6601,6 +6622,8 @@ remote_target::commit_resume ()
> Pedro> }
>
> Pedro> vcont_builder.flush ();
> Pedro> +
> Pedro> + target_async (1);
> Pedro> }
>
> I didn't understand this. Like, is it always ok to do this?
I had to back this one out to remember why it was needed.
It is simply that we now loop over various targets, and nothing
is calling target_async on each of them to register them
on the event loop. I've moved this to common code now
(in do_target_resume), where I think it's more obvious.
>
> Pedro> /* Callback for iterate_over_inferiors. Gets rid of the given
> Pedro> inferior. */
>
> Pedro> -static int
> Pedro> -dispose_inferior (struct inferior *inf, void *args)
> Pedro> +static void
> Pedro> +dispose_inferior (inferior *inf)
> Pedro> {
> Pedro> /* Not all killed inferiors can, or will ever be, removed from the
> Pedro> inferior list. Killed inferiors clearly don't need to be killed
> Pedro> again, so, we're done. */
> Pedro> if (inf->pid == 0)
> Pedro> - return 0;
> Pedro> + return;
>
> I think the comments here (both the intro comment and the one in the
> function) need to be updated, since it seems that just a single inferior
> is handled here now, and this is no longer a callback for
> iterate_over_inferiors.
Indeed. I think it's better to just delete the function an inline
its body in the caller.
>
> I didn't understand this change. Why did it used to iterate but now
> does not?
So before there was only ever one target stack. If you were e.g., connected
to the native target, and did "tar rem :9999", then we'd need to discard all
the native inferiors that were debugging. Since now each inferior has its
own connection, we only discard the current inferior, all other inferiors
keep using their current connections.
>
> Pedro> target_pass_ctrlc (void)
> Pedro> {
> Pedro> - current_top_target ()->pass_ctrlc ();
> Pedro> + /* Pass the Ctrl-C to the first inferior that has a thread
> Pedro> + running. */
> Pedro> + for (inferior *inf : all_inferiors ())
> Pedro> + {
> [...]
> Pedro> + return;
>
> I didn't understand this. It seemed to me that a C-c should maybe be
> sent to all running inferiors?
This is like what the kernel does -- The C-c is sent to one process
(the one in the foreground) and then when gdb intercepts the SIGINT, it
pauses all processes/threads. If we sent SIGINT to all running inferiors,
then we'd end up presenting one SIGINT stop to the user for each
inferior. Like:
* running *
Press C-c
Thread 1.1 stopped with SIGINT
(gdb) c
Thread 2.1 stopped with SIGINT
(gdb) c
Thread 3.1 stopped with SIGINT
(gdb) c
Thread 4.1 stopped with SIGINT
(gdb) c
* all running again *
The comment has a typo, which I fixed now. It should read:
/* Pass the Ctrl-C to the first target that has a thread
running. */
It doesn't matter which inferior is selected for a target,
as target_pass_ctrlc forwards the Ctrl-C to the process
in the foreground.
>
> I don't actually know this area. Maybe that's obvious now :)
>
> Pedro> /* See target.h. */
> Pedro> @@ -3987,10 +4047,8 @@ set_write_memory_permission (const char *args, int from_tty,
> Pedro> }
>
> Pedro> void
> Pedro> -initialize_targets (void)
> Pedro> +_initialize_target (void)
>
> You might as well remove the 'void' when touching the line.
Done.
>
> Pedro> - explicit all_matching_threads_iterator (ptid_t filter_ptid);
> Pedro> + explicit all_matching_threads_iterator (process_stratum_target *filter_target,
> Pedro> + ptid_t filter_ptid);
>
> I guess this could drop the "explicit".
Indeed, done.
>
> Pedro> - explicit all_matching_threads_range (ptid_t filter_ptid)
> Pedro> - : m_filter_ptid (filter_ptid)
> Pedro> + explicit all_matching_threads_range (process_stratum_target *filter_target,
> Pedro> + ptid_t filter_ptid)
>
> Here too.
>
> Pedro> - explicit all_non_exited_threads_range (ptid_t filter_ptid)
> Pedro> - : m_filter_ptid (filter_ptid)
> Pedro> + explicit all_non_exited_threads_range (process_stratum_target *filter_target,
> Pedro> + ptid_t filter_ptid)
> Pedro> + : m_filter_target (filter_target), m_filter_ptid (filter_ptid)
>
> And here.
All fixed.
Here's the patch that I'm folding into the main patch, FYI.
I've also went through a number of native targets and fixed/adjusted
them AIX, Solaris, Windows, etc.
From 53aacc25ea7e3856588e9ea9fe47a2e22bbedaf4 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 17 Oct 2019 02:48:50 +0100
Subject: [PATCH] Address Tromey's review & more
---
gdb/ada-tasks.c | 2 +-
gdb/aix-thread.c | 24 ++++++++++++++------
gdb/gdbserver/lynx-low.c | 2 +-
gdb/gdbserver/nto-low.c | 2 +-
gdb/gdbserver/target.h | 2 +-
gdb/gdbserver/win32-low.c | 4 ++--
gdb/inferior-iter.h | 3 +--
gdb/infrun.c | 56 ++++++++++++++++++++++++++++-------------------
gdb/nto-procfs.c | 2 +-
gdb/procfs.c | 49 ++++++++++++++++++++++-------------------
gdb/ravenscar-thread.c | 5 ++---
gdb/record-btrace.c | 2 +-
gdb/regcache.c | 4 ++--
gdb/remote.c | 5 ++---
gdb/sol-thread.c | 28 +++++++++++++++++-------
gdb/target.c | 36 ++++++++----------------------
gdb/thread-iter.h | 12 +++++-----
gdb/windows-nat.c | 20 +++++++++--------
18 files changed, 138 insertions(+), 120 deletions(-)
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 0c85b0f7fa..c43369c662 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -1340,7 +1340,7 @@ task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
computed if target_get_ada_task_ptid has not been implemented for
our target (yet). Rather than cause an assertion error in that case,
it's nicer for the user to just refuse to perform the task switch. */
- thread_info *tp = find_thread_ptid (inf->process_target (), task_info->ptid);
+ thread_info *tp = find_thread_ptid (inf, task_info->ptid);
if (tp == NULL)
error (_("Unable to compute thread ID for task %s.\n"
"Cannot switch to this task."),
diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index ffa3352d03..ec545221fb 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -805,7 +805,11 @@ sync_threadlists (void)
priv->pdtid = pbuf[pi].pdtid;
priv->tid = pbuf[pi].tid;
- thread = add_thread_with_info (ptid_t (infpid, 0, pbuf[pi].pthid), priv);
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ thread = add_thread_with_info (proc_target,
+ ptid_t (infpid, 0, pbuf[pi].pthid),
+ priv);
pi++;
}
@@ -837,7 +841,9 @@ sync_threadlists (void)
}
else
{
- thread = add_thread (pptid);
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ thread = add_thread (proc_target, pptid);
aix_thread_info *priv = new aix_thread_info;
thread->priv.reset (priv);
@@ -1043,7 +1049,7 @@ aix_thread_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
}
else
{
- thread = find_thread_ptid (ptid);
+ thread = find_thread_ptid (current_inferior (), ptid);
if (!thread)
error (_("aix-thread resume: unknown pthread %ld"),
ptid.lwp ());
@@ -1089,7 +1095,9 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
if (!pd_active && status->kind == TARGET_WAITKIND_STOPPED
&& status->value.sig == GDB_SIGNAL_TRAP)
{
- struct regcache *regcache = get_thread_regcache (ptid);
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ struct regcache *regcache = get_thread_regcache (proc_target, ptid);
struct gdbarch *gdbarch = regcache->arch ();
if (regcache_read_pc (regcache)
@@ -1354,7 +1362,7 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
beneath ()->fetch_registers (regcache, regno);
else
{
- thread = find_thread_ptid (regcache->ptid ());
+ thread = find_thread_ptid (current_inferior (), regcache->ptid ());
aix_thread_info *priv = get_aix_thread_info (thread);
tid = priv->tid;
@@ -1692,7 +1700,7 @@ aix_thread_target::store_registers (struct regcache *regcache, int regno)
beneath ()->store_registers (regcache, regno);
else
{
- thread = find_thread_ptid (regcache->ptid ());
+ thread = find_thread_ptid (current_inferior (), regcache->ptid ());
aix_thread_info *priv = get_aix_thread_info (thread);
tid = priv->tid;
@@ -1740,7 +1748,9 @@ aix_thread_target::thread_alive (ptid_t ptid)
/* We update the thread list every time the child stops, so all
valid threads should be in the thread list. */
- return in_thread_list (ptid);
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ return in_thread_list (proc_target, ptid);
}
/* Return a printable representation of composite PID for use in
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 2bd24e7cee..ea328d7433 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -721,7 +721,7 @@ lynx_request_interrupt (void)
/* The LynxOS target_ops vector. */
-static struct target_ops lynx_target_ops = {
+static process_stratum_target lynx_target_ops = {
lynx_create_inferior,
NULL, /* post_create_inferior */
lynx_attach,
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index d77fda54b8..f950cd0458 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -931,7 +931,7 @@ nto_sw_breakpoint_from_kind (int kind, int *size)
}
-static struct target_ops nto_target_ops = {
+static process_stratum_target nto_target_ops = {
nto_create_inferior,
NULL, /* post_create_inferior */
nto_attach,
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 6f7dd98764..ba14210826 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -705,7 +705,7 @@ ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
int connected_wait);
/* Prepare to read or write memory from the inferior process. See the
- corresponding target_ops methods for more details. */
+ corresponding process_stratum_target methods for more details. */
int prepare_to_access_memory (void);
void done_accessing_memory (void);
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7088ba4dd1..c915bcda09 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -306,7 +306,7 @@ win32_stopped_data_address (void)
/* Transfer memory from/to the debugged process. */
static int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
- int write, struct target_ops *target)
+ int write, process_stratum_target *target)
{
BOOL success;
SIZE_T done = 0;
@@ -1777,7 +1777,7 @@ win32_sw_breakpoint_from_kind (int kind, int *size)
return the_low_target.breakpoint;
}
-static struct target_ops win32_target_ops = {
+static process_stratum_target win32_target_ops = {
win32_create_inferior,
NULL, /* post_create_inferior */
win32_attach,
diff --git a/gdb/inferior-iter.h b/gdb/inferior-iter.h
index 0b2a3e55d8..0f484cde3e 100644
--- a/gdb/inferior-iter.h
+++ b/gdb/inferior-iter.h
@@ -36,8 +36,7 @@ public:
typedef int difference_type;
/* Create an iterator pointing at HEAD. */
- explicit all_inferiors_iterator (process_stratum_target *proc_target,
- inferior *head)
+ all_inferiors_iterator (process_stratum_target *proc_target, inferior *head)
: m_proc_target (proc_target)
{
/* Advance M_INF to the first inferior's position. */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 473a5e0b85..e86c22ca31 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -70,6 +70,7 @@
#include "gdbsupport/scope-exit.h"
#include "gdbsupport/forward-scope-exit.h"
#include "gdb_select.h"
+#include <unordered_map>
/* Prototypes for local functions */
@@ -2248,6 +2249,9 @@ do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig)
target_resume (resume_ptid, step, sig);
target_commit_resume ();
+
+ if (target_can_async_p ())
+ target_async (1);
}
/* Resume the inferior. SIG is the signal to give the inferior
@@ -2866,12 +2870,22 @@ commit_resume_all_targets ()
{
scoped_restore_current_thread restore_thread;
+ /* Map between process_target and a representative inferior. This
+ is to avoid committing a resume in the same target more than
+ once. Resumptions must be idempotent, so this is an
+ optimization. */
+ std::unordered_map<process_stratum_target *, inferior *> conn_inf;
+
for (inferior *inf : all_non_exited_inferiors ())
if (inf->has_execution ())
- {
- switch_to_inferior_no_thread (inf);
- target_commit_resume ();
- }
+ conn_inf[inf->process_target ()] = inf;
+
+ for (const auto &ci : conn_inf)
+ {
+ inferior *inf = ci.second;
+ switch_to_inferior_no_thread (inf);
+ target_commit_resume ();
+ }
}
/* Basic routine for continuing the program in various fashions.
@@ -4509,7 +4523,7 @@ THREAD_STOPPED_BY (hw_breakpoint)
/* Save the thread's event and stop reason to process it later. */
static void
-save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws)
+save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
{
if (debug_infrun)
{
@@ -4667,30 +4681,28 @@ stop_all_threads (void)
pass = -1;
wait_one_event event = wait_one ();
- target_waitstatus &ws = event.ws;
- ptid_t &event_ptid = event.ptid;
if (debug_infrun)
{
fprintf_unfiltered (gdb_stdlog,
"infrun: stop_all_threads %s %s\n",
- target_waitstatus_to_string (&ws).c_str (),
- target_pid_to_str (event_ptid).c_str ());
+ target_waitstatus_to_string (&event.ws).c_str (),
+ target_pid_to_str (event.ptid).c_str ());
}
- if (ws.kind == TARGET_WAITKIND_NO_RESUMED
- || ws.kind == TARGET_WAITKIND_THREAD_EXITED
- || ws.kind == TARGET_WAITKIND_EXITED
- || ws.kind == TARGET_WAITKIND_SIGNALLED)
+ if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED
+ || event.ws.kind == TARGET_WAITKIND_THREAD_EXITED
+ || event.ws.kind == TARGET_WAITKIND_EXITED
+ || event.ws.kind == TARGET_WAITKIND_SIGNALLED)
{
/* All resumed threads exited
or one thread/process exited/signalled. */
}
else
{
- thread_info *t = find_thread_ptid (event.target, event_ptid);
+ thread_info *t = find_thread_ptid (event.target, event.ptid);
if (t == NULL)
- t = add_thread (event.target, event_ptid);
+ t = add_thread (event.target, event.ptid);
t->stop_requested = 0;
t->executing = 0;
@@ -4699,15 +4711,15 @@ stop_all_threads (void)
/* This may be the first time we see the inferior report
a stop. */
- inferior *inf = find_inferior_ptid (event.target, event_ptid);
+ inferior *inf = find_inferior_ptid (event.target, event.ptid);
if (inf->needs_setup)
{
switch_to_thread_no_regs (t);
setup_inferior (0);
}
- if (ws.kind == TARGET_WAITKIND_STOPPED
- && ws.value.sig == GDB_SIGNAL_0)
+ if (event.ws.kind == TARGET_WAITKIND_STOPPED
+ && event.ws.value.sig == GDB_SIGNAL_0)
{
/* We caught the event that we intended to catch, so
there's no event pending. */
@@ -4736,7 +4748,7 @@ stop_all_threads (void)
if (debug_infrun)
{
- std::string statstr = target_waitstatus_to_string (&ws);
+ std::string statstr = target_waitstatus_to_string (&event.ws);
fprintf_unfiltered (gdb_stdlog,
"infrun: target_wait %s, saving "
@@ -4748,10 +4760,10 @@ stop_all_threads (void)
}
/* Record for later. */
- save_waitstatus (t, &ws);
+ save_waitstatus (t, &event.ws);
- sig = (ws.kind == TARGET_WAITKIND_STOPPED
- ? ws.value.sig : GDB_SIGNAL_0);
+ sig = (event.ws.kind == TARGET_WAITKIND_STOPPED
+ ? event.ws.value.sig : GDB_SIGNAL_0);
if (displaced_step_fixup (t, sig) < 0)
{
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index b9866c2259..ad33914c32 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -409,7 +409,7 @@ nto_procfs_target::update_thread_list ()
(e.g. thread exited). */
continue;
ptid = ptid_t (pid, 0, tid);
- new_thread = find_thread_ptid (ptid);
+ new_thread = find_thread_ptid (this, ptid);
if (!new_thread)
new_thread = add_thread (ptid);
update_thread_private_data (new_thread, tid, status.state, 0);
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 848ac7d6e7..f6b9bfbcfc 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -160,6 +160,8 @@ public:
int can_use_hw_breakpoint (enum bptype, int, int) override;
bool stopped_data_address (CORE_ADDR *) override;
+
+ void procfs_init_inferior (int pid);
};
static procfs_target the_procfs_target;
@@ -1315,6 +1317,7 @@ proc_set_current_signal (procinfo *pi, int signo)
char sinfo[sizeof (siginfo_t)];
} arg;
siginfo_t mysinfo;
+ process_stratum_target *wait_target;
ptid_t wait_ptid;
struct target_waitstatus wait_status;
@@ -1327,8 +1330,9 @@ proc_set_current_signal (procinfo *pi, int signo)
pi = find_procinfo_or_die (pi->pid, 0);
/* The pointer is just a type alias. */
- get_last_target_status (&wait_ptid, &wait_status);
- if (wait_ptid == inferior_ptid
+ get_last_target_status (&wait_target, &wait_ptid, &wait_status);
+ if (wait_target == &the_procfs_target
+ && wait_ptid == inferior_ptid
&& wait_status.kind == TARGET_WAITKIND_STOPPED
&& wait_status.value.sig == gdb_signal_from_host (signo)
&& proc_get_status (pi)
@@ -1988,7 +1992,7 @@ do_attach (ptid_t ptid)
/* Add it to gdb's thread list. */
ptid = ptid_t (pi->pid, lwpid, 0);
- add_thread (ptid);
+ add_thread (&the_procfs_target, ptid);
return ptid;
}
@@ -2286,7 +2290,7 @@ wait_again:
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"),
target_pid_to_str (retval).c_str ());
- delete_thread (find_thread_ptid (retval));
+ delete_thread (find_thread_ptid (this, retval));
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
@@ -2308,7 +2312,7 @@ wait_again:
if (!proc_run_process (pi, 0, 0))
proc_error (pi, "target_wait, run_process", __LINE__);
- inf = find_inferior_pid (pi->pid);
+ inf = find_inferior_pid (this, pi->pid);
if (inf->attach_flag)
{
/* Don't call wait: simulate waiting for exit,
@@ -2395,8 +2399,8 @@ wait_again:
temp_ptid = ptid_t (pi->pid, temp_tid, 0);
/* If not in GDB's thread list, add it. */
- if (!in_thread_list (temp_ptid))
- add_thread (temp_ptid);
+ if (!in_thread_list (this, temp_ptid))
+ add_thread (this, temp_ptid);
/* Return to WFI, but tell it to immediately resume. */
status->kind = TARGET_WAITKIND_SPURIOUS;
@@ -2407,7 +2411,7 @@ wait_again:
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"),
target_pid_to_str (retval).c_str ());
- delete_thread (find_thread_ptid (retval));
+ delete_thread (find_thread_ptid (this, retval));
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
@@ -2464,8 +2468,8 @@ wait_again:
/* If not in GDB's thread list, add it. */
temp_ptid = ptid_t (pi->pid, temp_tid, 0);
- if (!in_thread_list (temp_ptid))
- add_thread (temp_ptid);
+ if (!in_thread_list (this, temp_ptid))
+ add_thread (this, temp_ptid);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = GDB_SIGNAL_0;
@@ -2493,12 +2497,12 @@ wait_again:
threads database, add it. */
if (retval.pid () > 0
&& retval != inferior_ptid
- && !in_thread_list (retval))
+ && !in_thread_list (this, retval))
{
/* We have a new thread. We need to add it both to
GDB's list and to our own. If we don't create a
procinfo, resume may be unhappy later. */
- add_thread (retval);
+ add_thread (this, retval);
if (find_procinfo (retval.pid (),
retval.lwp ()) == NULL)
create_procinfo (retval.pid (),
@@ -2851,8 +2855,8 @@ procfs_target::mourn_inferior ()
whatever is necessary to make the child ready to be debugged, and
then wait for the child to synchronize. */
-static void
-procfs_init_inferior (struct target_ops *ops, int pid)
+void
+procfs_target::procfs_init_inferior (int pid)
{
procinfo *pi;
int fail;
@@ -2860,8 +2864,8 @@ procfs_init_inferior (struct target_ops *ops, int pid)
/* This routine called on the parent side (GDB side)
after GDB forks the inferior. */
- if (!target_is_pushed (ops))
- push_target (ops);
+ if (!target_is_pushed (this))
+ push_target (this);
pi = create_procinfo (pid, 0);
if (pi == NULL)
@@ -2922,8 +2926,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
/* We already have a main thread registered in the thread table at
this point, but it didn't have any lwp info yet. Notify the core
about it. This changes inferior_ptid as well. */
- thread_change_ptid (ptid_t (pid),
- ptid_t (pid, lwpid, 0));
+ thread_change_ptid (this, ptid_t (pid), ptid_t (pid, lwpid, 0));
gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
}
@@ -3090,9 +3093,9 @@ procfs_target::create_inferior (const char *exec_file,
/* We have something that executes now. We'll be running through
the shell at this point (if startup-with-shell is true), but the
pid shouldn't change. */
- add_thread_silent (ptid_t (pid));
+ add_thread_silent (this, ptid_t (pid));
- procfs_init_inferior (this, pid);
+ procfs_init_inferior (pid);
}
/* An observer for the "inferior_created" event. */
@@ -3109,9 +3112,9 @@ procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
{
ptid_t gdb_threadid = ptid_t (pi->pid, thread->tid, 0);
- thread_info *thr = find_thread_ptid (gdb_threadid);
+ thread_info *thr = find_thread_ptid (&the_procfs_target, gdb_threadid);
if (thr == NULL || thr->state == THREAD_EXITED)
- add_thread (gdb_threadid);
+ add_thread (&the_procfs_target, gdb_threadid);
return 0;
}
@@ -3740,7 +3743,7 @@ procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
char *note_data, int *note_size,
enum gdb_signal stop_signal)
{
- struct regcache *regcache = get_thread_regcache (ptid);
+ struct regcache *regcache = get_thread_regcache (&the_procfs_target, ptid);
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
unsigned long merged_pid;
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index 7afced0753..5c8d537aae 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -372,9 +372,8 @@ ravenscar_thread_target::wait (ptid_t ptid,
static void
ravenscar_add_thread (struct ada_task_info *task)
{
- process_stratum_target *targ = current_inferior ()->process_target ();
- if (find_thread_ptid (targ, task->ptid) == NULL)
- add_thread (targ, task->ptid);
+ if (find_thread_ptid (current_inferior (), task->ptid) == NULL)
+ add_thread (current_inferior ()->process_target (), task->ptid);
}
void
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 45bba8d146..936facbf1a 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2155,7 +2155,7 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
/* We just indicate the resume intent here. The actual stepping happens in
record_btrace_wait below.
- For all-stop targets, we only step INFERIOR_PTID and continue others. */
+ For all-stop targets, we only step INFERIOR_PTID and continue others. */
process_stratum_target *proc_target = current_inferior ()->process_target ();
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 7120882b10..ecea0aad0e 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -397,8 +397,8 @@ struct regcache *
get_thread_regcache_for_ptid (ptid_t ptid)
{
/* This function doesn't take a process_stratum_target parameter
- because it's a common/ routine implemented by both gdb and
- gdbserver. It always refers to a ptid of the current target. */
+ because it's a gdbsupport/ routine implemented by both gdb and
+ gdbserver. It always refers to a ptid of the current target. */
process_stratum_target *proc_target = current_inferior ()->process_target ();
return get_thread_regcache (proc_target, ptid);
}
diff --git a/gdb/remote.c b/gdb/remote.c
index d86d5cfd9b..92af4df099 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -277,7 +277,8 @@ public: /* data */
/* The status of the stub support for the various vCont actions. */
vCont_action_support supports_vCont;
- /* Whether vCont support was probed already. */
+ /* Whether vCont support was probed already. This is a workaround
+ until packet_support is per-connection. */
bool supports_vCont_probed;
/* True if the user has pressed Ctrl-C, but the target hasn't
@@ -6616,8 +6617,6 @@ remote_target::commit_resume ()
}
vcont_builder.flush ();
-
- target_async (1);
}
\f
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 68fa85130a..869a88acb8 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -461,9 +461,13 @@ sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
/* See if we have a new thread. */
if (rtnval.tid_p () && rtnval != save_ptid)
{
- thread_info *thr = find_thread_ptid (rtnval);
+ thread_info *thr = find_thread_ptid (current_inferior (), rtnval);
if (thr == NULL || thr->state == THREAD_EXITED)
- add_thread (rtnval);
+ {
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ add_thread (proc_target, rtnval);
+ }
}
}
@@ -853,7 +857,8 @@ ps_lgetregs (struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset)
{
ptid_t ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch ());
+ = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, target_gdbarch ());
target_fetch_registers (regcache, -1);
fill_gregset (regcache, (gdb_gregset_t *) gregset, -1);
@@ -869,7 +874,8 @@ ps_lsetregs (struct ps_prochandle *ph, lwpid_t lwpid,
{
ptid_t ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch ());
+ = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, target_gdbarch ());
supply_gregset (regcache, (const gdb_gregset_t *) gregset);
target_store_registers (regcache, -1);
@@ -921,7 +927,8 @@ ps_lgetfpregs (struct ps_prochandle *ph, lwpid_t lwpid,
{
ptid_t ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch ());
+ = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, target_gdbarch ());
target_fetch_registers (regcache, -1);
fill_fpregset (regcache, (gdb_fpregset_t *) fpregset, -1);
@@ -937,7 +944,8 @@ ps_lsetfpregs (struct ps_prochandle *ph, lwpid_t lwpid,
{
ptid_t ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch ());
+ = get_thread_arch_regcache (current_inferior ()->process_target (),
+ ptid, target_gdbarch ());
supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
target_store_registers (regcache, -1);
@@ -1037,9 +1045,13 @@ sol_update_thread_list_callback (const td_thrhandle_t *th, void *ignored)
return -1;
ptid_t ptid = ptid_t (inferior_ptid.pid (), 0, ti.ti_tid);
- thread_info *thr = find_thread_ptid (ptid);
+ thread_info *thr = find_thread_ptid (current_inferior (), ptid);
if (thr == NULL || thr->state == THREAD_EXITED)
- add_thread (ptid);
+ {
+ process_stratum_target *proc_target
+ = current_inferior ()->process_target ();
+ add_thread (proc_target, ptid);
+ }
return 0;
}
diff --git a/gdb/target.c b/gdb/target.c
index 0b4a7dfa1d..c62a45b2f7 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1969,31 +1969,6 @@ target_pre_inferior (int from_tty)
agent_capability_invalidate ();
}
-/* Callback for iterate_over_inferiors. Gets rid of the given
- inferior. */
-
-static void
-dispose_inferior (inferior *inf)
-{
- /* Not all killed inferiors can, or will ever be, removed from the
- inferior list. Killed inferiors clearly don't need to be killed
- again, so, we're done. */
- if (inf->pid == 0)
- return;
-
- thread_info *thread = any_thread_of_inferior (inf);
- if (thread != NULL)
- {
- switch_to_thread (thread);
-
- /* Core inferiors actually should be detached, not killed. */
- if (target_has_execution)
- target_kill ();
- else
- target_detach (inf, 0);
- }
-}
-
/* This is to be called by the open routine before it does
anything. */
@@ -2007,7 +1982,14 @@ target_preopen (int from_tty)
if (!from_tty
|| !target_has_execution
|| query (_("A program is being debugged already. Kill it? ")))
- dispose_inferior (current_inferior ());
+ {
+ /* Core inferiors actually should be detached, not
+ killed. */
+ if (target_has_execution)
+ target_kill ();
+ else
+ target_detach (current_inferior (), 0);
+ }
else
error (_("Program not killed."));
}
@@ -4045,7 +4027,7 @@ set_write_memory_permission (const char *args, int from_tty,
}
void
-_initialize_target (void)
+_initialize_target ()
{
the_debug_target = new debug_target ();
diff --git a/gdb/thread-iter.h b/gdb/thread-iter.h
index 8586653df2..445a349797 100644
--- a/gdb/thread-iter.h
+++ b/gdb/thread-iter.h
@@ -92,8 +92,8 @@ public:
/* Creates an iterator that iterates over all threads that match
FILTER_PTID. */
- explicit all_matching_threads_iterator (process_stratum_target *filter_target,
- ptid_t filter_ptid);
+ all_matching_threads_iterator (process_stratum_target *filter_target,
+ ptid_t filter_ptid);
/* Create a one-past-end iterator. */
all_matching_threads_iterator ()
@@ -214,8 +214,8 @@ struct all_threads_safe_range
struct all_matching_threads_range
{
public:
- explicit all_matching_threads_range (process_stratum_target *filter_target,
- ptid_t filter_ptid)
+ all_matching_threads_range (process_stratum_target *filter_target,
+ ptid_t filter_ptid)
: m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
all_matching_threads_range ()
@@ -241,8 +241,8 @@ private:
class all_non_exited_threads_range
{
public:
- explicit all_non_exited_threads_range (process_stratum_target *filter_target,
- ptid_t filter_ptid)
+ all_non_exited_threads_range (process_stratum_target *filter_target,
+ ptid_t filter_ptid)
: m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index a756913cab..7c10f83ddb 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -349,6 +349,8 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override;
const char *thread_name (struct thread_info *) override;
+
+ int get_windows_debug_event (int pid, struct target_waitstatus *ourstatus);
};
static windows_nat_target the_windows_nat_target;
@@ -457,9 +459,9 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
the main thread silently (in reality, this thread is really
more of a process to the user than a thread). */
if (main_thread_p)
- add_thread_silent (ptid);
+ add_thread_silent (&the_windows_nat_target, ptid);
else
- add_thread (ptid);
+ add_thread (&the_windows_nat_target, ptid);
/* Set the debug registers for the new thread if they are used. */
if (debug_registers_used)
@@ -528,7 +530,7 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p)
target_pid_to_str (ptid).c_str (),
(unsigned) exit_code);
- delete_thread (find_thread_ptid (ptid));
+ delete_thread (find_thread_ptid (&the_windows_nat_target, ptid));
for (th = &thread_head;
th->next != NULL && th->next->id != id;
@@ -1516,9 +1518,10 @@ ctrl_c_handler (DWORD event_type)
/* Get the next event from the child. Returns a non-zero thread id if the event
requires handling by WFI (or whatever). */
-static int
-get_windows_debug_event (struct target_ops *ops,
- int pid, struct target_waitstatus *ourstatus)
+
+int
+windows_nat_target::get_windows_debug_event (int pid,
+ struct target_waitstatus *ourstatus)
{
BOOL debug_event;
DWORD continue_status, event_code;
@@ -1548,8 +1551,7 @@ get_windows_debug_event (struct target_ops *ops,
"CREATE_THREAD_DEBUG_EVENT"));
if (saw_create != 1)
{
- struct inferior *inf;
- inf = find_inferior_pid (current_event.dwProcessId);
+ inferior *inf = find_inferior_pid (this, current_event.dwProcessId);
if (!saw_create && inf->attach_flag)
{
/* Kludge around a Windows bug where first event is a create
@@ -1756,7 +1758,7 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
the user tries to resume the execution in the inferior.
This is a classic race that we should try to fix one day. */
SetConsoleCtrlHandler (&ctrl_c_handler, TRUE);
- retval = get_windows_debug_event (this, pid, ourstatus);
+ retval = get_windows_debug_event (pid, ourstatus);
SetConsoleCtrlHandler (&ctrl_c_handler, FALSE);
if (retval)
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-09-07 6:33 ` Eli Zaretskii
@ 2019-10-17 2:08 ` Pedro Alves
2019-10-17 7:55 ` Eli Zaretskii
2019-10-17 2:42 ` Pedro Alves
1 sibling, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 2:08 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Hi Eli,
On 9/7/19 7:33 AM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> +@item
>> +the connection name, derived from the protocol used by the connection.
>
> "Name" sounds ... inaccurate, when it can be something like
> "extended-remote host:10000", doesn't it? How about "Type"? Or maybe
> call that "Description" and the last field "Details"?
You're right. I called it "name" because originally it was really
the target's short name (target_shortname). When I got to supporting
multiple remote connections, I figured that we'd want to see
the arguments that were passed to "target remote", but did not think
to rename the column.
How about calling it "what", like so:
(gdb) info connections
Num What Description
1 remote :9999 Remote serial target in gdb-specific protocol
2 native Native process
* 3 core Local core dump file
Not unlike the "What" column in info breakpoints.
(
It may be a good idea to make "core" show the core file's filename:
(gdb) info connections
Num What Description
1 remote :9999 Remote serial target in gdb-specific protocol
2 native Native process
* 3 core core.3263 Local core dump file
4 core core.7146 Local core dump file
)
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string
2019-09-09 20:18 ` Tom Tromey
@ 2019-10-17 2:21 ` Pedro Alves
2019-10-17 14:23 ` Tom Tromey
0 siblings, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 2:21 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 9/9/19 9:18 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> This commit extends the CLI a bit for multi-target, in three ways.
> Pedro> #1 - New "info connections" command.
>
> This looks good to me. Just one question below.
>
> FWIW I'm fine with the names you chose.
>
> Pedro> + uiout->table_header (name_len + 1, ui_left, "name", "Name");
>
> Why the "+ 1" here?
Without it, we get:
(gdb) info connections
Num What Description
* 1 remote :9999 Remote serial target in gdb-specific protocol
Since the "name" column can include spaces in the middle of its
string, it seemed to me that an extra space would make the separation
more obvious.
With the extra space we get:
(gdb) info connections
Num What Description
* 1 remote :9999 Remote serial target in gdb-specific protocol
We don't do that in "info threads", for example, so maybe
that was misguided.
WDYT? Keep the extra space or remove it?
I'll add a comment if we keep it.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-09-07 6:33 ` Eli Zaretskii
2019-10-17 2:08 ` Pedro Alves
@ 2019-10-17 2:42 ` Pedro Alves
2019-10-17 8:14 ` Eli Zaretskii
1 sibling, 1 reply; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 2:42 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On 9/7/19 7:33 AM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Date: Sat, 7 Sep 2019 00:28:07 +0100
>>
>> -
>> -* Inferiors and Programs:: Debugging multiple inferiors and programs
>> +* Inferiors Connections and Programs:: Debugging multiple inferiors connections and programs
>
> The new line is too long, please break it in two.
Ah, I didn't realize that would be valid here. Done.
>
>> +@item
>> +the target connection the inferior is bound to. This includes the
>> +unique connection number assigned by @value{GDBN}, and the name of the
>> +protocol used by the connection.
>
> Having this @item start with a lowercase letter, and then having
> another sentence in it looks awkward, English-wise. How about making
> this a single sentence, as in "... is bound to, including the unique
> connection number ..."?
>
Sounds good. Done.
>> +@enumerate
>> +@item
>> +the connection number assigned by @value{GDBN}
>
> This should end in a period, as the other items do.
Fixed.
>
>> +@item
>> +the connection name, derived from the protocol used by the connection.
>
> "Name" sounds ... inaccurate, when it can be something like
> "extended-remote host:10000", doesn't it? How about "Type"? Or maybe
> call that "Description" and the last field "Details"?
Replied to that in another email.
Tentatively going with "What".
>
>> +There's no explicit way to switch focus between connections. Instead,
>> +you switch focus between inferiors, which implicitly switches the
>> +focus to the selected inferior's connection.
>> +
>> To switch focus between inferiors, use the @code{inferior} command:
>
> What does "focus" mean in this context? Either we should explain that
> here, or have a cross-reference where that is already explained.
The manual talks about "focus of debugging" in a few places.
But, I've realized that this sentence doesn't really help much,
considering we have, just before the example:
An asterisk ‘*’ preceding the connection number indicates the connection of the current inferior.
So there's no need to talk about switching between connections.
I've removed that paragraph.
>
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index f382e887c0..20aad73aa5 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>
> This part is OK.
>
> Thanks.
>
Here's the updated patch.
From a9df9ed7a8fe45df468516710875428df3a9d74a Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 17 Sep 2019 03:40:38 +0100
Subject: [PATCH] Multi-target: NEWS and user manual
This commit documents the new multi-target features in both NEWS and
user manual.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* NEWS: Mention multi-target debugging, "info connections", and
"add-inferior -no-connection".
gdb/doc/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.texinfo (Starting): Say "current inferior not connected"
instead of "GDB not connected".
(Inferiors and Programs): Rename node to ...
(Inferiors Connections and Programs): ... this. Update all
references. Talk about multiple target connections. Update "info
inferiors" info to mention the connections column. Describe "info
connections". Document "add-inferior -no-connection".
* guile.texi, python.texi: Update cross references.
---
gdb/doc/gdb.texinfo | 137 +++++++++++++++++++++++++++++++++++++---------------
gdb/doc/guile.texi | 4 +-
gdb/doc/python.texi | 6 +--
gdb/NEWS | 29 +++++++++++
4 files changed, 132 insertions(+), 44 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1208e4f615..55ea3f21e8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2237,8 +2237,8 @@ kill a child process.
* Input/Output:: Your program's input and output
* Attach:: Debugging an already-running process
* Kill Process:: Killing the child process
-
-* Inferiors and Programs:: Debugging multiple inferiors and programs
+* Inferiors Connections and Programs::
+ Debugging multiple inferiors connections and programs
* Threads:: Debugging programs with multiple threads
* Forks:: Debugging forks
* Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@@ -2493,27 +2493,28 @@ $@file{.zshenv} for the Z shell, or the file specified in the
@itemx set auto-connect-native-target off
@itemx show auto-connect-native-target
-By default, if not connected to any target yet (e.g., with
-@code{target remote}), the @code{run} command starts your program as a
-native process under @value{GDBN}, on your local machine. If you're
-sure you don't want to debug programs on your local machine, you can
-tell @value{GDBN} to not connect to the native target automatically
-with the @code{set auto-connect-native-target off} command.
+By default, if the current inferior is not connected to any target yet
+(e.g., with @code{target remote}), the @code{run} command starts your
+program as a native process under @value{GDBN}, on your local machine.
+If you're sure you don't want to debug programs on your local machine,
+you can tell @value{GDBN} to not connect to the native target
+automatically with the @code{set auto-connect-native-target off}
+command.
-If @code{on}, which is the default, and if @value{GDBN} is not
+If @code{on}, which is the default, and if the current inferior is not
connected to a target already, the @code{run} command automaticaly
connects to the native target, if one is available.
-If @code{off}, and if @value{GDBN} is not connected to a target
-already, the @code{run} command fails with an error:
+If @code{off}, and if the current inferior is not connected to a
+target already, the @code{run} command fails with an error:
@smallexample
(@value{GDBP}) run
Don't know how to run. Try "help target".
@end smallexample
-If @value{GDBN} is already connected to a target, @value{GDBN} always
-uses it with the @code{run} command.
+If the current inferior is already connected to a target, @value{GDBN}
+always uses it with the @code{run} command.
In any case, you can explicitly connect to the native target with the
@code{target native} command. For example,
@@ -2943,15 +2944,17 @@ next type @code{run}, @value{GDBN} notices that the file has changed, and
reads the symbol table again (while trying to preserve your current
breakpoint settings).
-@node Inferiors and Programs
-@section Debugging Multiple Inferiors and Programs
+@node Inferiors Connections and Programs
+@section Debugging Multiple Inferiors Connections and Programs
@value{GDBN} lets you run and debug multiple programs in a single
session. In addition, @value{GDBN} on some systems may let you run
several programs simultaneously (otherwise you have to exit from one
-before starting another). In the most general case, you can have
-multiple threads of execution in each of multiple processes, launched
-from multiple executables.
+before starting another). On some systems @value{GDBN} may even let
+you debug several programs simultaneously on different remote systems.
+In the most general case, you can have multiple threads of execution
+in each of multiple processes, launched from multiple executables,
+running on different machines.
@cindex inferior
@value{GDBN} represents the state of each program execution with an
@@ -2985,6 +2988,11 @@ the inferior number assigned by @value{GDBN}
@item
the target system's inferior identifier
+@item
+the target connection the inferior is bound to, including the unique
+connection number assigned by @value{GDBN}, and the protocol used by
+the connection.
+
@item
the name of the executable the inferior is running.
@@ -3000,9 +3008,51 @@ For example,
@smallexample
(@value{GDBP}) info inferiors
- Num Description Executable
- 2 process 2307 hello
-* 1 process 3401 goodbye
+ Num Description Connection Executable
+* 1 process 3401 1 (native) goodbye
+ 2 process 2307 2 (extended-remote host:10000) hello
+@end smallexample
+
+To find out what open target connections exist at any moment, use
+@w{@code{info connections}}:
+
+@table @code
+@kindex info connections [ @var{id}@dots{} ]
+@item info connections
+Print a list of all open target connections currently being managed by
+@value{GDBN}. By default all connections are printed, but the
+argument @var{id}@dots{} -- a space separated list of connections
+numbers -- can be used to limit the display to just the requested
+connections.
+
+@value{GDBN} displays for each connection (in this order):
+
+@enumerate
+@item
+the connection number assigned by @value{GDBN}.
+
+@item
+the protocol used by the connection.
+
+@item
+a textual description of the protocol used by the connection.
+
+@end enumerate
+
+@noindent
+An asterisk @samp{*} preceding the connection number indicates the
+connection of the current inferior.
+
+For example,
+@end table
+@c end table here to get a little more width for example
+
+@smallexample
+(@value{GDBP}) info connections
+ Num What Description
+* 1 extended-remote host:10000 Extended remote serial target in gdb-specific protocol
+ 2 native Native process
+ 3 core Local core dump file
@end smallexample
To switch focus between inferiors, use the @code{inferior} command:
@@ -3031,13 +3081,22 @@ remove inferiors from the debugging session use the
@table @code
@kindex add-inferior
-@item add-inferior [ -copies @var{n} ] [ -exec @var{executable} ]
+@item add-inferior [ -copies @var{n} ] [ -exec @var{executable} ] [-no-connection ]
Adds @var{n} inferiors to be run using @var{executable} as the
executable; @var{n} defaults to 1. If no executable is specified,
the inferiors begins empty, with no program. You can still assign or
change the program assigned to the inferior at any time by using the
@code{file} command with the executable name as its argument.
+By default, the new inferior begins connected to the same target
+connection as the current inferior. For example, if the current
+inferior was connected to @code{gdbserver} with @code{target remote},
+then the new inferior will be connected to the same @code{gdbserver}
+instance. The @samp{-no-connection} option starts the new inferior
+with no connection yet. You can then for example use the @code{target
+remote} command to connect to some other @code{gdbserver} instance,
+use @code{run} to spawn a local program, etc.
+
@kindex clone-inferior
@item clone-inferior [ -copies @var{n} ] [ @var{infno} ]
Adds @var{n} inferiors ready to execute the same program as inferior
@@ -3047,15 +3106,15 @@ want to run another instance of the inferior you are debugging.
@smallexample
(@value{GDBP}) info inferiors
- Num Description Executable
-* 1 process 29964 helloworld
+ Num Description Connection Executable
+* 1 process 29964 1 (native) helloworld
(@value{GDBP}) clone-inferior
Added inferior 2.
1 inferiors added.
(@value{GDBP}) info inferiors
- Num Description Executable
- 2 <null> helloworld
-* 1 process 29964 helloworld
+ Num Description Connection Executable
+* 1 process 29964 1 (native) helloworld
+ 2 <null> 1 (native) helloworld
@end smallexample
You can now simply switch focus to inferior 2 and run it.
@@ -3708,14 +3767,14 @@ If you choose to set @samp{detach-on-fork} mode off, then @value{GDBN}
will retain control of all forked processes (including nested forks).
You can list the forked processes under the control of @value{GDBN} by
using the @w{@code{info inferiors}} command, and switch from one fork
-to another by using the @code{inferior} command (@pxref{Inferiors and
-Programs, ,Debugging Multiple Inferiors and Programs}).
+to another by using the @code{inferior} command (@pxref{Inferiors Connections and
+Programs, ,Debugging Multiple Inferiors Connections and Programs}).
To quit debugging one of the forked processes, you can either detach
from it by using the @w{@code{detach inferiors}} command (allowing it
to run independently), or kill it using the @w{@code{kill inferiors}}
-command. @xref{Inferiors and Programs, ,Debugging Multiple Inferiors
-and Programs}.
+command. @xref{Inferiors Connections and Programs, ,Debugging
+Multiple Inferiors Connections and Programs}.
If you ask to debug a child process and a @code{vfork} is followed by an
@code{exec}, @value{GDBN} executes the new target up to the first
@@ -11866,8 +11925,8 @@ gdbserver that supports the @code{qGetTIBAddr} request.
This variable contains the address of the thread information block.
@item $_inferior
-The number of the current inferior. @xref{Inferiors and
-Programs, ,Debugging Multiple Inferiors and Programs}.
+The number of the current inferior. @xref{Inferiors Connections and
+Programs, ,Debugging Multiple Inferiors Connections and Programs}.
@item $_thread
The thread number of the current thread. @xref{thread numbers}.
@@ -12974,7 +13033,7 @@ character.
@value{GDBN} caches data exchanged between the debugger and a target.
Each cache is associated with the address space of the inferior.
-@xref{Inferiors and Programs}, about inferior and address space.
+@xref{Inferiors Connections and Programs}, about inferior and address space.
Such caching generally improves performance in remote debugging
(@pxref{Remote Debugging}), because it reduces the overhead of the
remote protocol by bundling memory reads and writes into large chunks.
@@ -28256,7 +28315,7 @@ groups can be obtained using @samp{-list-thread-groups --available}.
In general, the content of a thread group may be only retrieved only
after attaching to that thread group.
-Thread groups are related to inferiors (@pxref{Inferiors and
+Thread groups are related to inferiors (@pxref{Inferiors Connections and
Programs}). Each inferior corresponds to a thread group of a special
type @samp{process}, and some additional operations are permitted on
such thread groups.
@@ -35156,7 +35215,7 @@ popup menu, but is needless clutter on the command line, and
-add-inferior
@end smallexample
-Creates a new inferior (@pxref{Inferiors and Programs}). The created
+Creates a new inferior (@pxref{Inferiors Connections and Programs}). The created
inferior is not associated with any executable. Such association may
be established with the @samp{-file-exec-and-symbols} command
(@pxref{GDB/MI File Commands}). The command response has a single
@@ -45394,11 +45453,11 @@ command, otherwise you may get an error that looks something like
@command{gdbserver} can also debug multiple inferiors at once,
described in
@ifset man
-the @value{GDBN} manual in node @code{Inferiors and Programs}
--- shell command @code{info -f gdb -n 'Inferiors and Programs'}.
+the @value{GDBN} manual in node @code{Inferiors Connections and Programs}
+-- shell command @code{info -f gdb -n 'Inferiors Connections and Programs'}.
@end ifset
@ifclear man
-@ref{Inferiors and Programs}.
+@ref{Inferiors Connections and Programs}.
@end ifclear
In such case use the @code{extended-remote} @value{GDBN} command variant:
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 699e0975a2..6e1a5cc4c9 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -2155,7 +2155,7 @@ A program space, or @dfn{progspace}, represents a symbolic view
of an address space.
It consists of all of the objfiles of the program.
@xref{Objfiles In Guile}.
-@xref{Inferiors and Programs, program spaces}, for more details
+@xref{Inferiors Connections and Programs, program spaces}, for more details
about program spaces.
Each progspace is represented by an instance of the @code{<gdb:progspace>}
@@ -2178,7 +2178,7 @@ if the program it refers to is not loaded in @value{GDBN} any longer.
@deffn {Scheme Procedure} current-progspace
This function returns the program space of the currently selected inferior.
There is always a current progspace, this never returns @code{#f}.
-@xref{Inferiors and Programs}.
+@xref{Inferiors Connections and Programs}.
@end deffn
@deffn {Scheme Procedure} progspaces
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 48adad4e97..b7d3b9173e 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -2928,7 +2928,7 @@ itself.
@findex gdb.Inferior
Programs which are being run under @value{GDBN} are called inferiors
-(@pxref{Inferiors and Programs}). Python scripts can access
+(@pxref{Inferiors Connections and Programs}). Python scripts can access
information about and manipulate inferiors controlled by @value{GDBN}
via objects of the @code{gdb.Inferior} class.
@@ -4158,7 +4158,7 @@ A program space, or @dfn{progspace}, represents a symbolic view
of an address space.
It consists of all of the objfiles of the program.
@xref{Objfiles In Python}.
-@xref{Inferiors and Programs, program spaces}, for more details
+@xref{Inferiors Connections and Programs, program spaces}, for more details
about program spaces.
The following progspace-related functions are available in the
@@ -4167,7 +4167,7 @@ The following progspace-related functions are available in the
@findex gdb.current_progspace
@defun gdb.current_progspace ()
This function returns the program space of the currently selected inferior.
-@xref{Inferiors and Programs}. This is identical to
+@xref{Inferiors Connections and Programs}. This is identical to
@code{gdb.selected_inferior().progspace} (@pxref{Inferiors In Python}) and is
included for historical compatibility.
@end defun
diff --git a/gdb/NEWS b/gdb/NEWS
index 25e67e43c8..a75726fabd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,21 @@
The 'outer_function::' prefix is only needed if 'inner_function' is
not visible in the current scope.
+* Multi-target debugging support
+
+ GDB now supports debugging multiple target connections
+ simultaneously. For example, you can now have each inferior
+ connected to different remote servers running in different machines,
+ or have one inferior debugging a local native process, an inferior
+ debugging a core dump, etc.
+
+ This support is experimental and comes with some limitations -- you
+ can only resume multiple targets simultaneously if all targets
+ support non-stop mode, and all remote stubs or servers must support
+ the same set of remote protocol features exactly. See also "info
+ connections" and "add-inferior -no-connection" below, and "maint set
+ target-non-stop" in the user manual.
+
* Python API
** The gdb.Value type has a new method 'format_string' which returns a
@@ -147,6 +162,9 @@ show print frame-info
'frame', 'stepi'. The python frame filtering also respect this setting.
The 'backtrace' '-frame-info' option can override this global setting.
+info connections
+ Lists the target connections currently in use.
+
* Changed commands
help
@@ -191,6 +209,17 @@ show print raw-frame-arguments
old commands are now deprecated and may be removed in a future
release.
+add-inferior [-no-connection]
+ The add-inferior command now supports a "-no-connection" flag that
+ makes the new inferior start with no target connection associated.
+ By default, the new inferior inherits the target connection of the
+ current inferior. See also "info connections".
+
+info inferior
+ This command's output now includes a new "Connection" column
+ indicating which target connection an inferior is bound to. See
+ "info connections" above.
+
maint test-options require-delimiter
maint test-options unknown-is-error
maint test-options unknown-is-operand
--
2.14.5
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-10-17 2:08 ` Pedro Alves
@ 2019-10-17 7:55 ` Eli Zaretskii
0 siblings, 0 replies; 68+ messages in thread
From: Eli Zaretskii @ 2019-10-17 7:55 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 17 Oct 2019 03:08:38 +0100
>
> How about calling it "what", like so:
>
> (gdb) info connections
> Num What Description
> 1 remote :9999 Remote serial target in gdb-specific protocol
> 2 native Native process
> * 3 core Local core dump file
Sounds fine to me, thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-10-17 2:42 ` Pedro Alves
@ 2019-10-17 8:14 ` Eli Zaretskii
2019-10-17 15:31 ` Pedro Alves
0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2019-10-17 8:14 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 17 Oct 2019 03:42:37 +0100
>
> * Kill Process:: Killing the child process
> -
> -* Inferiors and Programs:: Debugging multiple inferiors and programs
> +* Inferiors Connections and Programs::
> + Debugging multiple inferiors connections and programs
The last line should look like this:
* Inferiors Connections and Programs::
Debugging multiple inferiors connections
and programs
or like this:
* Inferiors Connections and Programs:: Debugging multiple inferiors
connections and programs
I prefer the latter variant, but it's up to you. The important part
is to keep the description aligned to the other descriptions or be to
the right of that alignment, and if you break in two, indent the
second line slightly.
> +@smallexample
> +(@value{GDBP}) info connections
> + Num What Description
> +* 1 extended-remote host:10000 Extended remote serial target in gdb-specific protocol
> + 2 native Native process
> + 3 core Local core dump file
> @end smallexample
Did you see if that long line causes overlong lines in the printed
output?
Otherwise, this is OK. Thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v1.1 01/23] Preserve selected thread in all-stop w/ background execution
2019-10-16 23:54 ` [PATCH v1.1 " Pedro Alves
@ 2019-10-17 10:21 ` Aktemur, Tankut Baris
0 siblings, 0 replies; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-17 10:21 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
* On Thursday, October 17, 2019 1:55 AM, Pedro Alves wrote:
>
> On 10/9/19 10:36 AM, Aktemur, Tankut Baris wrote:
> > * On September 7, 2019 1:28 AM, Pedro Alves wrote:
> >>
> >> diff --git a/gdb/infrun.c b/gdb/infrun.c
> >> index a9588f896a..9c888aa72f 100644
> >> --- a/gdb/infrun.c
> >> +++ b/gdb/infrun.c
> >> @@ -3048,6 +3048,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
> >>
> >> finish_state.release ();
> >>
> >> + /* If we've switched threads above, switch back to the previously
> >> + current thread. We don't want the user to see a different
> >> + selected thread. */
> >> + switch_to_thread (cur_thr);
> >> +
> >> /* Tell the event loop to wait for it to stop. If the target
> >> supports asynchronous execution, it'll do this from within
> >> target_resume. */
> >> @@ -3702,14 +3707,11 @@ fetch_inferior_event (void *client_data)
> >> set_current_traceframe (-1);
> >> }
> >>
> >> - gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
> >> -
> >> - if (non_stop)
> >> - /* In non-stop mode, the user/frontend should not notice a thread
> >> - switch due to internal events. Make sure we reverse to the
> >> - user selected thread and frame after handling the event and
> >> - running any breakpoint commands. */
> >> - maybe_restore_thread.emplace ();
> >> + /* The user/frontend should not notice a thread switch due to
> >> + internal events. Make sure we revert to the user selected
> >> + thread and frame after handling the event and running any
> >> + breakpoint commands. */
> >> + scoped_restore_current_thread restore_thread;
> >>
> >
> > Because this increases the refcount of the current thread, in case the
> > fetched inferior event denotes a thread exit, the thread will not be deleted
> > right away. A non-deleted but exited thread stays in the inferior's thread
> > list. This, in turn, causes the "init_thread_list" call in inferior.c to
> > be skipped. As a side effect, a regression is observed in
> >
> > gdb.arch/i386-mpx-simple_segv.exp
>
> Thanks for spotting this. I don't have MPX on my machine, so I'm not
> exactly sure the sequence of events that lead to a failure in that test,
> but I found a way to reproduce a related problem without MPX, and wrote
> a test based on it.
>
> >
> > IMHO, the 'any_thread_p' predicate should be updated. This predicate is used
> > in two places (one in 'inferior.c' and the other in 'mi/mi-main.c'). Both
> > uses, I believe, are in fact interested in whether there are any non-exited
> > threads. I'd suggest updating 'any_thread_p' to 'any_non_exited_thread_p'.
> >
>
> I'm really not sure about that. Exited threads have a thread number still,
> as long as they're on the list. Calling init_thread_list resets the
> global thread counter, meaning that you could end up with multiple threads
> with the same number, until the exited threads are purged.
>
> I think instead a delete_exited_threads call in inferior_appeared
> is better.
Thanks, this makes sense.
>
> >> overlay_cache_invalid = 1;
> >> /* Flush target cache before starting to handle each event. Target
> >> @@ -3786,6 +3788,19 @@ fetch_inferior_event (void *client_data)
> >> inferior_event_handler (INF_EXEC_COMPLETE, NULL);
> >> cmd_done = 1;
> >> }
> >> +
> >> + /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
> >> + previously selected thread is gone. We have two
> >> + choices - switch to no thread selected, or restore the
> >> + previously selected thread (now exited). We chose the
> >> + later, just because that's what GDB used to do. After
> >> + this, "info threads" says "The current thread <Thread
> >> + ID 2> has terminated." instead of "No thread
> >> + selected.". */
> >> + if (!non_stop
> >> + && cmd_done
> >> + && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
> >> + restore_thread.dont_restore ();
> >> }
> >> }
> >>
> >
> > The comment and the code seem to contradict each other. The comment says
> > "if we got a TARGET_WAITKIND_NO_RESUMED" whereas the condition is
> >
> > ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED
>
> I don't think they're contradicting, actually.
>
> When the 'if' condition is true, we won't restore the selected thread.
> So we if we got a TARGET_WAITKIND_NO_RESUMED, we restore the previous
> selected thread. For all other event kinds, we won't restore.
>
Right, sorry, my bad.
> >
> > Should TARGET_WAITKIND_THREAD_EXITED, TARGET_WAITKIND_EXITED, and
> > TARGET_WAITKIND_SIGNALLED be also included in the condition? They also mean
> > that the thread is gone, right?
>
> Not necessarily. With checkpoint, gdb automatically switches to
> another checkpoint on TARGET_WAITKIND_EXITED/TARGET_WAITKIND_SIGNALLED:
>
> (gdb) checkpoint
> checkpoint 1: fork returned pid 10741.
> (gdb) c
> Continuing.
> [Inferior 1 (process 10737) exited normally]
> [Switching to process 10741]
> (gdb) info threads
> Id Target Id Frame
> * 1 process 10741 "main" main () at main.cc:21
> (gdb)
>
> Here's an updated patch. I believe it should fix the MPX issue too.
Yes, the MPX test no longer regresses with this updated patch.
Regards,
-Baris
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 14.5/23] Avoid another inferior_ptid reference in gdb/remote.c (Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet)
2019-10-17 0:54 ` [PATCH 14.5/23] Avoid another inferior_ptid reference in gdb/remote.c (Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet) Pedro Alves
@ 2019-10-17 10:45 ` Aktemur, Tankut Baris
0 siblings, 0 replies; 68+ messages in thread
From: Aktemur, Tankut Baris @ 2019-10-17 10:45 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
* On Thursday, October 17, 2019 2:54 AM, Pedro Alves wrote:
>
> On 10/9/19 2:34 PM, Aktemur, Tankut Baris wrote:
> > * On September 7, 2019 1:28 AM, Pedro Alves wrote:
>
> > A similar problem could occur in case of an exit event, too -- for instance,
> > if the remote target does not support the multi-process packet or if the
> > packet is disabled.
> >
> > This can be checked by modifying the test
> >
> > testsuite/gdb.server/connect-without-multi-process.exp
> >
> > to continue the inferior to termination.
>
> Oh, excellent, this is the same issue that Philippe discovered with
> Valgrind, for which I sent a patch earlier:
>
> https://sourceware.org/ml/gdb-patches/2019-10/msg00512.html
>
> I did not realize you had already analyzed it. I was having second
> thoughts on whether we can use general_thread, and for that I like
> your patch better than mine. In haste, had completely forgot that
> patch #14 added first_remote_resumed_thread. Also, I wrote a new test
> from scratch, not realizing we already had connect-without-multi-process.exp.
> Sigh. Well, I actually originally wrote that one too, so I just
> completely forgot it. :-D Thanks for finding it.
>
> > I'm attaching these as a patch in case one wants to test. It should be applied
> > after the main multi-target patch.
>
> I tweaked it a bit further, reused the commit log from my version of
> the patch, and rebased it on top of patch #14. Here it is:
Thank you, this looks good to me.
Regards,
-Baris
>
> From 25f279aa79a9860c64d228a9eb7fc974c2367c64 Mon Sep 17 00:00:00 2001
> From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
> Date: Thu, 17 Oct 2019 01:34:19 +0100
> Subject: [PATCH] Avoid another inferior_ptid reference in gdb/remote.c
>
> The multi-target patch makes inferior_ptid point to null_ptid before
> calling into target_wait, which catches bad uses of inferior_ptid,
> since the current selected thread in gdb shouldn't have much relation
> to the thread that reports an event.
>
> One such bad use is found in remote_target::remote_parse_stop_reply,
> where we handle the 'W' or 'X' packets (process exit), and the remote
> target does not support the multi-process extensions, i.e., it does
> not report the PID of the process that exited.
>
> With the multi-target patch, that would result in a failed assertion,
> trying to find the inferior for process pid 0.
>
> gdb/ChangeLog:
> yyyy-mm-dd Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
> Pedro Alves <palves@redhat.com>
>
> * remote.c (remote_target::remote_parse_stop_reply) <W/X packets>:
> If no process is specified, return null_ptid instead of
> inferior_ptid.
> (remote_target::wait_as): Handle TARGET_WAITKIND_EXITED /
> TARGET_WAITKIND_SIGNALLED with no pid.
>
> gdb/testsuite/ChangeLog:
> yyyy-mm-dd Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
> Pedro Alves <palves@redhat.com>
>
> * gdb.server/connect-without-multi-process.exp: Also test
> continuing to end.
> ---
> gdb/remote.c | 18 +++++++++++++-----
> .../gdb.server/connect-without-multi-process.exp | 7 ++++++-
> 2 files changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 8f3fdf098d..ad8a14d80b 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -7446,7 +7446,6 @@ Packet: '%s'\n"),
> case 'W': /* Target exited. */
> case 'X':
> {
> - int pid;
> ULONGEST value;
>
> /* GDB used to accept only 2 hex chars here. Stubs should
> @@ -7470,8 +7469,9 @@ Packet: '%s'\n"),
> event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
> }
>
> - /* If no process is specified, assume inferior_ptid. */
> - pid = inferior_ptid.pid ();
> + /* If no process is specified, return null_ptid, and let the
> + caller figure out the right process to use. */
> + int pid = 0;
> if (*p == '\0')
> ;
> else if (*p == ';')
> @@ -7847,8 +7847,16 @@ remote_target::wait_as (ptid_t ptid, target_waitstatus *status, int options)
> event_ptid = first_remote_resumed_thread ();
> }
> else
> - /* A process exit. Invalidate our notion of current thread. */
> - record_currthread (rs, minus_one_ptid);
> + {
> + /* A process exit. Invalidate our notion of current thread. */
> + record_currthread (rs, minus_one_ptid);
> + /* It's possible that the packet did not include a pid. */
> + if (event_ptid == null_ptid)
> + event_ptid = first_remote_resumed_thread ();
> + /* EVENT_PTID could still be NULL_PTID. Double-check. */
> + if (event_ptid == null_ptid)
> + event_ptid = magic_null_ptid;
> + }
>
> return event_ptid;
> }
> diff --git a/gdb/testsuite/gdb.server/connect-without-multi-process.exp b/gdb/testsuite/gdb.server/connect-without-
> multi-process.exp
> index fba20a6a0b..6ba35bf508 100644
> --- a/gdb/testsuite/gdb.server/connect-without-multi-process.exp
> +++ b/gdb/testsuite/gdb.server/connect-without-multi-process.exp
> @@ -14,7 +14,7 @@
> # along with this program. If not, see <http://www.gnu.org/licenses/>. */
>
> # Check that we can connect to GDBserver with the multiprocess
> -# extensions disabled, and run to main.
> +# extensions disabled, run to main, and finish the process.
>
> load_lib gdbserver-support.exp
>
> @@ -52,6 +52,11 @@ proc do_test {multiprocess} {
> "target $gdbserver_protocol"
>
> gdb_test "continue" "main .*" "continue to main"
> +
> + # The W/X packets do not include the PID of the exiting process
> + # without the multi-process extensions. Check that we handle
> + # process exit correctly in that case.
> + gdb_continue_to_end
> }
>
> foreach multiprocess { "off" "auto" } {
> --
> 2.14.5
>
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string
2019-10-17 2:21 ` Pedro Alves
@ 2019-10-17 14:23 ` Tom Tromey
0 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2019-10-17 14:23 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> (gdb) info connections
Pedro> Num What Description
Pedro> * 1 remote :9999 Remote serial target in gdb-specific protocol
Pedro> We don't do that in "info threads", for example, so maybe
Pedro> that was misguided.
Pedro> WDYT? Keep the extra space or remove it?
Looks better with it, so keep IMO.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 23/23] Multi-target: NEWS and user manual
2019-10-17 8:14 ` Eli Zaretskii
@ 2019-10-17 15:31 ` Pedro Alves
0 siblings, 0 replies; 68+ messages in thread
From: Pedro Alves @ 2019-10-17 15:31 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On 10/17/19 9:13 AM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <palves@redhat.com>
>> Date: Thu, 17 Oct 2019 03:42:37 +0100
>>
>> * Kill Process:: Killing the child process
>> -
>> -* Inferiors and Programs:: Debugging multiple inferiors and programs
>> +* Inferiors Connections and Programs::
>> + Debugging multiple inferiors connections and programs
>
> The last line should look like this:
>
> * Inferiors Connections and Programs::
> Debugging multiple inferiors connections
> and programs
>
> or like this:
>
> * Inferiors Connections and Programs:: Debugging multiple inferiors
> connections and programs
>
> I prefer the latter variant, but it's up to you. The important part
> is to keep the description aligned to the other descriptions or be to
> the right of that alignment, and if you break in two, indent the
> second line slightly.
Thanks. I went with the latter then.
>
>> +@smallexample
>> +(@value{GDBP}) info connections
>> + Num What Description
>> +* 1 extended-remote host:10000 Extended remote serial target in gdb-specific protocol
>> + 2 native Native process
>> + 3 core Local core dump file
>> @end smallexample
>
> Did you see if that long line causes overlong lines in the printed
> output?
Yes, pdf output looks good. Also confirmed that the
"Debugging multiple inferiors connections and programs" title fits
in a single line.
> Otherwise, this is OK. Thanks.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2019-09-06 23:28 ` [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait Pedro Alves
@ 2020-07-31 3:17 ` Tom Tromey
2020-08-01 16:14 ` Simon Marchi
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2020-07-31 3:17 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> The multi-target patch sets inferior_ptid to null_ptid before handling
Pedro> a target event, and thus before calling target_wait, in order to catch
Pedro> places in target_ops::wait implementations that are incorrectly
Pedro> relying on inferior_ptid (which could otherwise be a ptid of a
Pedro> different target, for example). That caught this instance in
Pedro> record-full.c.
I found a few target_ops::wait implementations doing "return
inferior_ptid" in error cases. Based on this comment, and the comment
for target_wait, I suspect these should actually return minus_one_ptid
instead.
I've appended the patch so you can see what it looks like. I haven't
tried it at all. Does this seem correct?
Tom
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index ae0b0f7ff0d..2cae87023f9 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -343,7 +343,7 @@ inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
/* Claim it exited with unknown signal. */
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
- return inferior_ptid;
+ return minus_one_ptid;
}
/* Ignore terminated detached child processes. */
diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c
index 6667a0add7f..5414adec051 100644
--- a/gdb/obsd-nat.c
+++ b/gdb/obsd-nat.c
@@ -101,7 +101,7 @@ obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
/* Claim it exited with unknown signal. */
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
- return inferior_ptid;
+ return minus_one_ptid;
}
/* Ignore terminated detached child processes. */
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index 654e06e3e4b..f73919f055c 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -522,7 +522,7 @@ rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
/* Claim it exited with unknown signal. */
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
- return inferior_ptid;
+ return minus_one_ptid;
}
/* Ignore terminated detached child processes. */
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-07-31 3:17 ` Tom Tromey
@ 2020-08-01 16:14 ` Simon Marchi
2020-08-01 19:32 ` John Baldwin
2020-08-01 20:46 ` Tom Tromey
0 siblings, 2 replies; 68+ messages in thread
From: Simon Marchi @ 2020-08-01 16:14 UTC (permalink / raw)
To: Tom Tromey, Pedro Alves; +Cc: gdb-patches
On 2020-07-30 11:17 p.m., Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> The multi-target patch sets inferior_ptid to null_ptid before handling
> Pedro> a target event, and thus before calling target_wait, in order to catch
> Pedro> places in target_ops::wait implementations that are incorrectly
> Pedro> relying on inferior_ptid (which could otherwise be a ptid of a
> Pedro> different target, for example). That caught this instance in
> Pedro> record-full.c.
>
> I found a few target_ops::wait implementations doing "return
> inferior_ptid" in error cases. Based on this comment, and the comment
> for target_wait, I suspect these should actually return minus_one_ptid
> instead.
>
> I've appended the patch so you can see what it looks like. I haven't
> tried it at all. Does this seem correct?
I think you are right that it's incorrect, but...
> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
> index ae0b0f7ff0d..2cae87023f9 100644
> --- a/gdb/inf-ptrace.c
> +++ b/gdb/inf-ptrace.c
> @@ -343,7 +343,7 @@ inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
> /* Claim it exited with unknown signal. */
> ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
> ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
> - return inferior_ptid;
> + return minus_one_ptid;
> }
I don't know if this makes sense: you tell the core of GDB that some
process was signalled (terminated by a signal), but you don't tell
what process it is. I am not sure what the core of GDB can do with
this information.
The contract that the `wait` implementations must respect is not
very well documented I believe, so it's not clear which value is
valid with which event. But I expect that tying a
TARGET_WAITKIND_SIGNALLED event with a minus_one_ptid (or null_ptid
for that matter) is invalid, and will just break down later in
handle_inferior_event, where we handle this kind of event:
case TARGET_WAITKIND_EXITED:
case TARGET_WAITKIND_SIGNALLED:
{
/* Depending on the system, ecs->ptid may point to a thread or
to a process. On some targets, target_mourn_inferior may
need to have access to the just-exited thread. That is the
case of GNU/Linux's "checkpoint" support, for example.
Call the switch_to_xxx routine as appropriate. */
thread_info *thr = find_thread_ptid (ecs->target, ecs->ptid);
if (thr != nullptr)
switch_to_thread (thr);
else
{
inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
switch_to_inferior_no_thread (inf);
}
find_thread_ptid will return nullptr, so we'll go in the else.
find_inferior_ptid will return nullptr, which we'll pass to
switch_to_inferior_no_thread, and it will assert somewhere in there.
Note that this waitpid call is blocking (and there's no async stuff in
inf-ptrace.c), so I presume that this is only used in sync targets.
If GDB asked to wait for a specific (non-minus_one) ptid, waitpid returns
-1 and errno is ECHILD, it means that the process GDB is thinking about
doesn't exist. Something is wrong, we missed an event or something. I
suppose that the original intention of pretending the process was
terminated by an unknown signal was to at least make the debugger stop.
If we returned TARGET_WAITKIND_IGNORE, we would keep waiting for an event
that will never arrive, probably in an infinite busy loop of calling
waitpid and returning TARGET_WAITKIND_IGNORE. We could keep doing that
by returning the ptid that GDB passed as an argument to wait.
But if GDB asked us to wait for minus_one_ptid, then we can't really do that.
If we return TARGET_WAITKIND_IGNORE, we'll probably get into an infinite loop
as described above.
Perhaps we could return TARGET_WAITKIND_NO_RESUMED in both cases?
Simon
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-01 16:14 ` Simon Marchi
@ 2020-08-01 19:32 ` John Baldwin
2020-08-01 20:47 ` Tom Tromey
2020-08-01 20:46 ` Tom Tromey
1 sibling, 1 reply; 68+ messages in thread
From: John Baldwin @ 2020-08-01 19:32 UTC (permalink / raw)
To: Simon Marchi, Tom Tromey, Pedro Alves; +Cc: gdb-patches
On 8/1/20 9:14 AM, Simon Marchi wrote:
> On 2020-07-30 11:17 p.m., Tom Tromey wrote:
>>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>>
>> Pedro> The multi-target patch sets inferior_ptid to null_ptid before handling
>> Pedro> a target event, and thus before calling target_wait, in order to catch
>> Pedro> places in target_ops::wait implementations that are incorrectly
>> Pedro> relying on inferior_ptid (which could otherwise be a ptid of a
>> Pedro> different target, for example). That caught this instance in
>> Pedro> record-full.c.
>>
>> I found a few target_ops::wait implementations doing "return
>> inferior_ptid" in error cases. Based on this comment, and the comment
>> for target_wait, I suspect these should actually return minus_one_ptid
>> instead.
>>
>> I've appended the patch so you can see what it looks like. I haven't
>> tried it at all. Does this seem correct?
>
> I think you are right that it's incorrect, but...
>
>> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
>> index ae0b0f7ff0d..2cae87023f9 100644
>> --- a/gdb/inf-ptrace.c
>> +++ b/gdb/inf-ptrace.c
>> @@ -343,7 +343,7 @@ inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
>> /* Claim it exited with unknown signal. */
>> ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
>> ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
>> - return inferior_ptid;
>> + return minus_one_ptid;
>> }
>
> I don't know if this makes sense: you tell the core of GDB that some
> process was signalled (terminated by a signal), but you don't tell
> what process it is. I am not sure what the core of GDB can do with
> this information.
>
> The contract that the `wait` implementations must respect is not
> very well documented I believe, so it's not clear which value is
> valid with which event. But I expect that tying a
> TARGET_WAITKIND_SIGNALLED event with a minus_one_ptid (or null_ptid
> for that matter) is invalid, and will just break down later in
> handle_inferior_event, where we handle this kind of event:
>
> case TARGET_WAITKIND_EXITED:
> case TARGET_WAITKIND_SIGNALLED:
> {
> /* Depending on the system, ecs->ptid may point to a thread or
> to a process. On some targets, target_mourn_inferior may
> need to have access to the just-exited thread. That is the
> case of GNU/Linux's "checkpoint" support, for example.
> Call the switch_to_xxx routine as appropriate. */
> thread_info *thr = find_thread_ptid (ecs->target, ecs->ptid);
> if (thr != nullptr)
> switch_to_thread (thr);
> else
> {
> inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
> switch_to_inferior_no_thread (inf);
> }
>
> find_thread_ptid will return nullptr, so we'll go in the else.
> find_inferior_ptid will return nullptr, which we'll pass to
> switch_to_inferior_no_thread, and it will assert somewhere in there.
Note that prior to my fix to inf-ptrace.c in f37e5866aa, I was tripping
over this case and it did indeed result in an assertion failure as
wait was returning null_ptid. I kind of think an error like an assertion
failure is the right behavior as it's really an indication of a bug.
Arguably though inf-ptrace.c should not return null_ptid that later
triggers an obscure assertion failure, but instead it should probably
just die with an explicit error() or the like. It's not really clear
to me that we should be trying to do anything to gracefully handle an
ENOCHILD error.
--
John Baldwin
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-01 16:14 ` Simon Marchi
2020-08-01 19:32 ` John Baldwin
@ 2020-08-01 20:46 ` Tom Tromey
2020-08-01 22:56 ` Simon Marchi
1 sibling, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2020-08-01 20:46 UTC (permalink / raw)
To: Simon Marchi; +Cc: Tom Tromey, Pedro Alves, gdb-patches
Simon> I don't know if this makes sense: you tell the core of GDB that some
Simon> process was signalled (terminated by a signal), but you don't tell
Simon> what process it is. I am not sure what the core of GDB can do with
Simon> this information.
Simon> The contract that the `wait` implementations must respect is not
Simon> very well documented I believe, so it's not clear which value is
Simon> valid with which event.
Yeah. I think it would be good to fix this.
The reason I had it return minus_one_ptid is this text in
target/target.h:
Return pid of child, or -1 in case of error;
store status through argument pointer STATUS.
remote_target::wait does this as well, though perhaps not with this
target waitkind, e.g.:
status->kind = TARGET_WAITKIND_NO_RESUMED;
return minus_one_ptid;
or
if (status->kind == TARGET_WAITKIND_NO_RESUMED)
return minus_one_ptid;
... though not all returns set the kind.
Simon> Note that this waitpid call is blocking (and there's no async stuff in
Simon> inf-ptrace.c), so I presume that this is only used in sync targets.
Yeah. I found this because I was wondering what it would take to
convert the remaining sync targets, and have only target-async left.
I suspect the inf-ptrace targets can be converted by just lifting the
Linux code into in inf_ptrace_target. This comment in nbsd-nat.c is
worrying though:
/* The common code passes WNOHANG that leads to crashes, overwrite it. */
Other targets require a little more research. For Windows, Darwin, and
remote-sim, I thought perhaps we could put some of the current
resume/wait code into a separate thread. (Though in the case of the
sim, I think it would be better to move the sims to using the remote
protocol.)
Simon> Perhaps we could return TARGET_WAITKIND_NO_RESUMED in both cases?
remote.c does this in at least one case, though apparently not in all.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-01 19:32 ` John Baldwin
@ 2020-08-01 20:47 ` Tom Tromey
0 siblings, 0 replies; 68+ messages in thread
From: Tom Tromey @ 2020-08-01 20:47 UTC (permalink / raw)
To: John Baldwin; +Cc: Simon Marchi, Tom Tromey, Pedro Alves, gdb-patches
>>>>> "John" == John Baldwin <jhb@FreeBSD.org> writes:
John> Arguably though inf-ptrace.c should not return null_ptid that later
John> triggers an obscure assertion failure, but instead it should probably
John> just die with an explicit error() or the like.
I thought about this approach, but target_wait's intro comment says:
Note that it is
_NOT_ OK to throw_exception() out of target_wait() without popping
the debugging target from the stack; GDB isn't prepared to get back
to the prompt with a debugging target but without the frame cache,
stop_pc, etc., set up.
However, parts of this are obsolete, so maybe the entire thing is.
John> It's not really clear
John> to me that we should be trying to do anything to gracefully handle an
John> ENOCHILD error.
Yeah, it does seem like kernel bug territory.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-01 20:46 ` Tom Tromey
@ 2020-08-01 22:56 ` Simon Marchi
2020-08-02 17:52 ` Tom Tromey
0 siblings, 1 reply; 68+ messages in thread
From: Simon Marchi @ 2020-08-01 22:56 UTC (permalink / raw)
To: Tom Tromey; +Cc: Pedro Alves, gdb-patches
On 2020-08-01 4:46 p.m., Tom Tromey wrote:
> Simon> I don't know if this makes sense: you tell the core of GDB that some
> Simon> process was signalled (terminated by a signal), but you don't tell
> Simon> what process it is. I am not sure what the core of GDB can do with
> Simon> this information.
>
> Simon> The contract that the `wait` implementations must respect is not
> Simon> very well documented I believe, so it's not clear which value is
> Simon> valid with which event.
>
> Yeah. I think it would be good to fix this.
>
> The reason I had it return minus_one_ptid is this text in
> target/target.h:
>
> Return pid of child, or -1 in case of error;
> store status through argument pointer STATUS.
That (the -1 part) seems erroneous, because...
>
> remote_target::wait does this as well, though perhaps not with this
> target waitkind, e.g.:
>
> status->kind = TARGET_WAITKIND_NO_RESUMED;
> return minus_one_ptid;
>
> or
>
> if (status->kind == TARGET_WAITKIND_NO_RESUMED)
> return minus_one_ptid;
... TARGET_WAITKIND_NO_RESUMED is an example of waitkind that doesn't have any
ptid attached to it. It means "there is no resumed thread, so I won't have any
event to report", so it's not tied to a ptid.
AFAIK, the wait implementations don't really have a way to report "errors". That's
probably fine, because I am not sure what the core could really do about it.
> ... though not all returns set the kind.
Do you have an example? I think the kind is mandatory, because that's what the core
checks right when wait returns (see the do_wait lambda in do_target_wait). If the
target doesn't set the kind, then the core will read whatever was in there before.
Probably 0, since we memset `ecs` in fetch_inferior_event (don't know about other
code paths), which maps to TARGET_WAITKIND_EXITED.
Anyway, not setting the kind sounds like a bug to me, and this is something we should
be able to assert.
> Simon> Note that this waitpid call is blocking (and there's no async stuff in
> Simon> inf-ptrace.c), so I presume that this is only used in sync targets.
>
> Yeah. I found this because I was wondering what it would take to
> convert the remaining sync targets, and have only target-async left.
>
> I suspect the inf-ptrace targets can be converted by just lifting the
> Linux code into in inf_ptrace_target.
Assuming there isn't too much Linux-ism in there.
>This comment in nbsd-nat.c is
> worrying though:
>
> /* The common code passes WNOHANG that leads to crashes, overwrite it. */
Indeed, and that's a recent addition...
> Other targets require a little more research. For Windows, Darwin, and
> remote-sim, I thought perhaps we could put some of the current
> resume/wait code into a separate thread. (Though in the case of the
> sim, I think it would be better to move the sims to using the remote
> protocol.)
For Windows, that's what Pedro suggested here:
https://sourceware.org/legacy-ml/gdb/2016-09/msg00055.html
If we can avoid separate threads, I'd say it's better to, because it's more difficult
to debug. For Windows, that would mean finding if there's an equivalent of SIGCHLD +
the self pipe trick but for Windows. In other words, a way to wake up the event loop
when we know there's an event available.
> Simon> Perhaps we could return TARGET_WAITKIND_NO_RESUMED in both cases?
>
> remote.c does this in at least one case, though apparently not in all.
Simon
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-01 22:56 ` Simon Marchi
@ 2020-08-02 17:52 ` Tom Tromey
2020-08-03 0:08 ` Simon Marchi
0 siblings, 1 reply; 68+ messages in thread
From: Tom Tromey @ 2020-08-02 17:52 UTC (permalink / raw)
To: Simon Marchi; +Cc: Tom Tromey, Pedro Alves, gdb-patches
>> ... though not all returns set the kind.
Simon> Do you have an example?
No, I didn't notice that the wait_as function sets the kind at the
start. So some minus_one_ptid returns seem to use
TARGET_WAITKIND_IGNORE.
>> I suspect the inf-ptrace targets can be converted by just lifting the
>> Linux code into in inf_ptrace_target.
Simon> Assuming there isn't too much Linux-ism in there.
I think the async bits are really just a pipe and the SIGCHLD stuff,
which is generic across ptrace-using Unixes. (I'm not sure if that
works ok with procfs or not, I'm not familiar with that.)
>> /* The common code passes WNOHANG that leads to crashes, overwrite it. */
Simon> Indeed, and that's a recent addition...
Yeah :(
>> Other targets require a little more research. For Windows, Darwin, and
>> remote-sim, I thought perhaps we could put some of the current
>> resume/wait code into a separate thread. (Though in the case of the
>> sim, I think it would be better to move the sims to using the remote
>> protocol.)
Simon> For Windows, that's what Pedro suggested here:
Simon> https://sourceware.org/legacy-ml/gdb/2016-09/msg00055.html
Simon> If we can avoid separate threads, I'd say it's better to, because it's more difficult
Simon> to debug. For Windows, that would mean finding if there's an equivalent of SIGCHLD +
Simon> the self pipe trick but for Windows. In other words, a way to wake up the event loop
Simon> when we know there's an event available.
There isn't a way on Windows. A thread is preferable here since then
you don't have to poll -- the thread can just block in
WaitForDebugEvent.
Maybe we need to work around the mingw std::thread situation by
introducing our own gdb::thread and using Windows APIs there when
possible.
Tom
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait
2020-08-02 17:52 ` Tom Tromey
@ 2020-08-03 0:08 ` Simon Marchi
0 siblings, 0 replies; 68+ messages in thread
From: Simon Marchi @ 2020-08-03 0:08 UTC (permalink / raw)
To: Tom Tromey; +Cc: Pedro Alves, gdb-patches
On 2020-08-02 1:52 p.m., Tom Tromey wrote:
> No, I didn't notice that the wait_as function sets the kind at the
> start. So some minus_one_ptid returns seem to use
> TARGET_WAITKIND_IGNORE.
That's fine. But FWIW, I think it's not right to see the ptid as the "main" thing
the wait methods return. They primarily return a "waitkind", and depending on that
waitkind's kind, there may be a payload attached to it.
If you return TARGET_WAITKIND_IGNORE, there's no payload attached to it.
If you return TARGET_WAITKIND_EXITED, then there must be a ptid (in ecs->ptid)
as well as an exit code (in ecs->ws.value.integer).
If you return TARGET_WAITKIND_STOPPED, then there must be a ptid (in ecs->ptid)
as well as a signal number (in ecs->ws.value.sig).
And so on.
I think that the fact that the wait methods return a ptid is an historical quirk, but
my intuition is that it's not that important, and not the central piece of what "wait"
returns.
Simon
^ permalink raw reply [flat|nested] 68+ messages in thread
end of thread, other threads:[~2020-08-03 0:08 UTC | newest]
Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-06 23:28 [PATCH 00/23] Multi-target support Pedro Alves
2019-09-06 23:28 ` [PATCH 11/23] tfile_target::close: trace_fd can't be -1 Pedro Alves
2019-09-06 23:28 ` [PATCH 15/23] Fix reconnecting to a gdbserver already debugging multiple processes, I Pedro Alves
2019-09-06 23:28 ` [PATCH 09/23] switch inferior/thread before calling target methods Pedro Alves
2019-09-06 23:28 ` [PATCH 13/23] Delete exit_inferior_silent(int pid) Pedro Alves
2019-09-06 23:28 ` [PATCH 01/23] Preserve selected thread in all-stop w/ background execution Pedro Alves
2019-10-09 9:36 ` Aktemur, Tankut Baris
2019-10-16 23:54 ` [PATCH v1.1 " Pedro Alves
2019-10-17 10:21 ` Aktemur, Tankut Baris
2019-09-06 23:28 ` [PATCH 02/23] Don't rely on inferior_ptid in record_full_wait Pedro Alves
2020-07-31 3:17 ` Tom Tromey
2020-08-01 16:14 ` Simon Marchi
2020-08-01 19:32 ` John Baldwin
2020-08-01 20:47 ` Tom Tromey
2020-08-01 20:46 ` Tom Tromey
2020-08-01 22:56 ` Simon Marchi
2020-08-02 17:52 ` Tom Tromey
2020-08-03 0:08 ` Simon Marchi
2019-09-06 23:28 ` [PATCH 10/23] Some get_last_target_status tweaks Pedro Alves
2019-09-09 18:53 ` Tom Tromey
2019-10-17 1:14 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 08/23] Introduce switch_to_inferior_no_thread Pedro Alves
2019-09-09 18:42 ` Tom Tromey
2019-10-17 1:07 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 06/23] Don't check target is running in remote_target::mourn_inferior Pedro Alves
2019-09-06 23:28 ` [PATCH 20/23] Revert 'Remove unused struct serial::name field' Pedro Alves
2019-09-06 23:47 ` Christian Biesinger via gdb-patches
2019-09-08 19:30 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 19/23] gdbarch-selftests.c: No longer error out if debugging something Pedro Alves
2019-09-06 23:28 ` [PATCH 03/23] Make "show remote exec-file" inferior-aware Pedro Alves
2019-09-06 23:28 ` [PATCH 17/23] Multi-target support Pedro Alves
2019-09-11 17:11 ` Tom Tromey
2019-10-17 1:54 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 18/23] Add multi-target tests Pedro Alves
2019-10-09 16:01 ` Aktemur, Tankut Baris
2019-10-17 0:55 ` Pedro Alves
2019-09-06 23:28 ` [PATCH 16/23] Fix reconnecting to a gdbserver already debugging multiple processes, II Pedro Alves
2019-09-06 23:33 ` [PATCH 23/23] Multi-target: NEWS and user manual Pedro Alves
2019-09-07 6:33 ` Eli Zaretskii
2019-10-17 2:08 ` Pedro Alves
2019-10-17 7:55 ` Eli Zaretskii
2019-10-17 2:42 ` Pedro Alves
2019-10-17 8:14 ` Eli Zaretskii
2019-10-17 15:31 ` Pedro Alves
2019-09-06 23:34 ` [PATCH 04/23] exceptions.c:print_flush: Remove obsolete check Pedro Alves
2019-09-09 18:07 ` Tom Tromey
2019-09-06 23:35 ` [PATCH 05/23] Make target_ops::has_execution take an 'inferior *' instead of a ptid_t Pedro Alves
2019-09-09 18:12 ` Tom Tromey
2019-09-06 23:36 ` [PATCH 07/23] Delete unnecessary code from kill_command Pedro Alves
2019-10-01 10:19 ` Aktemur, Tankut Baris
2019-10-01 13:28 ` Aktemur, Tankut Baris
2019-09-06 23:36 ` [PATCH 12/23] Use all_non_exited_inferiors in infrun.c Pedro Alves
2019-09-06 23:36 ` [PATCH 14/23] Tweak handling of remote errors in response to resumption packet Pedro Alves
2019-10-09 13:35 ` Aktemur, Tankut Baris
2019-10-17 0:54 ` [PATCH 14.5/23] Avoid another inferior_ptid reference in gdb/remote.c (Re: [PATCH 14/23] Tweak handling of remote errors in response to resumption packet) Pedro Alves
2019-10-17 10:45 ` Aktemur, Tankut Baris
2019-09-06 23:37 ` [PATCH 21/23] Add "info connections" command, "info inferiors" connection number/string Pedro Alves
2019-09-09 20:18 ` Tom Tromey
2019-10-17 2:21 ` Pedro Alves
2019-10-17 14:23 ` Tom Tromey
2019-09-06 23:37 ` [PATCH 22/23] Require always-non-stop for multi-target resumptions Pedro Alves
2019-09-07 11:19 ` [PATCH 00/23] Multi-target support Philippe Waroquiers
2019-09-08 20:06 ` Pedro Alves
2019-09-08 20:50 ` Philippe Waroquiers
2019-10-16 19:08 ` Pedro Alves
2019-10-16 19:14 ` [PATCH] Avoid inferior_ptid reference in gdb/remote.c (Re: [PATCH 00/23] Multi-target support) Pedro Alves
2019-09-09 19:09 ` [PATCH 00/23] Multi-target support Tom Tromey
2019-09-09 20:22 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).