Enable support for the AArch64 dot-prod instruction in the Cortex A55 and A75 cpus.
[deliverable/binutils-gdb.git] / gdb / disasm.c
index 897f2f1412f366f9cd28bd35ae4d96b6f3ad196e..76c4ff31a6ee7861dc60ef292421693b98462644 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "target.h"
 #include "value.h"
 #include "ui-out.h"
 #include "disasm.h"
 #include "gdbcore.h"
+#include "gdbcmd.h"
 #include "dis-asm.h"
 #include "source.h"
+#include "safe-ctype.h"
 #include <algorithm>
 
 /* Disassemble functions.
    FIXME: We should get rid of all the duplicate code in gdb that does
    the same thing: disassemble_command() and the gdbtk variation.  */
 
+/* This variable is used to hold the prospective disassembler_options value
+   which is set by the "set disassembler_options" command.  */
+static char *prospective_options = NULL;
+
 /* This structure is used to store line number information for the
    deprecated /m option.
    We need a different sort of line table from the normal one cuz we can't
@@ -182,9 +189,9 @@ compare_lines (const void *mle1p, const void *mle2p)
 /* See disasm.h.  */
 
 int
-gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
-                                    const struct disasm_insn *insn,
-                                    int flags)
+gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
+                                                 const struct disasm_insn *insn,
+                                                 int flags)
 {
   /* parts of the symbolic representation of the address */
   int unmapped;
@@ -195,7 +202,6 @@ gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
   char *filename = NULL;
   char *name = NULL;
   CORE_ADDR pc;
-  struct ui_file *stb = stream ();
   struct gdbarch *gdbarch = arch ();
 
   ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -250,7 +256,8 @@ gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
   if (name != NULL)
     xfree (name);
 
-  ui_file_rewind (stb);
+  m_insn_stb.clear ();
+
   if (flags & DISASSEMBLY_RAW_INSN)
     {
       CORE_ADDR end_pc;
@@ -260,33 +267,25 @@ gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
 
       /* Build the opcodes using a temporary stream so we can
         write them out in a single go for the MI.  */
-      struct ui_file *opcode_stream = mem_fileopen ();
-      struct cleanup *cleanups =
-       make_cleanup_ui_file_delete (opcode_stream);
+      m_opcode_stb.clear ();
 
-      size = print_insn (pc);
+      size = m_di.print_insn (pc);
       end_pc = pc + size;
 
       for (;pc < end_pc; ++pc)
        {
-         err = m_di.read_memory_func (pc, &data, 1, &m_di);
-         if (err != 0)
-           m_di.memory_error_func (err, pc, &m_di);
-         fprintf_filtered (opcode_stream, "%s%02x",
-                           spacer, (unsigned) data);
+         read_code (pc, &data, 1);
+         m_opcode_stb.printf ("%s%02x", spacer, (unsigned) data);
          spacer = " ";
        }
 
-      uiout->field_stream ("opcodes", opcode_stream);
+      uiout->field_stream ("opcodes", m_opcode_stb);
       uiout->text ("\t");
-
-      do_cleanups (cleanups);
     }
   else
-    size = print_insn (pc);
+    size = m_di.print_insn (pc);
 
-  uiout->field_stream ("inst", stb);
-  ui_file_rewind (stb);
+  uiout->field_stream ("inst", m_insn_stb);
   do_cleanups (ui_out_chain);
   uiout->text ("\n");
 
@@ -294,10 +293,9 @@ gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
 }
 
 static int
-dump_insns (struct ui_out *uiout, gdb_disassembler *di,
-           CORE_ADDR low, CORE_ADDR high,
-           int how_many, int flags,
-           CORE_ADDR *end_pc)
+dump_insns (struct gdbarch *gdbarch,
+           struct ui_out *uiout, CORE_ADDR low, CORE_ADDR high,
+           int how_many, int flags, CORE_ADDR *end_pc)
 {
   struct disasm_insn insn;
   int num_displayed = 0;
@@ -305,11 +303,13 @@ dump_insns (struct ui_out *uiout, gdb_disassembler *di,
   memset (&insn, 0, sizeof (insn));
   insn.addr = low;
 
+  gdb_pretty_print_disassembler disasm (gdbarch);
+
   while (insn.addr < high && (how_many < 0 || num_displayed < how_many))
     {
       int size;
 
-      size = di->pretty_print_insn (uiout, &insn, flags);
+      size = disasm.pretty_print_insn (uiout, &insn, flags);
       if (size <= 0)
        break;
 
@@ -335,8 +335,8 @@ dump_insns (struct ui_out *uiout, gdb_disassembler *di,
 
 static void
 do_mixed_source_and_assembly_deprecated
-  (struct ui_out *uiout,
-   gdb_disassembler *di, struct symtab *symtab,
+  (struct gdbarch *gdbarch, struct ui_out *uiout,
+   struct symtab *symtab,
    CORE_ADDR low, CORE_ADDR high,
    int how_many, int flags)
 {
@@ -437,18 +437,15 @@ do_mixed_source_and_assembly_deprecated
                  for (; next_line < mle[i].line; next_line++)
                    {
                      struct cleanup *ui_out_list_chain_line;
-                     struct cleanup *ui_out_tuple_chain_line;
                      
-                     ui_out_tuple_chain_line
-                       = make_cleanup_ui_out_tuple_begin_end (uiout,
-                                                              "src_and_asm_line");
+                     ui_out_emit_tuple tuple_emitter (uiout,
+                                                      "src_and_asm_line");
                      print_source_lines (symtab, next_line, next_line + 1,
                                          psl_flags);
                      ui_out_list_chain_line
                        = make_cleanup_ui_out_list_begin_end (uiout,
                                                              "line_asm_insn");
                      do_cleanups (ui_out_list_chain_line);
-                     do_cleanups (ui_out_tuple_chain_line);
                    }
                  /* Print the last line and leave list open for
                     asm instructions to be added.  */
@@ -471,7 +468,7 @@ do_mixed_source_and_assembly_deprecated
            = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
        }
 
-      num_displayed += dump_insns (uiout, di,
+      num_displayed += dump_insns (gdbarch, uiout,
                                   mle[i].start_pc, mle[i].end_pc,
                                   how_many, flags, NULL);
 
@@ -499,7 +496,6 @@ do_mixed_source_and_assembly_deprecated
 static void
 do_mixed_source_and_assembly (struct gdbarch *gdbarch,
                              struct ui_out *uiout,
-                             gdb_disassembler *di,
                              struct symtab *main_symtab,
                              CORE_ADDR low, CORE_ADDR high,
                              int how_many, int flags)
@@ -681,22 +677,18 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
                 a bunch of line tuples with no asm entries.  */
              int l;
              struct cleanup *ui_out_list_chain_line;
-             struct cleanup *ui_out_tuple_chain_line;
 
              gdb_assert (sal.symtab != NULL);
              for (l = start_preceding_line_to_display;
                   l < end_preceding_line_to_display;
                   ++l)
                {
-                 ui_out_tuple_chain_line
-                   = make_cleanup_ui_out_tuple_begin_end (uiout,
-                                                          "src_and_asm_line");
+                 ui_out_emit_tuple tuple_emitter (uiout, "src_and_asm_line");
                  print_source_lines (sal.symtab, l, l + 1, psl_flags);
                  ui_out_list_chain_line
                    = make_cleanup_ui_out_list_begin_end (uiout,
                                                          "line_asm_insn");
                  do_cleanups (ui_out_list_chain_line);
-                 do_cleanups (ui_out_tuple_chain_line);
                }
            }
          ui_out_tuple_chain
@@ -721,7 +713,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
        end_pc = std::min (sal.end, high);
       else
        end_pc = pc + 1;
-      num_displayed += dump_insns (uiout, di, pc, end_pc,
+      num_displayed += dump_insns (gdbarch, uiout, pc, end_pc,
                                   how_many, flags, &end_pc);
       pc = end_pc;
 
@@ -736,18 +728,13 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
 }
 
 static void
-do_assembly_only (struct ui_out *uiout,
-                 gdb_disassembler *di,
+do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
                  CORE_ADDR low, CORE_ADDR high,
                  int how_many, int flags)
 {
-  struct cleanup *ui_out_chain;
-
-  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
+  ui_out_emit_list list_emitter (uiout, "asm_insns");
 
-  dump_insns (uiout, di, low, high, how_many, flags, NULL);
-
-  do_cleanups (ui_out_chain);
+  dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL);
 }
 
 /* Initialize the disassemble info struct ready for the specified
@@ -789,6 +776,7 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
   m_di.endian = gdbarch_byte_order (gdbarch);
   m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
   m_di.application_data = this;
+  m_di.disassembler_options = get_disassembler_options (gdbarch);
   disassemble_init_for_target (&m_di);
 }
 
@@ -815,12 +803,9 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr,
 
 void
 gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
-                char *file_string, int flags, int how_many,
+                int flags, int how_many,
                 CORE_ADDR low, CORE_ADDR high)
 {
-  struct ui_file *stb = mem_fileopen ();
-  struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
-  gdb_disassembler di (gdbarch, stb);
   struct symtab *symtab;
   int nlines = -1;
 
@@ -832,17 +817,16 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 
   if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
       || nlines <= 0)
-    do_assembly_only (uiout, &di, low, high, how_many, flags);
+    do_assembly_only (gdbarch, uiout, low, high, how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE)
-    do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
+    do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high,
                                  how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
-    do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+    do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab,
                                             low, high, how_many, flags);
 
-  do_cleanups (cleanups);
   gdb_flush (gdb_stdout);
 }
 
@@ -866,7 +850,7 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
 int
 gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
-  return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
+  return gdb_print_insn (gdbarch, addr, &null_stream, NULL);
 }
 
 /* fprintf-function for gdb_buffered_insn_length.  This function is a
@@ -901,6 +885,7 @@ gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
   di->endian = gdbarch_byte_order (gdbarch);
   di->endian_code = gdbarch_byte_order_for_code (gdbarch);
 
+  di->disassembler_options = get_disassembler_options (gdbarch);
   disassemble_init_for_target (di);
 }
 
@@ -917,3 +902,173 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
 
   return gdbarch_print_insn (gdbarch, addr, &di);
 }
+
+char *
+get_disassembler_options (struct gdbarch *gdbarch)
+{
+  char **disassembler_options = gdbarch_disassembler_options (gdbarch);
+  if (disassembler_options == NULL)
+    return NULL;
+  return *disassembler_options;
+}
+
+void
+set_disassembler_options (char *prospective_options)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  char **disassembler_options = gdbarch_disassembler_options (gdbarch);
+  const disasm_options_t *valid_options;
+  char *options = remove_whitespace_and_extra_commas (prospective_options);
+  const char *opt;
+
+  /* Allow all architectures, even ones that do not support 'set disassembler',
+     to reset their disassembler options to NULL.  */
+  if (options == NULL)
+    {
+      if (disassembler_options != NULL)
+       {
+         free (*disassembler_options);
+         *disassembler_options = NULL;
+       }
+      return;
+    }
+
+  valid_options = gdbarch_valid_disassembler_options (gdbarch);
+  if (valid_options  == NULL)
+    {
+      fprintf_filtered (gdb_stdlog, _("\
+'set disassembler-options ...' is not supported on this architecture.\n"));
+      return;
+    }
+
+  /* Verify we have valid disassembler options.  */
+  FOR_EACH_DISASSEMBLER_OPTION (opt, options)
+    {
+      size_t i;
+      for (i = 0; valid_options->name[i] != NULL; i++)
+       if (disassembler_options_cmp (opt, valid_options->name[i]) == 0)
+         break;
+      if (valid_options->name[i] == NULL)
+       {
+         fprintf_filtered (gdb_stdlog,
+                           _("Invalid disassembler option value: '%s'.\n"),
+                           opt);
+         return;
+       }
+    }
+
+  free (*disassembler_options);
+  *disassembler_options = xstrdup (options);
+}
+
+static void
+set_disassembler_options_sfunc (char *args, int from_tty,
+                               struct cmd_list_element *c)
+{
+  set_disassembler_options (prospective_options);
+}
+
+static void
+show_disassembler_options_sfunc (struct ui_file *file, int from_tty,
+                                struct cmd_list_element *c, const char *value)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  const disasm_options_t *valid_options;
+
+  const char *options = get_disassembler_options (gdbarch);
+  if (options == NULL)
+    options = "";
+
+  fprintf_filtered (file, _("The current disassembler options are '%s'\n"),
+                   options);
+
+  valid_options = gdbarch_valid_disassembler_options (gdbarch);
+
+  if (valid_options == NULL)
+    return;
+
+  fprintf_filtered (file, _("\n\
+The following disassembler options are supported for use with the\n\
+'set disassembler-options <option>[,<option>...]' command:\n"));
+
+  if (valid_options->description != NULL)
+    {
+      size_t i, max_len = 0;
+
+      /* Compute the length of the longest option name.  */
+      for (i = 0; valid_options->name[i] != NULL; i++)
+       {
+         size_t len = strlen (valid_options->name[i]);
+         if (max_len < len)
+           max_len = len;
+       }
+
+      for (i = 0, max_len++; valid_options->name[i] != NULL; i++)
+       {
+         fprintf_filtered (file, "  %s", valid_options->name[i]);
+         if (valid_options->description[i] != NULL)
+           fprintf_filtered (file, "%*c %s",
+                             (int)(max_len - strlen (valid_options->name[i])), ' ',
+                             valid_options->description[i]);
+         fprintf_filtered (file, "\n");
+       }
+    }
+  else
+    {
+      size_t i;
+      fprintf_filtered (file, "  ");
+      for (i = 0; valid_options->name[i] != NULL; i++)
+       {
+         fprintf_filtered (file, "%s", valid_options->name[i]);
+         if (valid_options->name[i + 1] != NULL)
+           fprintf_filtered (file, ", ");
+         wrap_here ("  ");
+       }
+      fprintf_filtered (file, "\n");
+    }
+}
+
+/* A completion function for "set disassembler".  */
+
+static void
+disassembler_options_completer (struct cmd_list_element *ignore,
+                               completion_tracker &tracker,
+                               const char *text, const char *word)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  const disasm_options_t *opts = gdbarch_valid_disassembler_options (gdbarch);
+
+  if (opts != NULL)
+    {
+      /* Only attempt to complete on the last option text.  */
+      const char *separator = strrchr (text, ',');
+      if (separator != NULL)
+       text = separator + 1;
+      text = skip_spaces_const (text);
+      complete_on_enum (tracker, opts->name, text, word);
+    }
+}
+
+
+/* Initialization code.  */
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_disasm;
+
+void
+_initialize_disasm (void)
+{
+  struct cmd_list_element *cmd;
+
+  /* Add the command that controls the disassembler options.  */
+  cmd = add_setshow_string_noescape_cmd ("disassembler-options", no_class,
+                                        &prospective_options, _("\
+Set the disassembler options.\n\
+Usage: set disassembler-options <option>[,<option>...]\n\n\
+See: 'show disassembler-options' for valid option values.\n"), _("\
+Show the disassembler options."), NULL,
+                                        set_disassembler_options_sfunc,
+                                        show_disassembler_options_sfunc,
+                                        &setlist, &showlist);
+  set_cmd_completer (cmd, disassembler_options_completer);
+}
This page took 0.149796 seconds and 4 git commands to generate.