of variables any more (the file target is handling them and they
never get to the process target). So when you push a file target,
it goes into the file stratum, which is always below the process
- stratum. */
+ stratum.
+
+ Note that rather than allow an empty stack, we always have the
+ dummy target at the bottom stratum, so we can call the target
+ methods without checking them. */
#include "target/target.h"
#include "target/resume.h"
const char *name;
};
-/* Return a pretty printed form of TARGET_OPTIONS.
- Space for the result is malloc'd, caller must free. */
-extern char *target_options_to_string (int target_options);
+/* Return a pretty printed form of TARGET_OPTIONS. */
+extern std::string target_options_to_string (int target_options);
/* Possible types of events that the inferior handler will have to
deal with. */
of the process ID of the process in question, in hexadecimal
format. */
TARGET_OBJECT_EXEC_FILE,
+ /* FreeBSD virtual memory mappings. */
+ TARGET_OBJECT_FREEBSD_VMMAP,
+ /* FreeBSD process strings. */
+ TARGET_OBJECT_FREEBSD_PS_STRINGS,
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};
#define TARGET_DEFAULT_RETURN(ARG)
#define TARGET_DEFAULT_FUNC(ARG)
+/* Each target that can be activated with "target TARGET_NAME" passes
+ the address of one of these objects to add_target, which uses the
+ object's address as unique identifier, and registers the "target
+ TARGET_NAME" command using SHORTNAME as target name. */
+
+struct target_info
+{
+ /* Name of this target. */
+ const char *shortname;
+
+ /* Name for printing. */
+ const char *longname;
+
+ /* Documentation. Does not include trailing newline, and starts
+ with a one-line description (probably similar to longname). */
+ const char *doc;
+};
+
struct target_ops
{
- struct target_ops *beneath; /* To the target under this one. */
+ /* To the target under this one. */
+ target_ops *beneath () const;
+ /* Free resources associated with the target. Note that singleton
+ targets, like e.g., native targets, are global objects, not
+ heap allocated, and are thus only deleted on GDB exit. The
+ main teardown entry point is the "close" method, below. */
virtual ~target_ops () {}
- /* Name this target type. */
- virtual const char *shortname () = 0;
-
- /* Name for printing. */
- virtual const char *longname () = 0;
+ /* Return a reference to this target's unique target_info
+ object. */
+ virtual const target_info &info () const = 0;
- /* Documentation. Does not include trailing newline, and starts
- ith a one-line description (probably similar to longname). */
- virtual const char *doc () = 0;
+ /* Name this target type. */
+ const char *shortname ()
+ { return info ().shortname; }
- /* The open routine takes the rest of the parameters from the
- command, and (if successful) pushes a new target onto the
- stack. Targets should supply this routine, if only to provide
- an error message. */
- virtual void open (const char *, int);
+ const char *longname ()
+ { return info ().longname; }
/* Close the target. This is where the target can handle
teardown. Heap-allocated targets should delete themselves
TARGET_DEFAULT_RETURN (false);
virtual int have_steppable_watchpoint ()
TARGET_DEFAULT_RETURN (false);
- virtual bool have_continuable_watchpoint ()
- TARGET_DEFAULT_RETURN (false);
virtual bool stopped_data_address (CORE_ADDR *)
TARGET_DEFAULT_RETURN (false);
virtual bool watchpoint_addr_within_range (CORE_ADDR, CORE_ADDR, int)
TARGET_DEFAULT_IGNORE ();
};
+/* Deleter for std::unique_ptr. See comments in
+ target_ops::~target_ops and target_ops::close about heap-allocated
+ targets. */
+struct target_ops_deleter
+{
+ void operator() (target_ops *target)
+ {
+ target->close ();
+ }
+};
+
+/* A unique pointer for target_ops. */
+typedef std::unique_ptr<target_ops, target_ops_deleter> target_ops_up;
+
+/* 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. */
+extern void set_native_target (target_ops *target);
+
+/* Get the registered native target, if there's one. Otherwise return
+ NULL. */
+extern target_ops *get_native_target ();
+
+/* Type that manages a target stack. See description of target stacks
+ and strata at the top of the file. */
+
+class target_stack
+{
+public:
+ target_stack () = default;
+ DISABLE_COPY_AND_ASSIGN (target_stack);
+
+ /* Push a new target into the stack of the existing target
+ accessors, possibly superseding some existing accessor. */
+ void push (target_ops *t);
+
+ /* Remove a target from the stack, wherever it may be. Return true
+ if it was removed, false otherwise. */
+ bool unpush (target_ops *t);
+
+ /* Returns true if T is pushed on the target stack. */
+ bool is_pushed (target_ops *t) const
+ { return at (t->to_stratum) == t; }
+
+ /* Return the target at STRATUM. */
+ target_ops *at (strata stratum) const { return m_stack[stratum]; }
+
+ /* Return the target at the top of the stack. */
+ target_ops *top () const { return at (m_top); }
+
+ /* Find the next target down the stack from the specified target. */
+ target_ops *find_beneath (const target_ops *t) const;
+
+private:
+ /* The stratum of the top target. */
+ enum strata m_top {};
+
+ /* The stack, represented as an array, with one slot per stratum.
+ If no target is pushed at some stratum, the corresponding slot is
+ null. */
+ target_ops *m_stack[(int) debug_stratum + 1] {};
+};
+
/* The ops structure for our "current" target process. This should
never be NULL. If there is no target, it points to the dummy_target. */
-extern struct target_ops *target_stack;
+extern target_ops *current_top_target ();
/* Define easy words for doing these operations on our current target. */
-#define target_shortname (target_stack->shortname ())
-#define target_longname (target_stack->longname ())
+#define target_shortname (current_top_target ()->shortname ())
+#define target_longname (current_top_target ()->longname ())
/* Does whatever cleanup is required for a target that we are no
longer going to be calling. This routine is automatically always
These targets must set to_attach_no_wait. */
#define target_attach_no_wait() \
- (target_stack->attach_no_wait ())
+ (current_top_target ()->attach_no_wait ())
/* The target_attach operation places a process under debugger control,
and stops the process.
This operation provides a target-specific hook that allows the
necessary bookkeeping to be performed after an attach completes. */
#define target_post_attach(pid) \
- (target_stack->post_attach) (pid)
+ (current_top_target ()->post_attach) (pid)
/* Display a message indicating we're about to detach from the current
inferior process. */
debugged. */
#define target_prepare_to_store(regcache) \
- (target_stack->prepare_to_store) (regcache)
+ (current_top_target ()->prepare_to_store) (regcache)
/* Determine current address space of thread PTID. */
while a trace experiment is running. */
#define target_supports_enable_disable_tracepoint() \
- (target_stack->supports_enable_disable_tracepoint) ()
+ (current_top_target ()->supports_enable_disable_tracepoint) ()
#define target_supports_string_tracing() \
- (target_stack->supports_string_tracing) ()
+ (current_top_target ()->supports_string_tracing) ()
/* Returns true if this target can handle breakpoint conditions
on its end. */
#define target_supports_evaluation_of_breakpoint_conditions() \
- (target_stack->supports_evaluation_of_breakpoint_conditions) ()
+ (current_top_target ()->supports_evaluation_of_breakpoint_conditions) ()
/* Returns true if this target can handle breakpoint commands
on its end. */
#define target_can_run_breakpoint_commands() \
- (target_stack->can_run_breakpoint_commands) ()
+ (current_top_target ()->can_run_breakpoint_commands) ()
extern int target_read_string (CORE_ADDR, gdb::unique_xmalloc_ptr<char> *,
int, int *);
/* Print a line about the current target. */
#define target_files_info() \
- (target_stack->files_info) ()
+ (current_top_target ()->files_info) ()
/* Insert a breakpoint at address BP_TGT->placed_address in
the target machine. Returns 0 for success, and returns non-zero or
Such targets will supply an appropriate definition for this function. */
#define target_post_startup_inferior(ptid) \
- (target_stack->post_startup_inferior) (ptid)
+ (current_top_target ()->post_startup_inferior) (ptid)
/* On some targets, we can catch an inferior fork or vfork event when
it occurs. These functions insert/remove an already-created
catchpoint type is not supported and -1 for failure. */
#define target_insert_fork_catchpoint(pid) \
- (target_stack->insert_fork_catchpoint) (pid)
+ (current_top_target ()->insert_fork_catchpoint) (pid)
#define target_remove_fork_catchpoint(pid) \
- (target_stack->remove_fork_catchpoint) (pid)
+ (current_top_target ()->remove_fork_catchpoint) (pid)
#define target_insert_vfork_catchpoint(pid) \
- (target_stack->insert_vfork_catchpoint) (pid)
+ (current_top_target ()->insert_vfork_catchpoint) (pid)
#define target_remove_vfork_catchpoint(pid) \
- (target_stack->remove_vfork_catchpoint) (pid)
+ (current_top_target ()->remove_vfork_catchpoint) (pid)
/* If the inferior forks or vforks, this function will be called at
the next resume in order to perform any bookkeeping and fiddling
catchpoint type is not supported and -1 for failure. */
#define target_insert_exec_catchpoint(pid) \
- (target_stack->insert_exec_catchpoint) (pid)
+ (current_top_target ()->insert_exec_catchpoint) (pid)
#define target_remove_exec_catchpoint(pid) \
- (target_stack->remove_exec_catchpoint) (pid)
+ (current_top_target ()->remove_exec_catchpoint) (pid)
/* Syscall catch.
for failure. */
#define target_set_syscall_catchpoint(pid, needed, any_count, syscall_counts) \
- (target_stack->set_syscall_catchpoint) (pid, needed, any_count, \
+ (current_top_target ()->set_syscall_catchpoint) (pid, needed, any_count, \
syscall_counts)
/* The debugger has completed a blocking wait() call. There is now
placed in OUTBUF. */
#define target_rcmd(command, outbuf) \
- (target_stack->rcmd) (command, outbuf)
+ (current_top_target ()->rcmd) (command, outbuf)
/* Does the target include all of memory, or only part of it? This
Can it lock the thread scheduler? */
#define target_can_lock_scheduler \
- (target_stack->get_thread_control_capabilities () & tc_schedlock)
+ (current_top_target ()->get_thread_control_capabilities () & tc_schedlock)
/* Controls whether async mode is permitted. */
extern int target_async_permitted;
/* Can the target support asynchronous execution? */
-#define target_can_async_p() (target_stack->can_async_p ())
+#define target_can_async_p() (current_top_target ()->can_async_p ())
/* Is the target in asynchronous execution mode? */
-#define target_is_async_p() (target_stack->is_async_p ())
+#define target_is_async_p() (current_top_target ()->is_async_p ())
/* Enables/disabled async target events. */
extern void target_async (int enable);
extern int target_is_non_stop_p (void);
#define target_execution_direction() \
- (target_stack->execution_direction ())
+ (current_top_target ()->execution_direction ())
/* Converts a process id to a string. Usually, the string just contains
`process xyz', but on some systems it may contain
is okay. */
#define target_extra_thread_info(TP) \
- (target_stack->extra_thread_info (TP))
+ (current_top_target ()->extra_thread_info (TP))
/* Return the thread's name, or NULL if the target is unable to determine it.
The returned value must not be freed by the caller. */
it must persist. */
#define target_pid_to_exec_file(pid) \
- (target_stack->pid_to_exec_file) (pid)
+ (current_top_target ()->pid_to_exec_file) (pid)
/* See the to_thread_architecture description in struct target_ops. */
#define target_thread_architecture(ptid) \
- (target_stack->thread_architecture (ptid))
+ (current_top_target ()->thread_architecture (ptid))
/*
* Iterator function for target memory regions.
*/
#define target_find_memory_regions(FUNC, DATA) \
- (target_stack->find_memory_regions) (FUNC, DATA)
+ (current_top_target ()->find_memory_regions) (FUNC, DATA)
/*
* Compose corefile .note section.
*/
#define target_make_corefile_notes(BFD, SIZE_P) \
- (target_stack->make_corefile_notes) (BFD, SIZE_P)
+ (current_top_target ()->make_corefile_notes) (BFD, SIZE_P)
/* Bookmark interfaces. */
#define target_get_bookmark(ARGS, FROM_TTY) \
- (target_stack->get_bookmark) (ARGS, FROM_TTY)
+ (current_top_target ()->get_bookmark) (ARGS, FROM_TTY)
#define target_goto_bookmark(ARG, FROM_TTY) \
- (target_stack->goto_bookmark) (ARG, FROM_TTY)
+ (current_top_target ()->goto_bookmark) (ARG, FROM_TTY)
/* Hardware watchpoint interfaces. */
+/* GDB's current model is that there are three "kinds" of watchpoints,
+ with respect to when they trigger and how you can move past them.
+
+ Those are: continuable, steppable, and non-steppable.
+
+ Continuable watchpoints are like x86's -- those trigger after the
+ memory access's side effects are fully committed to memory. I.e.,
+ they trap with the PC pointing at the next instruction already.
+ Continuing past such a watchpoint is doable by just normally
+ continuing, hence the name.
+
+ Both steppable and non-steppable watchpoints trap before the memory
+ access. I.e, the PC points at the instruction that is accessing
+ the memory. So GDB needs to single-step once past the current
+ instruction in order to make the access effective and check whether
+ the instruction's side effects change the watched expression.
+
+ Now, in order to step past that instruction, depending on
+ architecture and target, you can have two situations:
+
+ - steppable watchpoints: you can single-step with the watchpoint
+ still armed, and the watchpoint won't trigger again.
+
+ - non-steppable watchpoints: if you try to single-step with the
+ watchpoint still armed, you'd trap the watchpoint again and the
+ thread wouldn't make any progress. So GDB needs to temporarily
+ remove the watchpoint in order to step past it.
+
+ If your target/architecture does not signal that it has either
+ steppable or non-steppable watchpoints via either
+ target_have_steppable_watchpoint or
+ gdbarch_have_nonsteppable_watchpoint, GDB assumes continuable
+ watchpoints. */
+
/* Returns non-zero if we were stopped by a hardware watchpoint (memory read or
write). Only the INFERIOR_PTID task is being queried. */
#define target_stopped_by_watchpoint() \
- ((target_stack->stopped_by_watchpoint) ())
+ ((current_top_target ()->stopped_by_watchpoint) ())
/* Returns non-zero if the target stopped because it executed a
software breakpoint instruction. */
#define target_stopped_by_sw_breakpoint() \
- ((target_stack->stopped_by_sw_breakpoint) ())
+ ((current_top_target ()->stopped_by_sw_breakpoint) ())
#define target_supports_stopped_by_sw_breakpoint() \
- ((target_stack->supports_stopped_by_sw_breakpoint) ())
+ ((current_top_target ()->supports_stopped_by_sw_breakpoint) ())
#define target_stopped_by_hw_breakpoint() \
- ((target_stack->stopped_by_hw_breakpoint) ())
+ ((current_top_target ()->stopped_by_hw_breakpoint) ())
#define target_supports_stopped_by_hw_breakpoint() \
- ((target_stack->supports_stopped_by_hw_breakpoint) ())
+ ((current_top_target ()->supports_stopped_by_hw_breakpoint) ())
/* Non-zero if we have steppable watchpoints */
#define target_have_steppable_watchpoint \
- (target_stack->have_steppable_watchpoint ())
-
-/* Non-zero if we have continuable watchpoints */
-
-#define target_have_continuable_watchpoint \
- (target_stack->have_continuable_watchpoint ())
+ (current_top_target ()->have_steppable_watchpoint ())
/* Provide defaults for hardware watchpoint functions. */
this one used so far. */
#define target_can_use_hardware_watchpoint(TYPE,CNT,OTHERTYPE) \
- (target_stack->can_use_hw_breakpoint) ( \
+ (current_top_target ()->can_use_hw_breakpoint) ( \
TYPE, CNT, OTHERTYPE)
/* Returns the number of debug registers needed to watch the given
memory region, or zero if not supported. */
#define target_region_ok_for_hw_watchpoint(addr, len) \
- (target_stack->region_ok_for_hw_watchpoint) (addr, len)
+ (current_top_target ()->region_ok_for_hw_watchpoint) (addr, len)
#define target_can_do_single_step() \
- (target_stack->can_do_single_step) ()
+ (current_top_target ()->can_do_single_step) ()
/* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
-1 for failure. */
#define target_insert_watchpoint(addr, len, type, cond) \
- (target_stack->insert_watchpoint) (addr, len, type, cond)
+ (current_top_target ()->insert_watchpoint) (addr, len, type, cond)
#define target_remove_watchpoint(addr, len, type, cond) \
- (target_stack->remove_watchpoint) (addr, len, type, cond)
+ (current_top_target ()->remove_watchpoint) (addr, len, type, cond)
/* Insert a new masked watchpoint at ADDR using the mask MASK.
RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
message) otherwise. */
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
- (target_stack->insert_hw_breakpoint) (gdbarch, bp_tgt)
+ (current_top_target ()->insert_hw_breakpoint) (gdbarch, bp_tgt)
#define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
- (target_stack->remove_hw_breakpoint) (gdbarch, bp_tgt)
+ (current_top_target ()->remove_hw_breakpoint) (gdbarch, bp_tgt)
/* Return number of debug registers needed for a ranged breakpoint,
or -1 if ranged breakpoints are not supported. */
For this reason, GDB will still evaluate the condition expression when
the watchpoint triggers. */
#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
- (target_stack->can_accel_watchpoint_condition) (addr, len, type, cond)
+ (current_top_target ()->can_accel_watchpoint_condition) (addr, len, type, cond)
/* Return number of debug registers needed for a masked watchpoint,
-1 if masked watchpoints are not supported or -2 if the given address
/* Target can execute in reverse? */
#define target_can_execute_reverse \
- target_stack->can_execute_reverse ()
+ current_top_target ()->can_execute_reverse ()
extern const struct target_desc *target_read_description (struct target_ops *);
#define target_get_ada_task_ptid(lwp, tid) \
- (target_stack->get_ada_task_ptid) (lwp,tid)
+ (current_top_target ()->get_ada_task_ptid) (lwp,tid)
/* Utility implementation of searching memory. */
extern int simple_search_memory (struct target_ops* ops,
/* Return nonzero if the filesystem seen by the current inferior
is the local filesystem, zero otherwise. */
#define target_filesystem_is_local() \
- target_stack->filesystem_is_local ()
+ current_top_target ()->filesystem_is_local ()
/* Open FILENAME on the target, in the filesystem as seen by INF,
using FLAGS and MODE. If INF is NULL, use the filesystem seen
/* Tracepoint-related operations. */
#define target_trace_init() \
- (target_stack->trace_init) ()
+ (current_top_target ()->trace_init) ()
#define target_download_tracepoint(t) \
- (target_stack->download_tracepoint) (t)
+ (current_top_target ()->download_tracepoint) (t)
#define target_can_download_tracepoint() \
- (target_stack->can_download_tracepoint) ()
+ (current_top_target ()->can_download_tracepoint) ()
#define target_download_trace_state_variable(tsv) \
- (target_stack->download_trace_state_variable) (tsv)
+ (current_top_target ()->download_trace_state_variable) (tsv)
#define target_enable_tracepoint(loc) \
- (target_stack->enable_tracepoint) (loc)
+ (current_top_target ()->enable_tracepoint) (loc)
#define target_disable_tracepoint(loc) \
- (target_stack->disable_tracepoint) (loc)
+ (current_top_target ()->disable_tracepoint) (loc)
#define target_trace_start() \
- (target_stack->trace_start) ()
+ (current_top_target ()->trace_start) ()
#define target_trace_set_readonly_regions() \
- (target_stack->trace_set_readonly_regions) ()
+ (current_top_target ()->trace_set_readonly_regions) ()
#define target_get_trace_status(ts) \
- (target_stack->get_trace_status) (ts)
+ (current_top_target ()->get_trace_status) (ts)
#define target_get_tracepoint_status(tp,utp) \
- (target_stack->get_tracepoint_status) (tp, utp)
+ (current_top_target ()->get_tracepoint_status) (tp, utp)
#define target_trace_stop() \
- (target_stack->trace_stop) ()
+ (current_top_target ()->trace_stop) ()
#define target_trace_find(type,num,addr1,addr2,tpp) \
- (target_stack->trace_find) (\
+ (current_top_target ()->trace_find) (\
(type), (num), (addr1), (addr2), (tpp))
#define target_get_trace_state_variable_value(tsv,val) \
- (target_stack->get_trace_state_variable_value) ((tsv), (val))
+ (current_top_target ()->get_trace_state_variable_value) ((tsv), (val))
#define target_save_trace_data(filename) \
- (target_stack->save_trace_data) (filename)
+ (current_top_target ()->save_trace_data) (filename)
#define target_upload_tracepoints(utpp) \
- (target_stack->upload_tracepoints) (utpp)
+ (current_top_target ()->upload_tracepoints) (utpp)
#define target_upload_trace_state_variables(utsvp) \
- (target_stack->upload_trace_state_variables) (utsvp)
+ (current_top_target ()->upload_trace_state_variables) (utsvp)
#define target_get_raw_trace_data(buf,offset,len) \
- (target_stack->get_raw_trace_data) ((buf), (offset), (len))
+ (current_top_target ()->get_raw_trace_data) ((buf), (offset), (len))
#define target_get_min_fast_tracepoint_insn_len() \
- (target_stack->get_min_fast_tracepoint_insn_len) ()
+ (current_top_target ()->get_min_fast_tracepoint_insn_len) ()
#define target_set_disconnected_tracing(val) \
- (target_stack->set_disconnected_tracing) (val)
+ (current_top_target ()->set_disconnected_tracing) (val)
#define target_set_circular_trace_buffer(val) \
- (target_stack->set_circular_trace_buffer) (val)
+ (current_top_target ()->set_circular_trace_buffer) (val)
#define target_set_trace_buffer_size(val) \
- (target_stack->set_trace_buffer_size) (val)
+ (current_top_target ()->set_trace_buffer_size) (val)
#define target_set_trace_notes(user,notes,stopnotes) \
- (target_stack->set_trace_notes) ((user), (notes), (stopnotes))
+ (current_top_target ()->set_trace_notes) ((user), (notes), (stopnotes))
#define target_get_tib_address(ptid, addr) \
- (target_stack->get_tib_address) ((ptid), (addr))
+ (current_top_target ()->get_tib_address) ((ptid), (addr))
#define target_set_permissions() \
- (target_stack->set_permissions) ()
+ (current_top_target ()->set_permissions) ()
#define target_static_tracepoint_marker_at(addr, marker) \
- (target_stack->static_tracepoint_marker_at) (addr, marker)
+ (current_top_target ()->static_tracepoint_marker_at) (addr, marker)
#define target_static_tracepoint_markers_by_strid(marker_id) \
- (target_stack->static_tracepoint_markers_by_strid) (marker_id)
+ (current_top_target ()->static_tracepoint_markers_by_strid) (marker_id)
#define target_traceframe_info() \
- (target_stack->traceframe_info) ()
+ (current_top_target ()->traceframe_info) ()
#define target_use_agent(use) \
- (target_stack->use_agent) (use)
+ (current_top_target ()->use_agent) (use)
#define target_can_use_agent() \
- (target_stack->can_use_agent) ()
+ (current_top_target ()->can_use_agent) ()
#define target_augmented_libraries_svr4_read() \
- (target_stack->augmented_libraries_svr4_read) ()
+ (current_top_target ()->augmented_libraries_svr4_read) ()
/* Command logging facility. */
#define target_log_command(p) \
- (target_stack->log_command) (p)
+ (current_top_target ()->log_command) (p)
extern int target_core_of_thread (ptid_t ptid);
no matter where it is on the list. Returns 0 if no
change, 1 if removed from stack. */
-extern void add_target (struct target_ops *);
+/* Type of callback called when the user activates a target with
+ "target TARGET_NAME". The callback routine takes the rest of the
+ parameters from the command, and (if successful) pushes a new
+ target onto the stack. */
+typedef void target_open_ftype (const char *args, int from_tty);
+
+/* Add the target described by INFO to the list of possible targets
+ and add a new command 'target $(INFO->shortname)'. Set COMPLETER
+ as the command's completer if not NULL. */
-extern void add_target_with_completer (struct target_ops *t,
- completer_ftype *completer);
+extern void add_target (const target_info &info,
+ target_open_ftype *func,
+ completer_ftype *completer = NULL);
-/* Adds a command ALIAS for target T and marks it deprecated. This is useful
- for maintaining backwards compatibility when renaming targets. */
+/* Adds a command ALIAS for the target described by INFO and marks it
+ deprecated. This is useful for maintaining backwards compatibility
+ when renaming targets. */
-extern void add_deprecated_target_alias (struct target_ops *t,
+extern void add_deprecated_target_alias (const target_info &info,
const char *alias);
extern void push_target (struct target_ops *);
extern void target_require_runnable (void);
-extern struct target_ops *find_target_beneath (struct target_ops *);
-
/* Find the target at STRATUM. If no target is at that stratum,
return NULL. */
to_stratum = process_stratum;
}
- const char *shortname () override
- {
- return NULL;
- }
-
- const char *longname () override
- {
- return NULL;
- }
-
- const char *doc () override
- {
- return NULL;
- }
+ const target_info &info () const override;
bool has_registers () override
{