From: Luis Machado Date: Fri, 19 Jun 2020 20:36:14 +0000 (-0300) Subject: New gdbarch memory tagging hooks X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=507666716ce9667fd69254f313ed8fe547d233c9;p=thirdparty%2Fbinutils-gdb.git New gdbarch memory tagging hooks We need some new gdbarch hooks to help us manipulate memory tags without having to have GDB calls 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_mismatch_p -- Checks if there is a mismatch between the logical tag of a pointer and the allocation tag. 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_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 fixed types. gdb/ChangeLog: YYYY-MM-DD Luis Machado * arch-utils.c (default_memtag_to_string, +default_tagged_address_p) (default_memtag_mismatch_p, default_set_memtags) (default_get_memtag): New functions. * arch-utils.h (default_memtag_to_string, default_tagged_address_p) (default_memtag_mismatch_p, default_set_memtags) (default_get_memtag): New prototypes. * gdbarch.c: Regenerate. * gdbarch.h: Regenerate. * gdbarch.sh (memtag_to_string, tagged_address_p, memtag_mismatch_p) (set_memtags, get_memtag, memtag_granule_size): New gdbarch hooks. (enum memtag_type): New enum. --- diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 13ba50abe61..88e228fed08 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -78,6 +78,56 @@ 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 *address, + enum memtag_type tag_type) +{ + /* By default, assume the address is untagged. */ + return ""; +} + +/* 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_mismatch_p (struct gdbarch *gdbarch, struct value *address) +{ + /* By default, assume there is no mismatch. */ + return false; +} + +/* See arch-utils.h */ + +int +default_set_memtags (struct gdbarch *gdbarch, struct value *address, + size_t length, const gdb::byte_vector &tags, + enum memtag_type tag_type) +{ + /* By default, return 0; */ + return 0; +} + +/* See arch-utils.h */ + +struct value * +default_get_memtag (struct gdbarch *gdbarch, struct value *address, + enum memtag_type tag_type) +{ + /* By default, return no tag. */ + return NULL; +} + 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 43d64b1f4f2..75ddf676b21 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -134,6 +134,29 @@ extern const struct floatformat ** default_floatformat_for_type (struct gdbarch *gdbarch, const char *name, int len); +/* Default implementation of gdbarch_tagged_address_p. */ +extern std::string default_memtag_to_string (struct gdbarch *gdbarch, + struct value *address, + enum memtag_type tag_type); + +/* Default implementation of gdbarch_tagged_address_p. */ +bool default_tagged_address_p (struct gdbarch *gdbarch, struct value *address); + +/* Default implementation of gdbarch_memtag_mismatch_p. */ +extern bool default_memtag_mismatch_p (struct gdbarch *gdbarch, + struct value *address); + +/* Default implementation of gdbarch_set_memtags. */ +int default_set_memtags (struct gdbarch *gdbarch, + struct value *address, size_t length, + const gdb::byte_vector &tags, + enum memtag_type tag_type); + +/* Default implementation of gdbarch_get_memtag. */ +struct value *default_get_memtag (struct gdbarch *gdbarch, + struct value *address, + enum 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 21ee840e88f..34f9e51aaec 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -251,6 +251,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_mismatch_p_ftype *memtag_mismatch_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; @@ -426,6 +432,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_mismatch_p = default_memtag_mismatch_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; @@ -615,6 +626,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_mismatch_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 */ @@ -1053,6 +1070,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)); @@ -1188,6 +1208,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_mismatch_p = <%s>\n", + host_address_to_string (gdbarch->memtag_mismatch_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)); @@ -1332,6 +1361,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)); @@ -1440,6 +1472,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)); @@ -3212,6 +3247,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 *address, enum memtag_type tag_type) +{ + 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, address, tag_type); +} + +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_mismatch_p (struct gdbarch *gdbarch, struct value *address) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->memtag_mismatch_p != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_mismatch_p called\n"); + return gdbarch->memtag_mismatch_p (gdbarch, address); +} + +void +set_gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, + gdbarch_memtag_mismatch_p_ftype memtag_mismatch_p) +{ + gdbarch->memtag_mismatch_p = memtag_mismatch_p; +} + +int +gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum 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, enum 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; +} + int gdbarch_software_single_step_p (struct gdbarch *gdbarch) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 0940156aeb8..8d6e8c9524f 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -115,6 +115,18 @@ enum function_call_return_method return_method_struct, }; +enum memtag_type +{ + /* Logical tag, the tag that is stored in unused bits of a pointer to a + virtual address. */ + tag_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. */ + tag_allocation, +}; + /* The following are pre-initialized by GDBARCH. */ @@ -705,6 +717,47 @@ 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 TYPE of ADDRESS. + If no tag is associated with such an address, return the empty string. */ + +typedef std::string (gdbarch_memtag_to_string_ftype) (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type); +extern std::string gdbarch_memtag_to_string (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type); +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 does not match the memory tag for that + particular address. Return false otherwise. */ + +typedef bool (gdbarch_memtag_mismatch_p_ftype) (struct gdbarch *gdbarch, struct value *address); +extern bool gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, struct value *address); +extern void set_gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, gdbarch_memtag_mismatch_p_ftype *memtag_mismatch_p); + +/* Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS + Return 0 if successful and non-zero otherwise. */ + +typedef int (gdbarch_set_memtags_ftype) (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type); +extern int gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type); +extern void set_gdbarch_set_memtags (struct gdbarch *gdbarch, gdbarch_set_memtags_ftype *set_memtags); + +/* Return the tag portion of ADDRESS, assuming ADDRESS is tagged. */ + +typedef struct value * (gdbarch_get_memtag_ftype) (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type); +extern struct value * gdbarch_get_memtag (struct gdbarch *gdbarch, struct value *address, enum 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 41e7b8d5cc3..1df82c45ec5 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -604,6 +604,30 @@ 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 TYPE of ADDRESS. +# If no tag is associated with such an address, return the empty string. ++m;std::string;memtag_to_string;struct value *address, enum memtag_type tag_type;address, tag_type;;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 does not match the memory tag for that +# particular address. Return false otherwise. ++m;bool;memtag_mismatch_p;struct value *address;address;;default_memtag_mismatch_p;;0 + +# Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS +# Return 0 if successful and non-zero otherwise. ++m;int;set_memtags;struct value *address, size_t length, const gdb::byte_vector \&tags, enum memtag_type tag_type;address, length, tags, tag_type;;default_set_memtags;;0 + +# Return the tag portion of ADDRESS, assuming ADDRESS is tagged. ++m;struct value *;get_memtag;struct value *address, enum 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. @@ -1351,6 +1375,18 @@ enum function_call_return_method return_method_struct, }; +enum memtag_type +{ + /* Logical tag, the tag that is stored in unused bits of a pointer to a + virtual address. */ + tag_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. */ + tag_allocation, +}; + EOF # function typedef's