]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb] Add gdbarch_dwarf2_reg_piece_offset hook
authorTom de Vries <tdevries@suse.de>
Wed, 15 Jan 2025 16:02:00 +0000 (17:02 +0100)
committerTom de Vries <tdevries@suse.de>
Wed, 15 Jan 2025 16:02:00 +0000 (17:02 +0100)
In rw_pieced_value, when reading/writing part of a register, DW_OP_piece and
DW_OP_bit_piece are handled the same, but the standard tells us:
- DW_OP_piece: if the piece is located in a register, but does not occupy the
  entire register, the placement of the piece within that register is defined
  by the ABI.
- DW_OP_bit_piece: if the location is a register, the offset is from the least
  significant bit end of the register.

Add a new hook gdbarch_dwarf2_reg_piece_offset that allows us to define the
ABI-specific behaviour for DW_OP_piece.

The default implementation of the hook is the behaviour of DW_OP_bit_piece, so
there should not be any functional changes.

Tested on s390x-linux.

Approved-By: Tom Tromey <tom@tromey.com>
gdb/dwarf2/expr.c
gdb/findvar.c
gdb/gdbarch-gen.c
gdb/gdbarch-gen.h
gdb/gdbarch_components.py
gdb/value.h

index 2a1b85147d3112d368995a07e8dc3139979ecc86..ee1522b7437818e0bca14ca0e91f727e50fb39f7 100644 (file)
@@ -211,14 +211,33 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
            ULONGEST reg_bits = 8 * register_size (arch, gdb_regnum);
            int optim, unavail;
 
-           if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-               && p->offset + p->size < reg_bits)
+           if (p->offset + p->size < reg_bits)
              {
-               /* Big-endian, and we want less than full size.  */
-               bits_to_skip += reg_bits - (p->offset + p->size);
+               /* We want less than full size.  */
+
+               if (p->op == DW_OP_piece)
+                 {
+                   gdb_assert (p->offset == 0);
+
+                   /* If the piece is located in a register, but does not
+                      occupy the entire register, the placement of the piece
+                      within that register is defined by the ABI. */
+                   bits_to_skip
+                     += 8 * gdbarch_dwarf2_reg_piece_offset (arch, gdb_regnum,
+                                                             p->size / 8);
+                 }
+               else if (p->op == DW_OP_bit_piece)
+                 {
+                   /* If the location is a register, the offset is from the
+                      least significant bit end of the register.  */
+                   if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
+                     bits_to_skip += reg_bits - (p->offset + p->size);
+                   else
+                     bits_to_skip += p->offset;
+                 }
+               else
+                 error (_("Don't know how to get part of implicit pointer"));
              }
-           else
-             bits_to_skip += p->offset;
 
            this_size = bits_to_bytes (bits_to_skip, this_size_bits);
            buffer.resize (this_size);
index f7760aa61ca95b6a94c659d05c010eb48cecf558..1a9d2bedfc2b74a10632aa272e36e56efc990680 100644 (file)
@@ -541,6 +541,24 @@ default_value_from_register (gdbarch *gdbarch, type *type, int regnum,
   return value;
 }
 
+/* Default implementation of gdbarch_dwarf2_reg_piece_offset.  Implements
+   DW_OP_bits_piece for DW_OP_piece.  */
+
+ULONGEST
+default_dwarf2_reg_piece_offset (gdbarch *gdbarch, int gdb_regnum, ULONGEST size)
+{
+  ULONGEST reg_size = register_size (gdbarch, gdb_regnum);
+  gdb_assert (size <= reg_size);
+  if (reg_size == size)
+    return 0;
+
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    return reg_size - size;
+
+  return 0;
+}
+
+
 /* VALUE must be an lval_register value.  If regnum is the value's
    associated register number, and len the length of the value's type,
    read one or more registers in VALUE's frame, starting with register REGNUM,
index efc784c23118ea53d15f4ad578a10eb0080fffcc..8137ece78bcb1aca8a45658c2fbeb99f436903b3 100644 (file)
@@ -109,6 +109,7 @@ struct gdbarch
   gdbarch_register_to_value_ftype *register_to_value = nullptr;
   gdbarch_value_to_register_ftype *value_to_register = nullptr;
   gdbarch_value_from_register_ftype *value_from_register = default_value_from_register;
+  gdbarch_dwarf2_reg_piece_offset_ftype *dwarf2_reg_piece_offset = default_dwarf2_reg_piece_offset;
   gdbarch_pointer_to_address_ftype *pointer_to_address = unsigned_pointer_to_address;
   gdbarch_address_to_pointer_ftype *address_to_pointer = unsigned_address_to_pointer;
   gdbarch_integer_to_address_ftype *integer_to_address = nullptr;
@@ -372,6 +373,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of register_to_value, invalid_p == 0.  */
   /* Skip verify of value_to_register, invalid_p == 0.  */
   /* Skip verify of value_from_register, invalid_p == 0.  */
+  /* Skip verify of dwarf2_reg_piece_offset, invalid_p == 0.  */
   /* Skip verify of pointer_to_address, invalid_p == 0.  */
   /* Skip verify of address_to_pointer, invalid_p == 0.  */
   /* Skip verify of integer_to_address, has predicate.  */
@@ -789,6 +791,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   gdb_printf (file,
              "gdbarch_dump: value_from_register = <%s>\n",
              host_address_to_string (gdbarch->value_from_register));
+  gdb_printf (file,
+             "gdbarch_dump: dwarf2_reg_piece_offset = <%s>\n",
+             host_address_to_string (gdbarch->dwarf2_reg_piece_offset));
   gdb_printf (file,
              "gdbarch_dump: pointer_to_address = <%s>\n",
              host_address_to_string (gdbarch->pointer_to_address));
@@ -2588,6 +2593,23 @@ set_gdbarch_value_from_register (struct gdbarch *gdbarch,
   gdbarch->value_from_register = value_from_register;
 }
 
+ULONGEST
+gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, int regnum, ULONGEST size)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->dwarf2_reg_piece_offset != NULL);
+  if (gdbarch_debug >= 2)
+    gdb_printf (gdb_stdlog, "gdbarch_dwarf2_reg_piece_offset called\n");
+  return gdbarch->dwarf2_reg_piece_offset (gdbarch, regnum, size);
+}
+
+void
+set_gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch,
+                                    gdbarch_dwarf2_reg_piece_offset_ftype dwarf2_reg_piece_offset)
+{
+  gdbarch->dwarf2_reg_piece_offset = dwarf2_reg_piece_offset;
+}
+
 CORE_ADDR
 gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf)
 {
index 9627f6d6a9f150d25b45104546b5bdb51da4dc74..abffcf99fac6c832dc710b702ba4fedb76b9042c 100644 (file)
@@ -430,6 +430,14 @@ typedef struct value * (gdbarch_value_from_register_ftype) (struct gdbarch *gdba
 extern struct value * gdbarch_value_from_register (struct gdbarch *gdbarch, struct type *type, int regnum, const frame_info_ptr &this_frame);
 extern void set_gdbarch_value_from_register (struct gdbarch *gdbarch, gdbarch_value_from_register_ftype *value_from_register);
 
+/* For a DW_OP_piece located in a register, but not occupying the
+   entire register, return the placement of the piece within that
+   register as defined by the ABI. */
+
+typedef ULONGEST (gdbarch_dwarf2_reg_piece_offset_ftype) (struct gdbarch *gdbarch, int regnum, ULONGEST size);
+extern ULONGEST gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, int regnum, ULONGEST size);
+extern void set_gdbarch_dwarf2_reg_piece_offset (struct gdbarch *gdbarch, gdbarch_dwarf2_reg_piece_offset_ftype *dwarf2_reg_piece_offset);
+
 typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
index f9c18365add83a835c8c8237b484d291a06f59e1..2d528de2c56484f91d3bdcd1a9c5f827e429711d 100644 (file)
@@ -829,6 +829,22 @@ allocate and return a struct value with all value attributes
     invalid=False,
 )
 
+Method(
+    comment="""
+For a DW_OP_piece located in a register, but not occupying the
+entire register, return the placement of the piece within that
+register as defined by the ABI.
+""",
+    type="ULONGEST",
+    name="dwarf2_reg_piece_offset",
+    params=[
+        ("int", "regnum"),
+        ("ULONGEST", "size")
+    ],
+    predefault="default_dwarf2_reg_piece_offset",
+    invalid=False,
+)
+
 Method(
     type="CORE_ADDR",
     name="pointer_to_address",
index 2c94e09cbf3ac5f6c236be0e380b1e27a65b208b..8e5fd5403cc1a3f494fbc43cb4d8776419b2b8c6 100644 (file)
@@ -1128,6 +1128,8 @@ extern value *default_value_from_register (gdbarch *gdbarch, type *type,
                                           int regnum,
                                           const frame_info_ptr &this_frame);
 
+extern ULONGEST default_dwarf2_reg_piece_offset (gdbarch *gdbarch, int regnum, ULONGEST size);
+
 extern struct value *value_from_register (struct type *type, int regnum,
                                          const frame_info_ptr &frame);