/* Select target systems and architectures at runtime for GDB.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Cygnus Support.
#include "target-descriptions.h"
#include "gdbthread.h"
#include "solib.h"
+#include "exec.h"
+#include "inline-frame.h"
+#include "tracepoint.h"
static void target_info (char *, int);
-static void kill_or_be_killed (int);
-
static void default_terminal_info (char *, int);
static int default_watchpoint_addr_within_range (struct target_ops *,
static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
-static int nosymbol (char *, CORE_ADDR *);
-
-static void tcomplain (void) ATTR_NORETURN;
+static void tcomplain (void) ATTRIBUTE_NORETURN;
static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *);
static struct target_ops *find_default_run_target (char *);
-static void nosupport_runtime (void);
-
static LONGEST default_xfer_partial (struct target_ops *ops,
enum target_object object,
const char *annex, gdb_byte *readbuf,
void *readbuf, const void *writebuf,
ULONGEST offset, LONGEST len);
+static struct gdbarch *default_thread_architecture (struct target_ops *ops,
+ ptid_t ptid);
+
static void init_dummy_target (void);
static struct target_ops debug_target;
static void debug_to_files_info (struct target_ops *);
-static int debug_to_insert_breakpoint (struct bp_target_info *);
+static int debug_to_insert_breakpoint (struct gdbarch *,
+ struct bp_target_info *);
-static int debug_to_remove_breakpoint (struct bp_target_info *);
+static int debug_to_remove_breakpoint (struct gdbarch *,
+ struct bp_target_info *);
static int debug_to_can_use_hw_breakpoint (int, int, int);
-static int debug_to_insert_hw_breakpoint (struct bp_target_info *);
+static int debug_to_insert_hw_breakpoint (struct gdbarch *,
+ struct bp_target_info *);
-static int debug_to_remove_hw_breakpoint (struct bp_target_info *);
+static int debug_to_remove_hw_breakpoint (struct gdbarch *,
+ struct bp_target_info *);
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+ struct expression *);
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+ struct expression *);
static int debug_to_stopped_by_watchpoint (void);
static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+ struct expression *);
+
static void debug_to_terminal_init (void);
static void debug_to_terminal_inferior (void);
static void debug_to_load (char *, int);
-static int debug_to_lookup_symbol (char *, CORE_ADDR *);
-
static int debug_to_can_run (void);
-static void debug_to_notice_signals (ptid_t);
-
static void debug_to_stop (ptid_t);
-/* NOTE: cagney/2004-09-29: Many targets reference this variable in
- wierd and mysterious ways. Putting the variable here lets those
- wierd and mysterious ways keep building while they are being
- converted to the inferior inheritance structure. */
-struct target_ops deprecated_child_ops;
-
/* Pointer to array of target architecture structures; the size of the
array; the current index into the array; the allocated size of the
array. */
static int show_memory_breakpoints = 0;
+/* These globals control whether GDB attempts to perform these
+ operations; they are useful for targets that need to prevent
+ inadvertant disruption, such as in non-stop mode. */
+
+int may_write_registers = 1;
+
+int may_write_memory = 1;
+
+int may_insert_breakpoints = 1;
+
+int may_insert_tracepoints = 1;
+
+int may_insert_fast_tracepoints = 1;
+
+int may_stop = 1;
+
/* Non-zero if we want to see trace of target level stuff. */
static int targetdebug = 0;
static void setup_target_debug (void);
-DCACHE *target_dcache;
+/* The option sets this. */
+static int stack_cache_enabled_p_1 = 1;
+/* And set_stack_cache_enabled_p updates this.
+ The reason for the separation is so that we don't flush the cache for
+ on->on transitions. */
+static int stack_cache_enabled_p = 1;
+
+/* This is called *after* the stack-cache has been set.
+ Flush the cache for off->on and on->off transitions.
+ There's no real need to flush the cache for on->off transitions,
+ except cleanliness. */
+
+static void
+set_stack_cache_enabled_p (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ if (stack_cache_enabled_p != stack_cache_enabled_p_1)
+ target_dcache_invalidate ();
+
+ stack_cache_enabled_p = stack_cache_enabled_p_1;
+}
+
+static void
+show_stack_cache_enabled_p (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Cache use for stack accesses is %s.\n"), value);
+}
+
+/* Cache of memory operations, to speed up remote access. */
+static DCACHE *target_dcache;
+
+/* Invalidate the target dcache. */
+
+void
+target_dcache_invalidate (void)
+{
+ dcache_invalidate (target_dcache);
+}
/* The user just typed 'target' without the name of a target. */
gdb_stdout);
}
+/* Default target_has_* methods for process_stratum targets. */
+
+int
+default_child_has_all_memory (struct target_ops *ops)
+{
+ /* If no inferior selected, then we can't read memory here. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ return 1;
+}
+
+int
+default_child_has_memory (struct target_ops *ops)
+{
+ /* If no inferior selected, then we can't read memory here. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ return 1;
+}
+
+int
+default_child_has_stack (struct target_ops *ops)
+{
+ /* If no inferior selected, there's no stack. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ return 1;
+}
+
+int
+default_child_has_registers (struct target_ops *ops)
+{
+ /* Can't read registers from no inferior. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ return 1;
+}
+
+int
+default_child_has_execution (struct target_ops *ops, ptid_t the_ptid)
+{
+ /* If there's no thread selected, then we can't make it run through
+ hoops. */
+ if (ptid_equal (the_ptid, null_ptid))
+ return 0;
+
+ return 1;
+}
+
+
+int
+target_has_all_memory_1 (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_has_all_memory (t))
+ return 1;
+
+ return 0;
+}
+
+int
+target_has_memory_1 (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_has_memory (t))
+ return 1;
+
+ return 0;
+}
+
+int
+target_has_stack_1 (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_has_stack (t))
+ return 1;
+
+ return 0;
+}
+
+int
+target_has_registers_1 (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_has_registers (t))
+ return 1;
+
+ return 0;
+}
+
+int
+target_has_execution_1 (ptid_t the_ptid)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_has_execution (t, the_ptid))
+ return 1;
+
+ return 0;
+}
+
+int
+target_has_execution_current (void)
+{
+ return target_has_execution_1 (inferior_ptid);
+}
+
/* Add a possible target architecture to the list. */
void
if (t->to_xfer_partial == NULL)
t->to_xfer_partial = default_xfer_partial;
+ if (t->to_has_all_memory == NULL)
+ t->to_has_all_memory = (int (*) (struct target_ops *)) return_zero;
+
+ if (t->to_has_memory == NULL)
+ t->to_has_memory = (int (*) (struct target_ops *)) return_zero;
+
+ if (t->to_has_stack == NULL)
+ t->to_has_stack = (int (*) (struct target_ops *)) return_zero;
+
+ if (t->to_has_registers == NULL)
+ t->to_has_registers = (int (*) (struct target_ops *)) return_zero;
+
+ if (t->to_has_execution == NULL)
+ t->to_has_execution = (int (*) (struct target_ops *, ptid_t)) return_zero;
+
if (!target_structs)
{
target_struct_allocsize = DEFAULT_ALLOCSIZE;
void
target_load (char *arg, int from_tty)
{
- dcache_invalidate (target_dcache);
+ target_dcache_invalidate ();
(*current_target.to_load) (arg, from_tty);
}
char **env, int from_tty)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_create_inferior != NULL)
}
internal_error (__FILE__, __LINE__,
- "could not find a target to create inferior");
+ _("could not find a target to create inferior"));
}
void
target_terminal_inferior (void)
{
/* A background resume (``run&'') should leave GDB in control of the
- terminal. */
- if (target_is_async_p () && !sync_execution)
+ terminal. Use target_can_async_p, not target_is_async_p, since at
+ this point the target is not async yet. However, if sync_execution
+ is not set, we know it will become async prior to resume. */
+ if (target_can_async_p () && !sync_execution)
return;
/* If GDB is resuming the inferior in the foreground, install
nomemory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct target_ops *t)
{
- errno = EIO; /* Can't read/write this location */
- return 0; /* No bytes handled */
+ errno = EIO; /* Can't read/write this location. */
+ return 0; /* No bytes handled. */
}
static void
error (_("You can't do that without a process to debug."));
}
-static int
-nosymbol (char *name, CORE_ADDR *addrp)
-{
- return 1; /* Symbol does not exist in target env */
-}
-
-static void
-nosupport_runtime (void)
-{
- if (ptid_equal (inferior_ptid, null_ptid))
- noprocess ();
- else
- error (_("No run-time support for this"));
-}
-
-
static void
default_terminal_info (char *args, int from_tty)
{
printf_unfiltered (_("No saved terminal information.\n"));
}
-/* This is the default target_create_inferior and target_attach function.
- If the current target is executing, it asks whether to kill it off.
- If this function returns without calling error(), it has killed off
- the target, and the operation should be attempted. */
-
-static void
-kill_or_be_killed (int from_tty)
-{
- if (target_has_execution)
- {
- printf_unfiltered (_("You are already running a program:\n"));
- target_files_info ();
- if (query (_("Kill it? ")))
- {
- target_kill ();
- if (target_has_execution)
- error (_("Killing the program did not help."));
- return;
- }
- else
- {
- error (_("Program not killed."));
- }
- }
- tcomplain ();
-}
-
/* A default implementation for the to_get_ada_task_ptid target method.
This function builds the PTID by using both LWP and TID as part of
return ptid_build (ptid_get_pid (inferior_ptid), lwp, tid);
}
+static enum exec_direction_kind
+default_execution_direction (void)
+{
+ if (!target_can_execute_reverse)
+ return EXEC_FORWARD;
+ else if (!target_can_async_p ())
+ return EXEC_FORWARD;
+ else
+ gdb_assert_not_reached ("\
+to_execution_direction must be implemented for reverse async");
+}
+
/* Go through the target stack from top to bottom, copying over zero
entries in current_target, then filling in still empty entries. In
effect, we are doing class inheritance through the pushed target
INHERIT (to_can_use_hw_breakpoint, t);
INHERIT (to_insert_hw_breakpoint, t);
INHERIT (to_remove_hw_breakpoint, t);
+ /* Do not inherit to_ranged_break_num_registers. */
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ /* Do not inherit to_insert_mask_watchpoint. */
+ /* Do not inherit to_remove_mask_watchpoint. */
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
INHERIT (to_stopped_by_watchpoint, t);
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
+ INHERIT (to_can_accel_watchpoint_condition, t);
+ /* Do not inherit to_masked_watch_num_registers. */
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
INHERIT (to_terminal_info, t);
/* Do not inherit to_kill. */
INHERIT (to_load, t);
- INHERIT (to_lookup_symbol, t);
/* Do no inherit to_create_inferior. */
INHERIT (to_post_startup_inferior, t);
- INHERIT (to_acknowledge_created_inferior, t);
INHERIT (to_insert_fork_catchpoint, t);
INHERIT (to_remove_fork_catchpoint, t);
INHERIT (to_insert_vfork_catchpoint, t);
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
- /* Do not inherit to_mourn_inferiour. */
+ /* Do not inherit to_mourn_inferior. */
INHERIT (to_can_run, t);
- INHERIT (to_notice_signals, t);
+ /* Do not inherit to_pass_signals. */
/* Do not inherit to_thread_alive. */
/* Do not inherit to_find_new_threads. */
/* Do not inherit to_pid_to_str. */
INHERIT (to_extra_thread_info, t);
+ INHERIT (to_thread_name, t);
INHERIT (to_stop, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
INHERIT (to_pid_to_exec_file, t);
INHERIT (to_log_command, t);
INHERIT (to_stratum, t);
- INHERIT (to_has_all_memory, t);
- INHERIT (to_has_memory, t);
- INHERIT (to_has_stack, t);
- INHERIT (to_has_registers, t);
- INHERIT (to_has_execution, t);
+ /* Do not inherit to_has_all_memory. */
+ /* Do not inherit to_has_memory. */
+ /* Do not inherit to_has_stack. */
+ /* Do not inherit to_has_registers. */
+ /* Do not inherit to_has_execution. */
INHERIT (to_has_thread_control, t);
- INHERIT (to_sections, t);
- INHERIT (to_sections_end, t);
INHERIT (to_can_async_p, t);
INHERIT (to_is_async_p, t);
INHERIT (to_async, t);
- INHERIT (to_async_mask, t);
INHERIT (to_find_memory_regions, t);
INHERIT (to_make_corefile_notes, t);
+ INHERIT (to_get_bookmark, t);
+ INHERIT (to_goto_bookmark, t);
/* Do not inherit to_get_thread_local_address. */
INHERIT (to_can_execute_reverse, t);
+ INHERIT (to_execution_direction, t);
+ INHERIT (to_thread_architecture, t);
/* Do not inherit to_read_description. */
INHERIT (to_get_ada_task_ptid, t);
/* Do not inherit to_search_memory. */
INHERIT (to_supports_multi_process, t);
+ INHERIT (to_supports_enable_disable_tracepoint, t);
+ INHERIT (to_supports_string_tracing, t);
+ INHERIT (to_trace_init, t);
+ INHERIT (to_download_tracepoint, t);
+ INHERIT (to_can_download_tracepoint, t);
+ INHERIT (to_download_trace_state_variable, t);
+ INHERIT (to_enable_tracepoint, t);
+ INHERIT (to_disable_tracepoint, t);
+ INHERIT (to_trace_set_readonly_regions, t);
+ INHERIT (to_trace_start, t);
+ INHERIT (to_get_trace_status, t);
+ INHERIT (to_get_tracepoint_status, t);
+ INHERIT (to_trace_stop, t);
+ INHERIT (to_trace_find, t);
+ INHERIT (to_get_trace_state_variable_value, t);
+ INHERIT (to_save_trace_data, t);
+ INHERIT (to_upload_tracepoints, t);
+ INHERIT (to_upload_trace_state_variables, t);
+ INHERIT (to_get_raw_trace_data, t);
+ INHERIT (to_get_min_fast_tracepoint_insn_len, t);
+ INHERIT (to_set_disconnected_tracing, t);
+ INHERIT (to_set_circular_trace_buffer, t);
+ INHERIT (to_set_trace_notes, t);
+ INHERIT (to_get_tib_address, t);
+ INHERIT (to_set_permissions, t);
+ INHERIT (to_static_tracepoint_marker_at, t);
+ INHERIT (to_static_tracepoint_markers_by_strid, t);
+ INHERIT (to_traceframe_info, t);
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
(void (*) (struct regcache *))
noprocess);
de_fault (deprecated_xfer_memory,
- (int (*) (CORE_ADDR, gdb_byte *, int, int, struct mem_attrib *, struct target_ops *))
+ (int (*) (CORE_ADDR, gdb_byte *, int, int,
+ struct mem_attrib *, struct target_ops *))
nomemory);
de_fault (to_files_info,
(void (*) (struct target_ops *))
(int (*) (int, int, int))
return_zero);
de_fault (to_insert_hw_breakpoint,
- (int (*) (struct bp_target_info *))
+ (int (*) (struct gdbarch *, struct bp_target_info *))
return_minus_one);
de_fault (to_remove_hw_breakpoint,
- (int (*) (struct bp_target_info *))
+ (int (*) (struct gdbarch *, struct bp_target_info *))
return_minus_one);
de_fault (to_insert_watchpoint,
- (int (*) (CORE_ADDR, int, int))
+ (int (*) (CORE_ADDR, int, int, struct expression *))
return_minus_one);
de_fault (to_remove_watchpoint,
- (int (*) (CORE_ADDR, int, int))
+ (int (*) (CORE_ADDR, int, int, struct expression *))
return_minus_one);
de_fault (to_stopped_by_watchpoint,
(int (*) (void))
default_watchpoint_addr_within_range);
de_fault (to_region_ok_for_hw_watchpoint,
default_region_ok_for_hw_watchpoint);
+ de_fault (to_can_accel_watchpoint_condition,
+ (int (*) (CORE_ADDR, int, int, struct expression *))
+ return_zero);
de_fault (to_terminal_init,
(void (*) (void))
target_ignore);
de_fault (to_load,
(void (*) (char *, int))
tcomplain);
- de_fault (to_lookup_symbol,
- (int (*) (char *, CORE_ADDR *))
- nosymbol);
de_fault (to_post_startup_inferior,
(void (*) (ptid_t))
target_ignore);
- de_fault (to_acknowledge_created_inferior,
- (void (*) (int))
- target_ignore);
de_fault (to_insert_fork_catchpoint,
- (void (*) (int))
- tcomplain);
+ (int (*) (int))
+ return_one);
de_fault (to_remove_fork_catchpoint,
(int (*) (int))
- tcomplain);
+ return_one);
de_fault (to_insert_vfork_catchpoint,
- (void (*) (int))
- tcomplain);
+ (int (*) (int))
+ return_one);
de_fault (to_remove_vfork_catchpoint,
(int (*) (int))
- tcomplain);
+ return_one);
de_fault (to_insert_exec_catchpoint,
- (void (*) (int))
- tcomplain);
+ (int (*) (int))
+ return_one);
de_fault (to_remove_exec_catchpoint,
(int (*) (int))
- tcomplain);
+ return_one);
+ de_fault (to_set_syscall_catchpoint,
+ (int (*) (int, int, int, int, int *))
+ return_one);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
de_fault (to_can_run,
return_zero);
- de_fault (to_notice_signals,
- (void (*) (ptid_t))
- target_ignore);
de_fault (to_extra_thread_info,
(char *(*) (struct thread_info *))
return_zero);
+ de_fault (to_thread_name,
+ (char *(*) (struct thread_info *))
+ return_zero);
de_fault (to_stop,
(void (*) (ptid_t))
target_ignore);
de_fault (to_async,
(void (*) (void (*) (enum inferior_event_type, void*), void*))
tcomplain);
- de_fault (to_async_mask,
- (int (*) (int))
- return_one);
+ de_fault (to_thread_architecture,
+ default_thread_architecture);
current_target.to_read_description = NULL;
de_fault (to_get_ada_task_ptid,
(ptid_t (*) (long, long))
de_fault (to_supports_multi_process,
(int (*) (void))
return_zero);
+ de_fault (to_supports_enable_disable_tracepoint,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_supports_string_tracing,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_trace_init,
+ (void (*) (void))
+ tcomplain);
+ de_fault (to_download_tracepoint,
+ (void (*) (struct bp_location *))
+ tcomplain);
+ de_fault (to_can_download_tracepoint,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_download_trace_state_variable,
+ (void (*) (struct trace_state_variable *))
+ tcomplain);
+ de_fault (to_enable_tracepoint,
+ (void (*) (struct bp_location *))
+ tcomplain);
+ de_fault (to_disable_tracepoint,
+ (void (*) (struct bp_location *))
+ tcomplain);
+ de_fault (to_trace_set_readonly_regions,
+ (void (*) (void))
+ tcomplain);
+ de_fault (to_trace_start,
+ (void (*) (void))
+ tcomplain);
+ de_fault (to_get_trace_status,
+ (int (*) (struct trace_status *))
+ return_minus_one);
+ de_fault (to_get_tracepoint_status,
+ (void (*) (struct breakpoint *, struct uploaded_tp *))
+ tcomplain);
+ de_fault (to_trace_stop,
+ (void (*) (void))
+ tcomplain);
+ de_fault (to_trace_find,
+ (int (*) (enum trace_find_type, int, ULONGEST, ULONGEST, int *))
+ return_minus_one);
+ de_fault (to_get_trace_state_variable_value,
+ (int (*) (int, LONGEST *))
+ return_zero);
+ de_fault (to_save_trace_data,
+ (int (*) (const char *))
+ tcomplain);
+ de_fault (to_upload_tracepoints,
+ (int (*) (struct uploaded_tp **))
+ return_zero);
+ de_fault (to_upload_trace_state_variables,
+ (int (*) (struct uploaded_tsv **))
+ return_zero);
+ de_fault (to_get_raw_trace_data,
+ (LONGEST (*) (gdb_byte *, ULONGEST, LONGEST))
+ tcomplain);
+ de_fault (to_get_min_fast_tracepoint_insn_len,
+ (int (*) (void))
+ return_minus_one);
+ de_fault (to_set_disconnected_tracing,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_set_circular_trace_buffer,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_set_trace_notes,
+ (int (*) (char *, char *, char *))
+ return_zero);
+ de_fault (to_get_tib_address,
+ (int (*) (ptid_t, CORE_ADDR *))
+ tcomplain);
+ de_fault (to_set_permissions,
+ (void (*) (void))
+ target_ignore);
+ de_fault (to_static_tracepoint_marker_at,
+ (int (*) (CORE_ADDR, struct static_tracepoint_marker *))
+ return_zero);
+ de_fault (to_static_tracepoint_markers_by_strid,
+ (VEC(static_tracepoint_marker_p) * (*) (const char *))
+ tcomplain);
+ de_fault (to_traceframe_info,
+ (struct traceframe_info * (*) (void))
+ tcomplain);
+ de_fault (to_execution_direction, default_execution_direction);
+
#undef de_fault
/* Finally, position the target-stack beneath the squashed
setup_target_debug ();
}
-/* Mark OPS as a running target. This reverses the effect
- of target_mark_exited. */
-
-void
-target_mark_running (struct target_ops *ops)
-{
- struct target_ops *t;
-
- for (t = target_stack; t != NULL; t = t->beneath)
- if (t == ops)
- break;
- if (t == NULL)
- internal_error (__FILE__, __LINE__,
- "Attempted to mark unpushed target \"%s\" as running",
- ops->to_shortname);
-
- ops->to_has_execution = 1;
- ops->to_has_all_memory = 1;
- ops->to_has_memory = 1;
- ops->to_has_stack = 1;
- ops->to_has_registers = 1;
-
- update_current_target ();
-}
-
-/* Mark OPS as a non-running target. This reverses the effect
- of target_mark_running. */
-
-void
-target_mark_exited (struct target_ops *ops)
-{
- struct target_ops *t;
-
- for (t = target_stack; t != NULL; t = t->beneath)
- if (t == ops)
- break;
- if (t == NULL)
- internal_error (__FILE__, __LINE__,
- "Attempted to mark unpushed target \"%s\" as running",
- ops->to_shortname);
-
- ops->to_has_execution = 0;
- ops->to_has_all_memory = 0;
- ops->to_has_memory = 0;
- ops->to_has_stack = 0;
- ops->to_has_registers = 0;
-
- update_current_target ();
-}
-
/* Push a new target type into the stack of the existing target accessors,
possibly superseding some of the existing accessors.
- Result is zero if the pushed target ended up on top of the stack,
- nonzero if at least one target is on top of it.
-
Rather than allow an empty stack, we always have the dummy target at
the bottom stratum, so we can call the function vectors without
checking them. */
-int
+void
push_target (struct target_ops *t)
{
struct target_ops **cur;
fprintf_unfiltered (gdb_stderr,
"Magic number of %s target struct wrong\n",
t->to_shortname);
- internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
+ internal_error (__FILE__, __LINE__,
+ _("failed internal consistency check"));
}
/* Find the proper stratum to install this target in. */
/* There's already something at this stratum level. Close it,
and un-hook it from the stack. */
struct target_ops *tmp = (*cur);
+
(*cur) = (*cur)->beneath;
tmp->beneath = NULL;
target_close (tmp, 0);
(*cur) = t;
update_current_target ();
-
- /* Not on top? */
- return (t != target_stack);
}
/* Remove a target_ops vector from the stack, wherever it may be.
if (t->to_stratum == dummy_stratum)
internal_error (__FILE__, __LINE__,
- "Attempt to unpush the dummy target");
+ _("Attempt to unpush the dummy target"));
/* Look for the specified target. Note that we assume that a target
- can only occur once in the target stack. */
+ can only occur once in the target stack. */
for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
{
}
if ((*cur) == NULL)
- return 0; /* Didn't find target_ops, quit now */
+ return 0; /* Didn't find target_ops, quit now. */
/* NOTE: cagney/2003-12-06: In '94 the close call was made
unconditional by moving it to before the above check that the
targets should be closed. */
target_close (t, 0);
- /* Unchain the target */
+ /* Unchain the target. */
tmp = (*cur);
(*cur) = (*cur)->beneath;
tmp->beneath = NULL;
void
pop_target (void)
{
- target_close (target_stack, 0); /* Let it clean up */
+ target_close (target_stack, 0); /* Let it clean up. */
if (unpush_target (target_stack) == 1)
return;
fprintf_unfiltered (gdb_stderr,
"pop_target couldn't find target %s\n",
current_target.to_shortname);
- internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
+ internal_error (__FILE__, __LINE__,
+ _("failed internal consistency check"));
}
void
pop_all_targets_above (dummy_stratum, quitting);
}
+/* Return 1 if T is now pushed in the target stack. Return 0 otherwise. */
+
+int
+target_is_pushed (struct target_ops *t)
+{
+ struct target_ops **cur;
+
+ /* Check magic number. If wrong, it probably means someone changed
+ the struct definition, but not all the places that initialize one. */
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Magic number of %s target struct wrong\n",
+ t->to_shortname);
+ internal_error (__FILE__, __LINE__,
+ _("failed internal consistency check"));
+ }
+
+ for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
+ if (*cur == t)
+ return 1;
+
+ return 0;
+}
+
/* Using the objfile specified in OBJFILE, find the address for the
current thread's thread-local storage with offset OFFSET. */
CORE_ADDR
throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR,
_("TLS load module not found"));
- addr = target->to_get_thread_local_address (target, ptid, lm_addr, offset);
+ addr = target->to_get_thread_local_address (target, ptid,
+ lm_addr, offset);
}
/* If an error occurred, print TLS related messages here. Otherwise,
throw the error to some higher catcher. */
switch (ex.error)
{
case TLS_NO_LIBRARY_SUPPORT_ERROR:
- error (_("Cannot find thread-local variables in this thread library."));
+ error (_("Cannot find thread-local variables "
+ "in this thread library."));
break;
case TLS_LOAD_MODULE_NOT_FOUND_ERROR:
if (objfile_is_library)
if (errcode != 0)
{
/* The transfer request might have crossed the boundary to an
- unallocated region of memory. Retry the transfer, requesting
+ unallocated region of memory. Retry the transfer, requesting
a single byte. */
tlen = 1;
offset = 0;
if (bufptr - buffer + tlen > buffer_allocated)
{
unsigned int bytes;
+
bytes = bufptr - buffer;
buffer_allocated *= 2;
buffer = xrealloc (buffer, buffer_allocated);
return nbytes_read;
}
+struct target_section_table *
+target_get_section_table (struct target_ops *target)
+{
+ struct target_ops *t;
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_get_section_table ()\n");
+
+ for (t = target; t != NULL; t = t->beneath)
+ if (t->to_get_section_table != NULL)
+ return (*t->to_get_section_table) (t);
+
+ return NULL;
+}
+
/* Find a section containing ADDR. */
+
struct target_section *
target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
{
+ struct target_section_table *table = target_get_section_table (target);
struct target_section *secp;
- for (secp = target->to_sections;
- secp < target->to_sections_end;
- secp++)
+
+ if (table == NULL)
+ return NULL;
+
+ for (secp = table->sections; secp < table->sections_end; secp++)
{
if (addr >= secp->addr && addr < secp->endaddr)
return secp;
return NULL;
}
-/* Perform a partial memory transfer. The arguments and return
- value are just as for target_xfer_partial. */
+/* Read memory from the live target, even if currently inspecting a
+ traceframe. The return is the same as that of target_read. */
+
+static LONGEST
+target_read_live_memory (enum target_object object,
+ ULONGEST memaddr, gdb_byte *myaddr, LONGEST len)
+{
+ int ret;
+ struct cleanup *cleanup;
+
+ /* Switch momentarily out of tfind mode so to access live memory.
+ Note that this must not clear global state, such as the frame
+ cache, which must still remain valid for the previous traceframe.
+ We may be _building_ the frame cache at this point. */
+ cleanup = make_cleanup_restore_traceframe_number ();
+ set_traceframe_number (-1);
+
+ ret = target_read (current_target.beneath, object, NULL,
+ myaddr, memaddr, len);
+
+ do_cleanups (cleanup);
+ return ret;
+}
+
+/* Using the set of read-only target sections of OPS, read live
+ read-only memory. Note that the actual reads start from the
+ top-most target again.
+
+ For interface/parameters/return description see target.h,
+ to_xfer_partial. */
+
+static LONGEST
+memory_xfer_live_readonly_partial (struct target_ops *ops,
+ enum target_object object,
+ gdb_byte *readbuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ struct target_section *secp;
+ struct target_section_table *table;
+
+ secp = target_section_by_addr (ops, memaddr);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ {
+ struct target_section *p;
+ ULONGEST memend = memaddr + len;
+
+ table = target_get_section_table (ops);
+
+ for (p = table->sections; p < table->sections_end; p++)
+ {
+ if (memaddr >= p->addr)
+ {
+ if (memend <= p->endaddr)
+ {
+ /* Entire transfer is within this section. */
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ else if (memaddr >= p->endaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Perform a partial memory transfer.
+ For docs see target.h, to_xfer_partial. */
static LONGEST
-memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf,
- ULONGEST memaddr, LONGEST len)
+memory_xfer_partial_1 (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
{
LONGEST res;
int reg_len;
struct mem_region *region;
+ struct inferior *inf;
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- return 0;
+ /* For accesses to unmapped overlay sections, read directly from
+ files. Must do this first, as MEMADDR may need adjustment. */
+ if (readbuf != NULL && overlay_debugging)
+ {
+ struct obj_section *section = find_pc_overlay (memaddr);
- /* Try the executable file, if "trust-readonly-sections" is set. */
+ if (pc_in_unmapped_range (memaddr, section))
+ {
+ struct target_section_table *table
+ = target_get_section_table (ops);
+ const char *section_name = section->the_bfd_section->name;
+
+ memaddr = overlay_mapped_address (memaddr, section);
+ return section_table_xfer_memory_partial (readbuf, writebuf,
+ memaddr, len,
+ table->sections,
+ table->sections_end,
+ section_name);
+ }
+ }
+
+ /* Try the executable files, if "trust-readonly-sections" is set. */
if (readbuf != NULL && trust_readonly)
{
struct target_section *secp;
+ struct target_section_table *table;
secp = target_section_by_addr (ops, memaddr);
if (secp != NULL
&& (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
& SEC_READONLY))
- return xfer_memory (memaddr, readbuf, len, 0, NULL, ops);
+ {
+ table = target_get_section_table (ops);
+ return section_table_xfer_memory_partial (readbuf, writebuf,
+ memaddr, len,
+ table->sections,
+ table->sections_end,
+ NULL);
+ }
}
- /* Likewise for accesses to unmapped overlay sections. */
- if (readbuf != NULL && overlay_debugging)
+ /* If reading unavailable memory in the context of traceframes, and
+ this address falls within a read-only section, fallback to
+ reading from live memory. */
+ if (readbuf != NULL && get_traceframe_number () != -1)
{
- struct obj_section *section = find_pc_overlay (memaddr);
- if (pc_in_unmapped_range (memaddr, section))
- return xfer_memory (memaddr, readbuf, len, 0, NULL, ops);
+ VEC(mem_range_s) *available;
+
+ /* If we fail to get the set of available memory, then the
+ target does not support querying traceframe info, and so we
+ attempt reading from the traceframe anyway (assuming the
+ target implements the old QTro packet then). */
+ if (traceframe_available_memory (&available, memaddr, len))
+ {
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup (VEC_cleanup(mem_range_s), &available);
+
+ if (VEC_empty (mem_range_s, available)
+ || VEC_index (mem_range_s, available, 0)->start != memaddr)
+ {
+ /* Don't read into the traceframe's available
+ memory. */
+ if (!VEC_empty (mem_range_s, available))
+ {
+ LONGEST oldlen = len;
+
+ len = VEC_index (mem_range_s, available, 0)->start - memaddr;
+ gdb_assert (len <= oldlen);
+ }
+
+ do_cleanups (old_chain);
+
+ /* This goes through the topmost target again. */
+ res = memory_xfer_live_readonly_partial (ops, object,
+ readbuf, memaddr, len);
+ if (res > 0)
+ return res;
+
+ /* No use trying further, we know some memory starting
+ at MEMADDR isn't available. */
+ return -1;
+ }
+
+ /* Don't try to read more than how much is available, in
+ case the target implements the deprecated QTro packet to
+ cater for older GDBs (the target's knowledge of read-only
+ sections may be outdated by now). */
+ len = VEC_index (mem_range_s, available, 0)->length;
+
+ do_cleanups (old_chain);
+ }
}
/* Try GDB's internal data cache. */
return -1;
}
- if (region->attrib.cache)
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
+ else
+ inf = NULL;
+
+ if (inf != NULL
+ /* The dcache reads whole cache lines; that doesn't play well
+ with reading from a trace buffer, because reading outside of
+ the collected memory range fails. */
+ && get_traceframe_number () == -1
+ && (region->attrib.cache
+ || (stack_cache_enabled_p && object == TARGET_OBJECT_STACK_MEMORY)))
{
- /* FIXME drow/2006-08-09: This call discards OPS, so the raw
- memory request will start back at current_target. */
if (readbuf != NULL)
- res = dcache_xfer_memory (target_dcache, memaddr, readbuf,
+ res = dcache_xfer_memory (ops, target_dcache, memaddr, readbuf,
reg_len, 0);
else
/* FIXME drow/2006-08-09: If we're going to preserve const
correctness dcache_xfer_memory should take readbuf and
writebuf. */
- res = dcache_xfer_memory (target_dcache, memaddr,
+ res = dcache_xfer_memory (ops, target_dcache, memaddr,
(void *) writebuf,
reg_len, 1);
if (res <= 0)
return -1;
else
- {
- if (readbuf && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
- return res;
- }
+ return res;
}
/* If none of those methods found the memory we wanted, fall back
/* We want to continue past core files to executables, but not
past a running target's memory. */
- if (ops->to_has_all_memory)
+ if (ops->to_has_all_memory (ops))
break;
ops = ops->beneath;
}
while (ops != NULL);
- if (readbuf && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
+ /* Make sure the cache gets updated no matter what - if we are writing
+ to the stack. Even if this write is not tagged as such, we still need
+ to update the cache. */
+
+ if (res > 0
+ && inf != NULL
+ && writebuf != NULL
+ && !region->attrib.cache
+ && stack_cache_enabled_p
+ && object != TARGET_OBJECT_STACK_MEMORY)
+ {
+ dcache_update (target_dcache, memaddr, (void *) writebuf, res);
+ }
/* If we still haven't got anything, return the last error. We
give up. */
return res;
}
+/* Perform a partial memory transfer. For docs see target.h,
+ to_xfer_partial. */
+
+static LONGEST
+memory_xfer_partial (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ int res;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ return 0;
+
+ /* Fill in READBUF with breakpoint shadows, or WRITEBUF with
+ breakpoint insns, thus hiding out from higher layers whether
+ there are software breakpoints inserted in the code stream. */
+ if (readbuf != NULL)
+ {
+ res = memory_xfer_partial_1 (ops, object, readbuf, NULL, memaddr, len);
+
+ if (res > 0 && !show_memory_breakpoints)
+ breakpoint_xfer_memory (readbuf, NULL, NULL, memaddr, res);
+ }
+ else
+ {
+ void *buf;
+ struct cleanup *old_chain;
+
+ buf = xmalloc (len);
+ old_chain = make_cleanup (xfree, buf);
+ memcpy (buf, writebuf, len);
+
+ breakpoint_xfer_memory (NULL, buf, writebuf, memaddr, len);
+ res = memory_xfer_partial_1 (ops, object, NULL, buf, memaddr, len);
+
+ do_cleanups (old_chain);
+ }
+
+ return res;
+}
+
static void
restore_show_memory_breakpoints (void *arg)
{
make_show_memory_breakpoints_cleanup (int show)
{
int current = show_memory_breakpoints;
- show_memory_breakpoints = show;
+ show_memory_breakpoints = show;
return make_cleanup (restore_show_memory_breakpoints,
(void *) (uintptr_t) current);
}
+/* For docs see target.h, to_xfer_partial. */
+
static LONGEST
target_xfer_partial (struct target_ops *ops,
enum target_object object, const char *annex,
gdb_assert (ops->to_xfer_partial != NULL);
+ if (writebuf && !may_write_memory)
+ error (_("Writing to memory is not allowed (addr %s, len %s)"),
+ core_addr_to_string_nz (offset), plongest (len));
+
/* If this is a memory transfer, let the memory-specific code
have a look at it instead. Memory transfers are more
complicated. */
- if (object == TARGET_OBJECT_MEMORY)
- retval = memory_xfer_partial (ops, readbuf, writebuf, offset, len);
+ if (object == TARGET_OBJECT_MEMORY || object == TARGET_OBJECT_STACK_MEMORY)
+ retval = memory_xfer_partial (ops, object, readbuf,
+ writebuf, offset, len);
else
{
enum target_object raw_object = object;
const unsigned char *myaddr = NULL;
fprintf_unfiltered (gdb_stdlog,
- "%s:target_xfer_partial (%d, %s, %s, %s, %s, %s) = %s",
+ "%s:target_xfer_partial "
+ "(%d, %s, %s, %s, %s, %s) = %s",
ops->to_shortname,
(int) object,
(annex ? annex : "(null)"),
GDB's memory at MYADDR. Returns either 0 for success or an errno value
if any error occurs.
- If an error occurs, no guarantee is made about the contents of the data at
- MYADDR. In particular, the caller should not depend upon partial reads
- filling the buffer with good data. There is no way for the caller to know
- how much good data might have been transfered anyway. Callers that can
- deal with partial reads should call target_read (which will retry until
- it makes no progress, and then return how much was transferred). */
+ If an error occurs, no guarantee is made about the contents of the data at
+ MYADDR. In particular, the caller should not depend upon partial reads
+ filling the buffer with good data. There is no way for the caller to know
+ how much good data might have been transfered anyway. Callers that can
+ deal with partial reads should call target_read (which will retry until
+ it makes no progress, and then return how much was transferred). */
+
+int
+target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+{
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+ if (target_read (current_target.beneath, TARGET_OBJECT_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
+ else
+ return EIO;
+}
+
+/* Like target_read_memory, but specify explicitly that this is a read from
+ the target's stack. This may trigger different cache behavior. */
int
-target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
- if (target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL,
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+
+ if (target_read (current_target.beneath, TARGET_OBJECT_STACK_MEMORY, NULL,
myaddr, memaddr, len) == len)
return 0;
else
return EIO;
}
+/* Write LEN bytes from MYADDR to target memory at address MEMADDR.
+ Returns either 0 for success or an errno value if any error occurs.
+ If an error occurs, no guarantee is made about how much data got written.
+ Callers that can deal with partial writes should call target_write. */
+
int
target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
{
- if (target_write (¤t_target, TARGET_OBJECT_MEMORY, NULL,
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+ if (target_write (current_target.beneath, TARGET_OBJECT_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
+ else
+ return EIO;
+}
+
+/* Write LEN bytes from MYADDR to target raw memory at address
+ MEMADDR. Returns either 0 for success or an errno value if any
+ error occurs. If an error occurs, no guarantee is made about how
+ much data got written. Callers that can deal with partial writes
+ should call target_write. */
+
+int
+target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+{
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+ if (target_write (current_target.beneath, TARGET_OBJECT_RAW_MEMORY, NULL,
myaddr, memaddr, len) == len)
return 0;
else
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_flash_erase != NULL)
- {
- if (targetdebug)
- fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n",
- paddr (address), phex (length, 0));
- t->to_flash_erase (t, address, length);
- return;
- }
+ {
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n",
+ hex_string (address), phex (length, 0));
+ t->to_flash_erase (t, address, length);
+ return;
+ }
tcomplain ();
}
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_flash_done != NULL)
- {
- if (targetdebug)
- fprintf_unfiltered (gdb_stdlog, "target_flash_done\n");
- t->to_flash_done (t);
- return;
- }
+ {
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_flash_done\n");
+ t->to_flash_done (t);
+ return;
+ }
tcomplain ();
}
show_trust_readonly (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-Mode for reading from readonly sections is %s.\n"),
+ fprintf_filtered (file,
+ _("Mode for reading from readonly sections is %s.\n"),
value);
}
"deprecated_xfer_memory" method. */
{
int xfered = -1;
+
errno = 0;
if (writebuf != NULL)
{
void *buffer = xmalloc (len);
struct cleanup *cleanup = make_cleanup (xfree, buffer);
+
memcpy (buffer, writebuf, len);
xfered = ops->deprecated_xfer_memory (offset, buffer, len,
1/*write*/, NULL, ops);
return -1;
}
-/* Target vector read/write partial wrapper functions.
-
- NOTE: cagney/2003-10-21: I wonder if having "to_xfer_partial
- (inbuf, outbuf)", instead of separate read/write methods, make life
- easier. */
+/* Target vector read/write partial wrapper functions. */
static LONGEST
target_read_partial (struct target_ops *ops,
}
/* Wrappers to perform the full transfer. */
+
+/* For docs on target_read see target.h. */
+
LONGEST
target_read (struct target_ops *ops,
enum target_object object,
ULONGEST offset, LONGEST len)
{
LONGEST xfered = 0;
+
while (xfered < len)
{
LONGEST xfer = target_read_partial (ops, object, annex,
(gdb_byte *) buf + xfered,
offset + xfered, len - xfered);
+
/* Call an observer, notifying them of the xfer progress? */
if (xfer == 0)
return xfered;
return len;
}
-LONGEST
-target_read_until_error (struct target_ops *ops,
- enum target_object object,
- const char *annex, gdb_byte *buf,
- ULONGEST offset, LONGEST len)
+/* Assuming that the entire [begin, end) range of memory cannot be
+ read, try to read whatever subrange is possible to read.
+
+ The function returns, in RESULT, either zero or one memory block.
+ If there's a readable subrange at the beginning, it is completely
+ read and returned. Any further readable subrange will not be read.
+ Otherwise, if there's a readable subrange at the end, it will be
+ completely read and returned. Any readable subranges before it
+ (obviously, not starting at the beginning), will be ignored. In
+ other cases -- either no readable subrange, or readable subrange(s)
+ that is neither at the beginning, or end, nothing is returned.
+
+ The purpose of this function is to handle a read across a boundary
+ of accessible memory in a case when memory map is not available.
+ The above restrictions are fine for this case, but will give
+ incorrect results if the memory is 'patchy'. However, supporting
+ 'patchy' memory would require trying to read every single byte,
+ and it seems unacceptable solution. Explicit memory map is
+ recommended for this case -- and target_read_memory_robust will
+ take care of reading multiple ranges then. */
+
+static void
+read_whatever_is_readable (struct target_ops *ops,
+ ULONGEST begin, ULONGEST end,
+ VEC(memory_read_result_s) **result)
+{
+ gdb_byte *buf = xmalloc (end - begin);
+ ULONGEST current_begin = begin;
+ ULONGEST current_end = end;
+ int forward;
+ memory_read_result_s r;
+
+ /* If we previously failed to read 1 byte, nothing can be done here. */
+ if (end - begin <= 1)
+ {
+ xfree (buf);
+ return;
+ }
+
+ /* Check that either first or the last byte is readable, and give up
+ if not. This heuristic is meant to permit reading accessible memory
+ at the boundary of accessible region. */
+ if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
+ buf, begin, 1) == 1)
+ {
+ forward = 1;
+ ++current_begin;
+ }
+ else if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
+ buf + (end-begin) - 1, end - 1, 1) == 1)
+ {
+ forward = 0;
+ --current_end;
+ }
+ else
+ {
+ xfree (buf);
+ return;
+ }
+
+ /* Loop invariant is that the [current_begin, current_end) was previously
+ found to be not readable as a whole.
+
+ Note loop condition -- if the range has 1 byte, we can't divide the range
+ so there's no point trying further. */
+ while (current_end - current_begin > 1)
+ {
+ ULONGEST first_half_begin, first_half_end;
+ ULONGEST second_half_begin, second_half_end;
+ LONGEST xfer;
+ ULONGEST middle = current_begin + (current_end - current_begin)/2;
+
+ if (forward)
+ {
+ first_half_begin = current_begin;
+ first_half_end = middle;
+ second_half_begin = middle;
+ second_half_end = current_end;
+ }
+ else
+ {
+ first_half_begin = middle;
+ first_half_end = current_end;
+ second_half_begin = current_begin;
+ second_half_end = middle;
+ }
+
+ xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL,
+ buf + (first_half_begin - begin),
+ first_half_begin,
+ first_half_end - first_half_begin);
+
+ if (xfer == first_half_end - first_half_begin)
+ {
+ /* This half reads up fine. So, the error must be in the
+ other half. */
+ current_begin = second_half_begin;
+ current_end = second_half_end;
+ }
+ else
+ {
+ /* This half is not readable. Because we've tried one byte, we
+ know some part of this half if actually redable. Go to the next
+ iteration to divide again and try to read.
+
+ We don't handle the other half, because this function only tries
+ to read a single readable subrange. */
+ current_begin = first_half_begin;
+ current_end = first_half_end;
+ }
+ }
+
+ if (forward)
+ {
+ /* The [begin, current_begin) range has been read. */
+ r.begin = begin;
+ r.end = current_begin;
+ r.data = buf;
+ }
+ else
+ {
+ /* The [current_end, end) range has been read. */
+ LONGEST rlen = end - current_end;
+
+ r.data = xmalloc (rlen);
+ memcpy (r.data, buf + current_end - begin, rlen);
+ r.begin = current_end;
+ r.end = end;
+ xfree (buf);
+ }
+ VEC_safe_push(memory_read_result_s, (*result), &r);
+}
+
+void
+free_memory_read_result_vector (void *x)
+{
+ VEC(memory_read_result_s) *v = x;
+ memory_read_result_s *current;
+ int ix;
+
+ for (ix = 0; VEC_iterate (memory_read_result_s, v, ix, current); ++ix)
+ {
+ xfree (current->data);
+ }
+ VEC_free (memory_read_result_s, v);
+}
+
+VEC(memory_read_result_s) *
+read_memory_robust (struct target_ops *ops, ULONGEST offset, LONGEST len)
{
+ VEC(memory_read_result_s) *result = 0;
+
LONGEST xfered = 0;
while (xfered < len)
{
- LONGEST xfer = target_read_partial (ops, object, annex,
- (gdb_byte *) buf + xfered,
- offset + xfered, len - xfered);
- /* Call an observer, notifying them of the xfer progress? */
- if (xfer == 0)
- return xfered;
- if (xfer < 0)
+ struct mem_region *region = lookup_mem_region (offset + xfered);
+ LONGEST rlen;
+
+ /* If there is no explicit region, a fake one should be created. */
+ gdb_assert (region);
+
+ if (region->hi == 0)
+ rlen = len - xfered;
+ else
+ rlen = region->hi - offset;
+
+ if (region->attrib.mode == MEM_NONE || region->attrib.mode == MEM_WO)
+ {
+ /* Cannot read this region. Note that we can end up here only
+ if the region is explicitly marked inaccessible, or
+ 'inaccessible-by-default' is in effect. */
+ xfered += rlen;
+ }
+ else
{
- /* We've got an error. Try to read in smaller blocks. */
- ULONGEST start = offset + xfered;
- ULONGEST remaining = len - xfered;
- ULONGEST half;
-
- /* If an attempt was made to read a random memory address,
- it's likely that the very first byte is not accessible.
- Try reading the first byte, to avoid doing log N tries
- below. */
- xfer = target_read_partial (ops, object, annex,
- (gdb_byte *) buf + xfered, start, 1);
+ LONGEST to_read = min (len - xfered, rlen);
+ gdb_byte *buffer = (gdb_byte *)xmalloc (to_read);
+
+ LONGEST xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL,
+ (gdb_byte *) buffer,
+ offset + xfered, to_read);
+ /* Call an observer, notifying them of the xfer progress? */
if (xfer <= 0)
- return xfered;
- start += 1;
- remaining -= 1;
- half = remaining/2;
-
- while (half > 0)
{
- xfer = target_read_partial (ops, object, annex,
- (gdb_byte *) buf + xfered,
- start, half);
- if (xfer == 0)
- return xfered;
- if (xfer < 0)
- {
- remaining = half;
- }
- else
- {
- /* We have successfully read the first half. So, the
- error must be in the second half. Adjust start and
- remaining to point at the second half. */
- xfered += xfer;
- start += xfer;
- remaining -= xfer;
- }
- half = remaining/2;
+ /* Got an error reading full chunk. See if maybe we can read
+ some subrange. */
+ xfree (buffer);
+ read_whatever_is_readable (ops, offset + xfered,
+ offset + xfered + to_read, &result);
+ xfered += to_read;
}
-
- return xfered;
+ else
+ {
+ struct memory_read_result r;
+ r.data = buffer;
+ r.begin = offset + xfered;
+ r.end = r.begin + xfer;
+ VEC_safe_push (memory_read_result_s, result, &r);
+ xfered += xfer;
+ }
+ QUIT;
}
- xfered += xfer;
- QUIT;
}
- return len;
+ return result;
}
return len;
}
+/* For docs on target_write see target.h. */
+
LONGEST
target_write (struct target_ops *ops,
enum target_object object,
get_target_memory (struct target_ops *ops, CORE_ADDR addr, gdb_byte *buf,
LONGEST len)
{
- if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, buf, addr, len)
+ /* This method is used to read from an alternate, non-current
+ target. This read must bypass the overlay support (as symbols
+ don't match this target), and GDB's internal cache (wrong cache
+ for this target). */
+ if (target_read (ops, TARGET_OBJECT_RAW_MEMORY, NULL, buf, addr, len)
!= len)
memory_error (EIO, addr);
}
ULONGEST
-get_target_memory_unsigned (struct target_ops *ops,
- CORE_ADDR addr, int len)
+get_target_memory_unsigned (struct target_ops *ops, CORE_ADDR addr,
+ int len, enum bfd_endian byte_order)
{
gdb_byte buf[sizeof (ULONGEST)];
gdb_assert (len <= sizeof (buf));
get_target_memory (ops, addr, buf, len);
- return extract_unsigned_integer (buf, len);
+ return extract_unsigned_integer (buf, len, byte_order);
+}
+
+int
+target_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ if (!may_insert_breakpoints)
+ {
+ warning (_("May not insert breakpoints"));
+ return 1;
+ }
+
+ return (*current_target.to_insert_breakpoint) (gdbarch, bp_tgt);
+}
+
+int
+target_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ /* This is kind of a weird case to handle, but the permission might
+ have been changed after breakpoints were inserted - in which case
+ we should just take the user literally and assume that any
+ breakpoints should be left in place. */
+ if (!may_insert_breakpoints)
+ {
+ warning (_("May not remove breakpoints"));
+ return 1;
+ }
+
+ return (*current_target.to_remove_breakpoint) (gdbarch, bp_tgt);
}
static void
for (t = target_stack; t != NULL; t = t->beneath)
{
- if (!t->to_has_memory)
+ if (!(*t->to_has_memory) (t))
continue;
if ((int) (t->to_stratum) <= (int) dummy_stratum)
continue;
if (has_all_mem)
- printf_unfiltered (_("\tWhile running this, GDB does not access memory from...\n"));
+ printf_unfiltered (_("\tWhile running this, "
+ "GDB does not access memory from...\n"));
printf_unfiltered ("%s:\n", t->to_longname);
(t->to_files_info) (t);
- has_all_mem = t->to_has_all_memory;
+ has_all_mem = (*t->to_has_all_memory) (t);
}
}
void
target_pre_inferior (int from_tty)
{
- /* Clear out solib state. Otherwise the solib state of the previous
+ /* Clear out solib state. Otherwise the solib state of the previous
inferior might have survived and is entirely wrong for the new
- target. This has been observed on GNU/Linux using glibc 2.3. How
+ target. This has been observed on GNU/Linux using glibc 2.3. How
to reproduce:
bash$ ./foo&
}
}
+/* Callback for iterate_over_inferiors. Gets rid of the given
+ inferior. */
+
+static int
+dispose_inferior (struct inferior *inf, void *args)
+{
+ struct thread_info *thread;
+
+ thread = any_thread_of_process (inf->pid);
+ if (thread)
+ {
+ switch_to_thread (thread->ptid);
+
+ /* Core inferiors actually should be detached, not killed. */
+ if (target_has_execution)
+ target_kill ();
+ else
+ target_detach (NULL, 0);
+ }
+
+ return 0;
+}
+
/* This is to be called by the open routine before it does
anything. */
{
dont_repeat ();
- if (target_has_execution)
+ if (have_inferiors ())
{
if (!from_tty
- || query (_("A program is being debugged already. Kill it? ")))
- target_kill ();
+ || !have_live_inferiors ()
+ || query (_("A program is being debugged already. Kill it? ")))
+ iterate_over_inferiors (dispose_inferior, NULL);
else
error (_("Program not killed."));
}
else
/* If we're in breakpoints-always-inserted mode, have to remove
them before detaching. */
- remove_breakpoints ();
+ remove_breakpoints_pid (PIDGET (inferior_ptid));
+
+ prepare_for_detach ();
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
}
}
- internal_error (__FILE__, __LINE__, "could not find a target to detach");
+ internal_error (__FILE__, __LINE__, _("could not find a target to detach"));
}
void
return normal_pid_to_str (ptid);
}
+char *
+target_thread_name (struct thread_info *info)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_thread_name != NULL)
+ return (*t->to_thread_name) (info);
+ }
+
+ return NULL;
+}
+
void
target_resume (ptid_t ptid, int step, enum target_signal signal)
{
struct target_ops *t;
- dcache_invalidate (target_dcache);
+ target_dcache_invalidate ();
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
step ? "step" : "continue",
target_signal_to_name (signal));
+ registers_changed_ptid (ptid);
set_executing (ptid, 1);
set_running (ptid, 1);
+ clear_inline_frame_state (ptid);
return;
}
}
noprocess ();
}
+
+void
+target_pass_signals (int numsigs, unsigned char *pass_signals)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_pass_signals != NULL)
+ {
+ if (targetdebug)
+ {
+ int i;
+
+ fprintf_unfiltered (gdb_stdlog, "target_pass_signals (%d, {",
+ numsigs);
+
+ for (i = 0; i < numsigs; i++)
+ if (pass_signals[i])
+ fprintf_unfiltered (gdb_stdlog, " %s",
+ target_signal_to_name (i));
+
+ fprintf_unfiltered (gdb_stdlog, " })\n");
+ }
+
+ (*t->to_pass_signals) (numsigs, pass_signals);
+ return;
+ }
+ }
+}
+
/* Look through the list of possible targets for a target that can
follow forks. */
if (t->to_follow_fork != NULL)
{
int retval = t->to_follow_fork (t, follow_child);
+
if (targetdebug)
fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
follow_child, retval);
/* Some target returned a fork event, but did not know how to follow it. */
internal_error (__FILE__, __LINE__,
- "could not find a target to follow fork");
+ _("could not find a target to follow fork"));
}
void
target_mourn_inferior (void)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_mourn_inferior != NULL)
}
internal_error (__FILE__, __LINE__,
- "could not find a target to follow mourn inferiour");
+ _("could not find a target to follow mourn inferior"));
}
/* Look for a target which can describe architectural features, starting
if (found_ptr != NULL)
{
CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+
*found_addrp = found_addr;
do_cleanups (old_cleanups);
return 1;
if (search_space_len >= pattern_len)
{
unsigned keep_len = search_buf_size - chunk_size;
- CORE_ADDR read_addr = start_addr + keep_len;
+ CORE_ADDR read_addr = start_addr + chunk_size + keep_len;
int nr_to_read;
/* Copy the trailing part of the previous iteration to the front
search_buf + keep_len, read_addr,
nr_to_read) != nr_to_read)
{
- warning (_("Unable to access target memory at %s, halting search."),
+ warning (_("Unable to access target "
+ "memory at %s, halting search."),
hex_string (read_addr));
do_cleanups (old_cleanups);
return -1;
{
/* If a special version of to_search_memory isn't available, use the
simple version. */
- found = simple_search_memory (¤t_target,
+ found = simple_search_memory (current_target.beneath,
start_addr, search_space_len,
pattern, pattern_len, found_addrp);
}
/* Do not worry about thread_stratum targets that can not
create inferiors. Assume they will be pushed again if
necessary, and continue to the process_stratum. */
- if (t->to_stratum == thread_stratum)
+ if (t->to_stratum == thread_stratum
+ || t->to_stratum == arch_stratum)
continue;
- error (_("\
-The \"%s\" target does not support \"run\". Try \"help target\" or \"continue\"."),
+ error (_("The \"%s\" target does not support \"run\". "
+ "Try \"help target\" or \"continue\"."),
t->to_shortname);
}
/* This function is only called if the target is running. In that
case there should have been a process_stratum target and it
- should either know how to create inferiors, or not... */
- internal_error (__FILE__, __LINE__, "No targets found");
+ should either know how to create inferiors, or not... */
+ internal_error (__FILE__, __LINE__, _("No targets found"));
}
/* Look through the list of possible targets for a target that can
target_supports_non_stop (void)
{
struct target_ops *t;
+
for (t = ¤t_target; t != NULL; t = t->beneath)
if (t->to_supports_non_stop)
return t->to_supports_non_stop ();
return 0;
}
+static int
+find_default_supports_disable_randomization (void)
+{
+ struct target_ops *t;
+
+ t = find_default_run_target (NULL);
+ if (t && t->to_supports_disable_randomization)
+ return (t->to_supports_disable_randomization) ();
+ return 0;
+}
+
+int
+target_supports_disable_randomization (void)
+{
+ struct target_ops *t;
+
+ for (t = ¤t_target; t != NULL; t = t->beneath)
+ if (t->to_supports_disable_randomization)
+ return t->to_supports_disable_randomization ();
+
+ return 0;
+}
char *
target_get_osdata (const char *type)
{
- char *document;
struct target_ops *t;
/* If we're already connected to something that can get us OS
return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
}
-static int
-default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
-{
- return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
-}
-
-static int
-default_watchpoint_addr_within_range (struct target_ops *target,
- CORE_ADDR addr,
- CORE_ADDR start, int length)
-{
- return addr >= start && addr < start + length;
-}
-
-static int
-return_zero (void)
-{
- return 0;
-}
-
-static int
-return_one (void)
-{
- return 1;
-}
-
-static int
-return_minus_one (void)
-{
- return -1;
-}
-
-/*
- * Resize the to_sections pointer. Also make sure that anyone that
- * was holding on to an old value of it gets updated.
- * Returns the old size.
- */
+/* Determine the current address space of thread PTID. */
-int
-target_resize_to_sections (struct target_ops *target, int num_added)
+struct address_space *
+target_thread_address_space (ptid_t ptid)
{
- struct target_ops **t;
- struct target_section *old_value;
- int old_count;
-
- old_value = target->to_sections;
-
- if (target->to_sections)
- {
- old_count = target->to_sections_end - target->to_sections;
- target->to_sections = (struct target_section *)
- xrealloc ((char *) target->to_sections,
- (sizeof (struct target_section)) * (num_added + old_count));
- }
- else
- {
- old_count = 0;
- target->to_sections = (struct target_section *)
- xmalloc ((sizeof (struct target_section)) * num_added);
- }
- target->to_sections_end = target->to_sections + (num_added + old_count);
-
- /* Check to see if anyone else was pointing to this structure.
- If old_value was null, then no one was. */
+ struct address_space *aspace;
+ struct inferior *inf;
+ struct target_ops *t;
- if (old_value)
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
{
- for (t = target_structs; t < target_structs + target_struct_size;
- ++t)
+ if (t->to_thread_address_space != NULL)
{
- if ((*t)->to_sections == old_value)
- {
- (*t)->to_sections = target->to_sections;
- (*t)->to_sections_end = target->to_sections_end;
- }
- }
- /* There is a flattened view of the target stack in current_target,
- so its to_sections pointer might also need updating. */
- if (current_target.to_sections == old_value)
- {
- current_target.to_sections = target->to_sections;
- current_target.to_sections_end = target->to_sections_end;
+ aspace = t->to_thread_address_space (t, ptid);
+ gdb_assert (aspace);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog,
+ "target_thread_address_space (%s) = %d\n",
+ target_pid_to_str (ptid),
+ address_space_num (aspace));
+ return aspace;
}
}
- return old_count;
+ /* Fall-back to the "main" address space of the inferior. */
+ inf = find_inferior_pid (ptid_get_pid (ptid));
+
+ if (inf == NULL || inf->aspace == NULL)
+ internal_error (__FILE__, __LINE__,
+ _("Can't determine the current "
+ "address space of thread %s\n"),
+ target_pid_to_str (ptid));
+ return inf->aspace;
}
-/* Remove all target sections taken from ABFD.
-
- Scan the current target stack for targets whose section tables
- refer to sections from BFD, and remove those sections. We use this
- when we notice that the inferior has unloaded a shared object, for
- example. */
-void
-remove_target_sections (bfd *abfd)
+static int
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
- struct target_ops **t;
-
- for (t = target_structs; t < target_structs + target_struct_size; t++)
- {
- struct target_section *src, *dest;
+ return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
+}
- dest = (*t)->to_sections;
- for (src = (*t)->to_sections; src < (*t)->to_sections_end; src++)
- if (src->bfd != abfd)
- {
- /* Keep this section. */
- if (dest < src) *dest = *src;
- dest++;
- }
+static int
+default_watchpoint_addr_within_range (struct target_ops *target,
+ CORE_ADDR addr,
+ CORE_ADDR start, int length)
+{
+ return addr >= start && addr < start + length;
+}
- /* If we've dropped any sections, resize the section table. */
- if (dest < src)
- target_resize_to_sections (*t, dest - src);
- }
+static struct gdbarch *
+default_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+ return target_gdbarch;
}
+static int
+return_zero (void)
+{
+ return 0;
+}
+static int
+return_one (void)
+{
+ return 1;
+}
+static int
+return_minus_one (void)
+{
+ return -1;
+}
/* Find a single runnable target in the stack and return it. If for
some reason there is more than one, return NULL. */
return (count == 1 ? runable : NULL);
}
-/* Find a single core_stratum target in the list of targets and return it.
- If for some reason there is more than one, return NULL. */
-
-struct target_ops *
-find_core_target (void)
-{
- struct target_ops **t;
- struct target_ops *runable = NULL;
- int count;
-
- count = 0;
-
- for (t = target_structs; t < target_structs + target_struct_size;
- ++t)
- {
- if ((*t)->to_stratum == core_stratum)
- {
- runable = *t;
- ++count;
- }
- }
-
- return (count == 1 ? runable : NULL);
-}
-
/*
* Find the next target down the stack from the specified target.
*/
if (!ptid_equal (ptid, null_ptid))
{
int pid = ptid_get_pid (ptid);
- delete_inferior (pid);
+ exit_inferior (pid);
}
breakpoint_init_inferior (inf_exited);
return normal_pid_to_str (ptid);
}
-/* Error-catcher for target_find_memory_regions */
-static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
+/* Error-catcher for target_find_memory_regions. */
+static int
+dummy_find_memory_regions (find_memory_region_ftype ignore1, void *ignore2)
{
- error (_("No target."));
+ error (_("Command not implemented for this target."));
return 0;
}
-/* Error-catcher for target_make_corefile_notes */
-static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
+/* Error-catcher for target_make_corefile_notes. */
+static char *
+dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
+{
+ error (_("Command not implemented for this target."));
+ return NULL;
+}
+
+/* Error-catcher for target_get_bookmark. */
+static gdb_byte *
+dummy_get_bookmark (char *ignore1, int ignore2)
{
- error (_("No target."));
+ tcomplain ();
return NULL;
}
+/* Error-catcher for target_goto_bookmark. */
+static void
+dummy_goto_bookmark (gdb_byte *ignore, int from_tty)
+{
+ tcomplain ();
+}
+
/* Set up the handful of non-empty slots needed by the dummy target
vector. */
dummy_target.to_can_async_p = find_default_can_async_p;
dummy_target.to_is_async_p = find_default_is_async_p;
dummy_target.to_supports_non_stop = find_default_supports_non_stop;
+ dummy_target.to_supports_disable_randomization
+ = find_default_supports_disable_randomization;
dummy_target.to_pid_to_str = dummy_pid_to_str;
dummy_target.to_stratum = dummy_stratum;
dummy_target.to_find_memory_regions = dummy_find_memory_regions;
dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
+ dummy_target.to_get_bookmark = dummy_get_bookmark;
+ dummy_target.to_goto_bookmark = dummy_goto_bookmark;
dummy_target.to_xfer_partial = default_xfer_partial;
+ dummy_target.to_has_all_memory = (int (*) (struct target_ops *)) return_zero;
+ dummy_target.to_has_memory = (int (*) (struct target_ops *)) return_zero;
+ dummy_target.to_has_stack = (int (*) (struct target_ops *)) return_zero;
+ dummy_target.to_has_registers = (int (*) (struct target_ops *)) return_zero;
+ dummy_target.to_has_execution
+ = (int (*) (struct target_ops *, ptid_t)) return_zero;
+ dummy_target.to_stopped_by_watchpoint = return_zero;
+ dummy_target.to_stopped_data_address =
+ (int (*) (struct target_ops *, CORE_ADDR *)) return_zero;
dummy_target.to_magic = OPS_MAGIC;
}
\f
target_attach (char *args, int from_tty)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_attach != NULL)
}
internal_error (__FILE__, __LINE__,
- "could not find a target to attach");
+ _("could not find a target to attach"));
}
int
target_thread_alive (ptid_t ptid)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_thread_alive != NULL)
target_find_new_threads (void)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_find_new_threads != NULL)
}
}
+void
+target_stop (ptid_t ptid)
+{
+ if (!may_stop)
+ {
+ warning (_("May not interrupt or stop the target, ignoring attempt"));
+ return;
+ }
+
+ (*current_target.to_stop) (ptid);
+}
+
static void
debug_to_post_attach (int pid)
{
case TARGET_WAITKIND_EXECD:
return xstrprintf ("%sexecd", kind_str);
case TARGET_WAITKIND_SYSCALL_ENTRY:
- return xstrprintf ("%ssyscall-entry", kind_str);
+ return xstrprintf ("%sentered syscall", kind_str);
case TARGET_WAITKIND_SYSCALL_RETURN:
- return xstrprintf ("%ssyscall-return", kind_str);
+ return xstrprintf ("%sexited syscall", kind_str);
case TARGET_WAITKIND_SPURIOUS:
return xstrprintf ("%sspurious", kind_str);
case TARGET_WAITKIND_IGNORE:
return xstrprintf ("%signore", kind_str);
case TARGET_WAITKIND_NO_HISTORY:
return xstrprintf ("%sno-history", kind_str);
+ case TARGET_WAITKIND_NO_RESUMED:
+ return xstrprintf ("%sno-resumed", kind_str);
default:
return xstrprintf ("%sunknown???", kind_str);
}
struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
fprintf_unfiltered (gdb_stdlog, "%s ", func);
if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)
&& gdbarch_register_name (gdbarch, regno) != NULL
fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
if (regno >= 0 && regno < gdbarch_num_regs (gdbarch))
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int i, size = register_size (gdbarch, regno);
unsigned char buf[MAX_REGISTER_SIZE];
+
regcache_raw_collect (regcache, regno, buf);
fprintf_unfiltered (gdb_stdlog, " = ");
for (i = 0; i < size; i++)
}
if (size <= sizeof (LONGEST))
{
- ULONGEST val = extract_unsigned_integer (buf, size);
+ ULONGEST val = extract_unsigned_integer (buf, size, byte_order);
+
fprintf_unfiltered (gdb_stdlog, " %s %s",
core_addr_to_string_nz (val), plongest (val));
}
target_fetch_registers (struct regcache *regcache, int regno)
{
struct target_ops *t;
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_fetch_registers != NULL)
void
target_store_registers (struct regcache *regcache, int regno)
{
-
struct target_ops *t;
+
+ if (!may_write_registers)
+ error (_("Writing to registers is not allowed (regno %d)"), regno);
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_store_registers != NULL)
noprocess ();
}
+int
+target_core_of_thread (ptid_t ptid)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_core_of_thread != NULL)
+ {
+ int retval = t->to_core_of_thread (t, ptid);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog,
+ "target_core_of_thread (%d) = %d\n",
+ PIDGET (ptid), retval);
+ return retval;
+ }
+ }
+
+ return -1;
+}
+
+int
+target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_verify_memory != NULL)
+ {
+ int retval = t->to_verify_memory (t, data, memaddr, size);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog,
+ "target_verify_memory (%s, %s) = %d\n",
+ paddress (target_gdbarch, memaddr),
+ pulongest (size),
+ retval);
+ return retval;
+ }
+ }
+
+ tcomplain ();
+}
+
+/* The documentation for this function is in its prototype declaration in
+ target.h. */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_insert_mask_watchpoint != NULL)
+ {
+ int ret;
+
+ ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+ core_addr_to_string (addr),
+ core_addr_to_string (mask), rw, ret);
+
+ return ret;
+ }
+
+ return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+ target.h. */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_remove_mask_watchpoint != NULL)
+ {
+ int ret;
+
+ ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+ core_addr_to_string (addr),
+ core_addr_to_string (mask), rw, ret);
+
+ return ret;
+ }
+
+ return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+ in target.h. */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_masked_watch_num_registers != NULL)
+ return t->to_masked_watch_num_registers (t, addr, mask);
+
+ return -1;
+}
+
+/* The documentation for this function is in its prototype declaration
+ in target.h. */
+
+int
+target_ranged_break_num_registers (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_ranged_break_num_registers != NULL)
+ return t->to_ranged_break_num_registers (t);
+
+ return -1;
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
fprintf_unfiltered (gdb_stdlog,
"target_xfer_memory (%s, xxx, %d, %s, xxx) = %d",
- paddress (memaddr), len, write ? "write" : "read",
- retval);
+ paddress (target_gdbarch, memaddr), len,
+ write ? "write" : "read", retval);
if (retval > 0)
{
}
static int
-debug_to_insert_breakpoint (struct bp_target_info *bp_tgt)
+debug_to_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
int retval;
- retval = debug_target.to_insert_breakpoint (bp_tgt);
+ retval = debug_target.to_insert_breakpoint (gdbarch, bp_tgt);
fprintf_unfiltered (gdb_stdlog,
- "target_insert_breakpoint (0x%lx, xxx) = %ld\n",
- (unsigned long) bp_tgt->placed_address,
+ "target_insert_breakpoint (%s, xxx) = %ld\n",
+ core_addr_to_string (bp_tgt->placed_address),
(unsigned long) retval);
return retval;
}
static int
-debug_to_remove_breakpoint (struct bp_target_info *bp_tgt)
+debug_to_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
int retval;
- retval = debug_target.to_remove_breakpoint (bp_tgt);
+ retval = debug_target.to_remove_breakpoint (gdbarch, bp_tgt);
fprintf_unfiltered (gdb_stdlog,
- "target_remove_breakpoint (0x%lx, xxx) = %ld\n",
- (unsigned long) bp_tgt->placed_address,
+ "target_remove_breakpoint (%s, xxx) = %ld\n",
+ core_addr_to_string (bp_tgt->placed_address),
(unsigned long) retval);
return retval;
}
retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
fprintf_unfiltered (gdb_stdlog,
- "target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n",
- (unsigned long) addr,
- (unsigned long) len,
- (unsigned long) retval);
+ "target_region_ok_for_hw_watchpoint (%s, %ld) = %s\n",
+ core_addr_to_string (addr), (unsigned long) len,
+ core_addr_to_string (retval));
+ return retval;
+}
+
+static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
+{
+ int retval;
+
+ retval = debug_target.to_can_accel_watchpoint_condition (addr, len,
+ rw, cond);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_can_accel_watchpoint_condition "
+ "(%s, %d, %d, %s) = %ld\n",
+ core_addr_to_string (addr), len, rw,
+ host_address_to_string (cond), (unsigned long) retval);
return retval;
}
retval = debug_target.to_stopped_data_address (target, addr);
fprintf_unfiltered (gdb_stdlog,
- "target_stopped_data_address ([0x%lx]) = %ld\n",
- (unsigned long)*addr,
+ "target_stopped_data_address ([%s]) = %ld\n",
+ core_addr_to_string (*addr),
(unsigned long)retval);
return retval;
}
start, length);
fprintf_filtered (gdb_stdlog,
- "target_watchpoint_addr_within_range (0x%lx, 0x%lx, %d) = %d\n",
- (unsigned long) addr, (unsigned long) start, length,
- retval);
+ "target_watchpoint_addr_within_range (%s, %s, %d) = %d\n",
+ core_addr_to_string (addr), core_addr_to_string (start),
+ length, retval);
return retval;
}
static int
-debug_to_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
+debug_to_insert_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
int retval;
- retval = debug_target.to_insert_hw_breakpoint (bp_tgt);
+ retval = debug_target.to_insert_hw_breakpoint (gdbarch, bp_tgt);
fprintf_unfiltered (gdb_stdlog,
- "target_insert_hw_breakpoint (0x%lx, xxx) = %ld\n",
- (unsigned long) bp_tgt->placed_address,
+ "target_insert_hw_breakpoint (%s, xxx) = %ld\n",
+ core_addr_to_string (bp_tgt->placed_address),
(unsigned long) retval);
return retval;
}
static int
-debug_to_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
+debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
int retval;
- retval = debug_target.to_remove_hw_breakpoint (bp_tgt);
+ retval = debug_target.to_remove_hw_breakpoint (gdbarch, bp_tgt);
fprintf_unfiltered (gdb_stdlog,
- "target_remove_hw_breakpoint (0x%lx, xxx) = %ld\n",
- (unsigned long) bp_tgt->placed_address,
+ "target_remove_hw_breakpoint (%s, xxx) = %ld\n",
+ core_addr_to_string (bp_tgt->placed_address),
(unsigned long) retval);
return retval;
}
static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
- retval = debug_target.to_insert_watchpoint (addr, len, type);
+ retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
fprintf_unfiltered (gdb_stdlog,
- "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
- (unsigned long) addr, len, type, (unsigned long) retval);
+ "target_insert_watchpoint (%s, %d, %d, %s) = %ld\n",
+ core_addr_to_string (addr), len, type,
+ host_address_to_string (cond), (unsigned long) retval);
return retval;
}
static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
- retval = debug_target.to_remove_watchpoint (addr, len, type);
+ retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
fprintf_unfiltered (gdb_stdlog,
- "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
- (unsigned long) addr, len, type, (unsigned long) retval);
+ "target_remove_watchpoint (%s, %d, %d, %s) = %ld\n",
+ core_addr_to_string (addr), len, type,
+ host_address_to_string (cond), (unsigned long) retval);
return retval;
}
fprintf_unfiltered (gdb_stdlog, "target_load (%s, %d)\n", args, from_tty);
}
-static int
-debug_to_lookup_symbol (char *name, CORE_ADDR *addrp)
-{
- int retval;
-
- retval = debug_target.to_lookup_symbol (name, addrp);
-
- fprintf_unfiltered (gdb_stdlog, "target_lookup_symbol (%s, xxx)\n", name);
-
- return retval;
-}
-
static void
debug_to_post_startup_inferior (ptid_t ptid)
{
PIDGET (ptid));
}
-static void
-debug_to_acknowledge_created_inferior (int pid)
+static int
+debug_to_insert_fork_catchpoint (int pid)
{
- debug_target.to_acknowledge_created_inferior (pid);
+ int retval;
- fprintf_unfiltered (gdb_stdlog, "target_acknowledge_created_inferior (%d)\n",
- pid);
-}
+ retval = debug_target.to_insert_fork_catchpoint (pid);
-static void
-debug_to_insert_fork_catchpoint (int pid)
-{
- debug_target.to_insert_fork_catchpoint (pid);
+ fprintf_unfiltered (gdb_stdlog, "target_insert_fork_catchpoint (%d) = %d\n",
+ pid, retval);
- fprintf_unfiltered (gdb_stdlog, "target_insert_fork_catchpoint (%d)\n",
- pid);
+ return retval;
}
static int
return retval;
}
-static void
+static int
debug_to_insert_vfork_catchpoint (int pid)
{
- debug_target.to_insert_vfork_catchpoint (pid);
+ int retval;
+
+ retval = debug_target.to_insert_vfork_catchpoint (pid);
- fprintf_unfiltered (gdb_stdlog, "target_insert_vfork_catchpoint (%d)\n",
- pid);
+ fprintf_unfiltered (gdb_stdlog, "target_insert_vfork_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
}
static int
return retval;
}
-static void
+static int
debug_to_insert_exec_catchpoint (int pid)
{
- debug_target.to_insert_exec_catchpoint (pid);
+ int retval;
+
+ retval = debug_target.to_insert_exec_catchpoint (pid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_insert_exec_catchpoint (%d) = %d\n",
+ pid, retval);
- fprintf_unfiltered (gdb_stdlog, "target_insert_exec_catchpoint (%d)\n",
- pid);
+ return retval;
}
static int
return retval;
}
-static void
-debug_to_notice_signals (ptid_t ptid)
+static struct gdbarch *
+debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
{
- debug_target.to_notice_signals (ptid);
+ struct gdbarch *retval;
+
+ retval = debug_target.to_thread_architecture (ops, ptid);
- fprintf_unfiltered (gdb_stdlog, "target_notice_signals (%d)\n",
- PIDGET (ptid));
+ fprintf_unfiltered (gdb_stdlog,
+ "target_thread_architecture (%s) = %s [%s]\n",
+ target_pid_to_str (ptid),
+ host_address_to_string (retval),
+ gdbarch_bfd_arch_info (retval)->printable_name);
+ return retval;
}
static void
current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
current_target.to_stopped_data_address = debug_to_stopped_data_address;
- current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
- current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+ current_target.to_watchpoint_addr_within_range
+ = debug_to_watchpoint_addr_within_range;
+ current_target.to_region_ok_for_hw_watchpoint
+ = debug_to_region_ok_for_hw_watchpoint;
+ current_target.to_can_accel_watchpoint_condition
+ = debug_to_can_accel_watchpoint_condition;
current_target.to_terminal_init = debug_to_terminal_init;
current_target.to_terminal_inferior = debug_to_terminal_inferior;
- current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
+ current_target.to_terminal_ours_for_output
+ = debug_to_terminal_ours_for_output;
current_target.to_terminal_ours = debug_to_terminal_ours;
current_target.to_terminal_save_ours = debug_to_terminal_save_ours;
current_target.to_terminal_info = debug_to_terminal_info;
current_target.to_load = debug_to_load;
- current_target.to_lookup_symbol = debug_to_lookup_symbol;
current_target.to_post_startup_inferior = debug_to_post_startup_inferior;
- current_target.to_acknowledge_created_inferior = debug_to_acknowledge_created_inferior;
current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint;
current_target.to_remove_fork_catchpoint = debug_to_remove_fork_catchpoint;
current_target.to_insert_vfork_catchpoint = debug_to_insert_vfork_catchpoint;
current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
current_target.to_has_exited = debug_to_has_exited;
current_target.to_can_run = debug_to_can_run;
- current_target.to_notice_signals = debug_to_notice_signals;
current_target.to_stop = debug_to_stop;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
+ current_target.to_thread_architecture = debug_to_thread_architecture;
}
\f
static char targ_desc[] =
-"Names of targets and files being debugged.\n\
-Shows the entire stack of targets currently in use (including the exec-file,\n\
+"Names of targets and files being debugged.\nShows the entire \
+stack of targets currently in use (including the exec-file,\n\
core-file, and process, if any), as well as the symbol file name.";
static void
set_maintenance_target_async_permitted (char *args, int from_tty,
struct cmd_list_element *c)
{
- if (target_has_execution)
+ if (have_live_inferiors ())
{
target_async_permitted_1 = target_async_permitted;
error (_("Cannot change this setting while the inferior is running."));
struct cmd_list_element *c,
const char *value)
{
- fprintf_filtered (file, _("\
-Controlling the inferior in asynchronous mode is %s.\n"), value);
+ fprintf_filtered (file,
+ _("Controlling the inferior in "
+ "asynchronous mode is %s.\n"), value);
+}
+
+/* Temporary copies of permission settings. */
+
+static int may_write_registers_1 = 1;
+static int may_write_memory_1 = 1;
+static int may_insert_breakpoints_1 = 1;
+static int may_insert_tracepoints_1 = 1;
+static int may_insert_fast_tracepoints_1 = 1;
+static int may_stop_1 = 1;
+
+/* Make the user-set values match the real values again. */
+
+void
+update_target_permissions (void)
+{
+ may_write_registers_1 = may_write_registers;
+ may_write_memory_1 = may_write_memory;
+ may_insert_breakpoints_1 = may_insert_breakpoints;
+ may_insert_tracepoints_1 = may_insert_tracepoints;
+ may_insert_fast_tracepoints_1 = may_insert_fast_tracepoints;
+ may_stop_1 = may_stop;
+}
+
+/* The one function handles (most of) the permission flags in the same
+ way. */
+
+static void
+set_target_permissions (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ if (target_has_execution)
+ {
+ update_target_permissions ();
+ error (_("Cannot change this setting while the inferior is running."));
+ }
+
+ /* Make the real values match the user-changed values. */
+ may_write_registers = may_write_registers_1;
+ may_insert_breakpoints = may_insert_breakpoints_1;
+ may_insert_tracepoints = may_insert_tracepoints_1;
+ may_insert_fast_tracepoints = may_insert_fast_tracepoints_1;
+ may_stop = may_stop_1;
+ update_observer_mode ();
+}
+
+/* Set memory write permission independently of observer mode. */
+
+static void
+set_write_memory_permission (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ /* Make the real values match the user-changed values. */
+ may_write_memory = may_write_memory_1;
+ update_observer_mode ();
}
+
void
initialize_targets (void)
{
&setlist,
&showlist);
+ add_setshow_boolean_cmd ("stack-cache", class_support,
+ &stack_cache_enabled_p_1, _("\
+Set cache use for stack access."), _("\
+Show cache use for stack access."), _("\
+When on, use the data cache for all stack access, regardless of any\n\
+configured memory regions. This improves remote performance significantly.\n\
+By default, caching for stack access is on."),
+ set_stack_cache_enabled_p,
+ show_stack_cache_enabled_p,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-write-registers", class_support,
+ &may_write_registers_1, _("\
+Set permission to write into registers."), _("\
+Show permission to write into registers."), _("\
+When this permission is on, GDB may write into the target's registers.\n\
+Otherwise, any sort of write attempt will result in an error."),
+ set_target_permissions, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-write-memory", class_support,
+ &may_write_memory_1, _("\
+Set permission to write into target memory."), _("\
+Show permission to write into target memory."), _("\
+When this permission is on, GDB may write into the target's memory.\n\
+Otherwise, any sort of write attempt will result in an error."),
+ set_write_memory_permission, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-insert-breakpoints", class_support,
+ &may_insert_breakpoints_1, _("\
+Set permission to insert breakpoints in the target."), _("\
+Show permission to insert breakpoints in the target."), _("\
+When this permission is on, GDB may insert breakpoints in the program.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+ set_target_permissions, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-insert-tracepoints", class_support,
+ &may_insert_tracepoints_1, _("\
+Set permission to insert tracepoints in the target."), _("\
+Show permission to insert tracepoints in the target."), _("\
+When this permission is on, GDB may insert tracepoints in the program.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+ set_target_permissions, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-insert-fast-tracepoints", class_support,
+ &may_insert_fast_tracepoints_1, _("\
+Set permission to insert fast tracepoints in the target."), _("\
+Show permission to insert fast tracepoints in the target."), _("\
+When this permission is on, GDB may insert fast tracepoints.\n\
+Otherwise, any sort of insertion attempt will result in an error."),
+ set_target_permissions, NULL,
+ &setlist, &showlist);
+
+ add_setshow_boolean_cmd ("may-interrupt", class_support,
+ &may_stop_1, _("\
+Set permission to interrupt or signal the target."), _("\
+Show permission to interrupt or signal the target."), _("\
+When this permission is on, GDB may interrupt/stop the target's execution.\n\
+Otherwise, any attempt to interrupt or stop will be ignored."),
+ set_target_permissions, NULL,
+ &setlist, &showlist);
+
+
target_dcache = dcache_init ();
}