From: Luis Machado Date: Thu, 8 Oct 2020 09:14:37 +0000 (-0300) Subject: [General/Morello] Fetch and display register capability tags correctly X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=32487f77d3302aa782ba04b7291adc99b980abd8;p=thirdparty%2Fbinutils-gdb.git [General/Morello] Fetch and display register capability tags correctly This patch teaches GDB how to print the capability tag from registers. gdb/ChangeLog: 2020-10-20 Luis Machado * 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) : 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c480bc8077c..a85c361f820 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,26 @@ +2020-10-20 Luis Machado + + * 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) : 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 * aarch64-tdep.c: Include elf-bfd.h. diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 1cf1e9ccf23..72adec05884 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -3748,6 +3748,72 @@ aarch64_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, 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. @@ -4055,6 +4121,10 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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; diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 12e3b8dbbb9..c68add668db 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1052,6 +1052,24 @@ default_read_core_file_mappings (struct gdbarch *gdbarch, { } +/* 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 () diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index 8cb0db04c8c..b23dc17cb33 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -292,4 +292,14 @@ extern void default_read_core_file_mappings (struct gdbarch *gdbarch, 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 */ diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 8bab2d9de9e..875b31cb3b3 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -355,6 +355,8 @@ struct gdbarch 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 @@ -474,6 +476,8 @@ gdbarch_alloc (const struct gdbarch_info *info, 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; @@ -733,6 +737,8 @@ verify_gdbarch (struct gdbarch *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"), @@ -1329,6 +1335,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) 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)); @@ -1338,6 +1347,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) 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)); @@ -5300,6 +5312,40 @@ set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, 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. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index fd9692d1684..bcce5060ad0 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1664,6 +1664,20 @@ typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, s extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd,gdb::function_view pre_loop_cb,gdb::function_view 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); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 08ad20f2649..d0b58eca60e 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -1196,6 +1196,13 @@ f;std::string;get_pc_address_flags;frame_info *frame, CORE_ADDR pc;frame, pc;;de # Read core file mappings m;void;read_core_file_mappings;struct bfd *cbfd,gdb::function_view pre_loop_cb,gdb::function_view 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 } diff --git a/gdb/regcache.c b/gdb/regcache.c index 91d3202b94b..778b8f61dad 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -749,6 +749,14 @@ readable_regcache::cooked_read_value (int regnum) 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 diff --git a/gdb/valprint.c b/gdb/valprint.c index 6e1672a3dca..048512d3108 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -485,17 +485,34 @@ generic_value_print_capability (struct value *val, struct ui_file *stream, 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 ()); } diff --git a/gdb/value.c b/gdb/value.c index ef2ebf09ef5..01f47af7466 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -178,6 +178,7 @@ struct value lazy (1), initialized (1), stack (0), + tagged (0), type (type_), enclosing_type (type_) { @@ -228,6 +229,9 @@ struct value 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 { @@ -336,6 +340,9 @@ struct value 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 contents; @@ -1331,6 +1338,10 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset, 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; @@ -1385,6 +1396,18 @@ set_value_stack (struct value *value, int val) 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) { @@ -1489,6 +1512,18 @@ set_value_pointed_to_offset (struct value *value, LONGEST val) 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) { @@ -1690,6 +1725,8 @@ value_copy (struct value *arg) 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), diff --git a/gdb/value.h b/gdb/value.h index f7d57d12542..90a361c0168 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -240,6 +240,9 @@ extern void set_value_pointed_to_offset (struct value *value, LONGEST val); 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). @@ -334,6 +337,9 @@ extern void set_value_lazy (struct value *value, int val); 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. */