2011-07-22 Phil Muldoon <pmuldoon@redhat.com>
[deliverable/binutils-gdb.git] / gdb / macrocmd.c
index 65d8cd4eda3be233630d59e9d69840050ce354d8..d1ac7fae32548bff3f89db86377ab5af334de97c 100644 (file)
@@ -1,12 +1,13 @@
 /* C preprocessor macro expansion commands for GDB.
-   Copyright 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
    Contributed by Red Hat, 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,
@@ -15,9 +16,7 @@
    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"
@@ -26,6 +25,7 @@
 #include "macroscope.h"
 #include "command.h"
 #include "gdbcmd.h"
+#include "gdb_string.h"
 
 \f
 /* The `macro' prefix command.  */
@@ -51,6 +51,7 @@ macro_expand_command (char *exp, int from_tty)
   struct macro_scope *ms = NULL;
   char *expanded = NULL;
   struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+
   make_cleanup (free_current_contents, &expanded);
 
   /* You know, when the user doesn't specify any expression, it would be
@@ -116,7 +117,10 @@ macro_expand_once_command (char *exp, int from_tty)
   return;
 }
 
+/*  Outputs the include path of a macro starting at FILE and LINE to STREAM.
 
+    Care should be taken that this function does not cause any lookups into
+    the splay tree so that it can be safely used while iterating.  */
 static void
 show_pp_source_pos (struct ui_file *stream,
                     struct macro_source_file *file,
@@ -133,6 +137,46 @@ show_pp_source_pos (struct ui_file *stream,
     }
 }
 
+/* Outputs a macro for human consumption, detailing the include path
+   and macro definition.  NAME is the name of the macro.
+   D the definition.  FILE the start of the include path, and LINE the
+   line number in FILE.
+
+   Care should be taken that this function does not cause any lookups into
+   the splay tree so that it can be safely used while iterating.  */
+static void
+print_macro_definition (const char *name,
+                       const struct macro_definition *d,
+                       struct macro_source_file *file,
+                       int line)
+{
+      fprintf_filtered (gdb_stdout, "Defined at ");
+      show_pp_source_pos (gdb_stdout, file, line);
+
+      if (line != 0)
+       fprintf_filtered (gdb_stdout, "#define %s", name);
+      else
+       fprintf_filtered (gdb_stdout, "-D%s", name);
+
+      if (d->kind == macro_function_like)
+        {
+          int i;
+
+          fputs_filtered ("(", gdb_stdout);
+          for (i = 0; i < d->argc; i++)
+            {
+              fputs_filtered (d->argv[i], gdb_stdout);
+              if (i + 1 < d->argc)
+                fputs_filtered (", ", gdb_stdout);
+            }
+          fputs_filtered (")", gdb_stdout);
+        }
+
+      if (line != 0)
+       fprintf_filtered (gdb_stdout, " %s\n", d->replacement);
+      else
+       fprintf_filtered (gdb_stdout, "=%s\n", d->replacement);
+}
 
 static void
 info_macro_command (char *name, int from_tty)
@@ -140,7 +184,7 @@ info_macro_command (char *name, int from_tty)
   struct macro_scope *ms = NULL;
   struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
   struct macro_definition *d;
-  
+
   if (! name || ! *name)
     error (_("You must follow the `info macro' command with the name"
            " of the macro\n"
@@ -157,23 +201,7 @@ info_macro_command (char *name, int from_tty)
       struct macro_source_file *file
         = macro_definition_location (ms->file, ms->line, name, &line);
 
-      fprintf_filtered (gdb_stdout, "Defined at ");
-      show_pp_source_pos (gdb_stdout, file, line);
-      fprintf_filtered (gdb_stdout, "#define %s", name);
-      if (d->kind == macro_function_like)
-        {
-          int i;
-
-          fputs_filtered ("(", gdb_stdout);
-          for (i = 0; i < d->argc; i++)
-            {
-              fputs_filtered (d->argv[i], gdb_stdout);
-              if (i + 1 < d->argc)
-                fputs_filtered (", ", gdb_stdout);
-            }
-          fputs_filtered (")", gdb_stdout);
-        }
-      fprintf_filtered (gdb_stdout, " %s\n", d->replacement);
+      print_macro_definition (name, d, file, line);
     }
   else
     {
@@ -187,38 +215,252 @@ info_macro_command (char *name, int from_tty)
   do_cleanups (cleanup_chain);
 }
 
+/* A callback function for usage with macro_for_each and friends.
+   If USER_DATA is null all macros will be printed.
+   Otherwise USER_DATA is considered to be a string, printing
+   only macros who's NAME matches USER_DATA.  Other arguments are
+   routed to print_macro_definition.  */
+static void
+print_macro_callback (const char *name, const struct macro_definition *macro,
+                  struct macro_source_file *source, int line,
+                  void *user_data)
+{
+  if (! user_data || strcmp (user_data, name) == 0)
+    print_macro_definition (name, macro, source, line);
+}
+
+/* Implementation of the "info definitions" command. */
+static void
+info_definitions_command (char *name, int from_tty)
+{
+  struct macro_scope *ms = NULL;
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+
+  if (! name || ! *name)
+    error (_("The `info definitions' command requires a macro name as an \
+argument."));
+
+  ms = default_macro_scope ();
+
+  if (! ms || ! ms->file || ! ms->file->table)
+    error (_("GDB has no preprocessor macro information for that code."));
+
+  macro_for_each (ms->file->table, print_macro_callback, name);
+  do_cleanups (cleanup_chain);
+}
+
+/* Implementation of the "info macros" command. */
+static void
+info_macros_command (char *args, int from_tty)
+{
+  struct macro_scope *ms = NULL;
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+
+  if (args == NULL)
+    ms = default_macro_scope ();
+  else
+    {
+      struct symtabs_and_lines sals = decode_line_spec (args, 0);
+
+      if (sals.nelts)
+        ms = sal_macro_scope (sals.sals[0]);
+    }
+
+  if (! ms || ! ms->file || ! ms->file->table)
+    error (_("GDB has no preprocessor macro information for that code."));
+
+  macro_for_each_in_scope (ms->file, ms->line, print_macro_callback, NULL);
+  do_cleanups (cleanup_chain);
+}
 
 \f
 /* User-defined macros.  */
 
-/* A table of user-defined macros.  Unlike the macro tables used for
-   symtabs, this one uses xmalloc for all its allocation, not an
-   obstack, and it doesn't bcache anything; it just xmallocs things.  So
-   it's perfectly possible to remove things from this, or redefine
-   things.  */
-static struct macro_table *user_macros;
+static void
+skip_ws (char **expp)
+{
+  while (macro_is_whitespace (**expp))
+    ++*expp;
+}
+
+/* Try to find the bounds of an identifier.  If an identifier is
+   found, returns a newly allocated string; otherwise returns NULL.
+   EXPP is a pointer to an input string; it is updated to point to the
+   text following the identifier.  If IS_PARAMETER is true, this
+   function will also allow "..." forms as used in varargs macro
+   parameters.  */
+
+static char *
+extract_identifier (char **expp, int is_parameter)
+{
+  char *result;
+  char *p = *expp;
+  unsigned int len;
+
+  if (is_parameter && !strncmp (p, "...", 3))
+    {
+      /* Ok.  */
+    }
+  else
+    {
+      if (! *p || ! macro_is_identifier_nondigit (*p))
+       return NULL;
+      for (++p;
+          *p && (macro_is_identifier_nondigit (*p) || macro_is_digit (*p));
+          ++p)
+       ;
+    }
+
+  if (is_parameter && !strncmp (p, "...", 3))      
+    p += 3;
+
+  len = p - *expp;
+  result = (char *) xmalloc (len + 1);
+  memcpy (result, *expp, len);
+  result[len] = '\0';
+  *expp += len;
+  return result;
+}
+
+/* Helper function to clean up a temporarily-constructed macro object.
+   This assumes that the contents were all allocated with xmalloc.  */
+static void
+free_macro_definition_ptr (void *ptr)
+{
+  int i;
+  struct macro_definition *loc = (struct macro_definition *) ptr;
+
+  for (i = 0; i < loc->argc; ++i)
+    xfree ((char *) loc->argv[i]);
+  xfree ((char *) loc->argv);
+  /* Note that the 'replacement' field is not allocated.  */
+}
 
 static void
 macro_define_command (char *exp, int from_tty)
 {
-  error (_("Command not implemented yet."));
+  struct macro_definition new_macro;
+  char *name = NULL;
+  struct cleanup *cleanup_chain;
+
+  if (!exp)
+    error (_("usage: macro define NAME[(ARGUMENT-LIST)] [REPLACEMENT-LIST]"));
+
+  cleanup_chain = make_cleanup (free_macro_definition_ptr, &new_macro);
+  make_cleanup (free_current_contents, &name);
+
+  memset (&new_macro, 0, sizeof (struct macro_definition));
+
+  skip_ws (&exp);
+  name = extract_identifier (&exp, 0);
+  if (! name)
+    error (_("Invalid macro name."));
+  if (*exp == '(')
+    {
+      /* Function-like macro.  */
+      int alloced = 5;
+      char **argv = (char **) xmalloc (alloced * sizeof (char *));
+
+      new_macro.kind = macro_function_like;
+      new_macro.argc = 0;
+      new_macro.argv = (const char * const *) argv;
+
+      /* Skip the '(' and whitespace.  */
+      ++exp;
+      skip_ws (&exp);
+
+      while (*exp != ')')
+       {
+         int i;
+
+         if (new_macro.argc == alloced)
+           {
+             alloced *= 2;
+             argv = (char **) xrealloc (argv, alloced * sizeof (char *));
+             /* Must update new_macro as well...  */
+             new_macro.argv = (const char * const *) argv;
+           }
+         argv[new_macro.argc] = extract_identifier (&exp, 1);
+         if (! argv[new_macro.argc])
+           error (_("Macro is missing an argument."));
+         ++new_macro.argc;
+
+         for (i = new_macro.argc - 2; i >= 0; --i)
+           {
+             if (! strcmp (argv[i], argv[new_macro.argc - 1]))
+               error (_("Two macro arguments with identical names."));
+           }
+
+         skip_ws (&exp);
+         if (*exp == ',')
+           {
+             ++exp;
+             skip_ws (&exp);
+           }
+         else if (*exp != ')')
+           error (_("',' or ')' expected at end of macro arguments."));
+       }
+      /* Skip the closing paren.  */
+      ++exp;
+      skip_ws (&exp);
+
+      macro_define_function (macro_main (macro_user_macros), -1, name,
+                            new_macro.argc, (const char **) new_macro.argv,
+                            exp);
+    }
+  else
+    {
+      skip_ws (&exp);
+      macro_define_object (macro_main (macro_user_macros), -1, name, exp);
+    }
+
+  do_cleanups (cleanup_chain);
 }
 
 
 static void
 macro_undef_command (char *exp, int from_tty)
 {
-  error (_("Command not implemented yet."));
+  char *name;
+
+  if (!exp)
+    error (_("usage: macro undef NAME"));
+
+  skip_ws (&exp);
+  name = extract_identifier (&exp, 0);
+  if (! name)
+    error (_("Invalid macro name."));
+  macro_undef (macro_main (macro_user_macros), -1, name);
+  xfree (name);
 }
 
 
 static void
-macro_list_command (char *exp, int from_tty)
+print_one_macro (const char *name, const struct macro_definition *macro,
+                struct macro_source_file *source, int line,
+                void *ignore)
 {
-  error (_("Command not implemented yet."));
+  fprintf_filtered (gdb_stdout, "macro define %s", name);
+  if (macro->kind == macro_function_like)
+    {
+      int i;
+
+      fprintf_filtered (gdb_stdout, "(");
+      for (i = 0; i < macro->argc; ++i)
+       fprintf_filtered (gdb_stdout, "%s%s", (i > 0) ? ", " : "",
+                         macro->argv[i]);
+      fprintf_filtered (gdb_stdout, ")");
+    }
+  fprintf_filtered (gdb_stdout, " %s\n", macro->replacement);
 }
 
 
+static void
+macro_list_command (char *exp, int from_tty)
+{
+  macro_for_each (macro_user_macros, print_one_macro, NULL);
+}
+
 \f
 /* Initializing the `macrocmd' module.  */
 
@@ -227,8 +469,6 @@ extern initialize_file_ftype _initialize_macrocmd; /* -Wmissing-prototypes */
 void
 _initialize_macrocmd (void)
 {
-  struct cmd_list_element *c;
-
   /* We introduce a new command prefix, `macro', under which we'll put
      the various commands for working with preprocessor macros.  */
   add_prefix_cmd ("macro", class_info, macro_command,
@@ -258,6 +498,17 @@ expression work together to yield a pre-processed expression."),
           _("Show the definition of MACRO, and its source location."),
           &infolist);
 
+  add_cmd ("macros", no_class, info_macros_command,
+          _("Show the definitions of all macros at LINESPEC, or the current \
+source location.\n\
+Usage: info macros [LINESPEC]"),
+          &infolist);
+
+  add_cmd ("definitions", no_class, info_definitions_command,
+          _("Show all definitions of MACRO in the current compilation unit.\n\
+Usage: info definitions MACRO"),
+          &infolist);
+
   add_cmd ("define", no_class, macro_define_command, _("\
 Define a new C/C++ preprocessor macro.\n\
 The GDB command `macro define DEFINITION' is equivalent to placing a\n\
@@ -275,6 +526,4 @@ Remove the definition of the C/C++ preprocessor macro with the given name."),
   add_cmd ("list", no_class, macro_list_command,
           _("List all the macros defined using the `macro define' command."),
           &macrolist);
-
-  user_macros = new_macro_table (0, 0);
 }
This page took 0.027074 seconds and 4 git commands to generate.