From c193949e75809a656b99c8408e5b29504aec436a Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Fri, 19 Jun 2020 17:36:14 -0300 Subject: [PATCH] New gdbarch memory tagging hooks We need some new gdbarch hooks to help us manipulate memory tags without having to have GDB call the target methods directly. This patch adds the following hooks: gdbarch_memtag_to_string -- Returns a printable string corresponding to the tag. gdbarch_tagged_address_p -- Checks if a particular address is protected with memory tagging. gdbarch_memtag_matches_p -- Checks if the logical tag of a pointer and the allocation tag from the address the pointer points to matches. gdbarch_set_memtags: -- Sets either the allocation tag or the logical tag for a particular value. gdbarch_get_memtag: -- Gets either the allocation tag or the logical tag for a particular value. gdbarch_memtag_granule_size -- Sets the memory tag granule size, which represents the number of bytes a particular allocation tag covers. For example, this is 16 bytes for AArch64's MTE. I've used struct value as opposed to straight CORE_ADDR so other architectures can use the infrastructure without having to rely on a particular type for addresses/pointers. Some architecture may use pointers of 16 bytes that don't fit in a CORE_ADDR, for example. gdb/ChangeLog: 2021-03-24 Luis Machado * arch-utils.c (default_memtag_to_string, default_tagged_address_p) (default_memtag_matches_p, default_set_memtags) (default_get_memtag): New functions. * arch-utils.h (default_memtag_to_string, default_tagged_address_p) (default_memtag_matches_p, default_set_memtags) (default_get_memtag): New prototypes. * gdbarch.c: Regenerate. * gdbarch.h: Regenerate. * gdbarch.sh (memtag_to_string, tagged_address_p, memtag_matches_p) (set_memtags, get_memtag, memtag_granule_size): New gdbarch hooks. (enum memtag_type): New enum. --- gdb/ChangeLog | 14 +++++ gdb/arch-utils.c | 49 +++++++++++++++++ gdb/arch-utils.h | 22 ++++++++ gdb/gdbarch.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++- gdb/gdbarch.h | 54 ++++++++++++++++++ gdb/gdbarch.sh | 37 +++++++++++++ 6 files changed, 314 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9975cd6b308..37dc83da67f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2021-03-24 Luis Machado + + * arch-utils.c (default_memtag_to_string, default_tagged_address_p) + (default_memtag_matches_p, default_set_memtags) + (default_get_memtag): New functions. + * arch-utils.h (default_memtag_to_string, default_tagged_address_p) + (default_memtag_matches_p, default_set_memtags) + (default_get_memtag): New prototypes. + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * gdbarch.sh (memtag_to_string, tagged_address_p, memtag_matches_p) + (set_memtags, get_memtag, memtag_granule_size): New gdbarch hooks. + (enum memtag_type): New enum. + 2021-03-24 Luis Machado * remote.c (remote_target) : New method diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index b5547424e48..0017e706ef1 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -77,6 +77,55 @@ legacy_register_sim_regno (struct gdbarch *gdbarch, int regnum) return LEGACY_SIM_REGNO_IGNORE; } + +/* See arch-utils.h */ + +std::string +default_memtag_to_string (struct gdbarch *gdbarch, struct value *tag) +{ + error (_("This architecture has no method to convert a memory tag to" + " a string.")); +} + +/* See arch-utils.h */ + +bool +default_tagged_address_p (struct gdbarch *gdbarch, struct value *address) +{ + /* By default, assume the address is untagged. */ + return false; +} + +/* See arch-utils.h */ + +bool +default_memtag_matches_p (struct gdbarch *gdbarch, struct value *address) +{ + /* By default, assume the tags match. */ + return true; +} + +/* See arch-utils.h */ + +bool +default_set_memtags (struct gdbarch *gdbarch, struct value *address, + size_t length, const gdb::byte_vector &tags, + memtag_type tag_type) +{ + /* By default, return true (successful); */ + return true; +} + +/* See arch-utils.h */ + +struct value * +default_get_memtag (struct gdbarch *gdbarch, struct value *address, + memtag_type tag_type) +{ + /* By default, return no tag. */ + return nullptr; +} + CORE_ADDR generic_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index a7e53ea5ae8..a5b40ad8ff1 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -132,6 +132,28 @@ extern const struct floatformat ** default_floatformat_for_type (struct gdbarch *gdbarch, const char *name, int len); +/* Default implementation of gdbarch_memtag_to_string. */ +extern std::string default_memtag_to_string (struct gdbarch *gdbarch, + struct value *tag); + +/* Default implementation of gdbarch_tagged_address_p. */ +bool default_tagged_address_p (struct gdbarch *gdbarch, struct value *address); + +/* Default implementation of gdbarch_memtag_matches_p. */ +extern bool default_memtag_matches_p (struct gdbarch *gdbarch, + struct value *address); + +/* Default implementation of gdbarch_set_memtags. */ +bool default_set_memtags (struct gdbarch *gdbarch, + struct value *address, size_t length, + const gdb::byte_vector &tags, + memtag_type tag_type); + +/* Default implementation of gdbarch_get_memtag. */ +struct value *default_get_memtag (struct gdbarch *gdbarch, + struct value *address, + memtag_type tag_type); + extern CORE_ADDR generic_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc); diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 8fa3cbaea3d..23509ba0a98 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -253,6 +253,12 @@ struct gdbarch gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr; gdbarch_addr_bits_remove_ftype *addr_bits_remove; int significant_addr_bit; + gdbarch_memtag_to_string_ftype *memtag_to_string; + gdbarch_tagged_address_p_ftype *tagged_address_p; + gdbarch_memtag_matches_p_ftype *memtag_matches_p; + gdbarch_set_memtags_ftype *set_memtags; + gdbarch_get_memtag_ftype *get_memtag; + CORE_ADDR memtag_granule_size; gdbarch_software_single_step_ftype *software_single_step; gdbarch_single_step_through_delay_ftype *single_step_through_delay; gdbarch_print_insn_ftype *print_insn; @@ -433,6 +439,11 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr; gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity; gdbarch->addr_bits_remove = core_addr_identity; + gdbarch->memtag_to_string = default_memtag_to_string; + gdbarch->tagged_address_p = default_tagged_address_p; + gdbarch->memtag_matches_p = default_memtag_matches_p; + gdbarch->set_memtags = default_set_memtags; + gdbarch->get_memtag = default_get_memtag; gdbarch->print_insn = default_print_insn; gdbarch->skip_trampoline_code = generic_skip_trampoline_code; gdbarch->skip_solib_resolver = generic_skip_solib_resolver; @@ -626,6 +637,12 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */ /* Skip verify of addr_bits_remove, invalid_p == 0 */ /* Skip verify of significant_addr_bit, invalid_p == 0 */ + /* Skip verify of memtag_to_string, invalid_p == 0 */ + /* Skip verify of tagged_address_p, invalid_p == 0 */ + /* Skip verify of memtag_matches_p, invalid_p == 0 */ + /* Skip verify of set_memtags, invalid_p == 0 */ + /* Skip verify of get_memtag, invalid_p == 0 */ + /* Skip verify of memtag_granule_size, invalid_p == 0 */ /* Skip verify of software_single_step, has predicate. */ /* Skip verify of single_step_through_delay, has predicate. */ /* Skip verify of print_insn, invalid_p == 0 */ @@ -1088,6 +1105,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: get_longjmp_target = <%s>\n", host_address_to_string (gdbarch->get_longjmp_target)); + fprintf_unfiltered (file, + "gdbarch_dump: get_memtag = <%s>\n", + host_address_to_string (gdbarch->get_memtag)); fprintf_unfiltered (file, "gdbarch_dump: get_pc_address_flags = <%s>\n", host_address_to_string (gdbarch->get_pc_address_flags)); @@ -1217,6 +1237,15 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: memory_remove_breakpoint = <%s>\n", host_address_to_string (gdbarch->memory_remove_breakpoint)); + fprintf_unfiltered (file, + "gdbarch_dump: memtag_granule_size = %s\n", + core_addr_to_string_nz (gdbarch->memtag_granule_size)); + fprintf_unfiltered (file, + "gdbarch_dump: memtag_matches_p = <%s>\n", + host_address_to_string (gdbarch->memtag_matches_p)); + fprintf_unfiltered (file, + "gdbarch_dump: memtag_to_string = <%s>\n", + host_address_to_string (gdbarch->memtag_to_string)); fprintf_unfiltered (file, "gdbarch_dump: num_pseudo_regs = %s\n", plongest (gdbarch->num_pseudo_regs)); @@ -1370,6 +1399,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: sdb_reg_to_regnum = <%s>\n", host_address_to_string (gdbarch->sdb_reg_to_regnum)); + fprintf_unfiltered (file, + "gdbarch_dump: set_memtags = <%s>\n", + host_address_to_string (gdbarch->set_memtags)); fprintf_unfiltered (file, "gdbarch_dump: short_bit = %s\n", plongest (gdbarch->short_bit)); @@ -1478,6 +1510,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: syscalls_info = %s\n", host_address_to_string (gdbarch->syscalls_info)); + fprintf_unfiltered (file, + "gdbarch_dump: tagged_address_p = <%s>\n", + host_address_to_string (gdbarch->tagged_address_p)); fprintf_unfiltered (file, "gdbarch_dump: target_desc = %s\n", host_address_to_string (gdbarch->target_desc)); @@ -3283,6 +3318,108 @@ set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch, gdbarch->significant_addr_bit = significant_addr_bit; } +std::string +gdbarch_memtag_to_string (struct gdbarch *gdbarch, struct value *tag) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->memtag_to_string != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_to_string called\n"); + return gdbarch->memtag_to_string (gdbarch, tag); +} + +void +set_gdbarch_memtag_to_string (struct gdbarch *gdbarch, + gdbarch_memtag_to_string_ftype memtag_to_string) +{ + gdbarch->memtag_to_string = memtag_to_string; +} + +bool +gdbarch_tagged_address_p (struct gdbarch *gdbarch, struct value *address) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->tagged_address_p != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_tagged_address_p called\n"); + return gdbarch->tagged_address_p (gdbarch, address); +} + +void +set_gdbarch_tagged_address_p (struct gdbarch *gdbarch, + gdbarch_tagged_address_p_ftype tagged_address_p) +{ + gdbarch->tagged_address_p = tagged_address_p; +} + +bool +gdbarch_memtag_matches_p (struct gdbarch *gdbarch, struct value *address) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->memtag_matches_p != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_matches_p called\n"); + return gdbarch->memtag_matches_p (gdbarch, address); +} + +void +set_gdbarch_memtag_matches_p (struct gdbarch *gdbarch, + gdbarch_memtag_matches_p_ftype memtag_matches_p) +{ + gdbarch->memtag_matches_p = memtag_matches_p; +} + +bool +gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, memtag_type tag_type) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->set_memtags != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_set_memtags called\n"); + return gdbarch->set_memtags (gdbarch, address, length, tags, tag_type); +} + +void +set_gdbarch_set_memtags (struct gdbarch *gdbarch, + gdbarch_set_memtags_ftype set_memtags) +{ + gdbarch->set_memtags = set_memtags; +} + +struct value * +gdbarch_get_memtag (struct gdbarch *gdbarch, struct value *address, memtag_type tag_type) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_memtag != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_memtag called\n"); + return gdbarch->get_memtag (gdbarch, address, tag_type); +} + +void +set_gdbarch_get_memtag (struct gdbarch *gdbarch, + gdbarch_get_memtag_ftype get_memtag) +{ + gdbarch->get_memtag = get_memtag; +} + +CORE_ADDR +gdbarch_memtag_granule_size (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + /* Skip verify of memtag_granule_size, invalid_p == 0 */ + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_granule_size called\n"); + return gdbarch->memtag_granule_size; +} + +void +set_gdbarch_memtag_granule_size (struct gdbarch *gdbarch, + CORE_ADDR memtag_granule_size) +{ + gdbarch->memtag_granule_size = memtag_granule_size; +} + bool gdbarch_software_single_step_p (struct gdbarch *gdbarch) { @@ -5314,7 +5451,7 @@ struct gdbarch_data_registry struct gdbarch_data_registration *registrations; }; -static struct gdbarch_data_registry gdbarch_data_registry = +struct gdbarch_data_registry gdbarch_data_registry = { 0, NULL, }; diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 342c29c5980..7157e5596fd 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -117,6 +117,18 @@ enum function_call_return_method return_method_struct, }; +enum class memtag_type +{ + /* Logical tag, the tag that is stored in unused bits of a pointer to a + virtual address. */ + logical = 0, + + /* Allocation tag, the tag that is associated with every granule of memory in + the physical address space. Allocation tags are used to validate memory + accesses via pointers containing logical tags. */ + allocation, +}; + /* The following are pre-initialized by GDBARCH. */ @@ -712,6 +724,48 @@ extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_ extern int gdbarch_significant_addr_bit (struct gdbarch *gdbarch); extern void set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch, int significant_addr_bit); +/* Return a string representation of the memory tag TAG. */ + +typedef std::string (gdbarch_memtag_to_string_ftype) (struct gdbarch *gdbarch, struct value *tag); +extern std::string gdbarch_memtag_to_string (struct gdbarch *gdbarch, struct value *tag); +extern void set_gdbarch_memtag_to_string (struct gdbarch *gdbarch, gdbarch_memtag_to_string_ftype *memtag_to_string); + +/* Return true if ADDRESS contains a tag and false otherwise. */ + +typedef bool (gdbarch_tagged_address_p_ftype) (struct gdbarch *gdbarch, struct value *address); +extern bool gdbarch_tagged_address_p (struct gdbarch *gdbarch, struct value *address); +extern void set_gdbarch_tagged_address_p (struct gdbarch *gdbarch, gdbarch_tagged_address_p_ftype *tagged_address_p); + +/* Return true if the tag from ADDRESS matches the memory tag for that + particular address. Return false otherwise. */ + +typedef bool (gdbarch_memtag_matches_p_ftype) (struct gdbarch *gdbarch, struct value *address); +extern bool gdbarch_memtag_matches_p (struct gdbarch *gdbarch, struct value *address); +extern void set_gdbarch_memtag_matches_p (struct gdbarch *gdbarch, gdbarch_memtag_matches_p_ftype *memtag_matches_p); + +/* Set the tags of type TAG_TYPE, for the memory address range + [ADDRESS, ADDRESS + LENGTH) to TAGS. + Return true if successful and false otherwise. */ + +typedef bool (gdbarch_set_memtags_ftype) (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, memtag_type tag_type); +extern bool gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, memtag_type tag_type); +extern void set_gdbarch_set_memtags (struct gdbarch *gdbarch, gdbarch_set_memtags_ftype *set_memtags); + +/* Return the tag of type TAG_TYPE associated with the memory address ADDRESS, + assuming ADDRESS is tagged. */ + +typedef struct value * (gdbarch_get_memtag_ftype) (struct gdbarch *gdbarch, struct value *address, memtag_type tag_type); +extern struct value * gdbarch_get_memtag (struct gdbarch *gdbarch, struct value *address, memtag_type tag_type); +extern void set_gdbarch_get_memtag (struct gdbarch *gdbarch, gdbarch_get_memtag_ftype *get_memtag); + +/* memtag_granule_size is the size of the allocation tag granule, for + architectures that support memory tagging. + This is 0 for architectures that do not support memory tagging. + For a non-zero value, this represents the number of bytes of memory per tag. */ + +extern CORE_ADDR gdbarch_memtag_granule_size (struct gdbarch *gdbarch); +extern void set_gdbarch_memtag_granule_size (struct gdbarch *gdbarch, CORE_ADDR memtag_granule_size); + /* FIXME/cagney/2001-01-18: This should be split in two. A target method that indicates if the target needs software single step. An ISA method to implement it. diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 84b645e9915..6c361307428 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -605,6 +605,31 @@ m;CORE_ADDR;addr_bits_remove;CORE_ADDR addr;addr;;core_addr_identity;;0 # additional data associated with the address. v;int;significant_addr_bit;;;;;;0 +# Return a string representation of the memory tag TAG. +m;std::string;memtag_to_string;struct value *tag;tag;;default_memtag_to_string;;0 + +# Return true if ADDRESS contains a tag and false otherwise. +m;bool;tagged_address_p;struct value *address;address;;default_tagged_address_p;;0 + +# Return true if the tag from ADDRESS matches the memory tag for that +# particular address. Return false otherwise. +m;bool;memtag_matches_p;struct value *address;address;;default_memtag_matches_p;;0 + +# Set the tags of type TAG_TYPE, for the memory address range +# [ADDRESS, ADDRESS + LENGTH) to TAGS. +# Return true if successful and false otherwise. +m;bool;set_memtags;struct value *address, size_t length, const gdb::byte_vector \&tags, memtag_type tag_type;address, length, tags, tag_type;;default_set_memtags;;0 + +# Return the tag of type TAG_TYPE associated with the memory address ADDRESS, +# assuming ADDRESS is tagged. +m;struct value *;get_memtag;struct value *address, memtag_type tag_type;address, tag_type;;default_get_memtag;;0 + +# memtag_granule_size is the size of the allocation tag granule, for +# architectures that support memory tagging. +# This is 0 for architectures that do not support memory tagging. +# For a non-zero value, this represents the number of bytes of memory per tag. +v;CORE_ADDR;memtag_granule_size;;;;;;0 + # FIXME/cagney/2001-01-18: This should be split in two. A target method that # indicates if the target needs software single step. An ISA method to # implement it. @@ -1362,6 +1387,18 @@ enum function_call_return_method return_method_struct, }; +enum class memtag_type +{ + /* Logical tag, the tag that is stored in unused bits of a pointer to a + virtual address. */ + logical = 0, + + /* Allocation tag, the tag that is associated with every granule of memory in + the physical address space. Allocation tags are used to validate memory + accesses via pointers containing logical tags. */ + allocation, +}; + EOF # function typedef's -- 2.30.2