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.
This commit is contained in:
matt rice 2011-07-21 15:13:30 +00:00
parent d17b6f8101
commit 9b158ba08e
10 changed files with 442 additions and 32 deletions

View File

@ -1,3 +1,18 @@
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>

View File

@ -1,3 +1,9 @@
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.

View File

@ -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

View File

@ -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,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)
@ -141,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"
@ -158,29 +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);
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);
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\

View File

@ -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;
}

View File

@ -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.

View File

@ -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;

View File

@ -1,3 +1,9 @@
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.

View File

@ -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

View File

@ -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 <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"