* 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.
+2011-07-18 Matt Rice <ratmice@gmail.com>
+
+ 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 <pmuldoon@redhat.com>
Tom Tromey <tromey@redhat.com>
+2011-07-21 Matt Rice <ratmice@gmail.com>
+
+ 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 <pmuldoon@redhat.com>
* observer.texi (GDB Observers): Add before_prompt observer.
@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
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,
}
}
+/* 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;
}
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
{
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. */
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);
macro_for_each (macro_user_macros, print_one_macro, NULL);
}
-
\f
/* Initializing the `macrocmd' module. */
_("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\
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;
}
&& (!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;
}
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.
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;
+2011-07-21 Matt Rice <ratmice@gmail.com>
+
+ PR macros/12999
+ * gdb.base/info-macros.c: New test sources.
+ * gdb.base/info-macros.exp: New tests.
+
2011-07-21 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/python.exp: Add prompt substitution tests.
--- /dev/null
+#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
+
--- /dev/null
+# 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 <http://www.gnu.org/licenses/>.
+
+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"