[PATCH] gdbarch: Add pc_signed field and use it when adjusting BP addresses

vlad.ivanov@lab-systems.ru vlad.ivanov@lab-systems.ru
Thu Mar 15 11:22:00 GMT 2018


From: Vlad Ivanov <vlad.ivanov@lab-systems.ru>

MIPS targets use signed PC values.  Since commit a0de8c21
single-stepping on these targets didn't work due to the addition of
`address_significant` in adjust_breakpoint_address.  This commit
adds a new field to gdbarch struct which indicates the signedness
of the program counter.  This field is set to 1 for MIPS by default.

	* gdbarch.c: Add pc_signed field and access functions.
	* gdbarch.h: Add pc_signed access functions declarations.
	* mips-tdep.c (mips_gdbarch_init): Set PC to signed by default.
	* breakpoint.c (adjust_breakpoint_address): Check for PC
	signedness when calling `address_significant`.
---
 gdb/breakpoint.c |  5 ++++-
 gdb/gdbarch.c    | 20 ++++++++++++++++++++
 gdb/gdbarch.h    |  4 ++++
 gdb/mips-tdep.c  |  1 +
 4 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 454fda7684..247ec34857 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -6999,7 +6999,10 @@ adjust_breakpoint_address (struct gdbarch *gdbarch,
 	  adjusted_bpaddr = gdbarch_adjust_breakpoint_address (gdbarch, bpaddr);
 	}
 
-      adjusted_bpaddr = address_significant (gdbarch, adjusted_bpaddr);
+      /* Don't cut out "insignificant" address bits on targets with
+	 signed PC.  */
+      if (!gdbarch_pc_signed (gdbarch))
+	adjusted_bpaddr = address_significant (gdbarch, adjusted_bpaddr);
 
       /* An adjusted breakpoint address can significantly alter
          a user's expectations.  Print a warning if an adjustment
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index b8703e5a55..4d464c28f7 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -191,6 +191,7 @@ struct gdbarch
   int addr_bit;
   int dwarf2_addr_size;
   int char_signed;
+  int pc_signed;
   gdbarch_read_pc_ftype *read_pc;
   gdbarch_write_pc_ftype *write_pc;
   gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer;
@@ -397,6 +398,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->floatformat_for_type = default_floatformat_for_type;
   gdbarch->ptr_bit = gdbarch->int_bit;
   gdbarch->char_signed = -1;
+  gdbarch->pc_signed = -1;
   gdbarch->virtual_frame_pointer = legacy_virtual_frame_pointer;
   gdbarch->num_regs = -1;
   gdbarch->sp_regnum = -1;
@@ -550,6 +552,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
     gdbarch->dwarf2_addr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
   if (gdbarch->char_signed == -1)
     gdbarch->char_signed = 1;
+  if (gdbarch->pc_signed == -1)
+    gdbarch->pc_signed = 0;
   /* Skip verify of read_pc, has predicate.  */
   /* Skip verify of write_pc, has predicate.  */
   /* Skip verify of virtual_frame_pointer, invalid_p == 0 */
@@ -1810,6 +1814,22 @@ set_gdbarch_wchar_signed (struct gdbarch *gdbarch,
   gdbarch->wchar_signed = wchar_signed;
 }
 
+int
+gdbarch_pc_signed (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->pc_signed != -1);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_pc_signed called\n");
+  return gdbarch->pc_signed;
+}
+
+void
+set_gdbarch_pc_signed (struct gdbarch *gdbarch, int pc_signed)
+{
+  gdbarch->pc_signed = pc_signed;
+}
+
 const struct floatformat **
 gdbarch_floatformat_for_type (struct gdbarch *gdbarch, const char *name, int length)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 5cb131de1d..7af40154e0 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -194,6 +194,10 @@ extern void set_gdbarch_wchar_bit (struct gdbarch *gdbarch, int wchar_bit);
 extern int gdbarch_wchar_signed (struct gdbarch *gdbarch);
 extern void set_gdbarch_wchar_signed (struct gdbarch *gdbarch, int wchar_signed);
 
+/* One if PC values are signed, zero if unsigned. */
+extern int gdbarch_pc_signed (struct gdbarch *gdbarch);
+extern void set_gdbarch_pc_signed (struct gdbarch *gdbarch, int pc_signed);
+
 /* Returns the floating-point format to be used for values of length LENGTH.
    NAME, if non-NULL, is the type name, which may be used to distinguish
    different target formats of the same length. */
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index f9f84c4d48..6389bdbb95 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -8685,6 +8685,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Add/remove bits from an address.  The MIPS needs be careful to
      ensure that all 32 bit addresses are sign extended to 64 bits.  */
   set_gdbarch_addr_bits_remove (gdbarch, mips_addr_bits_remove);
+  set_gdbarch_pc_signed(gdbarch, 1);
 
   /* Unwind the frame.  */
   set_gdbarch_unwind_pc (gdbarch, mips_unwind_pc);
-- 
2.14.3



More information about the Gdb-patches mailing list