Files
binutils-gdb/gdb/testsuite/gdb.cp/local-static.exp
Pedro Alves e68cb8e001 Handle "p 'S::method()::static_var'" (quoted) in symbol lookup
While the previous commit made "p method()::static_var" (no
single-quotes) Just Work, if users (or frontends) try wrapping the
expression with quotes, they'll get:

  (gdb) p 'S::method()::static_var'
  'S::method()::static_var' has unknown type; cast it to its declared type

even if we _do_ have debug info for that variable.  That's better than
the bogus/confusing value what GDB would print before the
stop-assuming-int patch:

  (gdb) p 'S::method()::static_var'
  $1 = 1

but I think it'd still be nice to make this case Just Work too.

In this case, due to the quoting, the C/C++ parser (c-exp.y)
interprets the whole expression/string as a single symbol name, and we
end up calling lookup_symbol on that name.  There's no debug symbol
with that fully-qualified name, but since the compiler gives the
static variable a mangled linkage name exactly like the above, it
appears in the mininal symbols:

  $ nm -A local-static | c++filt | grep static_var
  local-static:0000000000601040 d S::method()::static_var

... and that's what GDB happens to find/print.  This only happens in
C++, note, since for C the compiler uses different linkage names:

  local-static-c:0000000000601040 d static_var.1848

So while (in C++, not C) function local static variables are given a
mangled name that demangles to the same syntax that GDB
documents/expects as the way to access function local statics, there's
no global symbol in the debug info with that name at all.  The debug
info for a static local variable for a non-inline function looks like
this:

 <1><2a1>: Abbrev Number: 19 (DW_TAG_subprogram)
 ...
 <2><2f7>: Abbrev Number: 20 (DW_TAG_variable)
    <2f8>   DW_AT_name        : (indirect string, offset: 0x4e9): static_var
    <2fc>   DW_AT_decl_file   : 1
    <2fd>   DW_AT_decl_line   : 64
    <2fe>   DW_AT_type        : <0x25>
    <302>   DW_AT_location    : 9 byte block: 3 40 10 60 0 0 0 0 0      (DW_OP_addr: 601040)

and for an inline function, it looks like this (linkage name run
through c++filt for convenience):

 <2><21b>: Abbrev Number: 16 (DW_TAG_variable)
    <21c>   DW_AT_name        : (indirect string, offset: 0x21a): static_var
    <220>   DW_AT_decl_file   : 1
    <221>   DW_AT_decl_line   : 48
    <222>   DW_AT_linkage_name: (indirect string, offset: 0x200): S::inline_method()::static_var
    <226>   DW_AT_type        : <0x25>
    <22a>   DW_AT_external    : 1
    <22a>   DW_AT_location    : 9 byte block: 3 a0 10 60 0 0 0 0 0      (DW_OP_addr: 6010a0)

(The inline case makes the variable external so that the linker can
merge the different inlined copies.  It seems like GCC never outputs
the linkage name for non-extern globals.)

When we read the DWARF, we record the static_var variable as a regular
variable of the containing function's block.  This makes stopping in
the function and printing the variable as usual.  The variable just so
happens to have a memory address as location.

So one way to make "p 'S::method()::static_var'" work would be to
record _two_ copies of the symbols for these variables.  One in the
function's scope/block, with "static_var" as name, as we currently do,
and another in the static or global blocks (depending on whether the
symbol is external), with a fully-qualified name.  I wrote a prototype
patch for that, and it works.  For the non-inline case above, since
the debug info doesn't point to the linkage same, that patch built the
physname of the static local variable as the concat of the physname of
the containing function, plus "::", plus the variable's name.  We
could make that approach work for C too, though it kind of feels
awkward to record fake symbol names like that in C.

The other approach I tried is to change the C++ symbol lookup routines
instead.  This is the approach this commit takes.  We can already
lookup up symbol in namespaces and classes, so this feels like a good
fit, and was easy enough.  The advantage is that this doesn't require
recording extra symbols.

The test in gdb.cp/m-static.exp that exposed the need for this is
removed, since the same functionality is now covered by
gdb.cp/local-static.exp.

gdb/ChangeLog:
2017-09-04  Pedro Alves  <palves@redhat.com>

	* cp-namespace.c (cp_search_static_and_baseclasses): Handle
	function/method scopes; lookup the nested name as a function local
	static variable.

gdb/testsuite/ChangeLog:
2017-09-04  Pedro Alves  <palves@redhat.com>

	* gdb.base/local-static.exp: Also test with
	class::method::variable wholly quoted.
	* gdb.cp/m-static.exp (class::method::variable): Remove test.
2017-09-04 20:21:16 +01:00

149 lines
3.9 KiB
Plaintext

# Copyright 2017 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/>.
# Tests for function local static variables, both C and C++.
# This file is part of the gdb testsuite.
standard_testfile .c
# 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 to make it
# easier to debug the test if something goes wrong.)
#SCOPE #PREFIX
set cxx_scopes_list {
{"S::method()" "S_M"}
{"S::static_method()" "S_SM"}
{"S::inline_method()" "S_IM"}
{"S::static_inline_method()" "S_SIM"}
{"S2<int>::method()" "S2_M"}
{"S2<int>::static_method()" "S2_SM"}
{"S2<int>::inline_method()" "S2_IM"}
{"S2<int>::static_inline_method()" "S2_SIM"}
{"free_func()" "FF"}
{"free_inline_func()" "FIF"}
}
set c_scopes_list {
{"free_func" "FF"}
{"free_inline_func" "FIF"}
}
# 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
set options {debug}
if {$lang == "c++"} {
if { [skip_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] then {
fail "couldn't run to breakpoint"
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 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]
gdb_test "print '${scope}'::${var_prefix}_${var}" $print_re
gdb_test "print ${scope}::${var_prefix}_${var}" $print_re
set sym "${scope}::${var_prefix}_${var}"
if {$lang == "c++"} {
gdb_test "print '${sym}'" $print_re
} 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
}
}