diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index f015dad4cf..2d02577bfe 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-06-11 Jim Blandy + + * macscp.exp, macscp1.c, macscp2.h, macscp3.h, macscp4.h: New + tests. + 2002-06-06 Michael Snyder * gdb.base/overlays.exp: Record addresses of overlay diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp new file mode 100644 index 0000000000..283fe84457 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp.exp @@ -0,0 +1,403 @@ +# Test macro scoping. +# Copyright 2002 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile "macscp" +set binfile ${objdir}/${subdir}/${testfile} + +if {[gdb_compile "${srcdir}/${subdir}/macscp1.c" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + +# Ask GDB to show the current definition of MACRO, and return a list +# describing the result. +# +# The return value has the form {FILE1 FILE2 ... DEF}, which means +# that MACRO has the definition `DEF', and was defined in `FILE1', +# which was included from `FILE2', included from ... . +# +# If GDB says that MACRO has no definition, return the string `undefined'. +# +# If GDB complains that it doesn't have any information about +# preprocessor macro definitions, return the string `no-macro-info'. +# +# If expect times out waiting for GDB, we return the string `timeout'. +# +# If GDB's output doesn't otherwise match what we're expecting, we +# return the empty string. + +proc info_macro {macro} { + global gdb_prompt + global decimal + + set filepat {macscp[0-9]+\.[ch]} + set definition {} + set location {} + + send_gdb "info macro ${macro}\n" + + set debug_me 0 + + if {$debug_me} {exp_internal 1} + gdb_expect { + -re "Defined at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" { + # `location' and `definition' should be empty when we see + # this message. + if {[llength $location] == 0 && [llength $definition] == 0} { + set location $expect_out(1,string) + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. + set definition {} + } + } + -re "The symbol `${macro}' has no definition as a C/C\\+\\+ preprocessor macro\[^\r\n\]*\[\r\n\]" { + # `location' and `definition' should be empty when we see + # this message. + if {[llength $location] == 0 && [llength $definition] == 0} { + set definition undefined + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. + set definition {} + } + } + -re "^\[\r\n\]* included at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" { + # `location' should *not* be empty when we see this + # message. It should have recorded at least the initial + # `Defined at ' message (for definitions) or ` at' message + # (for undefined symbols). + if {[llength $location] != 0} { + lappend location $expect_out(1,string) + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. + set definition {} + } + } + -re "^\[\r\n\]*at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" { + # This appears after a `has no definition' message. + # `location' should be empty when we see it. + if {[string compare $definition undefined] == 0 \ + && [llength $location] == 0} { + set location $expect_out(1,string) + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. + set definition {} + } + } + -re "#define ${macro} (\[^\r\n\]*)\[\r\n\]" { + # `definition' should be empty when we see this message. + if {[string compare $definition ""] == 0} { + set definition $expect_out(1,string) + exp_continue + } else { + # Exit this expect loop, with a result indicating failure. + set definition {} + } + } + -re "has no preprocessor macro information.*$gdb_prompt $" { + set definition no-macro-info + } + -re "$gdb_prompt $" { + # Exit the expect loop; let the existing value of `definition' + # indicate failure or success. + } + timeout { + set definition timeout + } + } + if {$debug_me} {exp_internal 0} + + switch -exact -- $definition { + no-macro-info { return no-macro-info } + timeout { return timeout } + undefined - + default { + if {[llength $location] >= 1} { + return [concat $location [list $definition]] + } else { + return {} + } + } + } +} + + +# Call info_macro to show the definition of MACRO. Expect a result of +# EXPECTED. Use WHERE in pass/fail messages to identify the context. +# Return non-zero if we should abort the entire test file, or zero if +# we can continue. +proc check_macro {macro expected where} { + set func_def [info_macro $macro] + if {[string compare $func_def $expected] == 0} { + pass "info macro $macro $where" + } else { + switch -exact -- $func_def { + no-macro-info { + xfail "executable includes no macro debugging information" + return 1 + } + timeout { + fail "info macro $macro $where (timeout)" + } + default { + fail "info macro $macro $where" + } + } + } + return 0 +} + + +# List the function FUNC, and then show the definition of MACRO, +# expecting the result EXPECTED. +proc list_and_check_macro {func macro expected} { + gdb_test "list $func" ".*${func}.*" + return [check_macro $macro $expected "after `list $func'"] +} + + +if {[list_and_check_macro main WHERE {macscp1.c {before macscp1_3}}]} { + return 0 +} +list_and_check_macro macscp2_2 WHERE {macscp2.h macscp1.c {before macscp2_2}} +list_and_check_macro macscp3_2 WHERE {macscp3.h macscp1.c {before macscp3_2}} + + +# Although GDB's macro table structures distinguish between multiple +# #inclusions of the same file, GDB's other structures don't. So the +# `list' command here doesn't reliably select one #inclusion or the +# other, even though it could. It would be nice to eventually change +# GDB's structures to handle this correctly. +gdb_test "list macscp4_2_from_macscp2" ".*macscp4_2_, MACSCP4_INCLUSION.*" +switch -exact -- [info_macro WHERE] { + {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} { + pass "info macro WHERE after `list macscp_4_2_from_macscp2'" + } + {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} { + # setup_kfail "gdb/555" + fail "info macro WHERE after `list macscp_4_2_from_macscp2' (gdb/555)" + } + timeout { + fail "info macro WHERE after `list macscp_4_2_from_macscp2' (timeout)" + } + default { fail "info macro WHERE after `list macscp_4_2_from_macscp2'" } +} + +gdb_test "list macscp4_2_from_macscp3" ".*macscp4_2_, MACSCP4_INCLUSION.*" +switch -exact -- [info_macro WHERE] { + {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} { + pass "info macro WHERE after `list macscp_4_2_from_macscp3'" + } + {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} { + # setup_kfail "gdb/555" + fail "info macro WHERE after `list macscp_4_2_from_macscp3' (gdb/555)" + } + timeout { + fail "info macro WHERE after `list macscp_4_2_from_macscp3' (timeout)" + } + default { fail "info macro WHERE after `list macscp_4_2_from_macscp3'" } +} + + +#### Test the selection of the macro scope by the current frame. + +### A table of functions, in the order they will be reached, which is +### also the order they appear in the preprocessed output. Each entry +### has the form {FUNCNAME WHERE KFAILWHERE}, where: +### - FUNCNAME is the name of the function, +### - WHERE is the definition we expect to see for the macro `WHERE', as +### returned by `info_macro', and +### - KFAILWHERE is an alternate definition which should be reported +### as a `known failure', due to GDB's inability to distinguish multiple +### #inclusions of the same file. +### KFAILWHERE may be omitted. + +set funcs { + { + macscp1_1 + {macscp1.c {before macscp1_1}} + } + { + macscp2_1 + {macscp2.h macscp1.c {before macscp2_1}} + } + { + macscp4_1_from_macscp2 + {macscp4.h macscp2.h macscp1.c {before macscp4_1_..., from macscp2.h}} + {macscp4.h macscp3.h macscp1.c {before macscp4_1_..., from macscp3.h}} + } + { + macscp4_2_from_macscp2 + {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} + {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} + } + { + macscp2_2 + {macscp2.h macscp1.c {before macscp2_2}} + } + { + macscp1_2 + {macscp1.c {before macscp1_2}} + } + { + macscp3_1 + {macscp3.h macscp1.c {before macscp3_1}} + } + { + macscp4_1_from_macscp3 + {macscp4.h macscp3.h macscp1.c {before macscp4_1_..., from macscp3.h}} + {macscp4.h macscp2.h macscp1.c {before macscp4_1_..., from macscp2.h}} + } + { + macscp4_2_from_macscp3 + {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} + {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} + } + { + macscp3_2 + {macscp3.h macscp1.c {before macscp3_2}} + } + { + macscp1_3 + {macscp1.c {before macscp1_3}} + } +} + + +# Start the program running. +if {! [runto_main]} { + fail "macro tests suppressed: couldn't run to main" + return 0 +} + +# Set a breakpoint on each of the functions. +foreach func_entry $funcs { + set func [lindex $func_entry 0] + gdb_test "break $func" "Breakpoint.*" +} + +# Run to each of the breakpoints and check the definition (or lack +# thereof) of each macro. +for {set i 0} {$i < [llength $funcs]} {incr i} { + set func_entry [lindex $funcs $i] + set func [lindex $func_entry 0] + set expected [lindex $func_entry 1] + set kfail_expected [lindex $func_entry 2] + + # Run to the breakpoint for $func. + gdb_test "continue" "Breakpoint $decimal, $func .*" "continue to $func" + + # Check the macro WHERE. + set result [info_macro WHERE] + if {[string compare $result $expected] == 0} { + pass "info macro WHERE stopped in $func" + } elseif {[string compare $result $kfail_expected] == 0} { + # setup_kfail "gdb/555" + fail "info macro WHERE stopped in $func (gdb/555)" + } elseif {[string compare $result timeout] == 0} { + fail "info macro WHERE stopped in $func (timeout)" + } else { + fail "info macro WHERE stopped in $func" + } + + # Check that the BEFORE_ macros for all prior functions are + # #defined, and that those for all subsequent functions are not. + for {set j 0} {$j < [llength $funcs]} {incr j} { + if {$j != $i} { + set func_j_entry [lindex $funcs $j] + set func_j [lindex $func_j_entry 0] + + set before_macro "BEFORE_[string toupper $func_j]" + set test_name \ + "$before_macro defined/undefined when stopped at $func" + set result [info_macro $before_macro] + + # We can't get the right scope info when we're stopped in + # the macro4_ functions. + if {[string match macscp4_* $func]} { + # setup_kfail "gdb/555" + set test_name "$test_name (gdb/555)" + } + if {$j < $i} { + if {[llength $result] >= 2 && \ + [string compare [lindex $result end] {}] == 0} { + pass $test_name + } elseif {[string compare $result timeout] == 0} { + fail "$test_name (timeout)" + } else { + fail "$test_name" + } + } elseif {$j > $i} { + switch -- [lindex $result end] { + undefined { pass $test_name } + timeout { fail "$test_name (timeout)" } + default { + fail "$test_name" + } + } + } + + set until_macro "UNTIL_[string toupper $func_j]" + set test_name \ + "$until_macro defined/undefined when stopped at $func" + set result [info_macro $until_macro] + + # We can't get the right scope info when we're stopped in + # the macro4_ functions. + if {[string match macscp4_* $func]} { + # setup_kfail "gdb/555" + set test_name "$test_name (gdb/555)" + } + if {$j <= $i} { + switch -- [lindex $result end] { + undefined { pass $test_name } + timeout { fail "$test_name (timeout)" } + default { + fail "$test_name" + } + } + } elseif {$j > $i} { + if {[llength $result] >= 2 && \ + [string compare [lindex $result end] {}] == 0} { + pass $test_name + } elseif {[string compare $result timeout] == 0} { + fail "$test_name (timeout)" + } else { + fail "$test_name" + } + } + } + } +} diff --git a/gdb/testsuite/gdb.base/macscp1.c b/gdb/testsuite/gdb.base/macscp1.c new file mode 100644 index 0000000000..89a1b07d1e --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp1.c @@ -0,0 +1,80 @@ +#include + +#define SPLICE(a, b) INNER_SPLICE(a, b) +#define INNER_SPLICE(a, b) a ## b +#define STRINGIFY(a) INNER_STRINGIFY(a) +#define INNER_STRINGIFY(a) #a + +/* A macro named UNTIL_ is #defined until just before the + definition of the function . + + A macro named BEFORE_ is not #defined until just before the + definition of . + + The macro WHERE is redefined before each function to the + token list ``before ''. + + The macscp IN_MACSCP2_H and IN_MACSCP3_H are defined while + processing those header files; macscp4.h uses them to choose + appropriate function names, output strings, and macro definitions. */ + +#define UNTIL_MACSCP1_1 +#define UNTIL_MACSCP2_1 +#define UNTIL_MACSCP4_1_FROM_MACSCP2 +#define UNTIL_MACSCP4_2_FROM_MACSCP2 +#define UNTIL_MACSCP2_2 +#define UNTIL_MACSCP1_2 +#define UNTIL_MACSCP3_1 +#define UNTIL_MACSCP4_1_FROM_MACSCP3 +#define UNTIL_MACSCP4_2_FROM_MACSCP3 +#define UNTIL_MACSCP3_2 +#define UNTIL_MACSCP1_3 + +#define WHERE before macscp1_1 +#define BEFORE_MACSCP1_1 +#undef UNTIL_MACSCP1_1 +void +macscp1_1 () +{ + puts ("macscp1_1"); +} + +#include "macscp2.h" + +#undef WHERE +#define WHERE before macscp1_2 +#define BEFORE_MACSCP1_2 +#undef UNTIL_MACSCP1_2 +void +macscp1_2 () +{ + puts ("macscp1_2"); +} + +#include "macscp3.h" + +#undef WHERE +#define WHERE before macscp1_3 +#define BEFORE_MACSCP1_3 +#undef UNTIL_MACSCP1_3 +void +macscp1_3 () +{ + puts ("macscp1_3"); +} + +int +main (int argc, char **argv) +{ + macscp1_1 (); + macscp2_1 (); + macscp4_1_from_macscp2 (); + macscp4_2_from_macscp2 (); + macscp2_2 (); + macscp1_2 (); + macscp3_1 (); + macscp4_1_from_macscp3 (); + macscp4_2_from_macscp3 (); + macscp3_2 (); + macscp1_3 (); +} diff --git a/gdb/testsuite/gdb.base/macscp2.h b/gdb/testsuite/gdb.base/macscp2.h new file mode 100644 index 0000000000..ef0feaac5a --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp2.h @@ -0,0 +1,25 @@ +#define IN_MACSCP2_H + +#undef WHERE +#define WHERE before macscp2_1 +#define BEFORE_MACSCP2_1 +#undef UNTIL_MACSCP2_1 +void +macscp2_1 () +{ + puts ("macscp2_1"); +} + +#include "macscp4.h" + +#undef WHERE +#define WHERE before macscp2_2 +#define BEFORE_MACSCP2_2 +#undef UNTIL_MACSCP2_2 +void +macscp2_2 () +{ + puts ("macscp2_2"); +} + +#undef IN_MACSCP2_H diff --git a/gdb/testsuite/gdb.base/macscp3.h b/gdb/testsuite/gdb.base/macscp3.h new file mode 100644 index 0000000000..ebfcc6e193 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp3.h @@ -0,0 +1,25 @@ +#define IN_MACSCP3_H + +#undef WHERE +#define WHERE before macscp3_1 +#define BEFORE_MACSCP3_1 +#undef UNTIL_MACSCP3_1 +void +macscp3_1 () +{ + puts ("macscp3_1"); +} + +#include "macscp4.h" + +#undef WHERE +#define WHERE before macscp3_2 +#define BEFORE_MACSCP3_2 +#undef UNTIL_MACSCP3_2 +void +macscp3_2 () +{ + puts ("macscp3_2"); +} + +#undef IN_MACSCP3_H diff --git a/gdb/testsuite/gdb.base/macscp4.h b/gdb/testsuite/gdb.base/macscp4.h new file mode 100644 index 0000000000..5302d8d3c4 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp4.h @@ -0,0 +1,44 @@ +/* Put together a macro we can use as part of function names. */ +#undef MACSCP4_INCLUSION +#ifdef IN_MACSCP2_H +#define MACSCP4_INCLUSION from_macscp2 +#endif +#ifdef IN_MACSCP3_H +#define MACSCP4_INCLUSION from_macscp3 +#endif + +#undef WHERE +#ifdef IN_MACSCP2_H +#define WHERE before macscp4_1_..., from macscp2.h +#define BEFORE_MACSCP4_1_FROM_MACSCP2 +#undef UNTIL_MACSCP4_1_FROM_MACSCP2 +#endif +#ifdef IN_MACSCP3_H +#define WHERE before macscp4_1_..., from macscp3.h +#define BEFORE_MACSCP4_1_FROM_MACSCP3 +#undef UNTIL_MACSCP4_1_FROM_MACSCP3 +#endif +void +SPLICE (macscp4_1_, MACSCP4_INCLUSION) () +{ + puts ("macscp4_1_" STRINGIFY(MACSCP4_INCLUSION)); +} + +#undef WHERE +#ifdef IN_MACSCP2_H +#define WHERE before macscp4_2_..., from macscp2.h +#define BEFORE_MACSCP4_2_FROM_MACSCP2 +#undef UNTIL_MACSCP4_2_FROM_MACSCP2 +#endif +#ifdef IN_MACSCP3_H +#define WHERE before macscp4_2_..., from macscp3.h +#define BEFORE_MACSCP4_2_FROM_MACSCP3 +#undef UNTIL_MACSCP4_2_FROM_MACSCP3 +#endif +void +SPLICE (macscp4_2_, MACSCP4_INCLUSION) () +{ + puts ("macscp4_2_" STRINGIFY(MACSCP4_INCLUSION)); +} + +#define DEFINED_IN_MACSCP4 this was defined in macscp4.h.