GNU Binutils with patches for OS216
修訂 | ec86fe6295f8f8c46e85dad08f76665001a366b8 (tree) |
---|---|
時間 | 2020-06-16 21:58:32 |
作者 | Luis Machado <luis.machado@lina...> |
Commiter | Luis Machado |
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
- mtag showatag <address>: Shows the allocation tag for a particular address.
- mtag setatag <address> <length> <tags>: Sets one or more allocation tags to
- mtag check <address>: Check if the logical tag in <address> matches its
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.
@@ -53,6 +53,11 @@ | ||
53 | 53 | #include "source.h" |
54 | 54 | #include "gdbsupport/byte-vector.h" |
55 | 55 | #include "gdbsupport/gdb_optional.h" |
56 | +#include "gdbsupport/rsp-low.h" | |
57 | + | |
58 | +/* Chain containing all defined mtag subcommands. */ | |
59 | + | |
60 | +struct cmd_list_element *mtaglist; | |
56 | 61 | |
57 | 62 | /* Last specified output format. */ |
58 | 63 |
@@ -1209,31 +1214,38 @@ print_value (value *val, const value_print_options &opts) | ||
1209 | 1214 | annotate_value_history_end (); |
1210 | 1215 | } |
1211 | 1216 | |
1212 | -/* Implementation of the "print" and "call" commands. */ | |
1217 | +/* Helper for parsing arguments for print_command_1. */ | |
1213 | 1218 | |
1214 | -static void | |
1215 | -print_command_1 (const char *args, int voidprint) | |
1219 | +static struct value * | |
1220 | +process_print_command_args (const char *args, value_print_options *print_opts) | |
1216 | 1221 | { |
1217 | - struct value *val; | |
1218 | - value_print_options print_opts; | |
1219 | - | |
1220 | - get_user_print_options (&print_opts); | |
1222 | + get_user_print_options (print_opts); | |
1221 | 1223 | /* Override global settings with explicit options, if any. */ |
1222 | - auto group = make_value_print_options_def_group (&print_opts); | |
1224 | + auto group = make_value_print_options_def_group (print_opts); | |
1223 | 1225 | gdb::option::process_options |
1224 | 1226 | (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group); |
1225 | 1227 | |
1226 | - print_command_parse_format (&args, "print", &print_opts); | |
1228 | + print_command_parse_format (&args, "print", print_opts); | |
1227 | 1229 | |
1228 | 1230 | const char *exp = args; |
1229 | 1231 | |
1230 | 1232 | if (exp != nullptr && *exp) |
1231 | 1233 | { |
1232 | 1234 | expression_up expr = parse_expression (exp); |
1233 | - val = evaluate_expression (expr.get ()); | |
1235 | + return evaluate_expression (expr.get ()); | |
1234 | 1236 | } |
1235 | - else | |
1236 | - val = access_value_history (0); | |
1237 | + | |
1238 | + return access_value_history (0); | |
1239 | +} | |
1240 | + | |
1241 | +/* Implementation of the "print" and "call" commands. */ | |
1242 | + | |
1243 | +static void | |
1244 | +print_command_1 (const char *args, int voidprint) | |
1245 | +{ | |
1246 | + value_print_options print_opts; | |
1247 | + | |
1248 | + struct value *val = process_print_command_args (args, &print_opts); | |
1237 | 1249 | |
1238 | 1250 | if (voidprint || (val && value_type (val) && |
1239 | 1251 | value_type (val)->code () != TYPE_CODE_VOID)) |
@@ -2701,6 +2713,245 @@ eval_command (const char *arg, int from_tty) | ||
2701 | 2713 | execute_command (expanded.c_str (), from_tty); |
2702 | 2714 | } |
2703 | 2715 | |
2716 | +/* Helper function for mtag commands. Cast VALUE to a non-lval | |
2717 | + (void *) pointer. */ | |
2718 | + | |
2719 | +static struct value *cast_non_lval_void_ptr (struct value *value) | |
2720 | +{ | |
2721 | + if (value == nullptr) | |
2722 | + return nullptr; | |
2723 | + | |
2724 | + struct value *val; | |
2725 | + | |
2726 | + /* Turn into a non_lval. */ | |
2727 | + val = value_non_lval (value); | |
2728 | + | |
2729 | + struct gdbarch *gdbarch = get_type_arch (value_type (val)); | |
2730 | + const struct builtin_type *builtin = builtin_type (gdbarch); | |
2731 | + | |
2732 | + /* Cast to (void *). */ | |
2733 | + val = value_cast (builtin->builtin_data_ptr, val); | |
2734 | + | |
2735 | + return val; | |
2736 | +} | |
2737 | + | |
2738 | +/* Convenience function for mtag commands. */ | |
2739 | + | |
2740 | +static void | |
2741 | +show_memtag_unsupported (void) | |
2742 | +{ | |
2743 | + error (_("Memory tagging not supported or disabled by the current" | |
2744 | + " architecture.")); | |
2745 | +} | |
2746 | + | |
2747 | +/* Implement the "mtag" prefix command. */ | |
2748 | + | |
2749 | +static void | |
2750 | +mtag_command (const char *arg, int from_tty) | |
2751 | +{ | |
2752 | + help_list (mtaglist, "mtag ", all_commands, gdb_stdout); | |
2753 | +} | |
2754 | + | |
2755 | +/* Helper for showltag and showatag. */ | |
2756 | + | |
2757 | +static void | |
2758 | +mtag_showtag_command (const char *args, enum memtag_type tag_type) | |
2759 | +{ | |
2760 | + if (args == nullptr) | |
2761 | + error_no_arg (_("address or pointer")); | |
2762 | + | |
2763 | + /* Parse args into a value. If the value is a pointer or an address, | |
2764 | + then fetch the logical or allocation tag. */ | |
2765 | + value_print_options print_opts; | |
2766 | + | |
2767 | + struct value *val = process_print_command_args (args, &print_opts); | |
2768 | + | |
2769 | + val = cast_non_lval_void_ptr (val); | |
2770 | + | |
2771 | + std::string tag = gdbarch_memtag_to_string (target_gdbarch (), | |
2772 | + val, tag_type); | |
2773 | + if (tag.empty ()) | |
2774 | + printf_filtered (_("%s tag unavailable.\n"), | |
2775 | + tag_type == tag_logical? "Logical" : "Allocation"); | |
2776 | + | |
2777 | + struct value *v_tag = process_print_command_args (tag.c_str (), | |
2778 | + &print_opts); | |
2779 | + print_opts.output_format = 'x'; | |
2780 | + print_value (v_tag, print_opts); | |
2781 | +} | |
2782 | + | |
2783 | +/* Implement the "mtag showltag" command. */ | |
2784 | + | |
2785 | +static void | |
2786 | +mtag_showltag_command (const char *args, int from_tty) | |
2787 | +{ | |
2788 | + if (!memtag || !target_supports_memory_tagging ()) | |
2789 | + show_memtag_unsupported (); | |
2790 | + | |
2791 | + mtag_showtag_command (args, tag_logical); | |
2792 | +} | |
2793 | + | |
2794 | +/* Implement the "mtag showatag" command. */ | |
2795 | + | |
2796 | +static void | |
2797 | +mtag_showatag_command (const char *args, int from_tty) | |
2798 | +{ | |
2799 | + if (!memtag || !target_supports_memory_tagging ()) | |
2800 | + show_memtag_unsupported (); | |
2801 | + | |
2802 | + mtag_showtag_command (args, tag_allocation); | |
2803 | +} | |
2804 | + | |
2805 | +/* Parse ARGS and extract ADDR and TAG. | |
2806 | + ARGS should have format <expression> <tag bytes>. */ | |
2807 | + | |
2808 | +static void | |
2809 | +parse_setltag_input (const char *args, struct value **val, | |
2810 | + gdb::byte_vector &tags, value_print_options *print_opts) | |
2811 | +{ | |
2812 | + /* Given <expression> can be reasonably complex, we parse things backwards | |
2813 | + so we can isolate the <tag bytes> portion. */ | |
2814 | + | |
2815 | + /* Fetch the address. */ | |
2816 | + std::string s_address = extract_string_maybe_quoted (&args); | |
2817 | + | |
2818 | + /* Parse the address into a value. */ | |
2819 | + *val = process_print_command_args (s_address.c_str (), print_opts); | |
2820 | + | |
2821 | + /* Fetch the tag bytes. */ | |
2822 | + std::string s_tags = extract_string_maybe_quoted (&args); | |
2823 | + | |
2824 | + /* Validate the input. */ | |
2825 | + if (s_address.empty () || s_tags.empty ()) | |
2826 | + error (_("Missing arguments.")); | |
2827 | + | |
2828 | + tags = hex2bin (s_tags.c_str ()); | |
2829 | +} | |
2830 | + | |
2831 | +/* Implement the "mtag setltag" command. */ | |
2832 | + | |
2833 | +static void | |
2834 | +mtag_setltag_command (const char *args, int from_tty) | |
2835 | +{ | |
2836 | + if (!memtag || !target_supports_memory_tagging ()) | |
2837 | + show_memtag_unsupported (); | |
2838 | + | |
2839 | + if (args == nullptr) | |
2840 | + error_no_arg (_("<address> <tag>")); | |
2841 | + | |
2842 | + gdb::byte_vector tags; | |
2843 | + struct value *val; | |
2844 | + value_print_options print_opts; | |
2845 | + | |
2846 | + /* Parse the input. */ | |
2847 | + parse_setltag_input (args, &val, tags, &print_opts); | |
2848 | + | |
2849 | + val = cast_non_lval_void_ptr (val); | |
2850 | + | |
2851 | + if (gdbarch_set_memtags (target_gdbarch (), val, 0, tags, | |
2852 | + tag_logical) != 0) | |
2853 | + printf_filtered (_("Could not update the logical tag data.\n")); | |
2854 | + else | |
2855 | + { | |
2856 | + /* Always print it in hex format. */ | |
2857 | + print_opts.output_format = 'x'; | |
2858 | + print_value (val, print_opts); | |
2859 | + } | |
2860 | +} | |
2861 | + | |
2862 | +/* Parse ARGS and extract ADDR, LENGTH and TAGS. */ | |
2863 | + | |
2864 | +static void | |
2865 | +parse_setatag_input (const char *args, struct value **val, size_t *length, | |
2866 | + gdb::byte_vector &tags) | |
2867 | +{ | |
2868 | + /* Fetch the address. */ | |
2869 | + std::string s_address = extract_string_maybe_quoted (&args); | |
2870 | + | |
2871 | + /* Parse the address into a value. */ | |
2872 | + value_print_options print_opts; | |
2873 | + *val = process_print_command_args (s_address.c_str (), &print_opts); | |
2874 | + | |
2875 | + /* Fetch the length. */ | |
2876 | + std::string s_length = extract_string_maybe_quoted (&args); | |
2877 | + | |
2878 | + /* Fetch the tag bytes. */ | |
2879 | + std::string s_tags = extract_string_maybe_quoted (&args); | |
2880 | + | |
2881 | + /* Validate the input. */ | |
2882 | + if (s_address.empty () || s_length.empty () || s_tags.empty ()) | |
2883 | + error (_("Missing arguments.")); | |
2884 | + | |
2885 | + errno = 0; | |
2886 | + *length = strtoulst (s_length.c_str (), NULL, 10); | |
2887 | + if (errno != 0) | |
2888 | + error (_("Error parsing length argument.")); | |
2889 | + | |
2890 | + tags = hex2bin (s_tags.c_str ()); | |
2891 | +} | |
2892 | + | |
2893 | +/* Implement the "mtag setatag" command. | |
2894 | + ARGS should be in the format <address> <length> <tags>. */ | |
2895 | + | |
2896 | +static void | |
2897 | +mtag_setatag_command (const char *args, int from_tty) | |
2898 | +{ | |
2899 | + if (!memtag || !target_supports_memory_tagging ()) | |
2900 | + show_memtag_unsupported (); | |
2901 | + | |
2902 | + if (args == nullptr) | |
2903 | + error_no_arg (_("<starting address> <length> <tag bytes>")); | |
2904 | + | |
2905 | + gdb::byte_vector tags; | |
2906 | + size_t length = 0; | |
2907 | + struct value *val; | |
2908 | + | |
2909 | + /* Parse the input. */ | |
2910 | + parse_setatag_input (args, &val, &length, tags); | |
2911 | + | |
2912 | + val = cast_non_lval_void_ptr (val); | |
2913 | + | |
2914 | + if (gdbarch_set_memtags (target_gdbarch (), val, length, tags, | |
2915 | + tag_allocation) != 0) | |
2916 | + printf_filtered (_("Could not update the allocation tag(s).\n")); | |
2917 | + else | |
2918 | + printf_filtered (_("Allocation tag(s) updated successfully.\n")); | |
2919 | +} | |
2920 | + | |
2921 | +/* Implement the "mtag check" command. */ | |
2922 | + | |
2923 | +static void | |
2924 | +mtag_check_command (const char *args, int from_tty) | |
2925 | +{ | |
2926 | + if (!memtag || !target_supports_memory_tagging ()) | |
2927 | + show_memtag_unsupported (); | |
2928 | + | |
2929 | + if (args == nullptr) | |
2930 | + error (_("Argument required (address or pointer)")); | |
2931 | + | |
2932 | + /* Parse the expression into a value. If the value is an address or | |
2933 | + pointer, then check its logical tag against the allocation tag. */ | |
2934 | + value_print_options print_opts; | |
2935 | + | |
2936 | + struct value *val = process_print_command_args (args, &print_opts); | |
2937 | + | |
2938 | + val = cast_non_lval_void_ptr (val); | |
2939 | + | |
2940 | + /* If memory tagging validation is on, check if the tag is valid. */ | |
2941 | + if (gdbarch_memtag_mismatch_p (target_gdbarch (), val)) | |
2942 | + { | |
2943 | + std::string ltag = gdbarch_memtag_to_string (target_gdbarch (), | |
2944 | + val, tag_logical); | |
2945 | + std::string atag = gdbarch_memtag_to_string (target_gdbarch (), | |
2946 | + val, tag_allocation); | |
2947 | + printf_filtered (_("Logical tag (%s) does not match" | |
2948 | + " the allocation tag (%s).\n"), | |
2949 | + ltag.c_str (), atag.c_str ()); | |
2950 | + } | |
2951 | + else | |
2952 | + printf_filtered (_("Memory tags match.\n")); | |
2953 | +} | |
2954 | + | |
2704 | 2955 | void _initialize_printcmd (); |
2705 | 2956 | void |
2706 | 2957 | _initialize_printcmd () |
@@ -2911,4 +3162,60 @@ certain operations have illegal tags."), | ||
2911 | 3162 | NULL, |
2912 | 3163 | show_memtag, |
2913 | 3164 | &setlist, &showlist); |
3165 | + | |
3166 | + /* Memory tagging commands. */ | |
3167 | + add_prefix_cmd ("mtag", class_vars, mtag_command, _("\ | |
3168 | +Generic command for showing and manipulating memory tag properties."), | |
3169 | + &mtaglist, "mtag ", 0, &cmdlist); | |
3170 | + add_cmd ("showltag", class_vars, mtag_showltag_command, | |
3171 | + ("Show the logical tag for an address.\n\ | |
3172 | +Usage: mtag showltag <address>.\n\ | |
3173 | +<address> is an expression that evaluates to a pointer or memory address.\n\ | |
3174 | +GDB will show the logical tag associated with <address>. The tag\n\ | |
3175 | +interpretation is architecture-specific."), | |
3176 | + &mtaglist); | |
3177 | + add_cmd ("showatag", class_vars, mtag_showatag_command, | |
3178 | + _("Show the allocation tag for an address.\n\ | |
3179 | +Usage: mtag showatag <address>.\n\ | |
3180 | +<address> is an expression that evaluates to a pointer or memory address.\n\ | |
3181 | +GDB will show the allocation tag associated with <address>. The tag\n\ | |
3182 | +interpretation is architecture-specific."), | |
3183 | + &mtaglist); | |
3184 | + add_cmd ("setltag", class_vars, mtag_setltag_command, | |
3185 | + _("Set the logical tag for an address.\n\ | |
3186 | +Usage: mtag setltag <address> <tag>\n\ | |
3187 | +<address> is an expression that evaluates to a pointer or memory address.\n\ | |
3188 | +<tag> is a sequence of hex bytes that will be interpreted by the\n\ | |
3189 | +architecture as a single memory tag.\n\ | |
3190 | +GDB will set the logical tag for <address> to <tag>, and will show the\n\ | |
3191 | +resulting address with the updated tag."), | |
3192 | + &mtaglist); | |
3193 | + add_cmd ("setatag", class_vars, mtag_setatag_command, | |
3194 | + _("Set the allocation tag for an address.\n\ | |
3195 | +Usage: mtag setatag <address> <length> <tag_bytes>\n\ | |
3196 | +<address> is an expression that evaluates to a pointer or memory address\n\ | |
3197 | +<length> is the number of bytes that will get added to <address> to calculate\n\ | |
3198 | +the memory range.\n\ | |
3199 | +<tag bytes> is a sequence of hex bytes that will be interpreted by the\n\ | |
3200 | +architecture as one or more memory tags.\n\ | |
3201 | +Sets the tags of the memory range [<address>, <address> + <length>)\n\ | |
3202 | +to the specified tag bytes.\n\ | |
3203 | +\n\ | |
3204 | +If the number of tags is greater than or equal to the number of tag granules\n\ | |
3205 | +in the [<address>, <address> + <length) range, only the tags up to the\n\ | |
3206 | +number of tag granules will be stored.\n\ | |
3207 | +\n\ | |
3208 | +If the number of tags is less than the number of tag granules, then the\n\ | |
3209 | +command is a fill operation. The tag bytes are interpreted as a pattern\n\ | |
3210 | +that will get repeated until the number of tag granules in the memory range\n\ | |
3211 | +[<address>, <address> + <length>] is stored to."), | |
3212 | + &mtaglist); | |
3213 | + add_cmd ("check", class_vars, mtag_check_command, | |
3214 | + _("Validate the logical tag against the allocation tag.\n\ | |
3215 | +Usage: mtag check <address>\n\ | |
3216 | +<address> is an expression that evaluates to a pointer or memory address\n\ | |
3217 | +GDB will fetch the logical and allocation tags for <address> and will\n\ | |
3218 | +compare them for equality. If the tags do not match, GDB will show\n\ | |
3219 | +additional information about the mismatch."), | |
3220 | + &mtaglist); | |
2914 | 3221 | } |
@@ -32,7 +32,7 @@ fromhex (int a) | ||
32 | 32 | else if (a >= 'A' && a <= 'F') |
33 | 33 | return a - 'A' + 10; |
34 | 34 | else |
35 | - error (_("Reply contains invalid hex digit %d"), a); | |
35 | + error (_("Invalid hex digit %d"), a); | |
36 | 36 | } |
37 | 37 | |
38 | 38 | /* See rsp-low.h. */ |