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;
val.size = '?';
val.count = 1;
val.raw = 0;
+ val.print_tags = false;
if (*p == '-')
{
val.raw = 1;
p++;
}
+ else if (*p == 'm')
+ {
+ val.print_tags = true;
+ p++;
+ }
else if (*p >= 'a' && *p <= 'z')
val.format = *p++;
else
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 (_("<Allocation Tag %s for range [%s,%s)>\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);
/* 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");
}
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 *
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
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;
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)
{
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 */
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
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; },