/* 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 "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 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_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
static int
nosymbol (char *name, CORE_ADDR *addrp)
{
- return 1; /* Symbol does not exist in target env */
+ 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
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);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, 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_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_can_async_p, t);
INHERIT (to_is_async_p, 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_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_trace_init, t);
+ INHERIT (to_download_tracepoint, t);
+ INHERIT (to_download_trace_state_variable, t);
+ INHERIT (to_trace_set_readonly_regions, t);
+ INHERIT (to_trace_start, t);
+ INHERIT (to_get_trace_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_set_disconnected_tracing, t);
+ INHERIT (to_set_circular_trace_buffer, 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_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_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_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_trace_init,
+ (void (*) (void))
+ tcomplain);
+ de_fault (to_download_tracepoint,
+ (void (*) (struct breakpoint *))
+ tcomplain);
+ de_fault (to_download_trace_state_variable,
+ (void (*) (struct trace_state_variable *))
+ 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_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_set_disconnected_tracing,
+ (void (*) (int))
+ target_ignore);
+ de_fault (to_set_circular_trace_buffer,
+ (void (*) (int))
+ target_ignore);
+ 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);
#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 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_partial (struct target_ops *ops, void *readbuf, const void *writebuf,
- ULONGEST memaddr, LONGEST len)
+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, 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)
if (readbuf != NULL && overlay_debugging)
{
struct obj_section *section = find_pc_overlay (memaddr);
+
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,
}
}
+ /* 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)
+ {
+ 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. */
region = lookup_mem_region (memaddr);
/* region->hi == 0 means there's no upper bound. */
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)
/* 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)
+ if (res > 0 && readbuf != NULL && !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;
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)"),
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). */
+ it makes no progress, and then return how much was transferred). */
int
target_read_memory (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_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_stack (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_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
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)
{
- LONGEST xfered = 0;
- while (xfered < len)
+ 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)
{
- 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)
+ 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)
+ {
+ 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,
}
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;
}
}
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 ();
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);
}
+/* Determine the current address space of thread PTID. */
+
+struct address_space *
+target_thread_address_space (ptid_t ptid)
+{
+ struct address_space *aspace;
+ struct inferior *inf;
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_thread_address_space != NULL)
+ {
+ 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;
+ }
+ }
+
+ /* 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;
+}
+
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
return addr >= start && addr < start + length;
}
+static struct gdbarch *
+default_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+ return target_gdbarch;
+}
+
static int
return_zero (void)
{
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_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:
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 ();
+}
+
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;
}
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;
- fprintf_unfiltered (gdb_stdlog, "target_insert_vfork_catchpoint (%d)\n",
- pid);
+ retval = debug_target.to_insert_vfork_catchpoint (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)\n",
- pid);
+ fprintf_unfiltered (gdb_stdlog, "target_insert_exec_catchpoint (%d) = %d\n",
+ pid, retval);
+
+ return retval;
}
static int
PIDGET (ptid));
}
+static struct gdbarch *
+debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+ struct gdbarch *retval;
+
+ retval = debug_target.to_thread_architecture (ops, 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
debug_to_stop (ptid_t ptid)
{
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_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 ();
}