From 9b158ba08eb1ad14dc2324b8391263b228fa928a Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 21 Jul 2011 15:13:30 +0000 Subject: [PATCH] PR macros/12999 * macrotab.h (macro_callback_fn): Add new arguments to callback. * macrotab.c (foreach_macro): Ditto. (foreach_macro_in_scope): Ditto. * macrocmd.c (print_macro_callback): New function. (info_macro_command): Move some code to print_macro_definition. (print_macro_definition): New function. (print_one_macro): Add new arguments to callback. testsuite/ * gdb.base/info-macros.c: New test sources. * gdb.base/info-macros.exp: New tests. docs/ * gdb.texinfo (Macros): Add info definitions and info macros commands. Update text and cindex entries for info macro command. --- gdb/ChangeLog | 15 ++ gdb/doc/ChangeLog | 6 + gdb/doc/gdb.texinfo | 17 ++- gdb/macrocmd.c | 133 +++++++++++++--- gdb/macrotab.c | 6 +- gdb/macrotab.h | 9 +- gdb/symtab.c | 1 + gdb/testsuite/ChangeLog | 6 + gdb/testsuite/gdb.base/info-macros.c | 73 +++++++++ gdb/testsuite/gdb.base/info-macros.exp | 202 +++++++++++++++++++++++++ 10 files changed, 439 insertions(+), 29 deletions(-) create mode 100644 gdb/testsuite/gdb.base/info-macros.c create mode 100644 gdb/testsuite/gdb.base/info-macros.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7b0b3b0bb6..120328a350 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,18 @@ +2011-07-18 Matt Rice + + PR macros/12999 + * macrotab.h (macro_callback_fn): Add new arguments to callback. + * macrotab.c (foreach_macro): Ditto. + (foreach_macro_in_scope): Ditto. + * macrocmd.c (print_macro_callback): New function. + (info_macro_command): Move some code to print_macro_definition. + (print_macro_definition): New function. + (print_one_macro): Add new arguments to callback. + (info_definitions_command): New function. + (info_macros_command): Ditto. + (_initialize_macrocmd): Add info macros and info definitions commands. + * symtab.c (add_macro_name): Add new arguments to callback. + 2011-07-21 Phil Muldoon Tom Tromey diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index e3e02c8441..34590f6c93 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,9 @@ +2011-07-21 Matt Rice + + PR macros/12999 + * gdb.texinfo (Macros): Add info definitions and info macros commands. + Update text and cindex entries for info macro command. + 2011-07-21 Phil Muldoon * observer.texi (GDB Observers): Add before_prompt observer. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 5b26bbbd7d..16bb6bc7f5 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -9588,11 +9588,24 @@ can be any string of tokens. @kindex info macro @cindex macro definition, showing -@cindex definition, showing a macro's +@cindex definition of a macro, showing +@cindex macros, from debug info @item info macro @var{macro} -Show the definition of the macro named @var{macro}, and describe the +Show the current definition of the named @var{macro}, and describe the source location or compiler command-line where that definition was established. +@kindex info macros +@item info macros @var{linespec} +Show all macro definitions that are in effect at the location specified +by @var{linespec}, and describe the source location or compiler +command-line where those definitions were established. + +@kindex info definitions +@item info definitions @var{macro} +Show all definitions of the named @var{macro} that are defined in the current +compilation unit, and describe the source location or compiler command-line +where those definitions were established. + @kindex macro define @cindex user-defined macros @cindex defining macros interactively diff --git a/gdb/macrocmd.c b/gdb/macrocmd.c index c77156a416..d1ac7fae32 100644 --- a/gdb/macrocmd.c +++ b/gdb/macrocmd.c @@ -117,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, @@ -134,36 +137,27 @@ 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 -info_macro_command (char *name, int from_tty) +print_macro_definition (const char *name, + const struct macro_definition *d, + struct macro_source_file *file, + int line) { - 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" - "whose definition you want to see.")); - - ms = default_macro_scope (); - if (! ms) - error (_("GDB has no preprocessor macro information for that code.")); - - d = macro_lookup_definition (ms->file, ms->line, name); - if (d) - { - int line; - 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); + 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; @@ -177,10 +171,37 @@ info_macro_command (char *name, int from_tty) } 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) +{ + 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" + "whose definition you want to see.")); + + ms = default_macro_scope (); + if (! ms) + error (_("GDB has no preprocessor macro information for that code.")); + + d = macro_lookup_definition (ms->file, ms->line, name); + if (d) + { + int line; + struct macro_source_file *file + = macro_definition_location (ms->file, ms->line, name, &line); + + print_macro_definition (name, d, file, line); } else { @@ -194,6 +215,63 @@ 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); +} /* User-defined macros. */ @@ -359,6 +437,7 @@ macro_undef_command (char *exp, int from_tty) static void print_one_macro (const char *name, const struct macro_definition *macro, + struct macro_source_file *source, int line, void *ignore) { fprintf_filtered (gdb_stdout, "macro define %s", name); @@ -382,7 +461,6 @@ macro_list_command (char *exp, int from_tty) macro_for_each (macro_user_macros, print_one_macro, NULL); } - /* Initializing the `macrocmd' module. */ @@ -420,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\ diff --git a/gdb/macrotab.c b/gdb/macrotab.c index cba285dc9d..efcf83563e 100644 --- a/gdb/macrotab.c +++ b/gdb/macrotab.c @@ -913,7 +913,8 @@ foreach_macro (splay_tree_node node, void *arg) struct macro_key *key = (struct macro_key *) node->key; struct macro_definition *def = (struct macro_definition *) node->value; - (*datum->fn) (key->name, def, datum->user_data); + (*datum->fn) (key->name, def, key->start_file, key->start_line, + datum->user_data); return 0; } @@ -945,7 +946,8 @@ foreach_macro_in_scope (splay_tree_node node, void *info) && (!key->end_file || compare_locations (key->end_file, key->end_line, datum->file, datum->line) >= 0)) - (*datum->fn) (key->name, def, datum->user_data); + (*datum->fn) (key->name, def, key->start_file, key->start_line, + datum->user_data); return 0; } diff --git a/gdb/macrotab.h b/gdb/macrotab.h index d2b2b63290..a10351a23b 100644 --- a/gdb/macrotab.h +++ b/gdb/macrotab.h @@ -306,11 +306,14 @@ struct macro_source_file *(macro_definition_location int *definition_line)); /* Callback function when walking a macro table. NAME is the name of - the macro, and DEFINITION is the definition. USER_DATA is an - arbitrary pointer which is passed by the caller to macro_for_each - or macro_for_each_in_scope. */ + the macro, and DEFINITION is the definition. SOURCE is the file at the + start of the include path, and LINE is the line number of the SOURCE file + where the macro was defined. USER_DATA is an arbitrary pointer which is + passed by the caller to macro_for_each or macro_for_each_in_scope. */ typedef void (*macro_callback_fn) (const char *name, const struct macro_definition *definition, + struct macro_source_file *source, + int line, void *user_data); /* Call the function FN for each macro in the macro table TABLE. diff --git a/gdb/symtab.c b/gdb/symtab.c index b792081af3..9447bd9177 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -3771,6 +3771,7 @@ struct add_name_data This adds a macro's name to the current completion list. */ static void add_macro_name (const char *name, const struct macro_definition *ignore, + struct macro_source_file *ignore2, int ignore3, void *user_data) { struct add_name_data *datum = (struct add_name_data *) user_data; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ac815ca20e..8a704cddc4 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-07-21 Matt Rice + + PR macros/12999 + * gdb.base/info-macros.c: New test sources. + * gdb.base/info-macros.exp: New tests. + 2011-07-21 Phil Muldoon * gdb.python/python.exp: Add prompt substitution tests. diff --git a/gdb/testsuite/gdb.base/info-macros.c b/gdb/testsuite/gdb.base/info-macros.c new file mode 100644 index 0000000000..f874156308 --- /dev/null +++ b/gdb/testsuite/gdb.base/info-macros.c @@ -0,0 +1,73 @@ +#ifdef DEF_MACROS + + #ifdef ONE + #ifdef FOO + #undef FOO + #endif + + #define FOO "hello" + #else + #undef FOO + #endif + + + #ifdef TWO + #ifdef FOO + #undef FOO + #endif + #define FOO " " + #endif + + #ifdef THREE + #ifdef FOO + #undef FOO + #endif + + #define FOO "world" + #endif + + #ifdef FOUR + #ifdef FOO + #undef FOO + #endif + #define FOO(a) foo = a + #endif +#else + +int main (int argc, const char **argv) +{ + char *foo; + + #define DEF_MACROS + #define ONE + #include "info-macros.c" + foo = FOO; + + #define TWO + #include "info-macros.c" + foo = FOO; + + #define THREE + #include "info-macros.c" + foo = FOO; + + #undef THREE + #include "info-macros.c" + foo = FOO; + + #undef TWO + #include "info-macros.c" + foo = FOO; + + #undef ONE + #include "info-macros.c" + foo = (char *)0; + + #define FOUR + #include "info-macros.c" + FOO ("the end."); + + return 0; +} +#endif + diff --git a/gdb/testsuite/gdb.base/info-macros.exp b/gdb/testsuite/gdb.base/info-macros.exp new file mode 100644 index 0000000000..bd5a870af8 --- /dev/null +++ b/gdb/testsuite/gdb.base/info-macros.exp @@ -0,0 +1,202 @@ +# Copyright 2011 Free Software Foundation, Inc. + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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, see . + +set testfile "info-macros" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +get_compiler_info ${binfile} +if [test_compiler_info gcc*] { + lappend options additional_flags=-g3 +} else { + untested ${testfile}.exp + return -1 +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $options] } { + untested ${testfile}.exp + return -1 +} + +if ![runto_main] { + untested ${testfile}.exp + return -1 +} + +set test "info definitions FOO" +set r1 ".*#define FOO \"hello\"" +set r2 ".*#define FOO \" \"" +set r3 ".*#define FOO \"world\"" +set r4 ".*#define FOO\\(a\\) foo = a" +set testname "$test 1" +gdb_test "$test" "$r1$r2$r3$r4" "$testname" + + +set test "info macros" +set r1 ".*#define FOO \"hello\"" +set r2 ".*#define ONE" +set r3 ".*\r\n$gdb_prompt" +set testname "$test 2" +gdb_test_multiple "$test" $testname { + -re "$r1$r2$r3" { + pass $testname + } + -re ".*#define TWO.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define THREE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $testname + } +} +gdb_test "next" ".*" "" + +set r1 ".*#define FOO \" \"" +set r2 ".*#define ONE" +set r3 ".*#define TWO" +set r4 ".*\r\n$gdb_prompt" +set testname "$test 4" +gdb_test_multiple "$test" $testname { + -re ".*#define THREE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $testname + } + -re "$r1$r2$r3$r4" { + pass $testname + } +} +gdb_test "next" ".*" "" + +# in alpabetical order... +set r1 ".*#define FOO \"world\"" +set r2 ".*#define ONE" +set r3 ".*#define THREE" +set r4 ".*#define TWO" +set r5 ".*\r\n$gdb_prompt" +set testname "$test 4" +gdb_test_multiple "$test" $testname { + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $testname + } + -re "$r1$r2$r3$r4$r5" { + pass $testname + } +} +# same as above with a linespec. +set test "info macros *\$pc" +gdb_test_multiple "$test" $test { + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $test + } + -re "$r1$r2$r3$r4$r5" { + pass $test + } +} +gdb_test "next" ".*" "" + +set r1 ".*#define FOO \" \"" +set r2 ".*#define ONE" +set r3 ".*#define TWO." +set r4 ".*\r\n$gdb_prompt" +set testname "$test 5" +set test "info macros" +gdb_test_multiple "$test" $test { + -re ".*#define THREE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $testname + } + -re "$r1$r2$r3$r4" { + pass $testname + } +} +gdb_test "next" ".*" "" +gdb_test "next" ".*" "" + +set r1 ".*#define DEF_MACROS" +set r2 ".*\r\n$gdb_prompt" +set testname "$test 6" +gdb_test_multiple "$test" $testname { + -re ".*#define FOO \" \".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOO \"hello\".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOO \"world\".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOO\\(a\\) foo = a.*" { + fail $testname + } + -re ".*#define ONE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define TWO.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define THREE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOUR.*\r\n$gdb_prompt" { + fail $testname + } + -re "$r1$r2" { + pass $testname + } +} + +gdb_test "next" ".*" "" +set r1 ".*#define DEF_MACROS" +set r2 ".*#define FOO\\(a\\) foo = a" +set r3 ".*#define FOUR" +set r4 ".*\r\n$gdb_prompt" +set testname "$test 7" +gdb_test_multiple "$test" $testname { + -re ".*#define FOO \" \".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOO \"hello\".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define FOO \"world\".*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define ONE.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define TWO.*\r\n$gdb_prompt" { + fail $testname + } + -re ".*#define THREE.*\r\n$gdb_prompt" { + fail $testname + } + -re "$r1$r2$r3$r4" { + pass $testname + } +} + +set test "info macros info-macros.c:42" + +set r1 ".*define DEF_MACROS" +set r2 ".*define ONE" +# info macros on the line where the #define or #include is +# fails to find the macro defined (though it works on the next line.) +setup_kfail "gdb/NNNN" *-*-* +gdb_test "$test" "$r1$r2" "$test" -- 2.34.1