gdb/mi: Add -symbol-info-module-{variables,functions}
[deliverable/binutils-gdb.git] / gdb / mi / mi-symbol-cmds.c
index 01ba17e857009eb81d4f006d4b500240ba58d3dd..2bebd11f799e5d9da2771160d114023b7156afb4 100644 (file)
@@ -1,11 +1,11 @@
 /* MI Command Set - symbol commands.
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "mi-cmds.h"
 #include "symtab.h"
+#include "objfiles.h"
 #include "ui-out.h"
+#include "source.h"
+#include "mi-getopt.h"
 
-/* SYMBOL-LIST-LINES:
+/* Print the list of all pc addresses and lines of code for the
+   provided (full or base) source file name.  The entries are sorted
+   in ascending PC order.  */
 
-   Print the list of all pc addresses and lines of code for
-   the provided (full or base) source file name.  The entries
-   are sorted in ascending PC order. */
-
-enum mi_cmd_result
-mi_cmd_symbol_list_lines (char *command, char **argv, int argc)
+void
+mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
 {
+  struct gdbarch *gdbarch;
   char *filename;
   struct symtab *s;
   int i;
-  struct cleanup *cleanup_stack, *cleanup_tuple;
+  struct ui_out *uiout = current_uiout;
 
   if (argc != 1)
-    error (_("mi_cmd_symbol_list_lines: Usage: SOURCE_FILENAME"));
+    error (_("-symbol-list-lines: Usage: SOURCE_FILENAME"));
 
   filename = argv[0];
   s = lookup_symtab (filename);
 
   if (s == NULL)
-    error (_("mi_cmd_symbol_list_lines: Unknown source file name."));
+    error (_("-symbol-list-lines: Unknown source file name."));
+
+  /* Now, dump the associated line table.  The pc addresses are
+     already sorted by increasing values in the symbol table, so no
+     need to perform any other sorting.  */
+
+  gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
+
+  ui_out_emit_list list_emitter (uiout, "lines");
+  if (SYMTAB_LINETABLE (s) != NULL && SYMTAB_LINETABLE (s)->nitems > 0)
+    for (i = 0; i < SYMTAB_LINETABLE (s)->nitems; i++)
+    {
+      ui_out_emit_tuple tuple_emitter (uiout, NULL);
+      uiout->field_core_addr ("pc", gdbarch, SYMTAB_LINETABLE (s)->item[i].pc);
+      uiout->field_signed ("line", SYMTAB_LINETABLE (s)->item[i].line);
+    }
+}
+
+/* Used by the -symbol-info-* and -symbol-info-module-* commands to print
+   information about the symbol SYM in a block of index BLOCK (either
+   GLOBAL_BLOCK or STATIC_BLOCK).  KIND is the kind of symbol we searched
+   for in order to find SYM, which impact which fields are displayed in the
+   results.  */
+
+static void
+output_debug_symbol (ui_out *uiout, enum search_domain kind,
+                    struct symbol *sym, int block)
+{
+  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+
+  if (SYMBOL_LINE (sym) != 0)
+    uiout->field_unsigned ("line", SYMBOL_LINE (sym));
+  uiout->field_string ("name", sym->print_name ());
+
+  if (kind == FUNCTIONS_DOMAIN || kind == VARIABLES_DOMAIN)
+    {
+      string_file tmp_stream;
+      type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
+      uiout->field_string ("type", tmp_stream.string ());
+
+      std::string str = symbol_to_info_string (sym, block, kind);
+      uiout->field_string ("description", str);
+    }
+}
+
+/* Actually output one nondebug symbol, puts a tuple emitter in place
+   and then outputs the fields for this msymbol.  */
+
+static void
+output_nondebug_symbol (ui_out *uiout,
+                       const struct bound_minimal_symbol &msymbol)
+{
+  struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
+  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+
+  uiout->field_core_addr ("address", gdbarch,
+                         BMSYMBOL_VALUE_ADDRESS (msymbol));
+  uiout->field_string ("name", msymbol.minsym->print_name ());
+}
+
+/* This is the guts of the commands '-symbol-info-functions',
+   '-symbol-info-variables', and '-symbol-info-types'.  It searches for
+   symbols matching KING, NAME_REGEXP, TYPE_REGEXP, and EXCLUDE_MINSYMS,
+   and then prints the matching [m]symbols in an MI structured format.  */
+
+static void
+mi_symbol_info (enum search_domain kind, const char *name_regexp,
+               const char *type_regexp, bool exclude_minsyms)
+{
+  global_symbol_searcher sym_search (kind, name_regexp);
+  sym_search.set_symbol_type_regexp (type_regexp);
+  sym_search.set_exclude_minsyms (exclude_minsyms);
+  std::vector<symbol_search> symbols = sym_search.search ();
+  ui_out *uiout = current_uiout;
+  int i = 0;
+
+  ui_out_emit_tuple outer_symbols_emitter (uiout, "symbols");
+
+  /* Debug symbols are placed first. */
+  if (i < symbols.size () && symbols[i].msymbol.minsym == nullptr)
+    {
+      ui_out_emit_list debug_symbols_list_emitter (uiout, "debug");
 
-  /* Now, dump the associated line table.  The pc addresses are already
-     sorted by increasing values in the symbol table, so no need to
-     perform any other sorting. */
+      /* As long as we have debug symbols...  */
+      while (i < symbols.size () && symbols[i].msymbol.minsym == nullptr)
+       {
+         symtab *symtab = symbol_symtab (symbols[i].symbol);
+         ui_out_emit_tuple symtab_tuple_emitter (uiout, nullptr);
 
-  cleanup_stack = make_cleanup_ui_out_list_begin_end (uiout, "lines");
+         uiout->field_string ("filename",
+                              symtab_to_filename_for_display (symtab));
+         uiout->field_string ("fullname", symtab_to_fullname (symtab));
 
-  if (LINETABLE (s) != NULL && LINETABLE (s)->nitems > 0)
-    for (i = 0; i < LINETABLE (s)->nitems; i++)
+         ui_out_emit_list symbols_list_emitter (uiout, "symbols");
+
+         /* As long as we have debug symbols from this symtab...  */
+         for (; (i < symbols.size ()
+                 && symbols[i].msymbol.minsym == nullptr
+                 && symbol_symtab (symbols[i].symbol) == symtab);
+              ++i)
+           {
+             symbol_search &s = symbols[i];
+
+             output_debug_symbol (uiout, kind, s.symbol, s.block);
+           }
+       }
+    }
+
+  /* Non-debug symbols are placed after.  */
+  if (i < symbols.size ())
     {
-      cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-      ui_out_field_core_addr (uiout, "pc", LINETABLE (s)->item[i].pc);
-      ui_out_field_int (uiout, "line", LINETABLE (s)->item[i].line);
-      do_cleanups (cleanup_tuple);
+      ui_out_emit_list nondebug_symbols_list_emitter (uiout, "nondebug");
+
+      /* As long as we have nondebug symbols...  */
+      for (; i < symbols.size (); i++)
+       {
+         gdb_assert (symbols[i].msymbol.minsym != nullptr);
+         output_nondebug_symbol (uiout, symbols[i].msymbol);
+       }
     }
+}
+
+/* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
+   Processes command line options from ARGV and ARGC.  */
+
+static void
+mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+  const char *t_regexp = nullptr;
+  bool exclude_minsyms = true;
+
+  enum opt
+    {
+     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0},
+    {"-type", TYPE_REGEXP_OPT, 1},
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      const char *cmd_string
+       = ((kind == FUNCTIONS_DOMAIN)
+          ? "-symbol-info-functions" : "-symbol-info-variables");
+      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
+      if (opt < 0)
+       break;
+      switch ((enum opt) opt)
+       {
+       case INCLUDE_NONDEBUG_OPT:
+         exclude_minsyms = false;
+         break;
+       case TYPE_REGEXP_OPT:
+         t_regexp = oarg;
+         break;
+       case NAME_REGEXP_OPT:
+         regexp = oarg;
+         break;
+       }
+    }
+
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+}
+
+/* Type for an iterator over a vector of module_symbol_search results.  */
+typedef std::vector<module_symbol_search>::const_iterator
+       module_symbol_search_iterator;
+
+/* Helper for mi_info_module_functions_or_variables.  Display the results
+   from ITER up to END or until we find a symbol that is in a different
+   module, or in a different symtab than the first symbol we print.  Update
+   and return the new value for ITER.  */
+static module_symbol_search_iterator
+output_module_symbols_in_single_module_and_file
+       (struct ui_out *uiout, module_symbol_search_iterator iter,
+        const module_symbol_search_iterator end, enum search_domain kind)
+{
+  /* The symbol for the module in which the first result resides.  */
+  const symbol *first_module_symbol = iter->first.symbol;
+
+  /* The symbol for the first result, and the symtab in which it resides.  */
+  const symbol *first_result_symbol = iter->second.symbol;
+  symtab *first_symbtab = symbol_symtab (first_result_symbol);
+
+  /* Formatted output.  */
+  ui_out_emit_tuple current_file (uiout, nullptr);
+  uiout->field_string ("filename",
+                      symtab_to_filename_for_display (first_symbtab));
+  uiout->field_string ("fullname", symtab_to_fullname (first_symbtab));
+  ui_out_emit_list item_list (uiout, "symbols");
+
+  /* Repeatedly output result symbols until either we run out of symbols,
+     we change module, or we change symtab.  */
+  for (; (iter != end
+         && first_module_symbol == iter->first.symbol
+         && first_symbtab == symbol_symtab (iter->second.symbol));
+       ++iter)
+    output_debug_symbol (uiout, kind, iter->second.symbol,
+                        iter->second.block);
+
+  return iter;
+}
+
+/* Helper for mi_info_module_functions_or_variables.  Display the results
+   from ITER up to END or until we find a symbol that is in a different
+   module than the first symbol we print.  Update and return the new value
+   for ITER.  */
+static module_symbol_search_iterator
+output_module_symbols_in_single_module
+       (struct ui_out *uiout, module_symbol_search_iterator iter,
+        const module_symbol_search_iterator end, enum search_domain kind)
+{
+  gdb_assert (iter->first.symbol != nullptr);
+  gdb_assert (iter->second.symbol != nullptr);
 
-  do_cleanups (cleanup_stack);
+  /* The symbol for the module in which the first result resides.  */
+  const symbol *first_module_symbol = iter->first.symbol;
 
-  return MI_CMD_DONE;
+  /* Create output formatting.  */
+  ui_out_emit_tuple module_tuple (uiout, nullptr);
+  uiout->field_string ("module", first_module_symbol->print_name ());
+  ui_out_emit_list files_list (uiout, "files");
+
+  /* The results are sorted so that symbols within the same file are next
+     to each other in the list.  Calling the output function once will
+     print all results within a single file.  We keep calling the output
+     function until we change module.  */
+  while (iter != end && first_module_symbol == iter->first.symbol)
+    iter = output_module_symbols_in_single_module_and_file (uiout, iter,
+                                                           end, kind);
+  return iter;
+}
+
+/* Core of -symbol-info-module-functions and -symbol-info-module-variables.
+   KIND indicates what we are searching for, and ARGV and ARGC are the
+   command line options passed to the MI command.  */
+
+static void
+mi_info_module_functions_or_variables (enum search_domain kind,
+                                       char **argv, int argc)
+{
+  const char *module_regexp = nullptr;
+  const char *regexp = nullptr;
+  const char *type_regexp = nullptr;
+
+  /* Process the command line options.  */
+
+  enum opt
+    {
+     MODULE_REGEXP_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-module", MODULE_REGEXP_OPT, 1},
+    {"-type", TYPE_REGEXP_OPT, 1},
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      const char *cmd_string
+       = ((kind == FUNCTIONS_DOMAIN)
+          ? "-symbol-info-module-functions"
+          : "-symbol-info-module-variables");
+      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
+      if (opt < 0)
+       break;
+      switch ((enum opt) opt)
+       {
+       case MODULE_REGEXP_OPT:
+         module_regexp = oarg;
+         break;
+       case TYPE_REGEXP_OPT:
+         type_regexp = oarg;
+         break;
+       case NAME_REGEXP_OPT:
+         regexp = oarg;
+         break;
+       }
+    }
+
+  std::vector<module_symbol_search> module_symbols
+    = search_module_symbols (module_regexp, regexp, type_regexp, kind);
+
+  struct ui_out *uiout = current_uiout;
+  ui_out_emit_list all_matching_symbols (uiout, "symbols");
+
+  /* The results in the module_symbols list are ordered so symbols in the
+     same module are next to each other.  Repeatedly call the output
+     function to print sequences of symbols that are in the same module
+     until we have no symbols left to print.  */
+  module_symbol_search_iterator iter = module_symbols.begin ();
+  const module_symbol_search_iterator end = module_symbols.end ();
+  while (iter != end)
+    iter = output_module_symbols_in_single_module (uiout, iter, end, kind);
+}
+
+/* Implement -symbol-info-functions command.  */
+
+void
+mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-info-module-functions command.  */
+
+void
+mi_cmd_symbol_info_module_functions (const char *command, char **argv,
+                                    int argc)
+{
+  mi_info_module_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-info-module-variables command.  */
+
+void
+mi_cmd_symbol_info_module_variables (const char *command, char **argv,
+                                    int argc)
+{
+  mi_info_module_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-inf-modules command.  */
+
+void
+mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+
+  enum opt
+    {
+     NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      int opt = mi_getopt ("-symbol-info-modules", argc, argv, opts,
+                          &oind, &oarg);
+      if (opt < 0)
+       break;
+      switch ((enum opt) opt)
+       {
+       case NAME_REGEXP_OPT:
+         regexp = oarg;
+         break;
+       }
+    }
+
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+}
+
+/* Implement -symbol-info-types command.  */
+
+void
+mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+
+  enum opt
+    {
+     NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (true)
+    {
+      int opt = mi_getopt ("-symbol-info-types", argc, argv, opts,
+                          &oind, &oarg);
+      if (opt < 0)
+       break;
+      switch ((enum opt) opt)
+       {
+       case NAME_REGEXP_OPT:
+         regexp = oarg;
+         break;
+       }
+    }
+
+  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true);
+}
+
+/* Implement -symbol-info-variables command.  */
+
+void
+mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
 }
This page took 0.028213 seconds and 4 git commands to generate.