This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: RFA: Patch: implement missing macro functions
>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
Eli> We use @code for GDB commands, not @command. (Yes, I know it was like
Eli> that in the original text.) Other than that, the patch for the manual
Eli> is fine with me.
I fixed all the macro-related uses of @command.
Eli> Btw, I think these new commands deserve a NEWS entry.
Done.
Here's a new patch. Let me know what you think.
Tom
ChangeLog:
2008-05-23 Tom Tromey <tromey@redhat.com>
* NEWS: Add entry for macro commands.
* macroscope.h (user_macro_scope): Declare.
(default_macro_scope): Update documentation.
* c-lang.c (c_preprocess_and_parse): Always attempt macro lookup.
Use user_macro_scope.
(null_macro_lookup): Remove.
* macrotab.h (macro_define_user, macro_definition_delete,
macro_user_macros): Declare.
(macro_callback_fn): Declare.
(macro_for_each): Likewise.
* macrotab.c (macro_definition_delete): New function.
(macro_tree_delete_value): Use it.
(macro_define_user): New function.
(macro_lookup_definition): Look in user-defined macro table.
(foreach_macro): New function
(macro_for_each): Likewise.
* macroscope.c (user_macro_scope): New function.
(default_macro_scope): Use it.
* macroexp.h (macro_is_whitespace, macro_is_digit,
macro_is_identifier_nondigit): Declare.
* macroexp.c (macro_is_whitespace): Rename. No longer static.
(macro_is_digit): Likewise.
(macro_is_identifier_nondigit): Likewise.
(get_identifier): Update.
(get_pp_number): Likewise.
(get_token): Likewise.
* macrocmd.c (skip_ws): New function.
(extract_identifier): Likewise.
(free_macro_definition_ptr): Likewise.
(macro_user_macros): Rename from user_macros. No longer static.
(macro_define_command): Implement.
(_initialize_macrocmd): Update. Set main file on
macro_user_macros.
(macro_undef_command): Implement.
(print_one_macro): New function.
(macro_list_command): Implement.
testsuite/ChangeLog:
2008-05-23 Tom Tromey <tromey@redhat.com>
* gdb.base/macscp.exp: Add macro tests.
doc/ChangeLog:
2008-05-23 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Macros): Update. Use @code rather than @command.
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.273
diff -u -r1.273 NEWS
--- NEWS 9 May 2008 19:17:46 -0000 1.273
+++ NEWS 23 May 2008 21:07:18 -0000
@@ -78,6 +78,12 @@
the current CPSR value for instructions without symbols; previous
versions of GDB behaved as if "set arm fallback-mode arm".
+macro define
+macro list
+macro undef
+ These commands are now implemented. These allow macros to be
+ defined, undefined, and listed interactively.
+
*** Changes in GDB 6.8
* New native configurations
Index: c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.53
diff -u -r1.53 c-lang.c
--- c-lang.c 6 Apr 2008 08:56:36 -0000 1.53
+++ c-lang.c 23 May 2008 21:07:18 -0000
@@ -261,13 +261,6 @@
void *expression_macro_lookup_baton;
-static struct macro_definition *
-null_macro_lookup (const char *name, void *baton)
-{
- return 0;
-}
-
-
static int
c_preprocess_and_parse (void)
{
@@ -279,17 +272,11 @@
scope = sal_macro_scope (find_pc_line (expression_context_pc, 0));
else
scope = default_macro_scope ();
+ if (! scope)
+ scope = user_macro_scope ();
- if (scope)
- {
- expression_macro_lookup_func = standard_macro_lookup;
- expression_macro_lookup_baton = (void *) scope;
- }
- else
- {
- expression_macro_lookup_func = null_macro_lookup;
- expression_macro_lookup_baton = 0;
- }
+ expression_macro_lookup_func = standard_macro_lookup;
+ expression_macro_lookup_baton = (void *) scope;
gdb_assert (! macro_original_text);
make_cleanup (scan_macro_cleanup, 0);
Index: macrocmd.c
===================================================================
RCS file: /cvs/src/src/gdb/macrocmd.c,v
retrieving revision 1.13
diff -u -r1.13 macrocmd.c
--- macrocmd.c 1 Jan 2008 22:53:12 -0000 1.13
+++ macrocmd.c 23 May 2008 21:07:18 -0000
@@ -24,6 +24,7 @@
#include "macroscope.h"
#include "command.h"
#include "gdbcmd.h"
+#include "gdb_string.h"
/* The `macro' prefix command. */
@@ -189,31 +190,159 @@
/* User-defined macros. */
+static void
+skip_ws (char **expp)
+{
+ while (macro_is_whitespace (**expp))
+ ++*expp;
+}
+
+static char *
+extract_identifier (char **expp)
+{
+ char *result;
+ char *p = *expp;
+ unsigned int len;
+ if (! *p || ! macro_is_identifier_nondigit (*p))
+ return NULL;
+ for (++p;
+ *p && (macro_is_identifier_nondigit (*p) || macro_is_digit (*p));
+ ++p)
+ ;
+ len = p - *expp;
+ result = (char *) xmalloc (len + 1);
+ memcpy (result, *expp, len);
+ result[len] = '\0';
+ *expp += len;
+ return result;
+}
+
+static void
+free_macro_definition_ptr (void *ptr)
+{
+ struct macro_definition **loc = (struct macro_definition **) ptr;
+ if (*loc)
+ macro_definition_delete (*loc);
+}
+
/* 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;
+struct macro_table *macro_user_macros;
static void
macro_define_command (char *exp, int from_tty)
{
- error (_("Command not implemented yet."));
+ struct macro_definition *new_macro = NULL;
+ char *name = NULL;
+ struct cleanup *cleanup_chain = make_cleanup (free_macro_definition_ptr,
+ &new_macro);
+ make_cleanup (free_current_contents, &name);
+
+ new_macro = XZALLOC (struct macro_definition);
+ new_macro->table = macro_user_macros;
+
+ skip_ws (&exp);
+ name = extract_identifier (&exp);
+ 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);
+ 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;
+ }
+ else
+ new_macro->kind = macro_object_like;
+
+ new_macro->replacement = xstrdup (exp);
+
+ macro_define_user (name, new_macro);
+ xfree (name);
+ discard_cleanups (cleanup_chain);
}
static void
macro_undef_command (char *exp, int from_tty)
{
- error (_("Command not implemented yet."));
+ char *name;
+ skip_ws (&exp);
+ name = extract_identifier (&exp);
+ if (! name)
+ error (_("Invalid macro name."));
+ macro_undef (macro_main (macro_user_macros), -1, name);
+ xfree (name);
+}
+
+
+static void
+print_one_macro (const char *name, const struct macro_definition *macro)
+{
+ 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, ")");
+ }
+ /* Note that we don't need a leading space here -- "macro define"
+ provided it. */
+ fprintf_filtered (gdb_stdout, "%s\n", macro->replacement);
}
static void
macro_list_command (char *exp, int from_tty)
{
- error (_("Command not implemented yet."));
+ macro_for_each (macro_user_macros, print_one_macro);
}
@@ -274,5 +403,6 @@
_("List all the macros defined using the `macro define' command."),
¯olist);
- user_macros = new_macro_table (0, 0);
+ macro_user_macros = new_macro_table (0, 0);
+ macro_set_main (macro_user_macros, "<user-defined>");
}
Index: macroexp.c
===================================================================
RCS file: /cvs/src/src/gdb/macroexp.c,v
retrieving revision 1.13
diff -u -r1.13 macroexp.c
--- macroexp.c 1 Jan 2008 22:53:12 -0000 1.13
+++ macroexp.c 23 May 2008 21:07:18 -0000
@@ -171,8 +171,8 @@
/* Recognizing preprocessor tokens. */
-static int
-is_whitespace (int c)
+int
+macro_is_whitespace (int c)
{
return (c == ' '
|| c == '\t'
@@ -182,15 +182,15 @@
}
-static int
-is_digit (int c)
+int
+macro_is_digit (int c)
{
return ('0' <= c && c <= '9');
}
-static int
-is_identifier_nondigit (int c)
+int
+macro_is_identifier_nondigit (int c)
{
return (c == '_'
|| ('a' <= c && c <= 'z')
@@ -255,13 +255,13 @@
get_identifier (struct macro_buffer *tok, char *p, char *end)
{
if (p < end
- && is_identifier_nondigit (*p))
+ && macro_is_identifier_nondigit (*p))
{
char *tok_start = p;
while (p < end
- && (is_identifier_nondigit (*p)
- || is_digit (*p)))
+ && (macro_is_identifier_nondigit (*p)
+ || macro_is_digit (*p)))
p++;
set_token (tok, tok_start, p);
@@ -277,15 +277,15 @@
get_pp_number (struct macro_buffer *tok, char *p, char *end)
{
if (p < end
- && (is_digit (*p)
+ && (macro_is_digit (*p)
|| *p == '.'))
{
char *tok_start = p;
while (p < end)
{
- if (is_digit (*p)
- || is_identifier_nondigit (*p)
+ if (macro_is_digit (*p)
+ || macro_is_identifier_nondigit (*p)
|| *p == '.')
p++;
else if (p + 2 <= end
@@ -485,7 +485,7 @@
only occur after a #include, which we will never see. */
while (p < end)
- if (is_whitespace (*p))
+ if (macro_is_whitespace (*p))
p++;
else if (get_comment (tok, p, end))
p += tok->len;
Index: macroexp.h
===================================================================
RCS file: /cvs/src/src/gdb/macroexp.h,v
retrieving revision 1.6
diff -u -r1.6 macroexp.h
--- macroexp.h 1 Jan 2008 22:53:12 -0000 1.6
+++ macroexp.h 23 May 2008 21:07:18 -0000
@@ -84,5 +84,11 @@
macro_lookup_ftype *lookup_func,
void *lookup_baton);
+/* Functions to classify characters according to cpp rules. */
+
+int macro_is_whitespace (int c);
+int macro_is_identifier_nondigit (int c);
+int macro_is_digit (int c);
+
#endif /* MACROEXP_H */
Index: macroscope.c
===================================================================
RCS file: /cvs/src/src/gdb/macroscope.c,v
retrieving revision 1.14
diff -u -r1.14 macroscope.c
--- macroscope.c 1 Jan 2008 22:53:12 -0000 1.14
+++ macroscope.c 23 May 2008 21:07:18 -0000
@@ -78,6 +78,16 @@
struct macro_scope *
+user_macro_scope (void)
+{
+ struct macro_scope *ms;
+ ms = XNEW (struct macro_scope);
+ ms->file = macro_main (macro_user_macros);
+ ms->line = -1;
+ return ms;
+}
+
+struct macro_scope *
default_macro_scope (void)
{
struct symtab_and_line sal;
@@ -110,7 +120,11 @@
sal.line = cursal.line;
}
- return sal_macro_scope (sal);
+ ms = sal_macro_scope (sal);
+ if (! ms)
+ ms = user_macro_scope ();
+
+ return ms;
}
Index: macroscope.h
===================================================================
RCS file: /cvs/src/src/gdb/macroscope.h,v
retrieving revision 1.6
diff -u -r1.6 macroscope.h
--- macroscope.h 1 Jan 2008 22:53:12 -0000 1.6
+++ macroscope.h 23 May 2008 21:07:18 -0000
@@ -39,12 +39,18 @@
struct macro_scope *sal_macro_scope (struct symtab_and_line sal);
+/* Return a `struct macro_scope' object representing just the
+ user-defined macros. The result is allocated using xmalloc; the
+ caller is responsible for freeing it. */
+struct macro_scope *user_macro_scope (void);
+
/* Return a `struct macro_scope' object describing the scope the `macro
expand' and `macro expand-once' commands should use for looking up
macros. If we have a selected frame, this is the source location of
its PC; otherwise, this is the last listing position.
- If we have no macro information for the current location, return zero.
+ If we have no macro information for the current location, return
+ the user macro scope.
The object returned is allocated using xmalloc; the caller is
responsible for freeing it. */
Index: macrotab.c
===================================================================
RCS file: /cvs/src/src/gdb/macrotab.c,v
retrieving revision 1.15
diff -u -r1.15 macrotab.c
--- macrotab.c 1 Jan 2008 22:53:12 -0000 1.15
+++ macrotab.c 23 May 2008 21:07:18 -0000
@@ -587,11 +587,9 @@
}
-/* Free a macro definition. */
-static void
-macro_tree_delete_value (void *untyped_definition)
+void
+macro_definition_delete (struct macro_definition *d)
{
- struct macro_definition *d = (struct macro_definition *) untyped_definition;
struct macro_table *t = d->table;
if (d->kind == macro_function_like)
@@ -608,6 +606,15 @@
}
+/* Free a macro definition. For use by splay trees. */
+static void
+macro_tree_delete_value (void *untyped_definition)
+{
+ struct macro_definition *d = (struct macro_definition *) untyped_definition;
+ macro_definition_delete (d);
+}
+
+
/* Find the splay tree node for the definition of NAME at LINE in
SOURCE, or zero if there is none. */
static splay_tree_node
@@ -786,6 +793,25 @@
void
+macro_define_user (const char *name, struct macro_definition *new_macro)
+{
+ struct macro_key *key;
+ splay_tree_node n = find_definition (name, new_macro->table->main_source, -1);
+
+ if (n)
+ {
+ key = (struct macro_key *) n->key;
+ splay_tree_remove (new_macro->table->definitions, n->key);
+ }
+
+ key = new_macro_key (new_macro->table, name, new_macro->table->main_source,
+ -1);
+ splay_tree_insert (new_macro->table->definitions, (splay_tree_key) key,
+ (splay_tree_value) new_macro);
+}
+
+
+void
macro_undef (struct macro_source_file *source, int line,
const char *name)
{
@@ -845,7 +871,12 @@
macro_lookup_definition (struct macro_source_file *source,
int line, const char *name)
{
- splay_tree_node n = find_definition (name, source, line);
+ splay_tree_node n;
+
+ /* Give user-defined macros priority over all others. */
+ n = find_definition (name, macro_user_macros->main_source, -1);
+ if (! n)
+ n = find_definition (name, source, line);
if (n)
return (struct macro_definition *) n->value;
@@ -873,6 +904,27 @@
}
+/* Helper function for macro_for_each. */
+static int
+foreach_macro (splay_tree_node node, void *fnp)
+{
+ macro_callback_fn *fn = (macro_callback_fn *) fnp;
+ struct macro_key *key = (struct macro_key *) node->key;
+ struct macro_definition *def = (struct macro_definition *) node->value;
+ (**fn) (key->name, def);
+ return 0;
+}
+
+void
+macro_for_each (struct macro_table *table, macro_callback_fn fn)
+{
+ /* Note that we pass in the address of 'fn' because, pedantically
+ speaking, we can't necessarily cast a pointer-to-function to a
+ void*. */
+ splay_tree_foreach (table->definitions, foreach_macro, &fn);
+}
+
+
/* Creating and freeing macro tables. */
Index: macrotab.h
===================================================================
RCS file: /cvs/src/src/gdb/macrotab.h,v
retrieving revision 1.9
diff -u -r1.9 macrotab.h
--- macrotab.h 1 Jan 2008 22:53:12 -0000 1.9
+++ macrotab.h 23 May 2008 21:07:18 -0000
@@ -72,6 +72,8 @@
/* A table of all the macro definitions for a given compilation unit. */
struct macro_table;
+/* The definition of a single macro. */
+struct macro_definition;
/* A source file that participated in a compilation unit --- either a
main file, or an #included file. If a file is #included more than
@@ -241,12 +243,23 @@
const char *replacement);
+/* Record a macro definition given a fully-filled macro_definition
+ object. The object and its contents must be allocated
+ appropriately for the table into which the new macro will be
+ inserted; it is the caller's responsibility to ensure this. A
+ previous macro definition of the same name will be silently
+ removed. NAME is the name of the new macro; it is copied by this
+ function as needed. */
+void macro_define_user (const char *name, struct macro_definition *new_macro);
+
/* Record an #undefinition.
Record in SOURCE's macro table that, at line number LINE in SOURCE,
we removed the definition for the preprocessor symbol named NAME. */
void macro_undef (struct macro_source_file *source, int line,
const char *name);
+/* Delete a macro_definition object. */
+void macro_definition_delete (struct macro_definition *obj);
/* Different kinds of macro definitions. */
enum macro_kind
@@ -298,5 +311,16 @@
const char *name,
int *definition_line));
+/* The table of macros defined by the user. */
+extern struct macro_table *macro_user_macros;
+
+
+/* Callback function when walking a macro table. */
+typedef void (*macro_callback_fn) (const char *,
+ const struct macro_definition *);
+
+/* Call a function for each macro in the table. */
+void macro_for_each (struct macro_table *, macro_callback_fn);
+
#endif /* MACROTAB_H */
Index: testsuite/gdb.base/macscp.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/macscp.exp,v
retrieving revision 1.7
diff -u -r1.7 macscp.exp
--- testsuite/gdb.base/macscp.exp 3 May 2008 22:30:51 -0000 1.7
+++ testsuite/gdb.base/macscp.exp 23 May 2008 21:07:20 -0000
@@ -423,8 +423,52 @@
" = 0" \
"print expression with macro in scope."
+gdb_test "macro define M 72" \
+ "" \
+ "user macro override"
+
+gdb_test "print M" \
+ " = 72" \
+ "choose user macro"
+
+gdb_test "macro undef M" \
+ "" \
+ "remove user override"
+
+gdb_test "print M" \
+ " = 0" \
+ "print expression with macro after removing override"
+
gdb_test "next" "foo = 2;" "next to definition"
gdb_test "print M" \
"No symbol \"M\" in current context\." \
"print expression with macro after undef."
+
+gdb_test "macro define M 5" \
+ "" \
+ "basic macro define"
+
+gdb_test "print M" \
+ " = 5" \
+ "expansion of defined macro"
+
+gdb_test "macro list" \
+ "macro define M 5" \
+ "basic macro list"
+
+gdb_test "macro define M(x) x" \
+ "" \
+ "basic redefine, macro with args"
+
+gdb_test "print M (7)" \
+ " = 7" \
+ "expansion of macro with arguments"
+
+gdb_test "macro undef M" \
+ "" \
+ "basic macro undef"
+
+gdb_test "print M" \
+ "No symbol \"M\" in current context\." \
+ "print expression with macro after user undef."
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.495
diff -u -r1.495 gdb.texinfo
--- doc/gdb.texinfo 9 May 2008 17:02:01 -0000 1.495
+++ doc/gdb.texinfo 23 May 2008 21:07:23 -0000
@@ -1,6 +1,6 @@
\input texinfo @c -*-texinfo-*-
@c Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
-@c 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+@c 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008
@c Free Software Foundation, Inc.
@c
@c %**start of header
@@ -7822,31 +7822,29 @@
@cindex macros, user-defined
@item macro define @var{macro} @var{replacement-list}
@itemx macro define @var{macro}(@var{arglist}) @var{replacement-list}
-@i{(This command is not yet implemented.)} Introduce a definition for a
-preprocessor macro named @var{macro}, invocations of which are replaced
-by the tokens given in @var{replacement-list}. The first form of this
-command defines an ``object-like'' macro, which takes no arguments; the
-second form defines a ``function-like'' macro, which takes the arguments
-given in @var{arglist}.
-
-A definition introduced by this command is in scope in every expression
-evaluated in @value{GDBN}, until it is removed with the @command{macro
-undef} command, described below. The definition overrides all
-definitions for @var{macro} present in the program being debugged, as
-well as any previous user-supplied definition.
+Introduce a definition for a preprocessor macro named @var{macro},
+invocations of which are replaced by the tokens given in
+@var{replacement-list}. The first form of this command defines an
+``object-like'' macro, which takes no arguments; the second form
+defines a ``function-like'' macro, which takes the arguments given in
+@var{arglist}.
+
+A definition introduced by this command is in scope in every
+expression evaluated in @value{GDBN}, until it is removed with the
+@code{macro undef} command, described below. The definition overrides
+all definitions for @var{macro} present in the program being debugged,
+as well as any previous user-supplied definition.
@kindex macro undef
@item macro undef @var{macro}
-@i{(This command is not yet implemented.)} Remove any user-supplied
-definition for the macro named @var{macro}. This command only affects
-definitions provided with the @command{macro define} command, described
-above; it cannot remove definitions present in the program being
-debugged.
+Remove any user-supplied definition for the macro named @var{macro}.
+This command only affects definitions provided with the @code{macro
+define} command, described above; it cannot remove definitions present
+in the program being debugged.
@kindex macro list
@item macro list
-@i{(This command is not yet implemented.)} List all the macros
-defined using the @code{macro define} command.
+List all the macros defined using the @code{macro define} command.
@end table
@cindex macros, example of debugging with
@@ -7925,7 +7923,7 @@
(@value{GDBP})
@end smallexample
-In the example above, note that @command{macro expand-once} expands only
+In the example above, note that @code{macro expand-once} expands only
the macro invocation explicit in the original text --- the invocation of
@code{ADD} --- but does not expand the invocation of the macro @code{M},
which was introduced by @code{ADD}.