758 lines
24 KiB
C
758 lines
24 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-2022 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;
|
|||
|
struct frame_info;
|
|||
|
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. */
|
|||
|
bool unwinding;
|
|||
|
#if __cpp_lib_uncaught_exceptions
|
|||
|
unwinding = std::uncaught_exceptions () > 0;
|
|||
|
#else
|
|||
|
unwinding = std::uncaught_exception ();
|
|||
|
#endif
|
|||
|
if (!unwinding)
|
|||
|
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,
|
|||
|
struct frame_info *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,
|
|||
|
struct frame_info *frame,
|
|||
|
const char *args);
|
|||
|
|
|||
|
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_terminal_init_with_pgrp (int pgrp);
|
|||
|
|
|||
|
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 set_inferior_args_vector (int, char **);
|
|||
|
|
|||
|
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
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/* Possible values for gdbarch_call_dummy_location. */
|
|||
|
#define ON_STACK 1
|
|||
|
#define AT_ENTRY_POINT 4
|
|||
|
|
|||
|
/* 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;
|
|||
|
};
|
|||
|
|
|||
|
/* 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);
|
|||
|
|
|||
|
/* 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 (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 (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 *, hash_ptid> 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 ()); }
|
|||
|
|
|||
|
/* Delete all threads in the thread list. If SILENT, exit threads
|
|||
|
silently. */
|
|||
|
void clear_thread_list (bool silent);
|
|||
|
|
|||
|
/* 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);
|
|||
|
};
|
|||
|
|
|||
|
/* 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;
|
|||
|
}
|
|||
|
|
|||
|
/* 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. */
|
|||
|
struct address_space *aspace = NULL;
|
|||
|
|
|||
|
/* 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 target vector implementation. */
|
|||
|
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 = NULL;
|
|||
|
|
|||
|
/* 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. */
|
|||
|
struct gdbarch *gdbarch = NULL;
|
|||
|
|
|||
|
/* Data related to displaced stepping. */
|
|||
|
displaced_step_inferior_state displaced_step_state;
|
|||
|
|
|||
|
/* Per inferior data-pointers required by other GDB modules. */
|
|||
|
REGISTRY_FIELDS;
|
|||
|
|
|||
|
private:
|
|||
|
/* 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;
|
|||
|
};
|
|||
|
|
|||
|
/* Keep a registry of per-inferior data-pointers required by other GDB
|
|||
|
modules. */
|
|||
|
|
|||
|
DECLARE_REGISTRY (inferior);
|
|||
|
|
|||
|
/* 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);
|
|||
|
|
|||
|
extern void exit_inferior (inferior *inf);
|
|||
|
|
|||
|
extern void exit_inferior_silent (inferior *inf);
|
|||
|
|
|||
|
extern void exit_inferior_num_silent (int num);
|
|||
|
|
|||
|
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;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/* 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);
|
|||
|
|
|||
|
#endif /* !defined (INFERIOR_H) */
|