# Copyright 2017-2023 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 . # Tests for function local static variables, both C and C++. # This file is part of the gdb testsuite. standard_testfile .c # A few expected errors. set syntax_re "A syntax error in expression, near.*" set cannot_resolve_re "Cannot resolve method S::method to any overloaded instance" # Build an "Cannot resolve method ..." expected error string for # method METH. # proc cannot_resolve {meth} { return "Cannot resolve method $meth to any overloaded instance" } # A list of scopes that have the static variables that we want to # print. Each entry has, in order, the scope/function name, and the # prefix used by the static variables. The prefix exists both to make # it easier to debug the test if something goes wrong, and, to make # sure that printing the static local of one method overload doesn't # find the variables of the wrong overload. # # While at it, we also try printing each scope without the static # local, to check that the parse copes with cv overloads without # quoting. That's what the third and forth columns are for. Note # that printing "func()" is different from "func(void)". The former # is an inferior function call, while the latter is a reference to the # function. #SCOPE #PREFIX #PRINT-SCOPE-QUOTED #PRINT-SCOPE-UNQUOTED (opt) set cxx_scopes_list { {"S::method()" "S_M" {= \\{void \\(S \\* const\\)\\} $hex } {[cannot_resolve "S::method"]}} {"S::method() const" "S_M_C" {= \\{void \\(const S \\* const\\)\\} $hex } $syntax_re} {"S::method() volatile" "S_M_V" {= \\{void \\(volatile S \\* const\\)\\} $hex } $syntax_re} {"S::method() const volatile" "S_M_CV" {= \\{void \\(const volatile S \\* const\\)\\} $hex } $syntax_re} {"S::method() volatile const" "S_M_CV" {= \\{void \\(const volatile S \\* const\\)\\} $hex } $syntax_re} {"S::method(void)" "S_M" {= \\{void \\(S \\* const\\)\\} $hex }} {"S::method(void) const" "S_M_C" {= \\{void \\(const S \\* const\\)\\} $hex }} {"S::method(void) volatile" "S_M_V" {= \\{void \\(volatile S \\* const\\)\\} $hex }} {"S::method(void) const volatile" "S_M_CV" {= \\{void \\(const volatile S \\* const\\)\\} $hex }} {"S::method(void) volatile const" "S_M_CV" {= \\{void \\(const volatile S \\* const\\)\\} $hex }} {"S::static_method()" "S_SM" {= \\{void \\(void\\)\\} $hex } "void"} {"S::static_method(void)" "S_SM" {= \\{void \\(void\\)\\} $hex }} {"S::inline_method()" "S_IM" {= \\{void \\(S \\* const\\)\\} $hex } {[cannot_resolve "S::inline_method"]}} {"S::inline_method(void)" "S_IM" {= \\{void \\(S \\* const\\)\\} $hex }} {"S::static_inline_method()" "S_SIM" {= \\{void \\(void\\)\\} $hex } "void"} {"S::static_inline_method(void)" "S_SIM" {= \\{void \\(void\\)\\} $hex }} {"S2::method()" "S2_M" {= \\{void \\(S2 \\* const\\)\\} $hex ::method\\(\\)>} {[cannot_resolve "S2::method"]}} {"S2::static_method()" "S2_SM" {= \\{void \\(void\\)\\} $hex ::static_method\\(\\)>} "void"} {"S2::inline_method()" "S2_IM" {= \\{void \\(S2 \\* const\\)\\} $hex ::inline_method\\(\\)>} {[cannot_resolve "S2::inline_method"]}} {"S2::static_inline_method()" "S2_SIM" {= \\{void \\(void\\)\\} $hex ::static_inline_method\\(\\)>} "void"} {"free_func" "FF" {= \\{void \\(void\\)\\} $hex }} {"free_func()" "FF" {= \\{void \\(void\\)\\} $hex } "void"} {"free_func(void)" "FF" {= \\{void \\(void\\)\\} $hex }} {"free_inline_func()" "FIF" {= \\{void \\(void\\)\\} $hex } "void"} {"free_inline_func(void)" "FIF" {= \\{void \\(void\\)\\} $hex }} } set c_scopes_list { {"free_func" "FF" {= \\{void \\(void\\)\\} $hex }} {"free_inline_func" "FIF" {= \\{void \\(void\\)\\} $hex }} } # A list of all the static varibles defined in each scope. The first # column is the name of the variable, without the prefix, and the # second column is a regex matching what printing the variable should # output. #VAR #PRINT set vars_list { {"s_var_int" " = 4"} {"s_var_float" " = 3.14.*"} {"s_var_aggregate" " = \\{i1 = 1, i2 = 2, i3 = 3\\}"} } proc do_test {lang} { global c_scopes_list global cxx_scopes_list global vars_list global srcfile testfile global gdb_prompt set options {debug} if {$lang == "c++"} { if { ![allow_cplus_tests] } { return } lappend options $lang set src ${srcfile}c } else { set src ${srcfile} } if {[prepare_for_testing "failed to prepare" $testfile-$lang \ [list $src] $options]} { return -1 } if {![runto_main]} { return } gdb_test "show language" " currently [string_to_regexp $lang]\"\\." if {$lang == "c"} { set scopes_list $c_scopes_list } else { set scopes_list $cxx_scopes_list } # Print each scope/function using these syntaxes: # # "(gdb) p 'S::method() const'" # quoted # "(gdb) p S::method() const" # unquoted # foreach scope_line $scopes_list { set scope [lindex $scope_line 0] set print_quoted_re [lindex $scope_line 2] set print_quoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_quoted_re\""] set print_unquoted_re [lindex $scope_line 3] set print_unquoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_unquoted_re\""] gdb_test "print '${scope}'" $print_quoted_re if {$print_unquoted_re != ""} { gdb_test "print ${scope}" $print_unquoted_re } else { gdb_test "print ${scope}" $print_quoted_re } } # Print each variable using these syntaxes: # # 'func()'::var # func()::var # 'func()::var' # # In C++, the latter case makes sure that symbol lookup finds the # debug symbol instead of the minimal symbol with that exact same # name. foreach scope_line $scopes_list { set scope [lindex $scope_line 0] set var_prefix [lindex $scope_line 1] foreach var_line $vars_list { set var [lindex $var_line 0] set print_re [lindex $var_line 1] # The gcc PR debug/55541 has the effect that local statics are # wrapped in a DW_TAG_lexical_block, making them unaddressable from # outside the function. XFAIL the relevant tests. set test "print '${scope}'::${var_prefix}_${var}" set xfail_pattern "No symbol \".*\" in specified context." gdb_test_multiple $test $test { -re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" { pass $test } -re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" { xfail $test } } set test "print ${scope}::${var_prefix}_${var}" gdb_test_multiple $test $test { -re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" { pass $test } -re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" { xfail $test } } set sym "${scope}::${var_prefix}_${var}" if {$lang == "c++"} { set test "print '${sym}'" set xfail_pattern "No symbol .* in current context." set xfail_pattern2 "has unknown type; cast it to its declared type" gdb_test_multiple $test $test { -re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" { pass $test } -re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" { xfail $test } -re "\[\r\n\]*(?:$xfail_pattern2)\[\r\n\]+$gdb_prompt $" { xfail $test } } } else { gdb_test "print '${sym}'" "No symbol \"$sym\" in current context\\." } } } # Now run to each function, and print its variables using the # localy-visible name. foreach scope_line $scopes_list { set scope [lindex $scope_line 0] set var_prefix [lindex $scope_line 1] with_test_prefix "$scope" { delete_breakpoints gdb_breakpoint "$scope" gdb_continue_to_breakpoint "$scope" foreach var_line $vars_list { set var [lindex $var_line 0] set print_re [lindex $var_line 1] gdb_test "print ${var_prefix}_${var}" $print_re } } } } foreach lang {"c" "c++"} { with_test_prefix $lang { do_test $lang } }