aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/printcmd.c353
-rw-r--r--gdbsupport/rsp-low.cc2
2 files changed, 342 insertions, 13 deletions
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index a422e0c..c285bc9 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -53,6 +53,11 @@
#include "source.h"
#include "gdbsupport/byte-vector.h"
#include "gdbsupport/gdb_optional.h"
+#include "gdbsupport/rsp-low.h"
+
+/* Chain containing all defined mtag subcommands. */
+
+struct cmd_list_element *mtaglist;
/* Last specified output format. */
@@ -1209,31 +1214,38 @@ print_value (value *val, const value_print_options &opts)
annotate_value_history_end ();
}
-/* Implementation of the "print" and "call" commands. */
+/* Helper for parsing arguments for print_command_1. */
-static void
-print_command_1 (const char *args, int voidprint)
+static struct value *
+process_print_command_args (const char *args, value_print_options *print_opts)
{
- struct value *val;
- value_print_options print_opts;
-
- get_user_print_options (&print_opts);
+ get_user_print_options (print_opts);
/* Override global settings with explicit options, if any. */
- auto group = make_value_print_options_def_group (&print_opts);
+ auto group = make_value_print_options_def_group (print_opts);
gdb::option::process_options
(&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group);
- print_command_parse_format (&args, "print", &print_opts);
+ print_command_parse_format (&args, "print", print_opts);
const char *exp = args;
if (exp != nullptr && *exp)
{
expression_up expr = parse_expression (exp);
- val = evaluate_expression (expr.get ());
+ return evaluate_expression (expr.get ());
}
- else
- val = access_value_history (0);
+
+ return access_value_history (0);
+}
+
+/* Implementation of the "print" and "call" commands. */
+
+static void
+print_command_1 (const char *args, int voidprint)
+{
+ value_print_options print_opts;
+
+ struct value *val = process_print_command_args (args, &print_opts);
if (voidprint || (val && value_type (val) &&
value_type (val)->code () != TYPE_CODE_VOID))
@@ -2701,6 +2713,267 @@ eval_command (const char *arg, int from_tty)
execute_command (expanded.c_str (), from_tty);
}
+/* Convenience function for error checking in mtag commands. */
+
+static void
+show_addr_not_tagged (CORE_ADDR address)
+{
+ error (_("Address %s not in a region mapped with a memory tagging flag."),
+ paddress (target_gdbarch (), address));
+}
+
+/* Convenience function for error checking in mtag commands. */
+
+static void
+show_memtag_unsupported (void)
+{
+ error (_("Memory tagging not supported or disabled by the current"
+ " architecture."));
+}
+
+/* Implement the "mtag" prefix command. */
+
+static void
+mtag_command (const char *arg, int from_tty)
+{
+ help_list (mtaglist, "mtag ", all_commands, gdb_stdout);
+}
+
+/* Helper for showltag and showatag. */
+
+static void
+mtag_showtag_command (const char *args, enum memtag_type tag_type)
+{
+ if (args == nullptr)
+ error_no_arg (_("address or pointer"));
+
+ /* Parse args into a value. If the value is a pointer or an address,
+ then fetch the logical or allocation tag. */
+ value_print_options print_opts;
+
+ struct value *val = process_print_command_args (args, &print_opts);
+
+ /* If the address is not in a region memory mapped with a memory tagging
+ flag, it is no use trying to access/manipulate its allocation tag.
+
+ It is OK to manipulate the logical tag though. */
+ if (tag_type == tag_allocation
+ && !gdbarch_tagged_address_p (target_gdbarch (), val))
+ show_addr_not_tagged (value_as_address (val));
+
+ std::string tag = gdbarch_memtag_to_string (target_gdbarch (),
+ val, tag_type);
+ if (tag.empty ())
+ printf_filtered (_("%s tag unavailable.\n"),
+ tag_type == tag_logical? "Logical" : "Allocation");
+
+ struct value *v_tag = process_print_command_args (tag.c_str (),
+ &print_opts);
+ print_opts.output_format = 'x';
+ print_value (v_tag, print_opts);
+}
+
+/* Implement the "mtag showltag" command. */
+
+static void
+mtag_showltag_command (const char *args, int from_tty)
+{
+ if (!memtag || !target_supports_memory_tagging ())
+ show_memtag_unsupported ();
+
+ mtag_showtag_command (args, tag_logical);
+}
+
+/* Implement the "mtag showatag" command. */
+
+static void
+mtag_showatag_command (const char *args, int from_tty)
+{
+ if (!memtag || !target_supports_memory_tagging ())
+ show_memtag_unsupported ();
+
+ mtag_showtag_command (args, tag_allocation);
+}
+
+/* Parse ARGS and extract ADDR and TAG.
+ ARGS should have format <expression> <tag bytes>. */
+
+static void
+parse_setltag_input (const char *args, struct value **val,
+ gdb::byte_vector &tags, value_print_options *print_opts)
+{
+ /* Given <expression> can be reasonably complex, we parse things backwards
+ so we can isolate the <tag bytes> portion. */
+
+ /* Fetch the address. */
+ std::string s_address = extract_string_maybe_quoted (&args);
+
+ /* Parse the address into a value. */
+ *val = process_print_command_args (s_address.c_str (), print_opts);
+
+ /* Fetch the tag bytes. */
+ std::string s_tags = extract_string_maybe_quoted (&args);
+
+ /* Validate the input. */
+ if (s_address.empty () || s_tags.empty ())
+ error (_("Missing arguments."));
+
+ tags = hex2bin (s_tags.c_str ());
+}
+
+/* Implement the "mtag setltag" command. */
+
+static void
+mtag_setltag_command (const char *args, int from_tty)
+{
+ if (!memtag || !target_supports_memory_tagging ())
+ show_memtag_unsupported ();
+
+ if (args == nullptr)
+ error_no_arg (_("<address> <tag>"));
+
+ gdb::byte_vector tags;
+ struct value *val;
+ value_print_options print_opts;
+
+ /* Parse the input. */
+ parse_setltag_input (args, &val, tags, &print_opts);
+
+ /* Setting the logical tag is just a local operation that does not touch
+ any memory from the target. Given an input value, we modify the value
+ to include the appropriate tag.
+
+ For this reason we need to cast the argument value to a
+ (void *) pointer. This is so we have the right the for the gdbarch
+ hook to manipulate the value and insert the tag.
+
+ Otherwise, this would fail if, for example, GDB parsed the argument value
+ into an int-sized value and the pointer value has a type of greater
+ length. */
+
+ /* Cast to (void *). */
+ val = value_cast (builtin_type (target_gdbarch ())->builtin_data_ptr,
+ val);
+
+ if (gdbarch_set_memtags (target_gdbarch (), val, 0, tags,
+ tag_logical) != 0)
+ printf_filtered (_("Could not update the logical tag data.\n"));
+ else
+ {
+ /* Always print it in hex format. */
+ print_opts.output_format = 'x';
+ print_value (val, print_opts);
+ }
+}
+
+/* Parse ARGS and extract ADDR, LENGTH and TAGS. */
+
+static void
+parse_setatag_input (const char *args, struct value **val, size_t *length,
+ gdb::byte_vector &tags)
+{
+ /* Fetch the address. */
+ std::string s_address = extract_string_maybe_quoted (&args);
+
+ /* Parse the address into a value. */
+ value_print_options print_opts;
+ *val = process_print_command_args (s_address.c_str (), &print_opts);
+
+ /* Fetch the length. */
+ std::string s_length = extract_string_maybe_quoted (&args);
+
+ /* Fetch the tag bytes. */
+ std::string s_tags = extract_string_maybe_quoted (&args);
+
+ /* Validate the input. */
+ if (s_address.empty () || s_length.empty () || s_tags.empty ())
+ error (_("Missing arguments."));
+
+ errno = 0;
+ *length = strtoulst (s_length.c_str (), NULL, 10);
+ if (errno != 0)
+ error (_("Error parsing length argument."));
+
+ tags = hex2bin (s_tags.c_str ());
+
+ /* If the address is not in a region memory mapped with a memory tagging
+ flag, it is no use trying to access/manipulate its allocation tag. */
+ if (!gdbarch_tagged_address_p (target_gdbarch (), *val))
+ show_addr_not_tagged (value_as_address (*val));
+}
+
+/* Implement the "mtag setatag" command.
+ ARGS should be in the format <address> <length> <tags>. */
+
+static void
+mtag_setatag_command (const char *args, int from_tty)
+{
+ if (!memtag || !target_supports_memory_tagging ())
+ show_memtag_unsupported ();
+
+ if (args == nullptr)
+ error_no_arg (_("<starting address> <length> <tag bytes>"));
+
+ gdb::byte_vector tags;
+ size_t length = 0;
+ struct value *val;
+
+ /* Parse the input. */
+ parse_setatag_input (args, &val, &length, tags);
+
+ if (gdbarch_set_memtags (target_gdbarch (), val, length, tags,
+ tag_allocation) != 0)
+ printf_filtered (_("Could not update the allocation tag(s).\n"));
+ else
+ printf_filtered (_("Allocation tag(s) updated successfully.\n"));
+}
+
+/* Implement the "mtag check" command. */
+
+static void
+mtag_check_command (const char *args, int from_tty)
+{
+ if (!memtag || !target_supports_memory_tagging ())
+ show_memtag_unsupported ();
+
+ if (args == nullptr)
+ error (_("Argument required (address or pointer)"));
+
+ /* Parse the expression into a value. If the value is an address or
+ pointer, then check its logical tag against the allocation tag. */
+ value_print_options print_opts;
+
+ struct value *val = process_print_command_args (args, &print_opts);
+
+ /* If the address is not in a region memory mapped with a memory tagging
+ flag, it is no use trying to access/manipulate its allocation tag. */
+ if (!gdbarch_tagged_address_p (target_gdbarch (), val))
+ show_addr_not_tagged (value_as_address (val));
+
+ CORE_ADDR addr = value_as_address (val);
+
+ /* If memory tagging validation is on, check if the tag is valid. */
+ if (gdbarch_memtag_mismatch_p (target_gdbarch (), val))
+ {
+ std::string ltag = gdbarch_memtag_to_string (target_gdbarch (),
+ val, tag_logical);
+ std::string atag = gdbarch_memtag_to_string (target_gdbarch (),
+ val, tag_allocation);
+
+ printf_filtered (_("Logical tag (%s) does not match"
+ " the allocation tag (%s) for address %s.\n"),
+ ltag.c_str (), atag.c_str (),
+ paddress (target_gdbarch (), addr));
+ }
+ else
+ {
+ std::string ltag = gdbarch_memtag_to_string (target_gdbarch (),
+ val, tag_logical);
+ printf_filtered (_("Memory tags for address %s match (%s).\n"),
+ paddress (target_gdbarch (), addr), ltag.c_str ());
+ }
+}
+
void _initialize_printcmd ();
void
_initialize_printcmd ()
@@ -2911,4 +3184,60 @@ certain operations have illegal tags."),
NULL,
show_memtag,
&setlist, &showlist);
+
+ /* Memory tagging commands. */
+ add_prefix_cmd ("mtag", class_vars, mtag_command, _("\
+Generic command for showing and manipulating memory tag properties."),
+ &mtaglist, "mtag ", 0, &cmdlist);
+ add_cmd ("showltag", class_vars, mtag_showltag_command,
+ ("Show the logical tag for an address.\n\
+Usage: mtag showltag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will show the logical tag associated with <address>. The tag\n\
+interpretation is architecture-specific."),
+ &mtaglist);
+ add_cmd ("showatag", class_vars, mtag_showatag_command,
+ _("Show the allocation tag for an address.\n\
+Usage: mtag showatag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will show the allocation tag associated with <address>. The tag\n\
+interpretation is architecture-specific."),
+ &mtaglist);
+ add_cmd ("setltag", class_vars, mtag_setltag_command,
+ _("Set the logical tag for an address.\n\
+Usage: mtag setltag <address> <tag>\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+<tag> is a sequence of hex bytes that will be interpreted by the\n\
+architecture as a single memory tag.\n\
+GDB will set the logical tag for <address> to <tag>, and will show the\n\
+resulting address with the updated tag."),
+ &mtaglist);
+ add_cmd ("setatag", class_vars, mtag_setatag_command,
+ _("Set the allocation tag for an address.\n\
+Usage: mtag setatag <address> <length> <tag_bytes>\n\
+<address> is an expression that evaluates to a pointer or memory address\n\
+<length> is the number of bytes that will get added to <address> to calculate\n\
+the memory range.\n\
+<tag bytes> is a sequence of hex bytes that will be interpreted by the\n\
+architecture as one or more memory tags.\n\
+Sets the tags of the memory range [<address>, <address> + <length>)\n\
+to the specified tag bytes.\n\
+\n\
+If the number of tags is greater than or equal to the number of tag granules\n\
+in the [<address>, <address> + <length) range, only the tags up to the\n\
+number of tag granules will be stored.\n\
+\n\
+If the number of tags is less than the number of tag granules, then the\n\
+command is a fill operation. The tag bytes are interpreted as a pattern\n\
+that will get repeated until the number of tag granules in the memory range\n\
+[<address>, <address> + <length>] is stored to."),
+ &mtaglist);
+ add_cmd ("check", class_vars, mtag_check_command,
+ _("Validate the logical tag against the allocation tag.\n\
+Usage: mtag check <address>\n\
+<address> is an expression that evaluates to a pointer or memory address\n\
+GDB will fetch the logical and allocation tags for <address> and will\n\
+compare them for equality. If the tags do not match, GDB will show\n\
+additional information about the mismatch."),
+ &mtaglist);
}
diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc
index 9bb1660..90b51db 100644
--- a/gdbsupport/rsp-low.cc
+++ b/gdbsupport/rsp-low.cc
@@ -32,7 +32,7 @@ fromhex (int a)
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else
- error (_("Reply contains invalid hex digit %d"), a);
+ error (_("Invalid hex digit %d"), a);
}
/* See rsp-low.h. */