/* 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
Free Software Foundation, Inc.
Contributed by Cygnus Support.
#include "regcache.h"
#include "gdb_assert.h"
#include "gdbcore.h"
+#include "exceptions.h"
+#include "target-descriptions.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 *);
{
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);
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_async,
(void (*) (void (*) (enum inferior_event_type, void*), void*))
tcomplain);
+ current_target.to_read_description = NULL;
#undef de_fault
/* Finally, position the target-stack beneath the squashed
current_target.beneath = target_stack;
}
+/* 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.
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
+/* Using the objfile specified in BATON, 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)
+{
+ volatile CORE_ADDR addr = 0;
+
+ if (target_get_thread_local_address_p ()
+ && gdbarch_fetch_tls_load_module_address_p (current_gdbarch))
+ {
+ ptid_t ptid = inferior_ptid;
+ volatile struct gdb_exception ex;
+
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ CORE_ADDR lm_addr;
+
+ /* Fetch the load module address for this objfile. */
+ lm_addr = gdbarch_fetch_tls_load_module_address (current_gdbarch,
+ objfile);
+ /* If it's 0, throw the appropriate exception. */
+ if (lm_addr == 0)
+ throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR,
+ _("TLS load module not found"));
+
+ addr = target_get_thread_local_address (ptid, lm_addr, offset);
+ }
+ /* If an error occurred, print TLS related messages here. Otherwise,
+ throw the error to some higher catcher. */
+ if (ex.reason < 0)
+ {
+ int objfile_is_library = (objfile->flags & OBJF_SHARED);
+
+ switch (ex.error)
+ {
+ case TLS_NO_LIBRARY_SUPPORT_ERROR:
+ error (_("Cannot find thread-local variables in this thread library."));
+ break;
+ case TLS_LOAD_MODULE_NOT_FOUND_ERROR:
+ if (objfile_is_library)
+ error (_("Cannot find shared library `%s' in dynamic"
+ " linker's load module list"), objfile->name);
+ else
+ error (_("Cannot find executable file `%s' in dynamic"
+ " linker's load module list"), objfile->name);
+ break;
+ case TLS_NOT_ALLOCATED_YET_ERROR:
+ if (objfile_is_library)
+ error (_("The inferior has not yet allocated storage for"
+ " thread-local variables in\n"
+ "the shared library `%s'\n"
+ "for %s"),
+ objfile->name, target_pid_to_str (ptid));
+ else
+ error (_("The inferior has not yet allocated storage for"
+ " thread-local variables in\n"
+ "the executable `%s'\n"
+ "for %s"),
+ objfile->name, target_pid_to_str (ptid));
+ break;
+ case TLS_GENERIC_ERROR:
+ if (objfile_is_library)
+ error (_("Cannot find thread-local storage for %s, "
+ "shared library %s:\n%s"),
+ target_pid_to_str (ptid),
+ objfile->name, ex.message);
+ else
+ error (_("Cannot find thread-local storage for %s, "
+ "executable file %s:\n%s"),
+ target_pid_to_str (ptid),
+ objfile->name, ex.message);
+ break;
+ default:
+ throw_exception (ex);
+ break;
+ }
+ }
+ }
+ /* It wouldn't be wrong here to try a gdbarch method, too; finding
+ TLS is an ABI-specific thing. But we don't do that yet. */
+ else
+ error (_("Cannot find thread-local variables on this target"));
+
+ return addr;
+}
+
#undef MIN
#define MIN(A, B) (((A) <= (B)) ? (A) : (B))
/* 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)
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;
+ /* We want to continue past core files to executables, but not
+ past a running target's memory. */
+ if (ops->to_has_all_memory)
+ return res;
+
ops = ops->beneath;
}
while (ops != NULL);
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 ();
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
"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 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.
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;
}
static void
-debug_print_register (const char * func, int regno)
+debug_print_register (const char * func,
+ struct regcache *regcache, int regno)
{
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 (current_gdbarch)
+ + gdbarch_num_pseudo_regs (current_gdbarch)
+ && gdbarch_register_name (current_gdbarch, regno) != NULL
+ && gdbarch_register_name (current_gdbarch, regno)[0] != '\0')
+ fprintf_unfiltered (gdb_stdlog, "(%s)", gdbarch_register_name
+ (current_gdbarch, regno));
else
fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
if (regno >= 0)
{
- int i;
+ int i, size = register_size (current_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;
}
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 ();
}