[PATCH 1/8] gdb: Add write_guessed_tracepoint_pc hook to gdbarch.

Marcin Kościelnicki
2016-01-24T12:12:27Z

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. Add a gdbarch hook that will handle
that for pseudo registers.

gdb/ChangeLog:

* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh: Add write_guessed_tracepoint_pc hook.
* tracefile.c (tracefile_fetch_registers): When PC is a pseudo,
ask gdbarch to handle guessed PC via the new hook.
---
gdb/ChangeLog | 8 ++++++++
gdb/gdbarch.c | 32 ++++++++++++++++++++++++++++++++
gdb/gdbarch.h | 6 ++++++
gdb/gdbarch.sh | 1 +
gdb/tracefile.c | 40 +++++++++++++++++++++++++++-------------
5 files changed, 74 insertions(+), 13 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 057c14f..983a243 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2016-01-24 Marcin KoÅ›cielnicki <koriakin@0x04.net>
+
+ * gdbarch.c: Regenerate.
+ * gdbarch.h: Regenerate.
+ * gdbarch.sh: Add write_guessed_tracepoint_pc hook.
+ * tracefile.c (tracefile_fetch_registers): When PC is a pseudo,
+ ask gdbarch to handle guessed PC via the new hook.
+
2016-01-22 John Baldwin <jhb@FreeBSD.org>

* fbsd-nat.c (fbsd_pid_to_str): Adjust string format.
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4143744..21942b0 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -181,6 +181,7 @@ struct gdbarch
int char_signed;
gdbarch_read_pc_ftype *read_pc;
gdbarch_write_pc_ftype *write_pc;
+ gdbarch_write_guessed_tracepoint_pc_ftype *write_guessed_tracepoint_pc;
gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer;
gdbarch_pseudo_register_read_ftype *pseudo_register_read;
gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value;
@@ -523,6 +524,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
gdbarch->char_signed = 1;
/* Skip verify of read_pc, has predicate. */
/* Skip verify of write_pc, has predicate. */
+ /* Skip verify of write_guessed_tracepoint_pc, has predicate. */
/* Skip verify of virtual_frame_pointer, invalid_p == 0 */
/* Skip verify of pseudo_register_read, has predicate. */
/* Skip verify of pseudo_register_read_value, has predicate. */
@@ -1402,6 +1404,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: vtable_function_descriptors = %s\n",
plongest (gdbarch->vtable_function_descriptors));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_write_guessed_tracepoint_pc_p() = %d\n",
+ gdbarch_write_guessed_tracepoint_pc_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: write_guessed_tracepoint_pc = <%s>\n",
+ host_address_to_string (gdbarch->write_guessed_tracepoint_pc));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_write_pc_p() = %d\n",
gdbarch_write_pc_p (gdbarch));
fprintf_unfiltered (file,
@@ -1821,6 +1829,30 @@ set_gdbarch_write_pc (struct gdbarch *gdbarch,
gdbarch->write_pc = write_pc;
}

+int
+gdbarch_write_guessed_tracepoint_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->write_guessed_tracepoint_pc != NULL;
+}
+
+void
+gdbarch_write_guessed_tracepoint_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->write_guessed_tracepoint_pc != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_write_guessed_tracepoint_pc called\n");
+ gdbarch->write_guessed_tracepoint_pc (regcache, val);
+}
+
+void
+set_gdbarch_write_guessed_tracepoint_pc (struct gdbarch *gdbarch,
+ gdbarch_write_guessed_tracepoint_pc_ftype write_guessed_tracepoint_pc)
+{
+ gdbarch->write_guessed_tracepoint_pc = write_guessed_tracepoint_pc;
+}
+
void
gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 3fadcd1..9e24d15 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -239,6 +239,12 @@ typedef void (gdbarch_write_pc_ftype) (struct regcache *regcache, CORE_ADDR val)
extern void gdbarch_write_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val);
extern void set_gdbarch_write_pc (struct gdbarch *gdbarch, gdbarch_write_pc_ftype *write_pc);

+extern int gdbarch_write_guessed_tracepoint_pc_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_write_guessed_tracepoint_pc_ftype) (struct regcache *regcache, CORE_ADDR val);
+extern void gdbarch_write_guessed_tracepoint_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val);
+extern void set_gdbarch_write_guessed_tracepoint_pc (struct gdbarch *gdbarch, gdbarch_write_guessed_tracepoint_pc_ftype *write_guessed_tracepoint_pc);
+
/* Function for getting target's idea of a frame pointer. FIXME: GDB's
whole scheme for dealing with "frames" and "frame pointers" needs a
serious shakedown. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 4ac6b90..b67ea72 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -417,6 +417,7 @@ v:int:char_signed:::1:-1:1
#
F:CORE_ADDR:read_pc:struct regcache *regcache:regcache
F:void:write_pc:struct regcache *regcache, CORE_ADDR val:regcache, val
+F:void:write_guessed_tracepoint_pc:struct regcache *regcache, CORE_ADDR val:regcache, val
# Function for getting target's idea of a frame pointer. FIXME: GDB's
# whole scheme for dealing with "frames" and "frame pointers" needs a
# serious shakedown.
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
index fef4ed9..7c2649d 100644
--- a/gdb/tracefile.c
+++ b/gdb/tracefile.c
@@ -396,16 +396,18 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
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 (pc_regno < 0)
return;

- if (regno == -1 || regno == pc_regno)
+ /* We try to guess PC if:
+
+ 1) We want all registers, or
+ 2) PC is a real register, and we want exactly it, or
+ 3) PC is a pseudo register (we don't know which real register it
+ corresponds to, so let's try to play safe). */
+
+ if (regno == -1 || regno == pc_regno ||
+ pc_regno >= gdbarch_num_regs (gdbarch))
{
struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
gdb_byte *regs;
@@ -429,11 +431,23 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
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);
+ if (pc_regno >= gdbarch_num_regs (gdbarch))
+ {
+ /* PC is a pseudo, let gdbarch deal with that. If it doesn't
+ know how, just bail. */
+ if (gdbarch_write_guessed_tracepoint_pc_p (gdbarch))
+ gdbarch_write_guessed_tracepoint_pc (gdbarch, regcache,
+ tp->base.loc->address);
+ }
+ else
+ {
+ /* PC is a real register. */
+ 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);
+ }
}
}
}
--
2.7.0