This patch teaches GDB how to print the capability tag from registers.
gdb/ChangeLog:
2020-10-20 Luis Machado <luis.machado@arm.com>
* aarch64-tdep.c (aarch64_register_has_tag, aarch64_register_tag): New
functions.
(aarch64_gdbarch_init): Register hooks.
* arch-utils.c (default_register_has_tag, default_register_tag): New
functions.
* arch-utils.h (default_register_has_tag, default_register_tag): New
prototypes.
* gdbarch.c: Regenerate.
* gdbarch.h: Likewise.
* gdbarch.sh (register_has_tag, register_tag): New gdbarch hooks.
* regcache.c (readable_regcache::cooked_read_value): Fetch the tag
metadata from registers.
* valprint.c (generic_value_print_capability): Display register tags.
* value.c (struct value) <tagged, tag>: New fields.
(value_contents_copy_raw): Handle tags.
(value_tagged, set_value_tagged, value_tag, set_value_tag): New
functions.
(value_copy): Handle tags.
* value.h (value_tagged, set_value_tagged, value_tag)
(set_value_tag): New prototypes.
+2020-10-20 Luis Machado <luis.machado@arm.com>
+
+ * aarch64-tdep.c (aarch64_register_has_tag, aarch64_register_tag): New
+ functions.
+ (aarch64_gdbarch_init): Register hooks.
+ * arch-utils.c (default_register_has_tag, default_register_tag): New
+ functions.
+ * arch-utils.h (default_register_has_tag, default_register_tag): New
+ prototypes.
+ * gdbarch.c: Regenerate.
+ * gdbarch.h: Likewise.
+ * gdbarch.sh (register_has_tag, register_tag): New gdbarch hooks.
+ * regcache.c (readable_regcache::cooked_read_value): Fetch the tag
+ metadata from registers.
+ * valprint.c (generic_value_print_capability): Display register tags.
+ * value.c (struct value) <tagged, tag>: New fields.
+ (value_contents_copy_raw): Handle tags.
+ (value_tagged, set_value_tagged, value_tag, set_value_tag): New
+ functions.
+ (value_copy): Handle tags.
+ * value.h (value_tagged, set_value_tagged, value_tag)
+ (set_value_tag): New prototypes.
+
2020-10-20 Luis Machado <luis.machado@arm.com>
* aarch64-tdep.c: Include elf-bfd.h.
name);
}
+/* Implements the gdbarch_register_has_tag hook. */
+
+static bool
+aarch64_register_has_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int regnum)
+{
+ if (aarch64_debug)
+ debug_printf ("%s: Entering\n", __func__);
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Only Morello's registers have tags. */
+ if (!tdep->has_capability ())
+ return false;
+
+ /* The last two registers of the C register set don't have tags. */
+ if (regnum < tdep->cap_reg_base ||
+ regnum > tdep->cap_reg_last - 2)
+ return false;
+
+ if (aarch64_debug)
+ debug_printf ("%s: regnum %d\n", __func__, regnum);
+
+ return true;
+}
+
+/* Implements the gdbarch_register_tag hook. */
+
+static bool
+aarch64_register_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int regnum)
+{
+ if (aarch64_debug)
+ debug_printf ("%s: Entering\n", __func__);
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Only Morello's registers have tags. */
+ if (!tdep->has_capability ())
+ return false;
+
+ /* The last two registers of the C register set don't have tags. */
+ if (regnum < tdep->cap_reg_base ||
+ regnum > tdep->cap_reg_last - 2)
+ return false;
+
+ /* Find the proper bit within the tag_map. */
+ int shift = regnum - tdep->cap_reg_base;
+ ULONGEST tag_map = 0;
+
+ /* Fetch the tag_map register. */
+ regcache->cooked_read (tdep->cap_reg_last - 1, &tag_map);
+
+ if (aarch64_debug)
+ debug_printf ("%s: regnum %d, shift %d, tag bit %ld, tag_map %lx\n",
+ __func__, regnum, shift,
+ (tag_map >> shift) & 1, tag_map);
+
+ if (((tag_map >> shift) & 1) == 0)
+ return false;
+
+ return true;
+}
+
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
set_gdbarch_record_special_symbol (gdbarch,
aarch64_record_special_symbol);
+ /* For fetching register tag information. */
+ set_gdbarch_register_has_tag (gdbarch, aarch64_register_has_tag);
+ set_gdbarch_register_tag (gdbarch, aarch64_register_tag);
+
/* Create the Morello register aliases. */
/* cip0 and cip1 */
aarch64_morello_register_aliases[0].regnum = tdep->cap_reg_base + 16;
{
}
+/* See arch-utils.h. */
+bool
+default_register_has_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int cookednum)
+{
+ return false;
+}
+
+/* See arch-utils.h. */
+bool
+default_register_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int cookednum)
+{
+ return false;
+}
+
void _initialize_gdbarch_utils ();
void
_initialize_gdbarch_utils ()
const char *filename,
const void *other)>
loop_cb);
+
+/* Default implementation of gdbarch_register_has_tag. */
+extern bool default_register_has_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int cookednum);
+
+/* Default implementation of gdbarch_register_tag. */
+extern bool default_register_tag (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int cookednum);
#endif /* ARCH_UTILS_H */
gdbarch_type_align_ftype *type_align;
gdbarch_get_pc_address_flags_ftype *get_pc_address_flags;
gdbarch_read_core_file_mappings_ftype *read_core_file_mappings;
+ gdbarch_register_has_tag_ftype *register_has_tag;
+ gdbarch_register_tag_ftype *register_tag;
};
/* Create a new ``struct gdbarch'' based on information provided by
gdbarch->type_align = default_type_align;
gdbarch->get_pc_address_flags = default_get_pc_address_flags;
gdbarch->read_core_file_mappings = default_read_core_file_mappings;
+ gdbarch->register_has_tag = default_register_has_tag;
+ gdbarch->register_tag = default_register_tag;
/* gdbarch_alloc() */
return gdbarch;
/* Skip verify of type_align, invalid_p == 0 */
/* Skip verify of get_pc_address_flags, invalid_p == 0 */
/* Skip verify of read_core_file_mappings, invalid_p == 0 */
+ /* Skip verify of register_has_tag, invalid_p == 0 */
+ /* Skip verify of register_tag, invalid_p == 0 */
if (!log.empty ())
internal_error (__FILE__, __LINE__,
_("verify_gdbarch: the following are invalid ...%s"),
fprintf_unfiltered (file,
"gdbarch_dump: record_special_symbol = <%s>\n",
host_address_to_string (gdbarch->record_special_symbol));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: register_has_tag = <%s>\n",
+ host_address_to_string (gdbarch->register_has_tag));
fprintf_unfiltered (file,
"gdbarch_dump: register_name = <%s>\n",
host_address_to_string (gdbarch->register_name));
fprintf_unfiltered (file,
"gdbarch_dump: register_sim_regno = <%s>\n",
host_address_to_string (gdbarch->register_sim_regno));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: register_tag = <%s>\n",
+ host_address_to_string (gdbarch->register_tag));
fprintf_unfiltered (file,
"gdbarch_dump: register_to_value = <%s>\n",
host_address_to_string (gdbarch->register_to_value));
gdbarch->read_core_file_mappings = read_core_file_mappings;
}
+bool
+gdbarch_register_has_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_has_tag != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_has_tag called\n");
+ return gdbarch->register_has_tag (gdbarch, regcache, cookednum);
+}
+
+void
+set_gdbarch_register_has_tag (struct gdbarch *gdbarch,
+ gdbarch_register_has_tag_ftype register_has_tag)
+{
+ gdbarch->register_has_tag = register_has_tag;
+}
+
+bool
+gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_tag != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_tag called\n");
+ return gdbarch->register_tag (gdbarch, regcache, cookednum);
+}
+
+void
+set_gdbarch_register_tag (struct gdbarch *gdbarch,
+ gdbarch_register_tag_ftype register_tag)
+{
+ gdbarch->register_tag = register_tag;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd,gdb::function_view<void (ULONGEST count)> pre_loop_cb,gdb::function_view<void (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs, const char *filename, const void *other)> loop_cb);
extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
+/* Returns true if register COOKEDNUM has a tag and false otherwise.
+ The default is to always return false. */
+
+typedef bool (gdbarch_register_has_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_has_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_has_tag (struct gdbarch *gdbarch, gdbarch_register_has_tag_ftype *register_has_tag);
+
+/* Returns true if the register tag bit is 1 and false otherwise.
+ The default is to always return false. */
+
+typedef bool (gdbarch_register_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_tag (struct gdbarch *gdbarch, gdbarch_register_tag_ftype *register_tag);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
# Read core file mappings
m;void;read_core_file_mappings;struct bfd *cbfd,gdb::function_view<void (ULONGEST count)> pre_loop_cb,gdb::function_view<void (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs, const char *filename, const void *other)> loop_cb;cbfd, pre_loop_cb, loop_cb;;default_read_core_file_mappings;;0
+# Returns true if register COOKEDNUM has a tag and false otherwise.
+# The default is to always return false.
+m;bool;register_has_tag;readable_regcache *regcache, int cookednum;regcache, cookednum;;default_register_has_tag;;0
+# Returns true if the register tag bit is 1 and false otherwise.
+# The default is to always return false.
+m;bool;register_tag;readable_regcache *regcache, int cookednum;regcache, cookednum;;default_register_tag;;0
+
EOF
}
mark_value_bytes_unavailable (result, 0,
TYPE_LENGTH (value_type (result)));
+ if (gdbarch_register_has_tag (m_descr->gdbarch, this, regnum))
+ {
+ set_value_tagged (result, 1);
+
+ bool tag = gdbarch_register_tag (m_descr->gdbarch, this, regnum);
+ set_value_tag (result, tag);
+ }
+
return result;
}
else
const struct value_print_options *options)
{
struct type *type = check_typedef (value_type (val));
- int length = TYPE_LENGTH (type);
+ /* Account for the tag bit in the length. */
+ int length = TYPE_LENGTH (type) + 1;
const gdb_byte *contents = value_contents_for_printing (val);
enum bfd_endian byte_order = type_byte_order (type);
+ bool tag = false;
+
+ switch (VALUE_LVAL (val))
+ {
+ case lval_register:
+ if (value_tagged (val))
+ tag = value_tag (val);
+ break;
+ case lval_memory:
+ /* TODO-Morello: Add hook that reads capabilities from memory. We
+ should use those here to fetch the tag from a memory location. */
+ tag = true;
+ break;
+ default:
+ break;
+ }
if (options->format && options->format == 'x')
- print_hex_chars (stream, contents, length, byte_order, 0);
+ print_hex_chars (stream, contents, length, byte_order, 0);
else
{
uint128_t dummy_cap;
memcpy (&dummy_cap, contents, length);
- capability cap (dummy_cap, false);
+ capability cap (dummy_cap, tag);
fprintf_filtered (stream, "%s", cap.to_str ().c_str ());
}
lazy (1),
initialized (1),
stack (0),
+ tagged (0),
type (type_),
enclosing_type (type_)
{
used instead of read_memory to enable extra caching. */
unsigned int stack : 1;
+ /* Whether the value has a tag bit. */
+ unsigned int tagged : 1;
+
/* Location of value (if lval). */
union
{
LONGEST embedded_offset = 0;
LONGEST pointed_to_offset = 0;
+ /* The tag value, if tagged. */
+ bool tag;
+
/* Actual contents of the value. Target byte-order. NULL or not
valid if lazy is nonzero. */
gdb::unique_xmalloc_ptr<gdb_byte> contents;
value_contents_all_raw (src) + src_offset * unit_size,
length * unit_size);
+ /* Copy the tagged and tag metadata. */
+ set_value_tagged (dst, value_tagged (src));
+ set_value_tag (dst, value_tag (src));
+
/* Copy the meta-data, adjusted. */
src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
dst_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
value->stack = val;
}
+int
+value_tagged (const struct value *value)
+{
+ return value->tagged;
+}
+
+void
+set_value_tagged (struct value *value, int val)
+{
+ value->tagged = val;
+}
+
const gdb_byte *
value_contents (struct value *value)
{
value->pointed_to_offset = val;
}
+bool
+value_tag (const struct value *value)
+{
+ return value->tag;
+}
+
+void
+set_value_tag (struct value *value, bool tag)
+{
+ value->tag = tag;
+}
+
const struct lval_funcs *
value_computed_funcs (const struct value *v)
{
val->embedded_offset = value_embedded_offset (arg);
val->pointed_to_offset = arg->pointed_to_offset;
val->modifiable = arg->modifiable;
+ val->tagged = arg->tagged;
+ val->tag = arg->tag;
if (!value_lazy (val))
{
memcpy (value_contents_all_raw (val), value_contents_all_raw (arg),
extern LONGEST value_embedded_offset (const struct value *value);
extern void set_value_embedded_offset (struct value *value, LONGEST val);
+extern bool value_tag (const struct value *value);
+extern void set_value_tag (struct value *value, bool tag);
+
/* For lval_computed values, this structure holds functions used to
retrieve and set the value (or portions of the value).
extern int value_stack (const struct value *);
extern void set_value_stack (struct value *value, int val);
+extern int value_tagged (const struct value *);
+extern void set_value_tagged (struct value *value, int val);
+
/* Throw an error complaining that the value has been optimized
out. */