aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Kościelnicki <koriakin@0x04.net>2016-02-18 09:21:38 +0100
committerMarcin Kościelnicki <koriakin@0x04.net>2016-02-18 17:21:22 +0100
commit5f034a78b986d30a90030b2409c61a8660b9b48c (patch)
tree312e005927c2673b81ad675d0e46e8b6ac5a5cd2
parentc304e18e5ca825f57963bd0c5f022fa8f5797b29 (diff)
downloadgdb-5f034a78b986d30a90030b2409c61a8660b9b48c.zip
gdb-5f034a78b986d30a90030b2409c61a8660b9b48c.tar.gz
gdb-5f034a78b986d30a90030b2409c61a8660b9b48c.tar.bz2
gdb: Add guess_tracepoint_registers hook to gdbarch.
When we're looking at a tracefile trace frame where registers are not available, and the tracepoint has only one location, we supply the location's address as the PC register. However, this only works if PC is not a pseudo register, and individual architectures may want to guess more registers. Add a gdbarch hook that will handle that. gdb/ChangeLog: * arch-utils.c (default_guess_tracepoint_registers): New function. * arch-utils.h (default_guess_tracepoint_registers): New prototype. * gdbarch.c: Regenerate. * gdbarch.h: Regenerate. * gdbarch.sh: Add guess_tracepoint_registers hook. * tracefile.c (tracefile_fetch_registers): Use the new gdbarch hook.
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/arch-utils.c23
-rw-r--r--gdb/arch-utils.h4
-rw-r--r--gdb/gdbarch.c23
-rw-r--r--gdb/gdbarch.h9
-rwxr-xr-xgdb/gdbarch.sh6
-rw-r--r--gdb/tracefile.c60
7 files changed, 95 insertions, 39 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e507dd1..c8832c9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2016-02-18 Marcin Kościelnicki <koriakin@0x04.net>
+
+ * arch-utils.c (default_guess_tracepoint_registers): New function.
+ * arch-utils.h (default_guess_tracepoint_registers): New prototype.
+ * gdbarch.c: Regenerate.
+ * gdbarch.h: Regenerate.
+ * gdbarch.sh: Add guess_tracepoint_registers hook.
+ * tracefile.c (tracefile_fetch_registers): Use the new gdbarch hook.
+
2016-02-17 Gary Benson <gbenson@redhat.com>
* exec.c (exec_file_locate_attach): Add missing cleanup.
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index fe64627..c3d7802 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -897,6 +897,29 @@ default_addressable_memory_unit_size (struct gdbarch *gdbarch)
return 1;
}
+void
+default_guess_tracepoint_registers (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR addr)
+{
+ int pc_regno = gdbarch_pc_regnum (gdbarch);
+ gdb_byte *regs;
+
+ /* This guessing code below only works if the PC register isn't
+ a pseudo-register. The value of a pseudo-register isn't stored
+ in the (non-readonly) regcache -- instead it's recomputed
+ (probably from some other cached raw register) whenever the
+ register is read. In this case, a custom method implementation
+ should be used by the architecture. */
+ if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch))
+ return;
+
+ regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno));
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch), addr);
+ regcache_raw_supply (regcache, pc_regno, regs);
+}
+
/* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_gdbarch_utils;
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 3fad2c3..9e1e70e 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -204,4 +204,8 @@ extern char *default_gcc_target_options (struct gdbarch *gdbarch);
extern const char *default_gnu_triplet_regexp (struct gdbarch *gdbarch);
extern int default_addressable_memory_unit_size (struct gdbarch *gdbarch);
+extern void default_guess_tracepoint_registers (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR addr);
+
#endif
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4143744..0136c75 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -312,6 +312,7 @@ struct gdbarch
int has_global_breakpoints;
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at;
+ gdbarch_guess_tracepoint_registers_ftype *guess_tracepoint_registers;
gdbarch_auto_charset_ftype *auto_charset;
gdbarch_auto_wide_charset_ftype *auto_wide_charset;
const char * solib_symbols_extension;
@@ -419,6 +420,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->relocate_instruction = NULL;
gdbarch->has_shared_address_space = default_has_shared_address_space;
gdbarch->fast_tracepoint_valid_at = default_fast_tracepoint_valid_at;
+ gdbarch->guess_tracepoint_registers = default_guess_tracepoint_registers;
gdbarch->auto_charset = default_auto_charset;
gdbarch->auto_wide_charset = default_auto_wide_charset;
gdbarch->gen_return_address = default_gen_return_address;
@@ -658,6 +660,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
/* Skip verify of has_shared_address_space, invalid_p == 0 */
/* Skip verify of fast_tracepoint_valid_at, invalid_p == 0 */
+ /* Skip verify of guess_tracepoint_registers, invalid_p == 0 */
/* Skip verify of auto_charset, invalid_p == 0 */
/* Skip verify of auto_wide_charset, invalid_p == 0 */
/* Skip verify of has_dos_based_file_system, invalid_p == 0 */
@@ -1024,6 +1027,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: gnu_triplet_regexp = <%s>\n",
host_address_to_string (gdbarch->gnu_triplet_regexp));
fprintf_unfiltered (file,
+ "gdbarch_dump: guess_tracepoint_registers = <%s>\n",
+ host_address_to_string (gdbarch->guess_tracepoint_registers));
+ fprintf_unfiltered (file,
"gdbarch_dump: half_bit = %s\n",
plongest (gdbarch->half_bit));
fprintf_unfiltered (file,
@@ -4450,6 +4456,23 @@ set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
gdbarch->fast_tracepoint_valid_at = fast_tracepoint_valid_at;
}
+void
+gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->guess_tracepoint_registers != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_guess_tracepoint_registers called\n");
+ gdbarch->guess_tracepoint_registers (gdbarch, regcache, addr);
+}
+
+void
+set_gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch,
+ gdbarch_guess_tracepoint_registers_ftype guess_tracepoint_registers)
+{
+ gdbarch->guess_tracepoint_registers = guess_tracepoint_registers;
+}
+
const char *
gdbarch_auto_charset (struct gdbarch *gdbarch)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 3fadcd1..7ffbf1f 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1327,6 +1327,15 @@ typedef int (gdbarch_fast_tracepoint_valid_at_ftype) (struct gdbarch *gdbarch, C
extern int gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr, char **msg);
extern void set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at);
+/* Guess register state based on tracepoint location. Used for tracepoints
+ where no registers have been collected, but there's only one location,
+ allowing us to guess the PC value, and perhaps some other registers.
+ On entry, regcache has all registers marked as unavailable. */
+
+typedef void (gdbarch_guess_tracepoint_registers_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr);
+extern void gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr);
+extern void set_gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, gdbarch_guess_tracepoint_registers_ftype *guess_tracepoint_registers);
+
/* Return the "auto" target charset. */
typedef const char * (gdbarch_auto_charset_ftype) (void);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 4ac6b90..61cb04a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1028,6 +1028,12 @@ m:int:has_shared_address_space:void:::default_has_shared_address_space::0
# True if a fast tracepoint can be set at an address.
m:int:fast_tracepoint_valid_at:CORE_ADDR addr, char **msg:addr, msg::default_fast_tracepoint_valid_at::0
+# Guess register state based on tracepoint location. Used for tracepoints
+# where no registers have been collected, but there's only one location,
+# allowing us to guess the PC value, and perhaps some other registers.
+# On entry, regcache has all registers marked as unavailable.
+m:void:guess_tracepoint_registers:struct regcache *regcache, CORE_ADDR addr:regcache, addr::default_guess_tracepoint_registers::0
+
# Return the "auto" target charset.
f:const char *:auto_charset:void::default_auto_charset:default_auto_charset::0
# Return the "auto" target wide charset.
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
index de42165..609b7e5 100644
--- a/gdb/tracefile.c
+++ b/gdb/tracefile.c
@@ -388,7 +388,8 @@ void
tracefile_fetch_registers (struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int regn, pc_regno;
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+ int regn;
/* We get here if no register data has been found. Mark registers
as unavailable. */
@@ -397,48 +398,29 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
/* We can often usefully guess that the PC is going to be the same
as the address of the tracepoint. */
- pc_regno = gdbarch_pc_regnum (gdbarch);
-
- /* XXX This guessing code below only works if the PC register isn't
- a pseudo-register. The value of a pseudo-register isn't stored
- in the (non-readonly) regcache -- instead it's recomputed
- (probably from some other cached raw register) whenever the
- register is read. This guesswork should probably move to some
- higher layer. */
- if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch))
+ if (tp == NULL || tp->base.loc == NULL)
return;
- if (regno == -1 || regno == pc_regno)
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next)
{
- struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
- gdb_byte *regs;
-
- if (tp && tp->base.loc)
- {
- /* But don't try to guess if tracepoint is multi-location... */
- if (tp->base.loc->next)
- {
- warning (_("Tracepoint %d has multiple "
- "locations, cannot infer $pc"),
- tp->base.number);
- return;
- }
- /* ... or does while-stepping. */
- if (tp->step_count > 0)
- {
- warning (_("Tracepoint %d does while-stepping, "
- "cannot infer $pc"),
- tp->base.number);
- return;
- }
-
- regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno));
- store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
- gdbarch_byte_order (gdbarch),
- tp->base.loc->address);
- regcache_raw_supply (regcache, pc_regno, regs);
- }
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ else if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
}
+
+ /* Guess what we can from the tracepoint location. */
+ gdbarch_guess_tracepoint_registers (gdbarch, regcache,
+ tp->base.loc->address);
}
/* This is the implementation of target_ops method to_has_all_memory. */