From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7435 invoked by alias); 23 May 2008 21:10:40 -0000 Received: (qmail 7405 invoked by uid 22791); 23 May 2008 21:10:35 -0000 X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 23 May 2008 21:10:17 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id m4NL7weH007385; Fri, 23 May 2008 17:07:58 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [10.11.255.20]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id m4NL7wK8019386; Fri, 23 May 2008 17:07:58 -0400 Received: from opsy.redhat.com (vpn-10-101.bos.redhat.com [10.16.10.101]) by pobox.corp.redhat.com (8.13.1/8.13.1) with ESMTP id m4NL7vTb029972; Fri, 23 May 2008 17:07:57 -0400 Received: by opsy.redhat.com (Postfix, from userid 500) id C83F0508079; Fri, 23 May 2008 15:07:56 -0600 (MDT) To: Eli Zaretskii Cc: pedro@codesourcery.com, gdb-patches@sourceware.org Subject: Re: RFA: Patch: implement missing macro functions References: <200805232030.20677.pedro@codesourcery.com> From: Tom Tromey Reply-To: Tom Tromey X-Attribution: Tom Date: Sun, 25 May 2008 21:51:00 -0000 In-Reply-To: (Eli Zaretskii's message of "Fri\, 23 May 2008 23\:39\:13 +0300") Message-ID: User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-05/txt/msg00696.txt.bz2 >>>>> "Eli" == Eli Zaretskii 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 * 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 * gdb.base/macscp.exp: Add macro tests. doc/ChangeLog: 2008-05-23 Tom Tromey * 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, ""); } 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}.