/* 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
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Cygnus Support.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include <errno.h>
#include "gdb_assert.h"
#include "gdbcore.h"
#include "exceptions.h"
+#include "target-descriptions.h"
+#include "gdb_stdint.h"
static void target_info (char *, int);
static ptid_t debug_to_wait (ptid_t, struct target_waitstatus *);
-static void debug_to_fetch_registers (int);
+static void debug_to_fetch_registers (struct regcache *, int);
-static void debug_to_store_registers (int);
+static void debug_to_store_registers (struct regcache *, int);
-static void debug_to_prepare_to_store (void);
+static void debug_to_prepare_to_store (struct regcache *);
static void debug_to_files_info (struct target_ops *);
static int trust_readonly = 0;
+/* Nonzero if we should show true memory content including
+ memory breakpoint inserted by gdb. */
+
+static int show_memory_breakpoints = 0;
+
/* Non-zero if we want to see trace of target level stuff. */
static int targetdebug = 0;
{
struct target_ops *t;
- /* First, reset curren'ts contents. */
+ /* First, reset current's contents. */
memset (¤t_target, 0, sizeof (current_target));
#define INHERIT(FIELD, TARGET) \
INHERIT (to_remove_watchpoint, t);
INHERIT (to_stopped_data_address, t);
INHERIT (to_stopped_by_watchpoint, t);
+ INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_terminal_init, t);
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
- INHERIT (to_reported_exec_events_per_exec_call, t);
INHERIT (to_has_exited, t);
INHERIT (to_mourn_inferior, t);
INHERIT (to_can_run, t);
INHERIT (to_stop, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
- INHERIT (to_enable_exception_callback, t);
- INHERIT (to_get_current_exception_event, 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_can_async_p, t);
INHERIT (to_is_async_p, t);
INHERIT (to_async, t);
- INHERIT (to_async_mask_value, t);
+ INHERIT (to_async_mask, t);
INHERIT (to_find_memory_regions, t);
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
+ /* Do not inherit to_read_description. */
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
(ptid_t (*) (ptid_t, struct target_waitstatus *))
noprocess);
de_fault (to_fetch_registers,
- (void (*) (int))
+ (void (*) (struct regcache *, int))
target_ignore);
de_fault (to_store_registers,
- (void (*) (int))
+ (void (*) (struct regcache *, int))
noprocess);
de_fault (to_prepare_to_store,
- (void (*) (void))
+ (void (*) (struct regcache *))
noprocess);
de_fault (deprecated_xfer_memory,
(int (*) (CORE_ADDR, gdb_byte *, int, int, struct mem_attrib *, struct target_ops *))
de_fault (to_remove_exec_catchpoint,
(int (*) (int))
tcomplain);
- de_fault (to_reported_exec_events_per_exec_call,
- (int (*) (void))
- return_one);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
de_fault (to_rcmd,
(void (*) (char *, struct ui_file *))
tcomplain);
- de_fault (to_enable_exception_callback,
- (struct symtab_and_line * (*) (enum exception_event_kind, int))
- nosupport_runtime);
- de_fault (to_get_current_exception_event,
- (struct exception_event_record * (*) (void))
- nosupport_runtime);
de_fault (to_pid_to_exec_file,
(char *(*) (int))
return_zero);
de_fault (to_async,
(void (*) (void (*) (enum inferior_event_type, void*), void*))
tcomplain);
+ de_fault (to_async_mask,
+ (int (*) (int))
+ return_one);
+ current_target.to_read_description = NULL;
#undef de_fault
/* Finally, position the target-stack beneath the squashed
"current_target". That way code looking for a non-inherited
target method can quickly and simply find it. */
current_target.beneath = target_stack;
+
+ if (targetdebug)
+ 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,
update_current_target ();
- if (targetdebug)
- setup_target_debug ();
-
/* Not on top? */
return (t != target_stack);
}
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
-/* Using the objfile specified in BATON, find the address for the
+/* Using the objfile specified in OBJFILE, find the address for the
current thread's thread-local storage with offset OFFSET. */
CORE_ADDR
target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset)
char *bufptr;
unsigned int nbytes_read = 0;
+ gdb_assert (string);
+
/* Small for testing. */
buffer_allocated = 4;
buffer = xmalloc (buffer_allocated);
nbytes_read += tlen;
}
done:
+ *string = buffer;
if (errnop != NULL)
*errnop = errcode;
- if (string != NULL)
- *string = buffer;
return nbytes_read;
}
return xfer_memory (memaddr, readbuf, len, 0, NULL, ops);
}
+ /* Likewise for accesses to unmapped overlay sections. */
+ if (readbuf != NULL && overlay_debugging)
+ {
+ asection *section = find_pc_overlay (memaddr);
+ if (pc_in_unmapped_range (memaddr, section))
+ return xfer_memory (memaddr, readbuf, len, 0, NULL, ops);
+ }
+
/* Try GDB's internal data cache. */
region = lookup_mem_region (memaddr);
- if (memaddr + len < region->hi)
+ /* region->hi == 0 means there's no upper bound. */
+ if (memaddr + len < region->hi || region->hi == 0)
reg_len = len;
else
reg_len = region->hi - memaddr;
if (writebuf != NULL)
error (_("Writing to flash memory forbidden in this context"));
break;
+
+ case MEM_NONE:
+ return -1;
}
if (region->attrib.cache)
if (res <= 0)
return -1;
else
- return res;
+ {
+ if (readbuf && !show_memory_breakpoints)
+ breakpoint_restore_shadows (readbuf, memaddr, reg_len);
+ return res;
+ }
}
/* If none of those methods found the memory we wanted, fall back
do
{
res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
- readbuf, writebuf, memaddr, len);
+ readbuf, writebuf, memaddr, reg_len);
if (res > 0)
- return res;
+ break;
+
+ /* We want to continue past core files to executables, but not
+ past a running target's memory. */
+ if (ops->to_has_all_memory)
+ break;
ops = ops->beneath;
}
while (ops != NULL);
+ if (readbuf && !show_memory_breakpoints)
+ breakpoint_restore_shadows (readbuf, memaddr, reg_len);
+
/* If we still haven't got anything, return the last error. We
give up. */
return res;
}
+static void
+restore_show_memory_breakpoints (void *arg)
+{
+ show_memory_breakpoints = (uintptr_t) arg;
+}
+
+struct cleanup *
+make_show_memory_breakpoints_cleanup (int show)
+{
+ int current = show_memory_breakpoints;
+ show_memory_breakpoints = show;
+
+ return make_cleanup (restore_show_memory_breakpoints,
+ (void *) (uintptr_t) current);
+}
+
static LONGEST
target_xfer_partial (struct target_ops *ops,
enum target_object object, const char *annex,
if (targetdebug)
fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n",
paddr (address), phex (length, 0));
- return t->to_flash_erase (t, address, length);
+ t->to_flash_erase (t, address, length);
+ return;
}
tcomplain ();
{
if (targetdebug)
fprintf_unfiltered (gdb_stdlog, "target_flash_done\n");
- return t->to_flash_done (t);
+ t->to_flash_done (t);
+ return;
}
tcomplain ();
do_cleanups (cleanup);
}
if (readbuf != NULL)
- xfered = ops->deprecated_xfer_memory (offset, readbuf, len, 0/*read*/,
- NULL, ops);
+ xfered = ops->deprecated_xfer_memory (offset, readbuf, len,
+ 0/*read*/, NULL, ops);
if (xfered > 0)
return xfered;
else if (xfered == 0 && errno == 0)
target_pre_inferior (int from_tty)
{
invalidate_target_mem_regions ();
+
+ target_clear_description ();
}
/* This is to be called by the open routine before it does
void
target_detach (char *args, int from_tty)
{
+ /* If we're in breakpoints-always-inserted mode, have to
+ remove them before detaching. */
+ remove_breakpoints ();
+
(current_target.to_detach) (args, from_tty);
}
{
struct target_ops *t;
+ /* If we're in breakpoints-always-inserted mode, have to
+ remove them before disconnecting. */
+ remove_breakpoints ();
+
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_disconnect != NULL)
{
tcomplain ();
}
-int
-target_async_mask (int mask)
-{
- int saved_async_masked_status = target_async_mask_value;
- target_async_mask_value = mask;
- return saved_async_masked_status;
-}
-
/* Look through the list of possible targets for a target that can
follow forks. */
"could not find a target to follow fork");
}
+/* Look for a target which can describe architectural features, starting
+ from TARGET. If we find one, return its description. */
+
+const struct target_desc *
+target_read_description (struct target_ops *target)
+{
+ struct target_ops *t;
+
+ for (t = target; t != NULL; t = t->beneath)
+ if (t->to_read_description != NULL)
+ {
+ const struct target_desc *tdesc;
+
+ tdesc = t->to_read_description (t);
+ if (tdesc)
+ return tdesc;
+ }
+
+ return NULL;
+}
+
+/* Look through the currently pushed targets. If none of them will
+ be able to restart the currently running process, issue an error
+ message. */
+
+void
+target_require_runnable (void)
+{
+ struct target_ops *t;
+
+ for (t = target_stack; t != NULL; t = t->beneath)
+ {
+ /* If this target knows how to create a new program, then
+ assume we will still be able to after killing the current
+ one. Either killing and mourning will not pop T, or else
+ find_default_run_target will find it again. */
+ if (t->to_create_inferior != NULL)
+ return;
+
+ /* 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)
+ 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");
+}
+
/* Look through the list of possible targets for a target that can
execute a run or attach command without any other data. This is
used to locate the default process stratum.
- Result is always valid (error() is called for errors). */
+ If DO_MESG is not NULL, the result is always valid (error() is
+ called for errors); else, return NULL on error. */
static struct target_ops *
find_default_run_target (char *do_mesg)
}
if (count != 1)
- error (_("Don't know how to %s. Try \"help target\"."), do_mesg);
+ {
+ if (do_mesg)
+ error (_("Don't know how to %s. Try \"help target\"."), do_mesg);
+ else
+ return NULL;
+ }
return runable;
}
return;
}
+int
+find_default_can_async_p (void)
+{
+ struct target_ops *t;
+
+ /* This may be called before the target is pushed on the stack;
+ look for the default process stratum. If there's none, gdb isn't
+ configured with a native debugger, and target remote isn't
+ connected yet. */
+ t = find_default_run_target (NULL);
+ if (t && t->to_can_async_p)
+ return (t->to_can_async_p) ();
+ return 0;
+}
+
+int
+find_default_is_async_p (void)
+{
+ struct target_ops *t;
+
+ /* This may be called before the target is pushed on the stack;
+ look for the default process stratum. If there's none, gdb isn't
+ configured with a native debugger, and target remote isn't
+ connected yet. */
+ t = find_default_run_target (NULL);
+ if (t && t->to_is_async_p)
+ return (t->to_is_async_p) ();
+ return 0;
+}
+
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
deprecated_detach_hook ();
}
\f
-/* Helper function for child_wait and the Lynx derivatives of child_wait.
+/* Helper function for child_wait and the derivatives of child_wait.
HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
translation of that in OURSTATUS. */
void
store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
{
-#ifdef CHILD_SPECIAL_WAITSTATUS
- /* CHILD_SPECIAL_WAITSTATUS should return nonzero and set *OURSTATUS
- if it wants to deal with hoststatus. */
- if (CHILD_SPECIAL_WAITSTATUS (ourstatus, hoststatus))
- return;
-#endif
-
if (WIFEXITED (hoststatus))
{
ourstatus->kind = TARGET_WAITKIND_EXITED;
dummy_target.to_doc = "";
dummy_target.to_attach = find_default_attach;
dummy_target.to_create_inferior = find_default_create_inferior;
+ 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_pid_to_str = normal_pid_to_str;
dummy_target.to_stratum = dummy_stratum;
dummy_target.to_find_memory_regions = dummy_find_memory_regions;
}
static void
-debug_print_register (const char * func, int regno)
+debug_print_register (const char * func,
+ struct regcache *regcache, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
fprintf_unfiltered (gdb_stdlog, "%s ", func);
- if (regno >= 0 && regno < NUM_REGS + NUM_PSEUDO_REGS
- && REGISTER_NAME (regno) != NULL && REGISTER_NAME (regno)[0] != '\0')
- fprintf_unfiltered (gdb_stdlog, "(%s)", REGISTER_NAME (regno));
+ if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch)
+ && gdbarch_register_name (gdbarch, regno) != NULL
+ && gdbarch_register_name (gdbarch, regno)[0] != '\0')
+ fprintf_unfiltered (gdb_stdlog, "(%s)",
+ gdbarch_register_name (gdbarch, regno));
else
fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
if (regno >= 0)
{
- int i;
+ int i, size = register_size (gdbarch, regno);
unsigned char buf[MAX_REGISTER_SIZE];
- deprecated_read_register_gen (regno, buf);
+ regcache_cooked_read (regcache, regno, buf);
fprintf_unfiltered (gdb_stdlog, " = ");
- for (i = 0; i < register_size (current_gdbarch, regno); i++)
+ for (i = 0; i < size; i++)
{
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
}
- if (register_size (current_gdbarch, regno) <= sizeof (LONGEST))
+ if (size <= sizeof (LONGEST))
{
+ ULONGEST val = extract_unsigned_integer (buf, size);
fprintf_unfiltered (gdb_stdlog, " 0x%s %s",
- paddr_nz (read_register (regno)),
- paddr_d (read_register (regno)));
+ paddr_nz (val), paddr_d (val));
}
}
fprintf_unfiltered (gdb_stdlog, "\n");
}
static void
-debug_to_fetch_registers (int regno)
+debug_to_fetch_registers (struct regcache *regcache, int regno)
{
- debug_target.to_fetch_registers (regno);
- debug_print_register ("target_fetch_registers", regno);
+ debug_target.to_fetch_registers (regcache, regno);
+ debug_print_register ("target_fetch_registers", regcache, regno);
}
static void
-debug_to_store_registers (int regno)
+debug_to_store_registers (struct regcache *regcache, int regno)
{
- debug_target.to_store_registers (regno);
- debug_print_register ("target_store_registers", regno);
+ debug_target.to_store_registers (regcache, regno);
+ debug_print_register ("target_store_registers", regcache, regno);
fprintf_unfiltered (gdb_stdlog, "\n");
}
static void
-debug_to_prepare_to_store (void)
+debug_to_prepare_to_store (struct regcache *regcache)
{
- debug_target.to_prepare_to_store ();
+ debug_target.to_prepare_to_store (regcache);
fprintf_unfiltered (gdb_stdlog, "target_prepare_to_store ()\n");
}
{
int retval;
- retval = debug_target.to_insert_watchpoint (addr, len, type);
+ retval = debug_target.to_remove_watchpoint (addr, len, type);
fprintf_unfiltered (gdb_stdlog,
- "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
+ "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
(unsigned long) addr, len, type, (unsigned long) retval);
return retval;
}
return retval;
}
-static int
-debug_to_reported_exec_events_per_exec_call (void)
-{
- int reported_exec_events;
-
- reported_exec_events = debug_target.to_reported_exec_events_per_exec_call ();
-
- fprintf_unfiltered (gdb_stdlog,
- "target_reported_exec_events_per_exec_call () = %d\n",
- reported_exec_events);
-
- return reported_exec_events;
-}
-
static int
debug_to_has_exited (int pid, int wait_status, int *exit_status)
{
fprintf_unfiltered (gdb_stdlog, "target_rcmd (%s, ...)\n", command);
}
-static struct symtab_and_line *
-debug_to_enable_exception_callback (enum exception_event_kind kind, int enable)
-{
- struct symtab_and_line *result;
- result = debug_target.to_enable_exception_callback (kind, enable);
- fprintf_unfiltered (gdb_stdlog,
- "target get_exception_callback_sal (%d, %d)\n",
- kind, enable);
- return result;
-}
-
-static struct exception_event_record *
-debug_to_get_current_exception_event (void)
-{
- struct exception_event_record *result;
- result = debug_target.to_get_current_exception_event ();
- fprintf_unfiltered (gdb_stdlog, "target get_current_exception_event ()\n");
- return result;
-}
-
static char *
debug_to_pid_to_exec_file (int pid)
{
current_target.to_remove_vfork_catchpoint = debug_to_remove_vfork_catchpoint;
current_target.to_insert_exec_catchpoint = debug_to_insert_exec_catchpoint;
current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
- current_target.to_reported_exec_events_per_exec_call = debug_to_reported_exec_events_per_exec_call;
current_target.to_has_exited = debug_to_has_exited;
current_target.to_mourn_inferior = debug_to_mourn_inferior;
current_target.to_can_run = debug_to_can_run;
current_target.to_find_new_threads = debug_to_find_new_threads;
current_target.to_stop = debug_to_stop;
current_target.to_rcmd = debug_to_rcmd;
- current_target.to_enable_exception_callback = debug_to_enable_exception_callback;
- current_target.to_get_current_exception_event = debug_to_get_current_exception_event;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
}
\f
target_rcmd (cmd, gdb_stdtarg);
}
+/* Print the name of each layers of our target stack. */
+
+static void
+maintenance_print_target_stack (char *cmd, int from_tty)
+{
+ struct target_ops *t;
+
+ printf_filtered (_("The current target stack is:\n"));
+
+ for (t = target_stack; t != NULL; t = t->beneath)
+ {
+ printf_filtered (" - %s (%s)\n", t->to_shortname, t->to_longname);
+ }
+}
+
void
initialize_targets (void)
{
add_com ("monitor", class_obscure, do_monitor_command,
_("Send a command to the remote monitor (remote targets only)."));
+ add_cmd ("target-stack", class_maintenance, maintenance_print_target_stack,
+ _("Print the name of each layer of the internal target stack."),
+ &maintenanceprintlist);
+
target_dcache = dcache_init ();
}