From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21252 invoked by alias); 25 Sep 2012 20:54:20 -0000 Received: (qmail 21234 invoked by uid 22791); 25 Sep 2012 20:54:14 -0000 X-SWARE-Spam-Status: No, hits=-6.8 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_BJ,TW_CX,TW_DC X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 25 Sep 2012 20:53:51 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q8PKrn8Z024226 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 25 Sep 2012 16:53:50 -0400 Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q8PKrkkS001785 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Tue, 25 Sep 2012 16:53:47 -0400 From: Tom Tromey To: Magnus Fromreide Cc: gcc-patches@gcc.gnu.org, libstdc Subject: Re: add typedef printers to libstdc++ References: <87vcf7qegs.fsf@fleche.redhat.com> <1348304048.22892.4.camel@sara> Date: Tue, 25 Sep 2012 21:30:00 -0000 In-Reply-To: <1348304048.22892.4.camel@sara> (Magnus Fromreide's message of "Sat, 22 Sep 2012 10:54:08 +0200") Message-ID: <873925259h.fsf@fleche.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2012-09/txt/msg01742.txt.bz2 >>>>> "Magnus" == Magnus Fromreide writes: Magnus> How does it display the types of the variables us, s and ss in the Magnus> following code: It does what you'd expect. Magnus> I would expect it to say std::basic_string, Magnus> std::string and std::basic_string, but I thought a test Magnus> case here couldn't hurt? Here's an updated patch with the new tests. Tom 2012-09-25 Tom Tromey * 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. diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 0eac413..5b11cb0 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -26,6 +26,15 @@ try: except ImportError: _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 # handles searching upward through superclasses. This is needed to # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. @@ -789,6 +798,97 @@ class Printer(object): 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): "Register libstdc++ pretty-printers with objfile Obj." @@ -802,6 +902,8 @@ def register_libstdcxx_printers (obj): obj = gdb obj.pretty_printers.append(libstdcxx_printer) + register_type_printers(obj) + def build_libstdcxx_dictionary (): global libstdcxx_printer diff --git a/libstdc++-v3/testsuite/lib/gdb-test.exp b/libstdc++-v3/testsuite/lib/gdb-test.exp index b9d4742..9457cfe 100644 --- a/libstdc++-v3/testsuite/lib/gdb-test.exp +++ b/libstdc++-v3/testsuite/lib/gdb-test.exp @@ -67,6 +67,13 @@ proc regexp-test {var result} { 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. # 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 # it still stores the filename of the testcase in a local variable "name". # A cleaner solution would require a new DejaGnu release. @@ -109,12 +122,21 @@ proc gdb-test { marker {selector {}} } { puts $fd "run" set count 0 - foreach {var result is_regexp} $gdb_tests { - puts $fd "print $var" + foreach {var result kind} $gdb_tests { incr count set gdb_var($count) $var 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 { + 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 {} @@ -128,28 +150,36 @@ proc gdb-test { marker {selector {}} } { return } + set test_counter 0 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)" - set num $expect_out(1,string) - set first $expect_out(2,string) - - if {$gdb_is_regexp($num)} { - set match [regexp -- $gdb_expected($num) $first] + incr test_counter + set first $expect_out(3,string) + + if {$gdb_is_type($test_counter)} { + 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 { - set match [expr {![string compare $first $gdb_expected($num)]}] + set match [expr {![string compare $first \ + $gdb_expected($test_counter)]}] } if {$match} { - pass "$testname print $gdb_var($num)" + pass "$testname $gdb_command($test_counter)" } else { - fail "$testname print $gdb_var($num)" + fail "$testname $gdb_command($test_counter)" verbose " got =>$first<=" - verbose "expected =>$gdb_expected($num)<=" + verbose "expected =>$gdb_expected($test_counter)<=" } - if {$num == $count} { + if {$test_counter == $count} { remote_close target return } else { @@ -180,16 +210,10 @@ proc gdb-test { marker {selector {}} } { return } -# 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 {} { - global gdb_version - +# Invoke gdb with a command and pattern-match the output. +proc gdb_batch_check {command pattern} { 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" set res [remote_spawn target "$cmd"] if { $res < 0 || $res == "" } { @@ -197,7 +221,7 @@ proc gdb_version_check {} { } remote_expect target [timeout_value] { - -re "" { + -re $pattern { return 1 } @@ -215,3 +239,13 @@ proc gdb_version_check {} { remote_close target 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" \ + ""] +} diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc new file mode 100644 index 0000000..c22246c --- /dev/null +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc @@ -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 +// . + +#include +#include +#include + +template +void +placeholder(const T *s) +{ + std::cout << (void *) s; +} + +template +struct holder +{ + T *f; +}; + +typedef std::basic_string 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 string_holder; +// { dg-final { whatis-test string_holder "holder" } } +std::ios *ios_ptr; +holder ios_holder; +// { dg-final { whatis-test ios_holder "holder" } } +std::streambuf *streambuf_ptr; +holder streambuf_holder; +// { dg-final { whatis-test streambuf_holder "holder" } } +std::istream *istream_ptr; +holder istream_holder; +// { dg-final { whatis-test istream_holder "holder" } } +std::ostream *ostream_ptr; +holder ostream_holder; +// { dg-final { whatis-test ostream_holder "holder" } } +std::iostream *iostream_ptr; +holder iostream_holder; +// { dg-final { whatis-test iostream_holder "holder" } } +std::stringbuf *stringbuf_ptr; +holder stringbuf_holder; +// { dg-final { whatis-test stringbuf_holder "holder" } } +std::istringstream *istringstream_ptr; +holder istringstream_holder; +// { dg-final { whatis-test istringstream_holder "holder" } } +std::ostringstream *ostringstream_ptr; +holder ostringstream_holder; +// { dg-final { whatis-test ostringstream_holder "holder" } } +std::stringstream *stringstream_ptr; +holder stringstream_holder; +// { dg-final { whatis-test stringstream_holder "holder" } } +std::filebuf *filebuf_ptr; +holder filebuf_holder; +// { dg-final { whatis-test filebuf_holder "holder" } } +std::ifstream *ifstream_ptr; +holder ifstream_holder; +// { dg-final { whatis-test ifstream_holder "holder" } } +std::ofstream *ofstream_ptr; +holder ofstream_holder; +// { dg-final { whatis-test ofstream_holder "holder" } } +std::fstream *fstream_ptr; +holder fstream_holder; +// { dg-final { whatis-test fstream_holder "holder" } } +std::streampos *streampos_ptr; +holder streampos_holder; +// { dg-final { whatis-test streampos_holder "holder" } } +std::regex *regex_ptr; +holder regex_holder; +// { dg-final { whatis-test regex_holder "holder" } } +std::csub_match *csub_match_ptr; +holder csub_match_holder; +// { dg-final { whatis-test csub_match_holder "holder" } } +std::ssub_match *ssub_match_ptr; +holder ssub_match_holder; +// { dg-final { whatis-test ssub_match_holder "holder" } } +std::cmatch *cmatch_ptr; +holder cmatch_holder; +// { dg-final { whatis-test cmatch_holder "holder" } } +std::smatch *smatch_ptr; +holder smatch_holder; +// { dg-final { whatis-test smatch_holder "holder" } } +std::cregex_iterator *cregex_iterator_ptr; +holder cregex_iterator_holder; +// { dg-final { whatis-test cregex_iterator_holder "holder" } } +std::sregex_iterator *sregex_iterator_ptr; +holder sregex_iterator_holder; +// { dg-final { whatis-test sregex_iterator_holder "holder" } } +std::cregex_token_iterator *cregex_token_iterator_ptr; +holder cregex_token_iterator_holder; +// { dg-final { whatis-test cregex_token_iterator_holder "holder" } } +std::sregex_token_iterator *sregex_token_iterator_ptr; +holder sregex_token_iterator_holder; +// { dg-final { whatis-test sregex_token_iterator_holder "holder" } } +std::u16string *u16string_ptr; +holder u16string_holder; +// { dg-final { whatis-test u16string_holder "holder" } } +std::u32string *u32string_ptr; +holder u32string_holder; +// { dg-final { whatis-test u32string_holder "holder" } } +std::minstd_rand0 *minstd_rand0_ptr; +holder minstd_rand0_holder; +// { dg-final { whatis-test minstd_rand0_holder "holder" } } +std::minstd_rand *minstd_rand_ptr; +holder minstd_rand_holder; +// { dg-final { whatis-test minstd_rand_holder "holder" } } +std::mt19937 *mt19937_ptr; +holder mt19937_holder; +// { dg-final { whatis-test mt19937_holder "holder" } } +std::mt19937_64 *mt19937_64_ptr; +holder mt19937_64_holder; +// { dg-final { whatis-test mt19937_64_holder "holder" } } +std::ranlux24_base *ranlux24_base_ptr; +holder ranlux24_base_holder; +// { dg-final { whatis-test ranlux24_base_holder "holder" } } +std::ranlux48_base *ranlux48_base_ptr; +holder ranlux48_base_holder; +// { dg-final { whatis-test ranlux48_base_holder "holder" } } +std::ranlux24 *ranlux24_ptr; +holder ranlux24_holder; +// { dg-final { whatis-test ranlux24_holder "holder" } } +std::ranlux48 *ranlux48_ptr; +holder ranlux48_holder; +// { dg-final { whatis-test ranlux48_holder "holder" } } +std::knuth_b *knuth_b_ptr; +holder knuth_b_holder; +// { dg-final { whatis-test knuth_b_holder "holder" } } + +ustring *ustring_ptr; +holder ustring_holder; +// { dg-final { whatis-test ustring_holder "holder, std::allocator > >" } } + +std::basic_string *sstring_ptr; +holder< std::basic_string > sstring_holder; +// { dg-final { whatis-test sstring_holder "holder, std::allocator > >" } } + +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(®ex_ptr); + placeholder(®ex_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 } }