Add dwarf2_per_objfile parameter to get_die_type_at_offset
[deliverable/binutils-gdb.git] / gdb / disasm.c
index e4653882045c53326bd667550fa13c6b88dff781..143ba2f59b9534b7f0faad25aa52c291aa4b64f7 100644 (file)
@@ -1,6 +1,6 @@
 /* Disassemble support for GDB.
 
-   Copyright (C) 2000-2018 Free Software Foundation, Inc.
+   Copyright (C) 2000-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -29,7 +29,9 @@
 #include "source.h"
 #include "safe-ctype.h"
 #include <algorithm>
-#include "common/gdb_optional.h"
+#include "gdbsupport/gdb_optional.h"
+#include "valprint.h"
+#include "cli/cli-style.h"
 
 /* Disassemble functions.
    FIXME: We should get rid of all the duplicate code in gdb that does
@@ -161,28 +163,27 @@ gdb_disassembler::dis_asm_print_address (bfd_vma addr,
   print_address (self->arch (), addr, self->stream ());
 }
 
-static int
-compare_lines (const void *mle1p, const void *mle2p)
+static bool
+line_is_less_than (const deprecated_dis_line_entry &mle1,
+                  const deprecated_dis_line_entry &mle2)
 {
-  struct deprecated_dis_line_entry *mle1, *mle2;
-  int val;
-
-  mle1 = (struct deprecated_dis_line_entry *) mle1p;
-  mle2 = (struct deprecated_dis_line_entry *) mle2p;
+  bool val;
 
   /* End of sequence markers have a line number of 0 but don't want to
      be sorted to the head of the list, instead sort by PC.  */
-  if (mle1->line == 0 || mle2->line == 0)
+  if (mle1.line == 0 || mle2.line == 0)
     {
-      val = mle1->start_pc - mle2->start_pc;
-      if (val == 0)
-        val = mle1->line - mle2->line;
+      if (mle1.start_pc != mle2.start_pc)
+       val = mle1.start_pc < mle2.start_pc;
+    else
+        val = mle1.line < mle2.line;
     }
   else
     {
-      val = mle1->line - mle2->line;
-      if (val == 0)
-        val = mle1->start_pc - mle2->start_pc;
+      if (mle1.line != mle2.line)
+       val = mle1.line < mle2.line;
+      else
+        val = mle1.start_pc < mle2.start_pc;
     }
   return val;
 }
@@ -190,8 +191,7 @@ compare_lines (const void *mle1p, const void *mle2p)
 /* See disasm.h.  */
 
 int
-gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
-                                                 const struct disasm_insn *insn,
+gdb_pretty_print_disassembler::pretty_print_insn (const struct disasm_insn *insn,
                                                  gdb_disassembly_flags flags)
 {
   /* parts of the symbolic representation of the address */
@@ -199,63 +199,62 @@ gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
   int offset;
   int line;
   int size;
-  char *filename = NULL;
-  char *name = NULL;
   CORE_ADDR pc;
   struct gdbarch *gdbarch = arch ();
 
   {
-    ui_out_emit_tuple tuple_emitter (uiout, NULL);
+    ui_out_emit_tuple tuple_emitter (m_uiout, NULL);
     pc = insn->addr;
 
     if (insn->number != 0)
       {
-       uiout->field_fmt ("insn-number", "%u", insn->number);
-       uiout->text ("\t");
+       m_uiout->field_unsigned ("insn-number", insn->number);
+       m_uiout->text ("\t");
       }
 
     if ((flags & DISASSEMBLY_SPECULATIVE) != 0)
       {
        if (insn->is_speculative)
          {
-           uiout->field_string ("is-speculative", "?");
+           m_uiout->field_string ("is-speculative", "?");
 
            /* The speculative execution indication overwrites the first
               character of the PC prefix.
               We assume a PC prefix length of 3 characters.  */
            if ((flags & DISASSEMBLY_OMIT_PC) == 0)
-             uiout->text (pc_prefix (pc) + 1);
+             m_uiout->text (pc_prefix (pc) + 1);
            else
-             uiout->text ("  ");
+             m_uiout->text ("  ");
          }
        else if ((flags & DISASSEMBLY_OMIT_PC) == 0)
-         uiout->text (pc_prefix (pc));
+         m_uiout->text (pc_prefix (pc));
        else
-         uiout->text ("   ");
+         m_uiout->text ("   ");
       }
     else if ((flags & DISASSEMBLY_OMIT_PC) == 0)
-      uiout->text (pc_prefix (pc));
-    uiout->field_core_addr ("address", gdbarch, pc);
+      m_uiout->text (pc_prefix (pc));
+    m_uiout->field_core_addr ("address", gdbarch, pc);
 
-    if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename,
-                                &line, &unmapped))
+    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))
       {
        /* We don't care now about line, filename and unmapped.  But we might in
           the future.  */
-       uiout->text (" <");
-       if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
-         uiout->field_string ("func-name", name);
-       uiout->text ("+");
-       uiout->field_int ("offset", offset);
-       uiout->text (">:\t");
+       m_uiout->text (" <");
+       if (!omit_fname)
+         m_uiout->field_string ("func-name", name.c_str (),
+                                function_name_style.style ());
+       /* For negative offsets, avoid displaying them as +-N; the sign of
+          the offset takes the place of the "+" here.  */
+       if (offset >= 0)
+         m_uiout->text ("+");
+       m_uiout->field_signed ("offset", offset);
+       m_uiout->text (">:\t");
       }
     else
-      uiout->text (":\t");
-
-    if (filename != NULL)
-      xfree (filename);
-    if (name != NULL)
-      xfree (name);
+      m_uiout->text (":\t");
 
     m_insn_stb.clear ();
 
@@ -279,15 +278,15 @@ gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
            spacer = " ";
          }
 
-       uiout->field_stream ("opcodes", m_opcode_stb);
-       uiout->text ("\t");
+       m_uiout->field_stream ("opcodes", m_opcode_stb);
+       m_uiout->text ("\t");
       }
     else
       size = m_di.print_insn (pc);
 
-    uiout->field_stream ("inst", m_insn_stb);
+    m_uiout->field_stream ("inst", m_insn_stb);
   }
-  uiout->text ("\n");
+  m_uiout->text ("\n");
 
   return size;
 }
@@ -303,13 +302,13 @@ dump_insns (struct gdbarch *gdbarch,
   memset (&insn, 0, sizeof (insn));
   insn.addr = low;
 
-  gdb_pretty_print_disassembler disasm (gdbarch);
+  gdb_pretty_print_disassembler disasm (gdbarch, uiout);
 
   while (insn.addr < high && (how_many < 0 || num_displayed < how_many))
     {
       int size;
 
-      size = disasm.pretty_print_insn (uiout, &insn, flags);
+      size = disasm.pretty_print_insn (&insn, flags);
       if (size <= 0)
        break;
 
@@ -377,6 +376,12 @@ 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;
@@ -404,8 +409,7 @@ do_mixed_source_and_assembly_deprecated
   /* Now, sort mle by line #s (and, then by addresses within lines).  */
 
   if (out_of_order)
-    qsort (mle, newlines, sizeof (struct deprecated_dis_line_entry),
-          compare_lines);
+    std::sort (mle, mle + newlines, line_is_less_than);
 
   /* Now, for each line entry, emit the specified lines (unless
      they have been emitted before), followed by the assembly code
@@ -438,8 +442,8 @@ do_mixed_source_and_assembly_deprecated
                                                       "src_and_asm_line");
                      print_source_lines (symtab, next_line, next_line + 1,
                                          psl_flags);
-                     ui_out_emit_list inner_list_emitter (uiout,
-                                                          "line_asm_insn");
+                     ui_out_emit_list temp_list_emitter (uiout,
+                                                         "line_asm_insn");
                    }
                  /* Print the last line and leave list open for
                     asm instructions to be added.  */
@@ -665,7 +669,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
                   l < end_preceding_line_to_display;
                   ++l)
                {
-                 ui_out_emit_tuple tuple_emitter (uiout, "src_and_asm_line");
+                 ui_out_emit_tuple line_tuple_emitter (uiout,
+                                                       "src_and_asm_line");
                  print_source_lines (sal.symtab, l, l + 1, psl_flags);
                  ui_out_emit_list chain_line_emitter (uiout, "line_asm_insn");
                }
@@ -727,6 +732,31 @@ fprintf_disasm (void *stream, const char *format, ...)
   return 0;
 }
 
+/* Combine implicit and user disassembler options and return them
+   in a newly-created string.  */
+
+static std::string
+get_all_disassembler_options (struct gdbarch *gdbarch)
+{
+  const char *implicit = gdbarch_disassembler_options_implicit (gdbarch);
+  const char *options = get_disassembler_options (gdbarch);
+  const char *comma = ",";
+
+  if (implicit == nullptr)
+    {
+      implicit = "";
+      comma = "";
+    }
+
+  if (options == nullptr)
+    {
+      options = "";
+      comma = "";
+    }
+
+  return string_printf ("%s%s%s", implicit, comma, options);
+}
+
 gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
                                    struct ui_file *file,
                                    di_read_memory_ftype read_memory_func)
@@ -738,12 +768,12 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
   m_di.memory_error_func = dis_asm_memory_error;
   m_di.print_address_func = dis_asm_print_address;
   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
-     disassembler had a local optomization here.  By default it would
+     disassembler had a local optimization here.  By default it would
      access the executable file, instead of the target memory (there
      was a growing list of exceptions though).  Unfortunately, the
      heuristic was flawed.  Commands like "disassemble &variable"
      didn't work as they relied on the access going to the target.
-     Further, it has been supperseeded by trust-read-only-sections
+     Further, it has been superseeded by trust-read-only-sections
      (although that should be superseeded by target_trust..._p()).  */
   m_di.read_memory_func = read_memory_func;
   m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
@@ -751,10 +781,17 @@ 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);
+  m_disassembler_options_holder = get_all_disassembler_options (gdbarch);
+  if (!m_disassembler_options_holder.empty ())
+    m_di.disassembler_options = m_disassembler_options_holder.c_str ();
   disassemble_init_for_target (&m_di);
 }
 
+gdb_disassembler::~gdb_disassembler ()
+{
+  disassemble_free_target (&m_di);
+}
+
 int
 gdb_disassembler::print_insn (CORE_ADDR memaddr,
                              int *branch_delay_insns)
@@ -838,13 +875,16 @@ gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...)
   return 0;
 }
 
-/* Initialize a struct disassemble_info for gdb_buffered_insn_length.  */
+/* Initialize a struct disassemble_info for gdb_buffered_insn_length.
+   Upon return, *DISASSEMBLER_OPTIONS_HOLDER owns the string pointed
+   to by DI.DISASSEMBLER_OPTIONS.  */
 
 static void
 gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
                                   struct disassemble_info *di,
                                   const gdb_byte *insn, int max_len,
-                                  CORE_ADDR addr)
+                                  CORE_ADDR addr,
+                                  std::string *disassembler_options_holder)
 {
   init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf);
 
@@ -860,7 +900,9 @@ 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);
+  *disassembler_options_holder = get_all_disassembler_options (gdbarch);
+  if (!disassembler_options_holder->empty ())
+    di->disassembler_options = disassembler_options_holder->c_str ();
   disassemble_init_for_target (di);
 }
 
@@ -872,10 +914,14 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
                          const gdb_byte *insn, int max_len, CORE_ADDR addr)
 {
   struct disassemble_info di;
+  std::string disassembler_options_holder;
 
-  gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
+  gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr,
+                                    &disassembler_options_holder);
 
-  return gdbarch_print_insn (gdbarch, addr, &di);
+  int result = gdbarch_print_insn (gdbarch, addr, &di);
+  disassemble_free_target (&di);
+  return result;
 }
 
 char *
@@ -892,6 +938,7 @@ set_disassembler_options (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);
   const char *opt;
@@ -908,24 +955,46 @@ set_disassembler_options (char *prospective_options)
       return;
     }
 
-  valid_options = gdbarch_valid_disassembler_options (gdbarch);
-  if (valid_options  == NULL)
+  valid_options_and_args = gdbarch_valid_disassembler_options (gdbarch);
+  if (valid_options_and_args == NULL)
     {
-      fprintf_filtered (gdb_stdlog, _("\
+      fprintf_filtered (gdb_stderr, _("\
 'set disassembler-options ...' is not supported on this architecture.\n"));
       return;
     }
 
+  valid_options = &valid_options_and_args->options;
+
   /* 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)
+       if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+         {
+           size_t len = strlen (valid_options->name[i]);
+           bool found = false;
+           const char *arg;
+           size_t j;
+
+           if (memcmp (opt, valid_options->name[i], len) != 0)
+             continue;
+           arg = opt + len;
+           for (j = 0; valid_options->arg[i]->values[j] != NULL; j++)
+             if (disassembler_options_cmp
+                   (arg, valid_options->arg[i]->values[j]) == 0)
+               {
+                 found = true;
+                 break;
+               }
+           if (found)
+             break;
+         }
+       else if (disassembler_options_cmp (opt, valid_options->name[i]) == 0)
          break;
       if (valid_options->name[i] == NULL)
        {
-         fprintf_filtered (gdb_stdlog,
+         fprintf_filtered (gdb_stderr,
                            _("Invalid disassembler option value: '%s'.\n"),
                            opt);
          return;
@@ -948,32 +1017,46 @@ 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_and_args_t *valid_options_and_args;
+  const disasm_option_arg_t *valid_args;
   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"),
+  fprintf_filtered (file, _("The current disassembler options are '%s'\n\n"),
                    options);
 
-  valid_options = gdbarch_valid_disassembler_options (gdbarch);
+  valid_options_and_args = gdbarch_valid_disassembler_options (gdbarch);
+
+  if (valid_options_and_args == NULL)
+    {
+      fputs_filtered (_("There are no disassembler options available "
+                       "for this architecture.\n"),
+                     file);
+      return;
+    }
 
-  if (valid_options == NULL)
-    return;
+  valid_options = &valid_options_and_args->options;
 
-  fprintf_filtered (file, _("\n\
+  fprintf_filtered (file, _("\
 The following disassembler options are supported for use with the\n\
-'set disassembler-options <option>[,<option>...]' command:\n"));
+'set disassembler-options OPTION [,OPTION]...' command:\n"));
 
   if (valid_options->description != NULL)
     {
       size_t i, max_len = 0;
 
+      fprintf_filtered (file, "\n");
+
       /* 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 (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+           len += strlen (valid_options->arg[i]->name);
          if (max_len < len)
            max_len = len;
        }
@@ -981,10 +1064,17 @@ The following disassembler options are supported for use with the\n\
       for (i = 0, max_len++; valid_options->name[i] != NULL; i++)
        {
          fprintf_filtered (file, "  %s", valid_options->name[i]);
+         if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+           fprintf_filtered (file, "%s", valid_options->arg[i]->name);
          if (valid_options->description[i] != NULL)
-           fprintf_filtered (file, "%*c %s",
-                             (int)(max_len - strlen (valid_options->name[i])), ' ',
-                             valid_options->description[i]);
+           {
+             size_t len = strlen (valid_options->name[i]);
+
+             if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+               len += strlen (valid_options->arg[i]->name);
+             fprintf_filtered (file, "%*c %s", (int) (max_len - len), ' ',
+                               valid_options->description[i]);
+           }
          fprintf_filtered (file, "\n");
        }
     }
@@ -995,12 +1085,33 @@ The following disassembler options are supported for use with the\n\
       for (i = 0; valid_options->name[i] != NULL; i++)
        {
          fprintf_filtered (file, "%s", valid_options->name[i]);
+         if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+           fprintf_filtered (file, "%s", valid_options->arg[i]->name);
          if (valid_options->name[i + 1] != NULL)
            fprintf_filtered (file, ", ");
          wrap_here ("  ");
        }
       fprintf_filtered (file, "\n");
     }
+
+  valid_args = valid_options_and_args->args;
+  if (valid_args != NULL)
+    {
+      size_t i, j;
+
+      for (i = 0; valid_args[i].name != NULL; i++)
+       {
+         fprintf_filtered (file, _("\n\
+  For the options above, the following values are supported for \"%s\":\n   "),
+                           valid_args[i].name);
+         for (j = 0; valid_args[i].values[j] != NULL; j++)
+           {
+             fprintf_filtered (file, " %s", valid_args[i].values[j]);
+             wrap_here ("   ");
+           }
+         fprintf_filtered (file, "\n");
+       }
+    }
 }
 
 /* A completion function for "set disassembler".  */
@@ -1011,10 +1122,13 @@ disassembler_options_completer (struct cmd_list_element *ignore,
                                const char *text, const char *word)
 {
   struct gdbarch *gdbarch = get_current_arch ();
-  const disasm_options_t *opts = gdbarch_valid_disassembler_options (gdbarch);
+  const disasm_options_and_args_t *opts_and_args
+    = gdbarch_valid_disassembler_options (gdbarch);
 
-  if (opts != NULL)
+  if (opts_and_args != NULL)
     {
+      const disasm_options_t *opts = &opts_and_args->options;
+
       /* Only attempt to complete on the last option text.  */
       const char *separator = strrchr (text, ',');
       if (separator != NULL)
@@ -1027,8 +1141,9 @@ disassembler_options_completer (struct cmd_list_element *ignore,
 
 /* Initialization code.  */
 
+void _initialize_disasm ();
 void
-_initialize_disasm (void)
+_initialize_disasm ()
 {
   struct cmd_list_element *cmd;
 
@@ -1037,7 +1152,7 @@ _initialize_disasm (void)
                                         &prospective_options, _("\
 Set the disassembler options.\n\
 Usage: set disassembler-options OPTION [,OPTION]...\n\n\
-See: 'show disassembler-options' for valid option values.\n"), _("\
+See: 'show disassembler-options' for valid option values."), _("\
 Show the disassembler options."), NULL,
                                         set_disassembler_options_sfunc,
                                         show_disassembler_options_sfunc,
This page took 0.051679 seconds and 4 git commands to generate.