Add `set print repeats' tests for C/C++ arrays
[binutils-gdb.git] / gdb / disasm.c
index 143ba2f59b9534b7f0faad25aa52c291aa4b64f7..724040faa9267628f7ae25c8b4cffe26fa187fed 100644 (file)
@@ -1,6 +1,6 @@
 /* Disassemble support for GDB.
 
-   Copyright (C) 2000-2020 Free Software Foundation, Inc.
+   Copyright (C) 2000-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -39,7 +39,7 @@
 
 /* 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;
+static std::string prospective_options;
 
 /* This structure is used to store line number information for the
    deprecated /m option.
@@ -148,7 +148,7 @@ gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
   gdb_disassembler *self
     = static_cast<gdb_disassembler *>(info->application_data);
 
-  self->m_err_memaddr = memaddr;
+  self->m_err_memaddr.emplace (memaddr);
 }
 
 /* Wrapper of print_address.  */
@@ -163,6 +163,20 @@ gdb_disassembler::dis_asm_print_address (bfd_vma addr,
   print_address (self->arch (), addr, self->stream ());
 }
 
+/* Format disassembler output to STREAM.  */
+
+int
+gdb_disassembler::dis_asm_fprintf (void *stream, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  vfprintf_filtered ((struct ui_file *) stream, format, args);
+  va_end (args);
+  /* Something non -ve.  */
+  return 0;
+}
+
 static bool
 line_is_less_than (const deprecated_dis_line_entry &mle1,
                   const deprecated_dis_line_entry &mle2)
@@ -176,14 +190,14 @@ line_is_less_than (const deprecated_dis_line_entry &mle1,
       if (mle1.start_pc != mle2.start_pc)
        val = mle1.start_pc < mle2.start_pc;
     else
-        val = mle1.line < mle2.line;
+       val = mle1.line < mle2.line;
     }
   else
     {
       if (mle1.line != mle2.line)
        val = mle1.line < mle2.line;
       else
-        val = mle1.start_pc < mle2.start_pc;
+       val = mle1.start_pc < mle2.start_pc;
     }
   return val;
 }
@@ -238,13 +252,13 @@ gdb_pretty_print_disassembler::pretty_print_insn (const struct disasm_insn *insn
     std::string name, filename;
     bool omit_fname = ((flags & DISASSEMBLY_OMIT_FNAME) != 0);
     if (!build_address_symbolic (gdbarch, pc, false, omit_fname, &name,
-                                 &offset, &filename, &line, &unmapped))
+                                &offset, &filename, &line, &unmapped))
       {
        /* We don't care now about line, filename and unmapped.  But we might in
           the future.  */
        m_uiout->text (" <");
        if (!omit_fname)
-         m_uiout->field_string ("func-name", name.c_str (),
+         m_uiout->field_string ("func-name", name,
                                 function_name_style.style ());
        /* For negative offsets, avoid displaying them as +-N; the sign of
           the offset takes the place of the "+" here.  */
@@ -256,8 +270,40 @@ gdb_pretty_print_disassembler::pretty_print_insn (const struct disasm_insn *insn
     else
       m_uiout->text (":\t");
 
+    /* Clear the buffer into which we will disassemble the instruction.  */
     m_insn_stb.clear ();
 
+    /* A helper function to write the M_INSN_STB buffer, followed by a
+       newline.  This can be called in a couple of situations.  */
+    auto write_out_insn_buffer = [&] ()
+    {
+      m_uiout->field_stream ("inst", m_insn_stb);
+      m_uiout->text ("\n");
+    };
+
+    try
+      {
+       /* Now we can disassemble the instruction.  If the disassembler
+          returns a negative value this indicates an error and is handled
+          within the print_insn call, resulting in an exception being
+          thrown.  Returning zero makes no sense, as this indicates we
+          disassembled something successfully, but it was something of no
+          size?  */
+       size = m_di.print_insn (pc);
+       gdb_assert (size > 0);
+      }
+    catch (const gdb_exception &ex)
+      {
+       /* An exception was thrown while disassembling the instruction.
+          However, the disassembler might still have written something
+          out, so ensure that we flush the instruction buffer before
+          rethrowing the exception.  We can't perform this write from an
+          object destructor as the write itself might throw an exception
+          if the pager kicks in, and the user selects quit.  */
+       write_out_insn_buffer ();
+       throw ex;
+      }
+
     if (flags & DISASSEMBLY_RAW_INSN)
       {
        CORE_ADDR end_pc;
@@ -268,7 +314,6 @@ gdb_pretty_print_disassembler::pretty_print_insn (const struct disasm_insn *insn
           write them out in a single go for the MI.  */
        m_opcode_stb.clear ();
 
-       size = m_di.print_insn (pc);
        end_pc = pc + size;
 
        for (;pc < end_pc; ++pc)
@@ -281,12 +326,10 @@ gdb_pretty_print_disassembler::pretty_print_insn (const struct disasm_insn *insn
        m_uiout->field_stream ("opcodes", m_opcode_stb);
        m_uiout->text ("\t");
       }
-    else
-      size = m_di.print_insn (pc);
 
-    m_uiout->field_stream ("inst", m_insn_stb);
+    /* Disassembly was a success, write out the instruction buffer.  */
+    write_out_insn_buffer ();
   }
-  m_uiout->text ("\n");
 
   return size;
 }
@@ -376,12 +419,6 @@ do_mixed_source_and_assembly_deprecated
       if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
        continue;               /* Ignore duplicates.  */
 
-      /* Ignore non-statement line table entries.  This means we print the
-        source line at the place where GDB would insert a breakpoint for
-        that line, which seems more intuitive.  */
-      if (le[i].is_stmt == 0)
-       continue;
-
       /* Skip any end-of-function markers.  */
       if (le[i].line == 0)
        continue;
@@ -466,7 +503,7 @@ do_mixed_source_and_assembly_deprecated
                                   how_many, flags, NULL);
 
       /* When we've reached the end of the mle array, or we've seen the last
-         assembly range for this source line, close out the list/tuple.  */
+        assembly range for this source line, close out the list/tuple.  */
       if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
        {
          inner_list_emitter.reset ();
@@ -717,21 +754,6 @@ do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
   dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL);
 }
 
-/* Initialize the disassemble info struct ready for the specified
-   stream.  */
-
-static int ATTRIBUTE_PRINTF (2, 3)
-fprintf_disasm (void *stream, const char *format, ...)
-{
-  va_list args;
-
-  va_start (args, format);
-  vfprintf_filtered ((struct ui_file *) stream, format, args);
-  va_end (args);
-  /* Something non -ve.  */
-  return 0;
-}
-
 /* Combine implicit and user disassembler options and return them
    in a newly-created string.  */
 
@@ -760,10 +782,9 @@ get_all_disassembler_options (struct gdbarch *gdbarch)
 gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
                                    struct ui_file *file,
                                    di_read_memory_ftype read_memory_func)
-  : m_gdbarch (gdbarch),
-    m_err_memaddr (0)
+  : m_gdbarch (gdbarch)
 {
-  init_disassemble_info (&m_di, file, fprintf_disasm);
+  init_disassemble_info (&m_di, file, dis_asm_fprintf);
   m_di.flavour = bfd_target_unknown_flavour;
   m_di.memory_error_func = dis_asm_memory_error;
   m_di.print_address_func = dis_asm_print_address;
@@ -796,12 +817,17 @@ int
 gdb_disassembler::print_insn (CORE_ADDR memaddr,
                              int *branch_delay_insns)
 {
-  m_err_memaddr = 0;
+  m_err_memaddr.reset ();
 
   int length = gdbarch_print_insn (arch (), memaddr, &m_di);
 
   if (length < 0)
-    memory_error (TARGET_XFER_E_IO, m_err_memaddr);
+    {
+      if (m_err_memaddr.has_value ())
+       memory_error (TARGET_XFER_E_IO, *m_err_memaddr);
+      else
+       error (_("unknown disassembler error (error = %d)"), length);
+    }
 
   if (branch_delay_insns != NULL)
     {
@@ -934,13 +960,16 @@ get_disassembler_options (struct gdbarch *gdbarch)
 }
 
 void
-set_disassembler_options (char *prospective_options)
+set_disassembler_options (const char *prospective_options)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   char **disassembler_options = gdbarch_disassembler_options (gdbarch);
   const disasm_options_and_args_t *valid_options_and_args;
   const disasm_options_t *valid_options;
-  char *options = remove_whitespace_and_extra_commas (prospective_options);
+  gdb::unique_xmalloc_ptr<char> prospective_options_local
+    = make_unique_xstrdup (prospective_options);
+  char *options = remove_whitespace_and_extra_commas
+    (prospective_options_local.get ());
   const char *opt;
 
   /* Allow all architectures, even ones that do not support 'set disassembler',
@@ -1009,7 +1038,7 @@ static void
 set_disassembler_options_sfunc (const char *args, int from_tty,
                                struct cmd_list_element *c)
 {
-  set_disassembler_options (prospective_options);
+  set_disassembler_options (prospective_options.c_str ());
 }
 
 static void
@@ -1145,11 +1174,10 @@ void _initialize_disasm ();
 void
 _initialize_disasm ()
 {
-  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_show_commands set_show_disas_opts
+    = 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."), _("\
@@ -1157,5 +1185,5 @@ Show the disassembler options."), NULL,
                                         set_disassembler_options_sfunc,
                                         show_disassembler_options_sfunc,
                                         &setlist, &showlist);
-  set_cmd_completer (cmd, disassembler_options_completer);
+  set_cmd_completer (set_show_disas_opts.set, disassembler_options_completer);
 }