diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 189884bcb0..5d7069a722 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2021-03-24 Luis Machado + + * printcmd.c (decode_format): Handle the 'm' modifier. + (do_examine): Display allocation tags when required/supported. + (should_validate_memtags): New function. + (print_command_1): Display memory tag mismatches. + * valprint.c (show_memory_tag_violations): New function. + (value_print_option_defs): Add new option "memory-tag-violations". + (user_print_options) : Initialize to 1. + * valprint.h (struct format_data) : New field. + (value_print_options) : New field. + 2021-03-24 Luis Machado * printcmd.c: Include gdbsupport/rsp-low.h. diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 9200e66db3..c82f709136 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -72,6 +72,10 @@ static char last_size = 'w'; static int last_count; +/* Last specified tag-printing option. */ + +static bool last_print_tags = false; + /* Default address to examine next, and associated architecture. */ static struct gdbarch *next_gdbarch; @@ -193,6 +197,7 @@ decode_format (const char **string_ptr, int oformat, int osize) val.size = '?'; val.count = 1; val.raw = 0; + val.print_tags = false; if (*p == '-') { @@ -215,6 +220,11 @@ decode_format (const char **string_ptr, int oformat, int osize) val.raw = 1; p++; } + else if (*p == 'm') + { + val.print_tags = true; + p++; + } else if (*p >= 'a' && *p <= 'z') val.format = *p++; else @@ -1100,12 +1110,50 @@ do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr) need_to_update_next_address = 1; } + /* Whether we need to print the memory tag information for the current + address range. */ + bool print_range_tag = true; + uint32_t gsize = gdbarch_memtag_granule_size (gdbarch); + /* Print as many objects as specified in COUNT, at most maxelts per line, with the address of the next one at the start of each line. */ while (count > 0) { QUIT; + + CORE_ADDR tag_laddr = 0, tag_haddr = 0; + + /* Print the memory tag information if requested. */ + if (fmt.print_tags && print_range_tag + && target_supports_memory_tagging ()) + { + tag_laddr = align_down (next_address, gsize); + tag_haddr = align_down (next_address + gsize, gsize); + + struct value *v_addr + = value_from_ulongest (builtin_type (gdbarch)->builtin_data_ptr, + tag_laddr); + + if (gdbarch_tagged_address_p (target_gdbarch (), v_addr)) + { + /* Fetch the allocation tag. */ + struct value *tag + = gdbarch_get_memtag (gdbarch, v_addr, memtag_type::allocation); + std::string atag + = gdbarch_memtag_to_string (gdbarch, tag); + + if (!atag.empty ()) + { + printf_filtered (_("\n"), + atag.c_str (), + paddress (gdbarch, tag_laddr), + paddress (gdbarch, tag_haddr)); + } + } + print_range_tag = false; + } + if (format == 'i') fputs_filtered (pc_prefix (next_address), gdb_stdout); print_address (next_gdbarch, next_address, gdb_stdout); @@ -1136,6 +1184,11 @@ do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr) /* Display any branch delay slots following the final insn. */ if (format == 'i' && count == 1) count += branch_delay_insns; + + /* Update the tag range based on the current address being + processed. */ + if (tag_haddr <= next_address) + print_range_tag = true; } printf_filtered ("\n"); } @@ -1208,6 +1261,26 @@ print_value (value *val, const value_print_options &opts) annotate_value_history_end (); } +/* Returns true if memory tags should be validated. False otherwise. */ + +static bool +should_validate_memtags (struct value *value) +{ + if (target_supports_memory_tagging () + && gdbarch_tagged_address_p (target_gdbarch (), value)) + { + gdb_assert (value != nullptr && value_type (value) != nullptr); + + enum type_code code = value_type (value)->code (); + + return (code == TYPE_CODE_PTR + || code == TYPE_CODE_REF + || code == TYPE_CODE_METHODPTR + || code == TYPE_CODE_MEMBERPTR); + } + return false; +} + /* Helper for parsing arguments for print_command_1. */ static struct value * @@ -1246,7 +1319,30 @@ print_command_1 (const char *args, int voidprint) if (voidprint || (val && value_type (val) && value_type (val)->code () != TYPE_CODE_VOID)) - print_value (val, print_opts); + { + /* If memory tagging validation is on, check if the tag is valid. */ + if (print_opts.memory_tag_violations && should_validate_memtags (val) + && !gdbarch_memtag_matches_p (target_gdbarch (), val)) + { + /* Fetch the logical tag. */ + struct value *tag + = gdbarch_get_memtag (target_gdbarch (), val, + memtag_type::logical); + std::string ltag + = gdbarch_memtag_to_string (target_gdbarch (), tag); + + /* Fetch the allocation tag. */ + tag = gdbarch_get_memtag (target_gdbarch (), val, + memtag_type::allocation); + std::string atag + = gdbarch_memtag_to_string (target_gdbarch (), tag); + + printf_filtered (_("Logical tag (%s) does not match the " + "allocation tag (%s).\n"), + ltag.c_str (), atag.c_str ()); + } + print_value (val, print_opts); + } } /* Called from command completion function to skip over /FMT @@ -1741,6 +1837,7 @@ x_command (const char *exp, int from_tty) struct value *val; fmt.format = last_format ? last_format : 'x'; + fmt.print_tags = last_print_tags; fmt.size = last_size; fmt.count = 1; fmt.raw = 0; @@ -1797,6 +1894,9 @@ x_command (const char *exp, int from_tty) last_size = fmt.size; last_format = fmt.format; + /* Remember tag-printing setting. */ + last_print_tags = fmt.print_tags; + /* Set a couple of internal variables if appropriate. */ if (last_examine_value != nullptr) { diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 848e089db4..8513f32e19 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2021-03-24 Luis Machado + + * gdb.base/options.exp: Adjust for new print options. + * gdb.base/with.exp: Likewise. + 2021-03-22 Andrew Burgess * gdb.dwarf2/dw2-missing-cu-tag.c: New file. diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 44c773c3fa..78ec54502c 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -165,6 +165,7 @@ proc_with_prefix test-print {{prefix ""}} { "-array-indexes" "-elements" "-max-depth" + "-memory-tag-violations" "-null-stop" "-object" "-pretty" diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp index 0e83ad4898..0d53dbebba 100644 --- a/gdb/testsuite/gdb.base/with.exp +++ b/gdb/testsuite/gdb.base/with.exp @@ -238,7 +238,7 @@ with_test_prefix "errors" { gdb_test "with w" \ "Ambiguous set command \"w\": watchdog, width, write\\." gdb_test "with print m" \ - "Ambiguous set print command \"m\": max-depth, max-symbolic-offset\\." + "Ambiguous set print command \"m\": max-depth, max-symbolic-offset, memory-tag-violations\\." gdb_test "with variable xxx=1" \ "Cannot use this setting with the \"with\" command" diff --git a/gdb/valprint.c b/gdb/valprint.c index 340a329f9d..c089ee27a2 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -110,6 +110,7 @@ struct value_print_options user_print_options = 10, /* repeat_count_threshold */ 0, /* output_format */ 0, /* format */ + 1, /* memory_tag_violations */ 0, /* stop_print_at_null */ 0, /* print_array_indexes */ 0, /* deref_ref */ @@ -203,6 +204,17 @@ show_repeat_count_threshold (struct ui_file *file, int from_tty, value); } +/* If nonzero, prints memory tag violations for pointers. */ + +static void +show_memory_tag_violations (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, + _("Printing of memory tag violations is %s.\n"), + value); +} + /* If nonzero, stops printing of char arrays at first null. */ static void @@ -3023,6 +3035,17 @@ will be replaced with either '{...}' or '(...)' depending on the language.\n\ Use \"unlimited\" to print the complete structure.") }, + boolean_option_def { + "memory-tag-violations", + [] (value_print_options *opt) { return &opt->memory_tag_violations; }, + show_memory_tag_violations, /* show_cmd_cb */ + N_("Set printing of memory tag violations for pointers."), + N_("Show printing of memory tag violations for pointers."), + N_("Issue a warning when the printed value is a pointer\n\ +whose logical tag doesn't match the allocation tag of the memory\n\ +location it points to."), + }, + boolean_option_def { "null-stop", [] (value_print_options *opt) { return &opt->stop_print_at_null; }, diff --git a/gdb/valprint.h b/gdb/valprint.h index ca8ad6aa71..e1dae2cc8f 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -65,6 +65,9 @@ struct value_print_options e.g. when the user passes a format to "print". */ int format; + /* Print memory tag violations for pointers. */ + bool memory_tag_violations; + /* Stop printing at null character? */ bool stop_print_at_null; @@ -252,6 +255,7 @@ struct format_data int count; char format; char size; + bool print_tags; /* True if the value should be printed raw -- that is, bypassing python-based formatters. */