mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
c12221171b
std::uncaught_exceptions is a C++17 feature, so I think we can remove this conditional code from inferior.h.
870 lines
28 KiB
C++
870 lines
28 KiB
C++
/* Variables that describe the inferior process running under GDB:
|
||
Where it is, why it stopped, and how to step it.
|
||
|
||
Copyright (C) 1986-2024 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/>. */
|
||
|
||
#if !defined (INFERIOR_H)
|
||
#define INFERIOR_H 1
|
||
|
||
#include <exception>
|
||
#include <list>
|
||
|
||
struct target_waitstatus;
|
||
class frame_info_ptr;
|
||
struct ui_file;
|
||
struct type;
|
||
struct gdbarch;
|
||
struct regcache;
|
||
struct ui_out;
|
||
struct terminal_info;
|
||
struct target_desc_info;
|
||
struct inferior;
|
||
struct thread_info;
|
||
|
||
/* For bpstat. */
|
||
#include "breakpoint.h"
|
||
|
||
/* For enum gdb_signal. */
|
||
#include "target.h"
|
||
|
||
/* For struct frame_id. */
|
||
#include "frame.h"
|
||
|
||
/* For gdb_environ. */
|
||
#include "gdbsupport/environ.h"
|
||
|
||
#include "progspace.h"
|
||
#include "registry.h"
|
||
|
||
#include "symfile-add-flags.h"
|
||
#include "gdbsupport/refcounted-object.h"
|
||
#include "gdbsupport/forward-scope-exit.h"
|
||
#include "gdbsupport/gdb_unique_ptr.h"
|
||
#include "gdbsupport/intrusive_list.h"
|
||
|
||
#include "gdbsupport/common-inferior.h"
|
||
#include "gdbthread.h"
|
||
|
||
#include "process-stratum-target.h"
|
||
#include "displaced-stepping.h"
|
||
|
||
#include <unordered_map>
|
||
|
||
struct infcall_suspend_state;
|
||
struct infcall_control_state;
|
||
|
||
extern void restore_infcall_suspend_state (struct infcall_suspend_state *);
|
||
extern void restore_infcall_control_state (struct infcall_control_state *);
|
||
|
||
/* A deleter for infcall_suspend_state that calls
|
||
restore_infcall_suspend_state. */
|
||
struct infcall_suspend_state_deleter
|
||
{
|
||
void operator() (struct infcall_suspend_state *state) const
|
||
{
|
||
try
|
||
{
|
||
restore_infcall_suspend_state (state);
|
||
}
|
||
catch (const gdb_exception_error &e)
|
||
{
|
||
/* If we are restoring the inferior state due to an exception,
|
||
some error message will be printed. So, only warn the user
|
||
when we cannot restore during normal execution. */
|
||
if (std::uncaught_exceptions () == 0)
|
||
warning (_("Failed to restore inferior state: %s"), e.what ());
|
||
}
|
||
}
|
||
};
|
||
|
||
/* A unique_ptr specialization for infcall_suspend_state. */
|
||
typedef std::unique_ptr<infcall_suspend_state, infcall_suspend_state_deleter>
|
||
infcall_suspend_state_up;
|
||
|
||
extern infcall_suspend_state_up save_infcall_suspend_state ();
|
||
|
||
/* A deleter for infcall_control_state that calls
|
||
restore_infcall_control_state. */
|
||
struct infcall_control_state_deleter
|
||
{
|
||
void operator() (struct infcall_control_state *state) const
|
||
{
|
||
restore_infcall_control_state (state);
|
||
}
|
||
};
|
||
|
||
/* A unique_ptr specialization for infcall_control_state. */
|
||
typedef std::unique_ptr<infcall_control_state, infcall_control_state_deleter>
|
||
infcall_control_state_up;
|
||
|
||
extern infcall_control_state_up save_infcall_control_state ();
|
||
|
||
extern void discard_infcall_suspend_state (struct infcall_suspend_state *);
|
||
extern void discard_infcall_control_state (struct infcall_control_state *);
|
||
|
||
extern readonly_detached_regcache *
|
||
get_infcall_suspend_state_regcache (struct infcall_suspend_state *);
|
||
|
||
extern void set_sigint_trap (void);
|
||
|
||
extern void clear_sigint_trap (void);
|
||
|
||
/* Collected pid, tid, etc. of the debugged inferior. When there's
|
||
no inferior, inferior_ptid.pid () will be 0. */
|
||
|
||
extern ptid_t inferior_ptid;
|
||
|
||
extern void generic_mourn_inferior (void);
|
||
|
||
extern CORE_ADDR unsigned_pointer_to_address (struct gdbarch *gdbarch,
|
||
struct type *type,
|
||
const gdb_byte *buf);
|
||
extern void unsigned_address_to_pointer (struct gdbarch *gdbarch,
|
||
struct type *type, gdb_byte *buf,
|
||
CORE_ADDR addr);
|
||
extern CORE_ADDR signed_pointer_to_address (struct gdbarch *gdbarch,
|
||
struct type *type,
|
||
const gdb_byte *buf);
|
||
extern void address_to_signed_pointer (struct gdbarch *gdbarch,
|
||
struct type *type, gdb_byte *buf,
|
||
CORE_ADDR addr);
|
||
|
||
extern void reopen_exec_file (void);
|
||
|
||
/* From misc files */
|
||
|
||
extern void default_print_registers_info (struct gdbarch *gdbarch,
|
||
struct ui_file *file,
|
||
const frame_info_ptr &frame,
|
||
int regnum, int all);
|
||
|
||
/* Default implementation of gdbarch_print_float_info. Print
|
||
the values of all floating point registers. */
|
||
|
||
extern void default_print_float_info (struct gdbarch *gdbarch,
|
||
struct ui_file *file,
|
||
const frame_info_ptr &frame,
|
||
const char *args);
|
||
|
||
/* Try to determine whether TTY is GDB's input terminal. Returns
|
||
TRIBOOL_UNKNOWN if we can't tell. */
|
||
|
||
extern tribool is_gdb_terminal (const char *tty);
|
||
|
||
/* Helper for sharing_input_terminal. Try to determine whether pid
|
||
PID is using the same TTY for input as GDB is. Returns
|
||
TRIBOOL_UNKNOWN if we can't tell. */
|
||
|
||
extern tribool sharing_input_terminal (int pid);
|
||
|
||
/* The type of the function that is called when SIGINT is handled. */
|
||
|
||
typedef void c_c_handler_ftype (int);
|
||
|
||
/* Install a new SIGINT handler in a host-dependent way. The previous
|
||
handler is returned. It is fine to pass SIG_IGN for FN, but not
|
||
SIG_DFL. */
|
||
|
||
extern c_c_handler_ftype *install_sigint_handler (c_c_handler_ftype *fn);
|
||
|
||
extern void child_terminal_info (struct target_ops *self, const char *, int);
|
||
|
||
extern void child_terminal_ours (struct target_ops *self);
|
||
|
||
extern void child_terminal_ours_for_output (struct target_ops *self);
|
||
|
||
extern void child_terminal_inferior (struct target_ops *self);
|
||
|
||
extern void child_terminal_save_inferior (struct target_ops *self);
|
||
|
||
extern void child_terminal_init (struct target_ops *self);
|
||
|
||
extern void child_pass_ctrlc (struct target_ops *self);
|
||
|
||
extern void child_interrupt (struct target_ops *self);
|
||
|
||
/* From fork-child.c */
|
||
|
||
/* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
|
||
This function already calls set_executing. Return the ptid_t from
|
||
STARTUP_INFERIOR. */
|
||
extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
|
||
|
||
/* From infcmd.c */
|
||
|
||
/* Initial inferior setup. Determines the exec file is not yet known,
|
||
takes any necessary post-attaching actions, fetches the target
|
||
description and syncs the shared library list. */
|
||
|
||
extern void setup_inferior (int from_tty);
|
||
|
||
extern void post_create_inferior (int from_tty);
|
||
|
||
extern void attach_command (const char *, int);
|
||
|
||
extern void registers_info (const char *, int);
|
||
|
||
extern void continue_1 (int all_threads);
|
||
|
||
extern void interrupt_target_1 (bool all_threads);
|
||
|
||
using delete_longjmp_breakpoint_cleanup
|
||
= FORWARD_SCOPE_EXIT (delete_longjmp_breakpoint);
|
||
|
||
extern void detach_command (const char *, int);
|
||
|
||
extern void notice_new_inferior (struct thread_info *, bool, int);
|
||
|
||
/* Return the value of the result of a function at the end of a 'finish'
|
||
command/BP. If the result's value cannot be retrieved, return NULL.
|
||
|
||
FUNC_SYMBOL is the symbol of the function being returned from. FUNCTION is
|
||
a value containing the address of the function. */
|
||
|
||
extern struct value *get_return_value (struct symbol *func_symbol,
|
||
struct value *function);
|
||
|
||
/* Prepare for execution command. TARGET is the target that will run
|
||
the command. BACKGROUND determines whether this is a foreground
|
||
(synchronous) or background (asynchronous) command. */
|
||
|
||
extern void prepare_execution_command (struct target_ops *target,
|
||
int background);
|
||
|
||
/* Nonzero if stopped due to completion of a stack dummy routine. */
|
||
|
||
extern enum stop_stack_kind stop_stack_dummy;
|
||
|
||
/* Nonzero if program stopped due to a random (unexpected) signal in
|
||
inferior process. */
|
||
|
||
extern int stopped_by_random_signal;
|
||
|
||
/* Print notices on inferior events (attach, detach, etc.), set with
|
||
`set print inferior-events'. */
|
||
extern bool print_inferior_events;
|
||
|
||
/* Anything but NO_STOP_QUIETLY means we expect a trap and the caller
|
||
will handle it themselves. STOP_QUIETLY is used when running in
|
||
the shell before the child program has been exec'd and when running
|
||
through shared library loading. STOP_QUIETLY_REMOTE is used when
|
||
setting up a remote connection; it is like STOP_QUIETLY_NO_SIGSTOP
|
||
except that there is no need to hide a signal. */
|
||
|
||
/* STOP_QUIETLY_NO_SIGSTOP is used to handle a tricky situation with attach.
|
||
When doing an attach, the kernel stops the debuggee with a SIGSTOP.
|
||
On newer GNU/Linux kernels (>= 2.5.61) the handling of SIGSTOP for
|
||
a ptraced process has changed. Earlier versions of the kernel
|
||
would ignore these SIGSTOPs, while now SIGSTOP is treated like any
|
||
other signal, i.e. it is not muffled.
|
||
|
||
If the gdb user does a 'continue' after the 'attach', gdb passes
|
||
the global variable stop_signal (which stores the signal from the
|
||
attach, SIGSTOP) to the ptrace(PTRACE_CONT,...) call. This is
|
||
problematic, because the kernel doesn't ignore such SIGSTOP
|
||
now. I.e. it is reported back to gdb, which in turn presents it
|
||
back to the user.
|
||
|
||
To avoid the problem, we use STOP_QUIETLY_NO_SIGSTOP, which allows
|
||
gdb to clear the value of stop_signal after the attach, so that it
|
||
is not passed back down to the kernel. */
|
||
|
||
enum stop_kind
|
||
{
|
||
NO_STOP_QUIETLY = 0,
|
||
STOP_QUIETLY,
|
||
STOP_QUIETLY_REMOTE,
|
||
STOP_QUIETLY_NO_SIGSTOP
|
||
};
|
||
|
||
|
||
|
||
/* Base class for target-specific inferior data. */
|
||
|
||
struct private_inferior
|
||
{
|
||
virtual ~private_inferior () = 0;
|
||
};
|
||
|
||
/* Inferior process specific part of `struct infcall_control_state'.
|
||
|
||
Inferior thread counterpart is `struct thread_control_state'. */
|
||
|
||
struct inferior_control_state
|
||
{
|
||
inferior_control_state ()
|
||
: stop_soon (NO_STOP_QUIETLY)
|
||
{
|
||
}
|
||
|
||
explicit inferior_control_state (enum stop_kind when)
|
||
: stop_soon (when)
|
||
{
|
||
}
|
||
|
||
/* See the definition of stop_kind above. */
|
||
enum stop_kind stop_soon;
|
||
};
|
||
|
||
/* Initialize the inferior-related global state. */
|
||
extern void initialize_inferiors ();
|
||
|
||
/* Return a pointer to the current inferior. */
|
||
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);
|
||
|
||
/* Ensure INF is the current inferior.
|
||
|
||
If the current inferior was changed, return an RAII object that will
|
||
restore the original current context. */
|
||
extern std::optional<scoped_restore_current_thread> maybe_switch_inferior
|
||
(inferior *inf);
|
||
|
||
/* Info about an inferior's target description. There's one of these
|
||
for each inferior. */
|
||
|
||
struct target_desc_info
|
||
{
|
||
/* Returns true if this target description information has been supplied by
|
||
the user. */
|
||
bool from_user_p ()
|
||
{ return !this->filename.empty (); }
|
||
|
||
/* A flag indicating that a description has already been fetched
|
||
from the target, so it should not be queried again. */
|
||
bool fetched = false;
|
||
|
||
/* The description fetched from the target, or NULL if the target
|
||
did not supply any description. Only valid when
|
||
FETCHED is set. Only the description initialization
|
||
code should access this; normally, the description should be
|
||
accessed through the gdbarch object. */
|
||
const struct target_desc *tdesc = nullptr;
|
||
|
||
/* If not empty, the filename to read a target description from, as set by
|
||
"set tdesc filename ...".
|
||
|
||
If empty, there is not filename specified by the user. */
|
||
std::string filename;
|
||
};
|
||
|
||
/* 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
|
||
notion of processes. Each run of an executable creates a new
|
||
inferior, as does each attachment to an existing process.
|
||
Inferiors have unique internal identifiers that are different from
|
||
target process ids. Each inferior may in turn have multiple
|
||
threads running in it.
|
||
|
||
Inferiors are intrusively refcounted objects. Unlike thread
|
||
objects, being the user-selected inferior is considered a strong
|
||
reference and is thus accounted for in the inferior object's
|
||
refcount (see set_current_inferior). When GDB needs to remember
|
||
the selected inferior to later restore it, GDB temporarily bumps
|
||
the inferior object's refcount, to prevent something deleting the
|
||
inferior object before reverting back (e.g., due to a
|
||
"remove-inferiors" command (see
|
||
scoped_restore_current_inferior). All other inferior
|
||
references are considered weak references. Inferiors are always
|
||
listed exactly once in the inferior list, so placing an inferior in
|
||
the inferior list is an implicit, not counted strong reference. */
|
||
|
||
class inferior : public refcounted_object,
|
||
public intrusive_list_node<inferior>
|
||
{
|
||
public:
|
||
explicit inferior (int pid);
|
||
~inferior ();
|
||
|
||
/* 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); }
|
||
|
||
/* An overload that deletes the target on failure. */
|
||
void push_target (target_ops_up &&t)
|
||
{
|
||
m_target_stack.push (t.get ());
|
||
t.release ();
|
||
}
|
||
|
||
/* Unpush T from this inferior's target stack. */
|
||
int unpush_target (struct target_ops *t);
|
||
|
||
/* Returns true if T is pushed in this inferior's target stack. */
|
||
bool target_is_pushed (const target_ops *t) const
|
||
{ 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 (); }
|
||
|
||
/* Unpush all targets except the dummy target from m_target_stack. As
|
||
targets are removed from m_target_stack their reference count is
|
||
decremented, which may cause a target to close. */
|
||
void pop_all_targets ()
|
||
{ pop_all_targets_above (dummy_stratum); }
|
||
|
||
/* Unpush all targets above STRATUM from m_target_stack. As targets are
|
||
removed from m_target_stack their reference count is decremented,
|
||
which may cause a target to close. */
|
||
void pop_all_targets_above (enum strata stratum);
|
||
|
||
/* Unpush all targets at and above STRATUM from m_target_stack. As
|
||
targets are removed from m_target_stack their reference count is
|
||
decremented, which may cause a target to close. */
|
||
void pop_all_targets_at_and_above (enum strata stratum);
|
||
|
||
/* 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 (this); }
|
||
|
||
/* This inferior's thread list, sorted by creation order. */
|
||
intrusive_list<thread_info> thread_list;
|
||
|
||
/* A map of ptid_t to thread_info*, for average O(1) ptid_t lookup.
|
||
Exited threads do not appear in the map. */
|
||
std::unordered_map<ptid_t, thread_info *> ptid_thread_map;
|
||
|
||
/* Returns a range adapter covering the inferior's threads,
|
||
including exited threads. Used like this:
|
||
|
||
for (thread_info *thr : inf->threads ())
|
||
{ .... }
|
||
*/
|
||
inf_threads_range threads ()
|
||
{ return inf_threads_range (this->thread_list.begin ()); }
|
||
|
||
/* Returns a range adapter covering the inferior's non-exited
|
||
threads. Used like this:
|
||
|
||
for (thread_info *thr : inf->non_exited_threads ())
|
||
{ .... }
|
||
*/
|
||
inf_non_exited_threads_range non_exited_threads ()
|
||
{ return inf_non_exited_threads_range (this->thread_list.begin ()); }
|
||
|
||
/* Like inferior::threads(), but returns a range adapter that can be
|
||
used with range-for, safely. I.e., it is safe to delete the
|
||
currently-iterated thread, like this:
|
||
|
||
for (thread_info *t : inf->threads_safe ())
|
||
if (some_condition ())
|
||
delete f;
|
||
*/
|
||
inline safe_inf_threads_range threads_safe ()
|
||
{ return safe_inf_threads_range (this->thread_list.begin ()); }
|
||
|
||
/* Find (non-exited) thread PTID of this inferior. */
|
||
thread_info *find_thread (ptid_t ptid);
|
||
|
||
/* Delete all threads in the thread list, silently. */
|
||
void clear_thread_list ();
|
||
|
||
/* Continuations-related methods. A continuation is an std::function
|
||
to be called to finish the execution of a command when running
|
||
GDB asynchronously. A continuation is executed after any thread
|
||
of this inferior stops. Continuations are used by the attach
|
||
command and the remote target when a new inferior is detected. */
|
||
void add_continuation (std::function<void ()> &&cont);
|
||
void do_all_continuations ();
|
||
|
||
/* Set/get file name for default use for standard in/out in the inferior.
|
||
|
||
On Unix systems, we try to make TERMINAL_NAME the inferior's controlling
|
||
terminal.
|
||
|
||
If TERMINAL_NAME is the empty string, then the inferior inherits GDB's
|
||
terminal (or GDBserver's if spawning a remote process). */
|
||
void set_tty (std::string terminal_name);
|
||
const std::string &tty ();
|
||
|
||
/* Set the argument string to use when running this inferior.
|
||
|
||
An empty string can be used to represent "no arguments". */
|
||
void set_args (std::string args)
|
||
{
|
||
m_args = std::move (args);
|
||
};
|
||
|
||
/* Set the argument string from some strings. */
|
||
void set_args (gdb::array_view<char * const> args);
|
||
|
||
/* Get the argument string to use when running this inferior.
|
||
|
||
No arguments is represented by an empty string. */
|
||
const std::string &args () const
|
||
{
|
||
return m_args;
|
||
}
|
||
|
||
/* Set the inferior current working directory.
|
||
|
||
If CWD is empty, unset the directory. */
|
||
void set_cwd (std::string cwd)
|
||
{
|
||
m_cwd = std::move (cwd);
|
||
}
|
||
|
||
/* Get the inferior current working directory.
|
||
|
||
Return an empty string if the current working directory is not
|
||
specified. */
|
||
const std::string &cwd () const
|
||
{
|
||
return m_cwd;
|
||
}
|
||
|
||
/* Set this inferior's arch. */
|
||
void set_arch (gdbarch *arch);
|
||
|
||
/* Get this inferior's arch. */
|
||
gdbarch *arch ()
|
||
{ return m_gdbarch; }
|
||
|
||
/* Convenient handle (GDB inferior id). Unique across all
|
||
inferiors. */
|
||
int num = 0;
|
||
|
||
/* Actual target inferior id, usually, a process id. This matches
|
||
the ptid_t.pid member of threads of this inferior. */
|
||
int pid = 0;
|
||
/* True if the PID was actually faked by GDB. */
|
||
bool fake_pid_p = false;
|
||
|
||
/* The highest thread number this inferior ever had. */
|
||
int highest_thread_num = 0;
|
||
|
||
/* State of GDB control of inferior process execution.
|
||
See `struct inferior_control_state'. */
|
||
inferior_control_state control;
|
||
|
||
/* True if this was an auto-created inferior, e.g. created from
|
||
following a fork; false, if this inferior was manually added by
|
||
the user, and we should not attempt to prune it
|
||
automatically. */
|
||
bool removable = false;
|
||
|
||
/* The address space bound to this inferior. */
|
||
address_space_ref_ptr aspace;
|
||
|
||
/* The program space bound to this inferior. */
|
||
struct program_space *pspace = NULL;
|
||
|
||
/* The terminal state as set by the last target_terminal::terminal_*
|
||
call. */
|
||
target_terminal_state terminal_state = target_terminal_state::is_ours;
|
||
|
||
/* Environment to use for running inferior,
|
||
in format described in environ.h. */
|
||
gdb_environ environment;
|
||
|
||
/* True if this child process was attached rather than forked. */
|
||
bool attach_flag = false;
|
||
|
||
/* If this inferior is a vfork child, then this is the pointer to
|
||
its vfork parent, if GDB is still attached to it. */
|
||
inferior *vfork_parent = NULL;
|
||
|
||
/* If this process is a vfork parent, this is the pointer to the
|
||
child. Since a vfork parent is left frozen by the kernel until
|
||
the child execs or exits, a process can only have one vfork child
|
||
at a given time. */
|
||
inferior *vfork_child = NULL;
|
||
|
||
/* True if this inferior should be detached when it's vfork sibling
|
||
exits or execs. */
|
||
bool pending_detach = false;
|
||
|
||
/* If non-nullptr, points to a thread that called vfork and is now waiting
|
||
for a vfork child not under our control to be done with the shared memory
|
||
region, either by exiting or execing. */
|
||
thread_info *thread_waiting_for_vfork_done = nullptr;
|
||
|
||
/* True if we're in the process of detaching from this inferior. */
|
||
bool detaching = false;
|
||
|
||
/* True if setup_inferior wasn't called for this inferior yet.
|
||
Until that is done, we must not access inferior memory or
|
||
registers, as we haven't determined the target
|
||
architecture/description. */
|
||
bool needs_setup = false;
|
||
|
||
/* True if the inferior is starting up (inside startup_inferior),
|
||
and we're nursing it along (through the shell) until it is ready
|
||
to execute its first instruction. Until that is done, we must
|
||
not access inferior memory or registers, as we haven't determined
|
||
the target architecture/description. */
|
||
bool starting_up = false;
|
||
|
||
/* True when we are reading the library list of the inferior during an
|
||
attach or handling a fork child. */
|
||
bool in_initial_library_scan = false;
|
||
|
||
/* Private data used by the process_stratum target. */
|
||
std::unique_ptr<private_inferior> priv;
|
||
|
||
/* HAS_EXIT_CODE is true if the inferior exited with an exit code.
|
||
In this case, the EXIT_CODE field is also valid. */
|
||
bool has_exit_code = false;
|
||
LONGEST exit_code = 0;
|
||
|
||
/* Default flags to pass to the symbol reading functions. These are
|
||
used whenever a new objfile is created. */
|
||
symfile_add_flags symfile_flags = 0;
|
||
|
||
/* Info about an inferior's target description (if it's fetched; the
|
||
user supplied description's filename, if any; etc.). */
|
||
target_desc_info tdesc_info;
|
||
|
||
/* Data related to displaced stepping. */
|
||
displaced_step_inferior_state displaced_step_state;
|
||
|
||
/* Per inferior data-pointers required by other GDB modules. */
|
||
registry<inferior> registry_fields;
|
||
|
||
private:
|
||
|
||
/* Unpush TARGET and assert that it worked. */
|
||
void unpush_target_and_assert (struct target_ops *target);
|
||
|
||
/* The inferior's target stack. */
|
||
target_stack m_target_stack;
|
||
|
||
/* The name of terminal device to use for I/O. */
|
||
std::string m_terminal;
|
||
|
||
/* The list of continuations. */
|
||
std::list<std::function<void ()>> m_continuations;
|
||
|
||
/* The arguments string to use when running. */
|
||
std::string m_args;
|
||
|
||
/* The current working directory that will be used when starting
|
||
this inferior. */
|
||
std::string m_cwd;
|
||
|
||
/* The architecture associated with the inferior through the
|
||
connection to the target.
|
||
|
||
The architecture vector provides some information that is really
|
||
a property of the inferior, accessed through a particular target:
|
||
ptrace operations; the layout of certain RSP packets; the
|
||
solib_ops vector; etc. To differentiate architecture accesses to
|
||
per-inferior/target properties from
|
||
per-thread/per-frame/per-objfile properties, accesses to
|
||
per-inferior/target properties should be made through
|
||
this gdbarch. */
|
||
gdbarch *m_gdbarch = nullptr;
|
||
};
|
||
|
||
/* Add an inferior to the inferior list, print a message that a new
|
||
inferior is found, and return the pointer to the new inferior.
|
||
Caller may use this pointer to initialize the private inferior
|
||
data. */
|
||
extern struct inferior *add_inferior (int pid);
|
||
|
||
/* Same as add_inferior, but don't print new inferior notifications to
|
||
the CLI. */
|
||
extern struct inferior *add_inferior_silent (int pid);
|
||
|
||
extern void delete_inferior (struct inferior *todel);
|
||
|
||
/* Delete an existing inferior list entry, due to inferior detaching. */
|
||
extern void detach_inferior (inferior *inf);
|
||
|
||
/* Notify observers and interpreters that INF has gone away. Reset the INF
|
||
object back to an default, empty, state. Clear register and frame
|
||
caches. */
|
||
extern void exit_inferior (inferior *inf);
|
||
|
||
extern void inferior_appeared (struct inferior *inf, int pid);
|
||
|
||
/* 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 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);
|
||
|
||
/* Find an inferior bound to PSPACE, giving preference to the current
|
||
inferior. */
|
||
extern struct inferior *
|
||
find_inferior_for_program_space (struct program_space *pspace);
|
||
|
||
/* Returns true if the inferior list is not empty. */
|
||
extern int have_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). */
|
||
extern int have_live_inferiors (void);
|
||
|
||
/* Save/restore the current inferior. */
|
||
|
||
class scoped_restore_current_inferior
|
||
{
|
||
public:
|
||
scoped_restore_current_inferior ()
|
||
: m_saved_inf (current_inferior ())
|
||
{}
|
||
|
||
~scoped_restore_current_inferior ()
|
||
{ set_current_inferior (m_saved_inf); }
|
||
|
||
DISABLE_COPY_AND_ASSIGN (scoped_restore_current_inferior);
|
||
|
||
private:
|
||
inferior *m_saved_inf;
|
||
};
|
||
|
||
/* When reading memory from an inferior, the global inferior_ptid must
|
||
also be set. This class arranges to save and restore the necessary
|
||
state for reading or writing memory, but without invalidating the
|
||
frame cache. */
|
||
|
||
class scoped_restore_current_inferior_for_memory
|
||
{
|
||
public:
|
||
|
||
/* Save the current globals and switch to the given inferior and the
|
||
inferior's program space. inferior_ptid is set to point to the
|
||
inferior's process id (and not to any particular thread). */
|
||
explicit scoped_restore_current_inferior_for_memory (inferior *inf)
|
||
: m_save_ptid (&inferior_ptid)
|
||
{
|
||
set_current_inferior (inf);
|
||
set_current_program_space (inf->pspace);
|
||
inferior_ptid = ptid_t (inf->pid);
|
||
}
|
||
|
||
DISABLE_COPY_AND_ASSIGN (scoped_restore_current_inferior_for_memory);
|
||
|
||
private:
|
||
|
||
scoped_restore_current_inferior m_save_inferior;
|
||
scoped_restore_current_program_space m_save_progspace;
|
||
scoped_restore_tmpl<ptid_t> m_save_ptid;
|
||
};
|
||
|
||
|
||
/* Traverse all inferiors. */
|
||
|
||
extern intrusive_list<inferior> inferior_list;
|
||
|
||
/* Pull in the internals of the inferiors ranges and iterators. Must
|
||
be done after struct inferior is defined. */
|
||
#include "inferior-iter.h"
|
||
|
||
/* Return a range that can be used to walk over all inferiors
|
||
inferiors, with range-for, safely. I.e., it is safe to delete the
|
||
currently-iterated inferior. When combined with range-for, this
|
||
allow convenient patterns like this:
|
||
|
||
for (inferior *inf : all_inferiors_safe ())
|
||
if (some_condition ())
|
||
delete inf;
|
||
*/
|
||
|
||
inline all_inferiors_safe_range
|
||
all_inferiors_safe ()
|
||
{
|
||
return all_inferiors_safe_range (nullptr, inferior_list);
|
||
}
|
||
|
||
/* Returns a range representing all inferiors, suitable to use with
|
||
range-for, like this:
|
||
|
||
for (inferior *inf : all_inferiors ())
|
||
[...]
|
||
*/
|
||
|
||
inline all_inferiors_range
|
||
all_inferiors (process_stratum_target *proc_target = nullptr)
|
||
{
|
||
return all_inferiors_range (proc_target, inferior_list);
|
||
}
|
||
|
||
/* 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 (process_stratum_target *proc_target = nullptr)
|
||
{
|
||
return all_non_exited_inferiors_range (proc_target, inferior_list);
|
||
}
|
||
|
||
/* Prune away automatically added inferiors that aren't required
|
||
anymore. */
|
||
extern void prune_inferiors (void);
|
||
|
||
extern int number_of_inferiors (void);
|
||
|
||
extern struct inferior *add_inferior_with_spaces (void);
|
||
|
||
/* Print the current selected inferior. */
|
||
extern void print_selected_inferior (struct ui_out *uiout);
|
||
|
||
/* 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. */
|
||
|
||
extern void switch_to_inferior_and_push_target
|
||
(inferior *new_inf, bool no_connection, inferior *org_inf);
|
||
|
||
/* Return true if ID is a valid global inferior number. */
|
||
|
||
inline bool
|
||
valid_global_inferior_id (int id)
|
||
{
|
||
for (inferior *inf : all_inferiors ())
|
||
if (inf->num == id)
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
#endif /* !defined (INFERIOR_H) */
|