whatis.cc: New file.

* testsuite/libstdc++-prettyprinters/whatis.cc: New file.
	* testsuite/lib/gdb-test.exp (whatis-test): New proc.
	(gdb-test): Handle 'whatis' tests.
	(gdb_batch_check): New proc.
	(gdb_version_check): Rewrite to use gdb_batch_check.
	* python/libstdcxx/v6/printers.py: Import gdb.types.
	(FilteringTypePrinter): New class.
	(add_one_type_printer, register_type_printers): New functions.
	(register_libstdcxx_printers): Call register_type_printers.

From-SVN: r193573
This commit is contained in:
Tom Tromey 2012-11-16 18:17:25 +00:00 committed by Tom Tromey
parent 9bec80b04e
commit 50605a7f19
4 changed files with 418 additions and 23 deletions

View File

@ -1,3 +1,15 @@
2012-11-16 Tom Tromey <tromey@redhat.com>
* testsuite/libstdc++-prettyprinters/whatis.cc: New file.
* testsuite/lib/gdb-test.exp (whatis-test): New proc.
(gdb-test): Handle 'whatis' tests.
(gdb_batch_check): New proc.
(gdb_version_check): Rewrite to use gdb_batch_check.
* python/libstdcxx/v6/printers.py: Import gdb.types.
(FilteringTypePrinter): New class.
(add_one_type_printer, register_type_printers): New functions.
(register_libstdcxx_printers): Call register_type_printers.
2012-11-15 Jonathan Wakely <jwakely.gcc@gmail.com> 2012-11-15 Jonathan Wakely <jwakely.gcc@gmail.com>
PR libstdc++/53841 PR libstdc++/53841

View File

@ -26,6 +26,15 @@ try:
except ImportError: except ImportError:
_use_gdb_pp = False _use_gdb_pp = False
# Try to install type-printers.
_use_type_printing = False
try:
import gdb.types
if hasattr(gdb.types, 'TypePrinter'):
_use_type_printing = True
except ImportError:
pass
# Starting with the type ORIG, search for the member type NAME. This # Starting with the type ORIG, search for the member type NAME. This
# handles searching upward through superclasses. This is needed to # handles searching upward through superclasses. This is needed to
# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
@ -801,6 +810,97 @@ class Printer(object):
libstdcxx_printer = None libstdcxx_printer = None
class FilteringTypePrinter(object):
def __init__(self, match, name):
self.match = match
self.name = name
self.enabled = True
class _recognizer(object):
def __init__(self, match, name):
self.match = match
self.name = name
self.type_obj = None
def recognize(self, type_obj):
if type_obj.tag is None:
return None
if self.type_obj is None:
if not self.match in type_obj.tag:
# Filter didn't match.
return None
try:
self.type_obj = gdb.lookup_type(self.name).strip_typedefs()
except:
pass
if self.type_obj == type_obj:
return self.name
return None
def instantiate(self):
return self._recognizer(self.match, self.name)
def add_one_type_printer(obj, match, name):
printer = FilteringTypePrinter(match, 'std::' + name)
gdb.types.register_type_printer(obj, printer)
def register_type_printers(obj):
global _use_type_printing
if not _use_type_printing:
return
for pfx in ('', 'w'):
add_one_type_printer(obj, 'basic_string', pfx + 'string')
add_one_type_printer(obj, 'basic_ios', pfx + 'ios')
add_one_type_printer(obj, 'basic_streambuf', pfx + 'streambuf')
add_one_type_printer(obj, 'basic_istream', pfx + 'istream')
add_one_type_printer(obj, 'basic_ostream', pfx + 'ostream')
add_one_type_printer(obj, 'basic_iostream', pfx + 'iostream')
add_one_type_printer(obj, 'basic_stringbuf', pfx + 'stringbuf')
add_one_type_printer(obj, 'basic_istringstream',
pfx + 'istringstream')
add_one_type_printer(obj, 'basic_ostringstream',
pfx + 'ostringstream')
add_one_type_printer(obj, 'basic_stringstream',
pfx + 'stringstream')
add_one_type_printer(obj, 'basic_filebuf', pfx + 'filebuf')
add_one_type_printer(obj, 'basic_ifstream', pfx + 'ifstream')
add_one_type_printer(obj, 'basic_ofstream', pfx + 'ofstream')
add_one_type_printer(obj, 'basic_fstream', pfx + 'fstream')
add_one_type_printer(obj, 'basic_regex', pfx + 'regex')
add_one_type_printer(obj, 'sub_match', pfx + 'csub_match')
add_one_type_printer(obj, 'sub_match', pfx + 'ssub_match')
add_one_type_printer(obj, 'match_results', pfx + 'cmatch')
add_one_type_printer(obj, 'match_results', pfx + 'smatch')
add_one_type_printer(obj, 'regex_iterator', pfx + 'cregex_iterator')
add_one_type_printer(obj, 'regex_iterator', pfx + 'sregex_iterator')
add_one_type_printer(obj, 'regex_token_iterator',
pfx + 'cregex_token_iterator')
add_one_type_printer(obj, 'regex_token_iterator',
pfx + 'sregex_token_iterator')
# Note that we can't have a printer for std::wstreampos, because
# it shares the same underlying type as std::streampos.
add_one_type_printer(obj, 'fpos', 'streampos')
add_one_type_printer(obj, 'basic_string', 'u16string')
add_one_type_printer(obj, 'basic_string', 'u32string')
for dur in ('nanoseconds', 'microseconds', 'milliseconds',
'seconds', 'minutes', 'hours'):
add_one_type_printer(obj, 'duration', dur)
add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64')
add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base')
add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base')
add_one_type_printer(obj, 'discard_block_engine', 'ranlux24')
add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
def register_libstdcxx_printers (obj): def register_libstdcxx_printers (obj):
"Register libstdc++ pretty-printers with objfile Obj." "Register libstdc++ pretty-printers with objfile Obj."
@ -814,6 +914,8 @@ def register_libstdcxx_printers (obj):
obj = gdb obj = gdb
obj.pretty_printers.append(libstdcxx_printer) obj.pretty_printers.append(libstdcxx_printer)
register_type_printers(obj)
def build_libstdcxx_dictionary (): def build_libstdcxx_dictionary ():
global libstdcxx_printer global libstdcxx_printer

View File

@ -67,6 +67,13 @@ proc regexp-test {var result} {
lappend gdb_tests $var $result 1 lappend gdb_tests $var $result 1
} }
# A test of 'whatis'. This tests a type rather than a variable.
proc whatis-test {var result} {
global gdb_tests
lappend gdb_tests $var $result whatis
}
# Utility for testing variable values using gdb, invoked via dg-final. # Utility for testing variable values using gdb, invoked via dg-final.
# Tests all tests indicated by note-test and regexp-test. # Tests all tests indicated by note-test and regexp-test.
# #
@ -84,6 +91,12 @@ proc gdb-test { marker {selector {}} } {
} }
} }
set do_whatis_tests [gdb_batch_check "python print gdb.type_printers" \
"\\\[\\\]"]
if {!$do_whatis_tests} {
send_log "skipping 'whatis' tests - gdb too old"
}
# This assumes that we are three frames down from dg-test, and that # This assumes that we are three frames down from dg-test, and that
# it still stores the filename of the testcase in a local variable "name". # it still stores the filename of the testcase in a local variable "name".
# A cleaner solution would require a new DejaGnu release. # A cleaner solution would require a new DejaGnu release.
@ -109,12 +122,25 @@ proc gdb-test { marker {selector {}} } {
puts $fd "run" puts $fd "run"
set count 0 set count 0
foreach {var result is_regexp} $gdb_tests { foreach {var result kind} $gdb_tests {
puts $fd "print $var"
incr count incr count
set gdb_var($count) $var set gdb_var($count) $var
set gdb_expected($count) $result set gdb_expected($count) $result
set gdb_is_regexp($count) $is_regexp if {$kind == "whatis"} {
if {$do_whatis_tests} {
set gdb_is_type($count) 1
set gdb_command($count) "whatis $var"
} else {
unsupported "$testname"
close $fd
return
}
} else {
set gdb_is_type($count) 0
set gdb_is_regexp($count) $kind
set gdb_command($count) "print $var"
}
puts $fd $gdb_command($count)
} }
set gdb_tests {} set gdb_tests {}
@ -128,28 +154,36 @@ proc gdb-test { marker {selector {}} } {
return return
} }
set test_counter 0
remote_expect target [timeout_value] { remote_expect target [timeout_value] {
-re {^\$([0-9]+) = ([^\n\r]*)[\n\r]+} { -re {^(type|\$([0-9]+)) = ([^\n\r]*)[\n\r]+} {
send_log "got: $expect_out(buffer)" send_log "got: $expect_out(buffer)"
set num $expect_out(1,string) incr test_counter
set first $expect_out(2,string) set first $expect_out(3,string)
if {$gdb_is_regexp($num)} { if {$gdb_is_type($test_counter)} {
set match [regexp -- $gdb_expected($num) $first] if {$expect_out(1,string) != "type"} {
error "gdb failure"
}
set match [expr {![string compare $first \
$gdb_expected($test_counter)]}]
} elseif {$gdb_is_regexp($test_counter)} {
set match [regexp -- $gdb_expected($test_counter) $first]
} else { } else {
set match [expr {![string compare $first $gdb_expected($num)]}] set match [expr {![string compare $first \
$gdb_expected($test_counter)]}]
} }
if {$match} { if {$match} {
pass "$testname print $gdb_var($num)" pass "$testname $gdb_command($test_counter)"
} else { } else {
fail "$testname print $gdb_var($num)" fail "$testname $gdb_command($test_counter)"
verbose " got =>$first<=" verbose " got =>$first<="
verbose "expected =>$gdb_expected($num)<=" verbose "expected =>$gdb_expected($test_counter)<="
} }
if {$num == $count} { if {$test_counter == $count} {
remote_close target remote_close target
return return
} else { } else {
@ -180,16 +214,10 @@ proc gdb-test { marker {selector {}} } {
return return
} }
# Check for a new-enough version of gdb. The pretty-printer tests # Invoke gdb with a command and pattern-match the output.
# require gdb 7.3, but we don't want to test versions, so instead we proc gdb_batch_check {command pattern} {
# check for the python "lookup_global_symbol" method, which is in 7.3
# but not earlier versions.
# Return 1 if the version is ok, 0 otherwise.
proc gdb_version_check {} {
global gdb_version
set gdb_name $::env(GUALITY_GDB_NAME) set gdb_name $::env(GUALITY_GDB_NAME)
set cmd "$gdb_name -nw -nx -quiet -batch -ex \"python print gdb.lookup_global_symbol\"" set cmd "$gdb_name -nw -nx -quiet -batch -ex \"$command\""
send_log "Spawning: $cmd\n" send_log "Spawning: $cmd\n"
set res [remote_spawn target "$cmd"] set res [remote_spawn target "$cmd"]
if { $res < 0 || $res == "" } { if { $res < 0 || $res == "" } {
@ -197,7 +225,7 @@ proc gdb_version_check {} {
} }
remote_expect target [timeout_value] { remote_expect target [timeout_value] {
-re "<built-in function lookup_global_symbol>" { -re $pattern {
return 1 return 1
} }
@ -215,3 +243,13 @@ proc gdb_version_check {} {
remote_close target remote_close target
return 0 return 0
} }
# Check for a new-enough version of gdb. The pretty-printer tests
# require gdb 7.3, but we don't want to test versions, so instead we
# check for the python "lookup_global_symbol" method, which is in 7.3
# but not earlier versions.
# Return 1 if the version is ok, 0 otherwise.
proc gdb_version_check {} {
return [gdb_batch_check "python print gdb.lookup_global_symbol" \
"<built-in function lookup_global_symbol>"]
}

View File

@ -0,0 +1,243 @@
// { dg-do run }
// { dg-options "-g -O0 -std=gnu++11" }
// Copyright (C) 2011, 2012 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library 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, or (at your option)
// any later version.
// This library 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 library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include <string>
#include <iostream>
#include <regex>
template<class T>
void
placeholder(const T *s)
{
std::cout << (void *) s;
}
template<class T>
struct holder
{
T *f;
};
typedef std::basic_string<unsigned char> ustring;
// This test is written in a somewhat funny way.
// Each type under test is used twice: first, to form a pointer type,
// and second, as a template parameter. This is done to work around
// apparent GCC oddities. The pointer type is needed to ensure that
// the typedef in question ends up in the debuginfo; while the
// template type is used to ensure that a typedef-less variant is
// presented to gdb.
std::string *string_ptr;
holder<std::string> string_holder;
// { dg-final { whatis-test string_holder "holder<std::string>" } }
std::ios *ios_ptr;
holder<std::ios> ios_holder;
// { dg-final { whatis-test ios_holder "holder<std::ios>" } }
std::streambuf *streambuf_ptr;
holder<std::streambuf> streambuf_holder;
// { dg-final { whatis-test streambuf_holder "holder<std::streambuf>" } }
std::istream *istream_ptr;
holder<std::istream> istream_holder;
// { dg-final { whatis-test istream_holder "holder<std::istream>" } }
std::ostream *ostream_ptr;
holder<std::ostream> ostream_holder;
// { dg-final { whatis-test ostream_holder "holder<std::ostream>" } }
std::iostream *iostream_ptr;
holder<std::iostream> iostream_holder;
// { dg-final { whatis-test iostream_holder "holder<std::iostream>" } }
std::stringbuf *stringbuf_ptr;
holder<std::stringbuf> stringbuf_holder;
// { dg-final { whatis-test stringbuf_holder "holder<std::stringbuf>" } }
std::istringstream *istringstream_ptr;
holder<std::istringstream> istringstream_holder;
// { dg-final { whatis-test istringstream_holder "holder<std::istringstream>" } }
std::ostringstream *ostringstream_ptr;
holder<std::ostringstream> ostringstream_holder;
// { dg-final { whatis-test ostringstream_holder "holder<std::ostringstream>" } }
std::stringstream *stringstream_ptr;
holder<std::stringstream> stringstream_holder;
// { dg-final { whatis-test stringstream_holder "holder<std::stringstream>" } }
std::filebuf *filebuf_ptr;
holder<std::filebuf> filebuf_holder;
// { dg-final { whatis-test filebuf_holder "holder<std::filebuf>" } }
std::ifstream *ifstream_ptr;
holder<std::ifstream> ifstream_holder;
// { dg-final { whatis-test ifstream_holder "holder<std::ifstream>" } }
std::ofstream *ofstream_ptr;
holder<std::ofstream> ofstream_holder;
// { dg-final { whatis-test ofstream_holder "holder<std::ofstream>" } }
std::fstream *fstream_ptr;
holder<std::fstream> fstream_holder;
// { dg-final { whatis-test fstream_holder "holder<std::fstream>" } }
std::streampos *streampos_ptr;
holder<std::streampos> streampos_holder;
// { dg-final { whatis-test streampos_holder "holder<std::streampos>" } }
std::regex *regex_ptr;
holder<std::regex> regex_holder;
// { dg-final { whatis-test regex_holder "holder<std::regex>" } }
std::csub_match *csub_match_ptr;
holder<std::csub_match> csub_match_holder;
// { dg-final { whatis-test csub_match_holder "holder<std::csub_match>" } }
std::ssub_match *ssub_match_ptr;
holder<std::ssub_match> ssub_match_holder;
// { dg-final { whatis-test ssub_match_holder "holder<std::ssub_match>" } }
std::cmatch *cmatch_ptr;
holder<std::cmatch> cmatch_holder;
// { dg-final { whatis-test cmatch_holder "holder<std::cmatch>" } }
std::smatch *smatch_ptr;
holder<std::smatch> smatch_holder;
// { dg-final { whatis-test smatch_holder "holder<std::smatch>" } }
std::cregex_iterator *cregex_iterator_ptr;
holder<std::cregex_iterator> cregex_iterator_holder;
// { dg-final { whatis-test cregex_iterator_holder "holder<std::cregex_iterator>" } }
std::sregex_iterator *sregex_iterator_ptr;
holder<std::sregex_iterator> sregex_iterator_holder;
// { dg-final { whatis-test sregex_iterator_holder "holder<std::sregex_iterator>" } }
std::cregex_token_iterator *cregex_token_iterator_ptr;
holder<std::cregex_token_iterator> cregex_token_iterator_holder;
// { dg-final { whatis-test cregex_token_iterator_holder "holder<std::cregex_token_iterator>" } }
std::sregex_token_iterator *sregex_token_iterator_ptr;
holder<std::sregex_token_iterator> sregex_token_iterator_holder;
// { dg-final { whatis-test sregex_token_iterator_holder "holder<std::sregex_token_iterator>" } }
std::u16string *u16string_ptr;
holder<std::u16string> u16string_holder;
// { dg-final { whatis-test u16string_holder "holder<std::u16string>" } }
std::u32string *u32string_ptr;
holder<std::u32string> u32string_holder;
// { dg-final { whatis-test u32string_holder "holder<std::u32string>" } }
std::minstd_rand0 *minstd_rand0_ptr;
holder<std::minstd_rand0> minstd_rand0_holder;
// { dg-final { whatis-test minstd_rand0_holder "holder<std::minstd_rand0>" } }
std::minstd_rand *minstd_rand_ptr;
holder<std::minstd_rand> minstd_rand_holder;
// { dg-final { whatis-test minstd_rand_holder "holder<std::minstd_rand>" } }
std::mt19937 *mt19937_ptr;
holder<std::mt19937> mt19937_holder;
// { dg-final { whatis-test mt19937_holder "holder<std::mt19937>" } }
std::mt19937_64 *mt19937_64_ptr;
holder<std::mt19937_64> mt19937_64_holder;
// { dg-final { whatis-test mt19937_64_holder "holder<std::mt19937_64>" } }
std::ranlux24_base *ranlux24_base_ptr;
holder<std::ranlux24_base> ranlux24_base_holder;
// { dg-final { whatis-test ranlux24_base_holder "holder<std::ranlux24_base>" } }
std::ranlux48_base *ranlux48_base_ptr;
holder<std::ranlux48_base> ranlux48_base_holder;
// { dg-final { whatis-test ranlux48_base_holder "holder<std::ranlux48_base>" } }
std::ranlux24 *ranlux24_ptr;
holder<std::ranlux24> ranlux24_holder;
// { dg-final { whatis-test ranlux24_holder "holder<std::ranlux24>" } }
std::ranlux48 *ranlux48_ptr;
holder<std::ranlux48> ranlux48_holder;
// { dg-final { whatis-test ranlux48_holder "holder<std::ranlux48>" } }
std::knuth_b *knuth_b_ptr;
holder<std::knuth_b> knuth_b_holder;
// { dg-final { whatis-test knuth_b_holder "holder<std::knuth_b>" } }
ustring *ustring_ptr;
holder<ustring> ustring_holder;
// { dg-final { whatis-test ustring_holder "holder<std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> > >" } }
std::basic_string<signed char> *sstring_ptr;
holder< std::basic_string<signed char> > sstring_holder;
// { dg-final { whatis-test sstring_holder "holder<std::basic_string<signed char, std::char_traits<signed char>, std::allocator<signed char> > >" } }
int
main()
{
placeholder(&ios_ptr); // Mark SPOT
placeholder(&ios_holder);
placeholder(&string_ptr);
placeholder(&string_holder);
placeholder(&streambuf_ptr);
placeholder(&streambuf_holder);
placeholder(&istream_ptr);
placeholder(&istream_holder);
placeholder(&ostream_ptr);
placeholder(&ostream_holder);
placeholder(&iostream_ptr);
placeholder(&iostream_holder);
placeholder(&stringbuf_ptr);
placeholder(&stringbuf_holder);
placeholder(&istringstream_ptr);
placeholder(&istringstream_holder);
placeholder(&ostringstream_ptr);
placeholder(&ostringstream_holder);
placeholder(&stringstream_ptr);
placeholder(&stringstream_holder);
placeholder(&filebuf_ptr);
placeholder(&filebuf_holder);
placeholder(&ifstream_ptr);
placeholder(&ifstream_holder);
placeholder(&ofstream_ptr);
placeholder(&ofstream_holder);
placeholder(&fstream_ptr);
placeholder(&fstream_holder);
placeholder(&streampos_ptr);
placeholder(&streampos_holder);
placeholder(&regex_ptr);
placeholder(&regex_holder);
placeholder(&csub_match_ptr);
placeholder(&csub_match_holder);
placeholder(&ssub_match_ptr);
placeholder(&ssub_match_holder);
placeholder(&cmatch_ptr);
placeholder(&cmatch_holder);
placeholder(&smatch_ptr);
placeholder(&smatch_holder);
placeholder(&cregex_iterator_ptr);
placeholder(&cregex_iterator_holder);
placeholder(&sregex_iterator_ptr);
placeholder(&sregex_iterator_holder);
placeholder(&cregex_token_iterator_ptr);
placeholder(&cregex_token_iterator_holder);
placeholder(&sregex_token_iterator_ptr);
placeholder(&sregex_token_iterator_holder);
placeholder(&u16string_ptr);
placeholder(&u16string_holder);
placeholder(&u32string_ptr);
placeholder(&u32string_holder);
placeholder(&minstd_rand0_ptr);
placeholder(&minstd_rand0_holder);
placeholder(&minstd_rand_ptr);
placeholder(&minstd_rand_holder);
placeholder(&mt19937_ptr);
placeholder(&mt19937_holder);
placeholder(&mt19937_64_ptr);
placeholder(&mt19937_64_holder);
placeholder(&ranlux24_base_ptr);
placeholder(&ranlux24_base_holder);
placeholder(&ranlux48_base_ptr);
placeholder(&ranlux48_base_holder);
placeholder(&ranlux24_ptr);
placeholder(&ranlux24_holder);
placeholder(&ranlux48_ptr);
placeholder(&ranlux48_holder);
placeholder(&knuth_b_ptr);
placeholder(&knuth_b_holder);
placeholder(&ustring_ptr);
placeholder(&ustring_holder);
placeholder(&sstring_ptr);
placeholder(&sstring_holder);
return 0;
}
// { dg-final { gdb-test SPOT } }