mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 09:08:59 +00:00
New mtag commands
Add new commands under the "mtag" prefix to allow users to inspect, modify and check memory tags in different ways. The available subcommands are the following: - mtag showltag <address>: Shows the logical tag for a particular address. - mtag setltag <address> <tag>: Prints the address tagged with the logical tag <tag> - mtag showatag <address>: Shows the allocation tag for a particular address. - mtag setatag <address> <length> <tags>: Sets one or more allocation tags to the specified tags. - mtag check <address>: Check if the logical tag in <address> matches its allocation tag. These commands make use of the memory tagging gdbarch methods, and are still available, but disabled, when memory tagging is not supported by the architecture. gdb/ChangeLog: YYYY-MM-DD Luis Machado <luis.machado@linaro.org> * printcmd.c: Include gdbsupport/rsp-low.h. (mtaglist): New static global. (process_print_command_args): Factored out of print_command_1. (print_command_1): Use process_print_command_args. (cast_non_lval_void_ptr, show_memtag_unsupported, mtag_command) (mtag_showtag_command, mtag_showltag_command, mtag_showatag_command) (parse_setltag_input, mtag_setltag_command, parse_setatag_input) (mtag_setatag_command, mtag_check_command): New functions. (_initialize_printcmd): Add "mtag" prefix and subcommands. gdbsupport/ChangeLog: YYYY-MM-DD Luis Machado <luis.machado@linaro.org> * rsp-low.cc (fromhex): Change error message text to not be RSP-specific.
This commit is contained in:
331
gdb/printcmd.c
331
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,245 @@ eval_command (const char *arg, int from_tty)
|
||||
execute_command (expanded.c_str (), from_tty);
|
||||
}
|
||||
|
||||
/* Helper function for mtag commands. Cast VALUE to a non-lval
|
||||
(void *) pointer. */
|
||||
|
||||
static struct value *cast_non_lval_void_ptr (struct value *value)
|
||||
{
|
||||
if (value == nullptr)
|
||||
return nullptr;
|
||||
|
||||
struct value *val;
|
||||
|
||||
/* Turn into a non_lval. */
|
||||
val = value_non_lval (value);
|
||||
|
||||
struct gdbarch *gdbarch = get_type_arch (value_type (val));
|
||||
const struct builtin_type *builtin = builtin_type (gdbarch);
|
||||
|
||||
/* Cast to (void *). */
|
||||
val = value_cast (builtin->builtin_data_ptr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Convenience function for 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);
|
||||
|
||||
val = cast_non_lval_void_ptr (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);
|
||||
|
||||
val = cast_non_lval_void_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 ());
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
val = cast_non_lval_void_ptr (val);
|
||||
|
||||
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);
|
||||
|
||||
val = cast_non_lval_void_ptr (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).\n"),
|
||||
ltag.c_str (), atag.c_str ());
|
||||
}
|
||||
else
|
||||
printf_filtered (_("Memory tags match.\n"));
|
||||
}
|
||||
|
||||
void _initialize_printcmd ();
|
||||
void
|
||||
_initialize_printcmd ()
|
||||
@@ -2911,4 +3162,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);
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user