mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-11 19:33:33 +08:00
294c36eb6a
On "exec", some targets need to unpush themselves from the inferior, and do some bookkeeping, like forgetting the data associated to the exec'ing inferior. One such example is the thread-db target. It does so in a special case in thread_db_target::wait, just before returning the TARGET_WAITKIND_EXECD event to its caller. We have another such case in the context of rocm-gdb [1], where the "rocm" target is pushed on top of the linux-nat target. When an exec happens, we want to unpush the rocm target from the exec'ing inferior to close some file descriptors that refer to the pre-exec address space and forget about that inferior. We then want to push the target on the inferior in which execution continues, to open the file descriptors for the post-exec address space. I think that a good way to address this cleanly is to do all this in the target_ops::follow_exec implementations. Make the process_stratum_target::follow_exec implementation have the default behavior of pushing itself to the new inferior's target stack (if execution continues in a new inferior) and add the initial thread. remote_target::follow_exec is an example of process target that wants to do a bit more than the default behavior. So it calls process_stratum_target::follow_exec first and does the extra work second. linux-thread-db (a non-process target) implements follow_exec to do some bookeeping (forget about that process' data), before handing down the event down to the process target (which hits process_stratum_target::follow_exec). gdb/ChangeLog: * target.h (struct target_ops) <follow_exec>: Add ptid_t parameter. (target_follow_exec): Likewise. * target.c (target_follow_exec): Add ptid_t parameter. * infrun.c (follow_exec): Adjust call to target_follow_exec, don't push target nor create thread. * linux-thread-db.c (class thread_db_target) <follow_exec>: New. (thread_db_target::wait): Just return on TARGET_WAITKIND_EXECD. (thread_db_target::follow_exec): New. * remote.c (class remote_target) <follow_exec>: Add ptid_t parameter. (remote_target::follow_exec): Call process_stratum_target::follow_exec. * target-delegates.c: Re-generate. Change-Id: I3f96d0ba3ea0dde6540b7e1b4d5cdb01635088c8
136 lines
5.2 KiB
C++
136 lines
5.2 KiB
C++
/* Abstract base class inherited by all process_stratum targets
|
|
|
|
Copyright (C) 2018-2021 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 PROCESS_STRATUM_TARGET_H
|
|
#define PROCESS_STRATUM_TARGET_H
|
|
|
|
#include "target.h"
|
|
#include <set>
|
|
|
|
/* Abstract base class inherited by all process_stratum targets. */
|
|
|
|
class process_stratum_target : public target_ops
|
|
{
|
|
public:
|
|
~process_stratum_target () override = 0;
|
|
|
|
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; }
|
|
bool supports_non_stop () override { return false; }
|
|
bool supports_disable_randomization () override { return false; }
|
|
|
|
/* This default implementation returns the inferior's address
|
|
space. */
|
|
struct address_space *thread_address_space (ptid_t ptid) override;
|
|
|
|
/* This default implementation always returns target_gdbarch (). */
|
|
struct gdbarch *thread_architecture (ptid_t ptid) override;
|
|
|
|
/* Default implementations for process_stratum targets. Return true
|
|
if there's a selected inferior, false otherwise. */
|
|
bool has_all_memory () override;
|
|
bool has_memory () override;
|
|
bool has_stack () override;
|
|
bool has_registers () override;
|
|
bool has_execution (inferior *inf) override;
|
|
|
|
/* Default implementation of follow_exec.
|
|
|
|
If the current inferior and FOLLOW_INF are different (execution continues
|
|
in a new inferior), push this process target to FOLLOW_INF's target stack
|
|
and add an initial thread to FOLLOW_INF. */
|
|
void follow_exec (inferior *follow_inf, ptid_t ptid,
|
|
const char *execd_pathname) 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;
|
|
|
|
/* The connection number. Visible in "info connections". */
|
|
int connection_number = 0;
|
|
|
|
/* Whether resumed threads must be committed to the target.
|
|
|
|
When true, resumed threads must be committed to the execution
|
|
target.
|
|
|
|
When false, the target may leave resumed threads stopped when
|
|
it's convenient or efficient to do so. When the core requires
|
|
resumed threads to be committed again, this is set back to true
|
|
and calls the `commit_resumed` method to allow the target to do
|
|
so.
|
|
|
|
To simplify the implementation of targets, the following methods
|
|
are guaranteed to be called with COMMIT_RESUMED_STATE set to
|
|
false:
|
|
|
|
- resume
|
|
- stop
|
|
- wait
|
|
|
|
Knowing this, the target doesn't need to implement different
|
|
behaviors depending on the COMMIT_RESUMED_STATE, and can simply
|
|
assume that it is false.
|
|
|
|
Targets can take advantage of this to batch resumption requests,
|
|
for example. In that case, the target doesn't actually resume in
|
|
its `resume` implementation. Instead, it takes note of the
|
|
resumption intent in `resume` and defers the actual resumption to
|
|
`commit_resumed`. For example, the remote target uses this to
|
|
coalesce multiple resumption requests in a single vCont
|
|
packet. */
|
|
bool commit_resumed_state = 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);
|
|
}
|
|
|
|
/* Return a collection of targets that have non-exited inferiors. */
|
|
|
|
extern std::set<process_stratum_target *> all_non_exited_process_targets ();
|
|
|
|
/* Switch to the first inferior (and program space) of TARGET, and
|
|
switch to no thread selected. */
|
|
|
|
extern void switch_to_target_no_thread (process_stratum_target *target);
|
|
|
|
#endif /* !defined (PROCESS_STRATUM_TARGET_H) */
|