Add `set print array-indexes' tests for C/C++ arrays
[binutils-gdb.git] / gdb / printcmd.c
index 9200e66db39a0859bcabdd0a46638b7ddafb320b..509f62c21c76f671763ad2d7d325d58b6a349b3d 100644 (file)
@@ -1,6 +1,6 @@
 /* Print values for GNU debugger GDB.
 
-   Copyright (C) 1986-2021 Free Software Foundation, Inc.
+   Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -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
@@ -498,7 +508,7 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
        opts.format = 0;
        if (type->is_unsigned ())
          type = builtin_type (gdbarch)->builtin_true_unsigned_char;
-       else
+       else
          type = builtin_type (gdbarch)->builtin_true_char;
 
        value_print (value_from_longest (type, *val_long), stream, &opts);
@@ -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 (_("<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);
@@ -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,33 @@ 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)
+{
+  gdb_assert (value != nullptr && value_type (value) != nullptr);
+
+  if (!target_supports_memory_tagging ())
+    return false;
+
+  enum type_code code = value_type (value)->code ();
+
+  /* Skip non-address values.  */
+  if (code != TYPE_CODE_PTR
+      && !TYPE_IS_REFERENCE (value_type (value)))
+    return false;
+
+  /* OK, we have an address value.  Check we have a complete value we
+     can extract.  */
+  if (value_optimized_out (value)
+      || !value_entirely_available (value))
+    return false;
+
+  /* We do.  Check whether it includes any tags.  */
+  return gdbarch_tagged_address_p (target_gdbarch (), value);
+}
+
 /* Helper for parsing arguments for print_command_1.  */
 
 static struct value *
@@ -1246,7 +1326,46 @@ 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)
+       {
+         try
+           {
+             if (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 ());
+               }
+           }
+         catch (gdb_exception_error &ex)
+           {
+             if (ex.error == TARGET_CLOSE_ERROR)
+               throw;
+
+             fprintf_filtered (gdb_stderr,
+                               _("Could not validate memory tag: %s\n"),
+                               ex.message->c_str ());
+           }
+       }
+
+      print_value (val, print_opts);
+    }
 }
 
 /* Called from command completion function to skip over /FMT
@@ -1429,8 +1548,7 @@ info_symbol_command (const char *arg, int from_tty)
 
        sect_addr = overlay_mapped_address (addr, osect);
 
-       if (obj_section_addr (osect) <= sect_addr
-           && sect_addr < obj_section_endaddr (osect)
+       if (osect->addr () <= sect_addr && sect_addr < osect->endaddr ()
            && (msymbol
                = lookup_minimal_symbol_by_pc_section (sect_addr,
                                                       osect).minsym))
@@ -1565,8 +1683,7 @@ info_address_command (const char *exp, int from_tty)
     }
 
   printf_filtered ("Symbol \"");
-  fprintf_symbol_filtered (gdb_stdout, sym->print_name (),
-                          current_language->la_language, DMGL_ANSI);
+  fputs_filtered (sym->print_name (), gdb_stdout);
   printf_filtered ("\" is ");
   val = SYMBOL_VALUE (sym);
   if (SYMBOL_OBJFILE_OWNED (sym))
@@ -1607,7 +1724,7 @@ info_address_command (const char *exp, int from_tty)
       break;
 
     case LOC_COMPUTED:
-      gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
+      gdb_assert_not_reached ("LOC_COMPUTED variable missing a method");
 
     case LOC_REGISTER:
       /* GDBARCH is the architecture associated with the objfile the symbol
@@ -1741,6 +1858,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 +1915,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)
     {
@@ -1937,7 +2058,7 @@ map_display_numbers (const char *args,
                                      return item->number == num;
                                    });
          if (iter == all_displays.end ())
-           printf_unfiltered (_("No display number %d.\n"), num);
+           printf_filtered (_("No display number %d.\n"), num);
          else
            function (iter->get ());
        }
@@ -2132,7 +2253,7 @@ disable_display (int num)
        d->enabled_p = false;
        return;
       }
-  printf_unfiltered (_("No display number %d.\n"), num);
+  printf_filtered (_("No display number %d.\n"), num);
 }
 
 void
@@ -2153,7 +2274,7 @@ static void
 info_display_command (const char *ignore, int from_tty)
 {
   if (all_displays.empty ())
-    printf_unfiltered (_("There are no auto-display expressions now.\n"));
+    printf_filtered (_("There are no auto-display expressions now.\n"));
   else
     printf_filtered (_("Auto-display expressions now in effect:\n\
 Num Enb Expression\n"));
@@ -2287,7 +2408,7 @@ print_variable_and_value (const char *name, struct symbol *var,
       val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
-      common_val_print (val, stream, indent, &opts, current_language);
+      common_val_print_checked (val, stream, indent, &opts, current_language);
 
       /* common_val_print invalidates FRAME when a pretty printer calls inferior
         function.  */
@@ -2326,7 +2447,7 @@ printf_c_string (struct ui_file *stream, const char *format,
         null terminated) to be printed without problems.  */
       gdb_byte *tem_str = (gdb_byte *) alloca (len + 1);
 
-      memcpy (tem_str, value_contents (value), len);
+      memcpy (tem_str, value_contents (value).data (), len);
       tem_str [len] = 0;
       str = tem_str;
     }
@@ -2390,7 +2511,7 @@ printf_wide_c_string (struct ui_file *stream, const char *format,
   if (VALUE_LVAL (value) == lval_internalvar
       && c_is_string_type_p (value_type (value)))
     {
-      str = value_contents (value);
+      str = value_contents (value).data ();
       len = TYPE_LENGTH (value_type (value));
     }
   else
@@ -2499,14 +2620,15 @@ printf_floating (struct ui_file *stream, const char *format,
     {
       param_type = float_type_from_length (param_type);
       if (param_type != value_type (value))
-       value = value_from_contents (param_type, value_contents (value));
+       value = value_from_contents (param_type,
+                                    value_contents (value).data ());
     }
 
   value = value_cast (fmt_type, value);
 
   /* Convert the value to a string and print it.  */
   std::string str
-    = target_float_to_string (value_contents (value), fmt_type, format);
+    = target_float_to_string (value_contents (value).data (), fmt_type, format);
   fputs_filtered (str.c_str (), stream);
 }
 
@@ -2667,7 +2789,7 @@ ui_printf (const char *arg, struct ui_file *stream)
                  || valtype->code () != TYPE_CODE_INT)
                error (_("expected wchar_t argument for %%lc"));
 
-             bytes = value_contents (val_args[i]);
+             bytes = value_contents (val_args[i]).data ();
 
              auto_obstack output;
 
@@ -3086,7 +3208,8 @@ _initialize_printcmd ()
 
   current_display_number = -1;
 
-  gdb::observers::free_objfile.attach (clear_dangling_display_expressions);
+  gdb::observers::free_objfile.attach (clear_dangling_display_expressions,
+                                      "printcmd");
 
   add_info ("address", info_address_command,
            _("Describe where symbol SYM is stored.\n\
@@ -3180,7 +3303,7 @@ Use \"set variable\" for variables with names identical to set subcommands.\n\
 \n\
 With a subcommand, this command modifies parts of the gdb environment.\n\
 You can see these environment settings with the \"show\" command."),
-                 &setlist, "set ", 1, &cmdlist);
+                 &setlist, 1, &cmdlist);
   if (dbx_commands)
     add_com ("assign", class_vars, set_command, _("\
 Evaluate expression EXP and assign result to variable VAR.\n\
@@ -3203,7 +3326,8 @@ current working language.  The result is printed and saved in the value\n\
 history, if it is not void."));
   set_cmd_completer_handle_brkchars (c, print_command_completer);
 
-  add_cmd ("variable", class_vars, set_command, _("\
+  cmd_list_element *set_variable_cmd
+    = add_cmd ("variable", class_vars, set_command, _("\
 Evaluate expression EXP and assign result to variable VAR.\n\
 Usage: set variable VAR = EXP\n\
 This uses assignment syntax appropriate for the current language\n\
@@ -3212,8 +3336,8 @@ VAR may be a debugger \"convenience\" variable (names starting\n\
 with $), a register (a few standard names starting with $), or an actual\n\
 variable in the program being debugged.  EXP is any valid expression.\n\
 This may usually be abbreviated to simply \"set\"."),
-          &setlist);
-  add_alias_cmd ("var", "variable", class_vars, 0, &setlist);
+              &setlist);
+  add_alias_cmd ("var", set_variable_cmd, class_vars, 0, &setlist);
 
   const auto print_opts = make_value_print_options_def_group (nullptr);
 
@@ -3250,10 +3374,11 @@ EXP may be preceded with /FMT, where FMT is a format letter\n\
 but no count or size letter (see \"x\" command)."),
                                              print_opts);
 
-  c = add_com ("print", class_vars, print_command, print_help.c_str ());
-  set_cmd_completer_handle_brkchars (c, print_command_completer);
-  add_com_alias ("p", "print", class_vars, 1);
-  add_com_alias ("inspect", "print", class_vars, 1);
+  cmd_list_element *print_cmd
+    = add_com ("print", class_vars, print_command, print_help.c_str ());
+  set_cmd_completer_handle_brkchars (print_cmd, print_command_completer);
+  add_com_alias ("p", print_cmd, class_vars, 1);
+  add_com_alias ("inspect", print_cmd, class_vars, 1);
 
   add_setshow_uinteger_cmd ("max-symbolic-offset", no_class,
                            &max_symbolic_offset, _("\
@@ -3284,7 +3409,7 @@ treat this string as a command line, and evaluate it."));
   /* Memory tagging commands.  */
   add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
 Generic command for printing and manipulating memory tag properties."),
-                 &memory_tag_list, "memory-tag ", 0, &cmdlist);
+                 &memory_tag_list, 0, &cmdlist);
   add_cmd ("print-logical-tag", class_vars,
           memory_tag_print_logical_tag_command,
           ("Print the logical tag from POINTER.\n\