[v2] libstdc++: Add pretty printer for std::stringstreams

Message ID 20220906212429.42986-1-fent@in.tum.de
State Committed
Commit 93257ed603d72b58bb2616da5b63c4c6737f424b
Delegated to: Jonathan Wakely
Headers
Series [v2] libstdc++: Add pretty printer for std::stringstreams |

Commit Message

Philipp Fent Sept. 6, 2022, 9:24 p.m. UTC
  To display (o-,i-)stringstreams in the common case, we just print the
underlying stringbuf, without the many ios_base members. In the
unconventional case that the underlying streambuf was redirected, we
report the redirected target.

Signed-off-by: Philipp Fent <fent@in.tum.de>
---
 libstdc++-v3/python/libstdcxx/v6/printers.py  | 56 +++++++++++++++++++
 .../libstdc++-prettyprinters/debug.cc         | 15 +++++
 .../libstdc++-prettyprinters/simple.cc        | 15 +++++
 .../libstdc++-prettyprinters/simple11.cc      | 15 +++++
 4 files changed, 101 insertions(+)
  

Comments

Jonathan Wakely Sept. 14, 2022, 12:45 p.m. UTC | #1
On Tue, 6 Sept 2022 at 22:25, Philipp Fent <fent@in.tum.de> wrote:
>
> To display (o-,i-)stringstreams in the common case, we just print the
> underlying stringbuf, without the many ios_base members. In the
> unconventional case that the underlying streambuf was redirected, we
> report the redirected target.
>
> Signed-off-by: Philipp Fent <fent@in.tum.de>
> ---
>  libstdc++-v3/python/libstdcxx/v6/printers.py  | 56 +++++++++++++++++++
>  .../libstdc++-prettyprinters/debug.cc         | 15 +++++
>  .../libstdc++-prettyprinters/simple.cc        | 15 +++++
>  .../libstdc++-prettyprinters/simple11.cc      | 15 +++++
>  4 files changed, 101 insertions(+)
>
> diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
> index d70c8d5d616..bd4289c1c62 100644
> --- a/libstdc++-v3/python/libstdcxx/v6/printers.py
> +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
> @@ -969,6 +969,57 @@ class StdStringPrinter:
>      def display_hint (self):
>          return 'string'
>
> +def access_streambuf_ptrs(streambuf):
> +    "Access the streambuf put area pointers"
> +    pbase = streambuf['_M_out_beg']
> +    pptr = streambuf['_M_out_cur']
> +    egptr = streambuf['_M_in_end']
> +    return pbase, pptr, egptr
> +
> +class StdStringBufPrinter:
> +    "Print a std::basic_stringbuf"
> +
> +    def __init__(self, _, val):
> +        self.val = val
> +
> +    def to_string(self):
> +        (pbase, pptr, egptr) = access_streambuf_ptrs(self.val)
> +        # Logic from basic_stringbuf::_M_high_mark()
> +        if pptr:
> +            if not egptr or pptr > egptr:
> +                return pbase.string(length = pptr - pbase)
> +            else:
> +                return pbase.string(length = egptr - pbase)
> +        return self.val['_M_string']
> +
> +    def display_hint(self):
> +        return 'string'
> +
> +class StdStringStreamPrinter:
> +    "Print a std::basic_stringstream"
> +
> +    def __init__(self, typename, val):
> +        self.val = val
> +        self.typename = typename
> +
> +        # Check if the stream was redirected:
> +        # This is essentially: val['_M_streambuf'] == val['_M_stringbuf'].address
> +        # However, GDB can't resolve the virtual inheritance, so we do that manually

Oh yuck, sorry you had to figure that out.

The patch looks good, thanks. I'll get it pushed to trunk.


> +        basetype = [f.type for f in val.type.fields() if f.is_base_class][0]
> +        gdb.set_convenience_variable('__stream', val.cast(basetype).address)
> +        self.streambuf = gdb.parse_and_eval('$__stream->rdbuf()')
> +        self.was_redirected = self.streambuf != val['_M_stringbuf'].address
> +
> +    def to_string(self):
> +        if self.was_redirected:
> +            return "%s redirected to %s" % (self.typename, self.streambuf.dereference())
> +        return self.val['_M_stringbuf']
> +
> +    def display_hint(self):
> +        if self.was_redirected:
> +            return None
> +        return 'string'
> +
>  class Tr1HashtableIterator(Iterator):
>      def __init__ (self, hashtable):
>          self.buckets = hashtable['_M_buckets']
> @@ -2232,6 +2283,11 @@ def build_libstdcxx_dictionary ():
>      libstdcxx_printer.add_version('std::', 'initializer_list',
>                                    StdInitializerListPrinter)
>      libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
> +    libstdcxx_printer.add_version('std::', 'basic_stringbuf', StdStringBufPrinter)
> +    libstdcxx_printer.add_version('std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter)
> +    for sstream in ('istringstream', 'ostringstream', 'stringstream'):
> +        libstdcxx_printer.add_version('std::', 'basic_' + sstream, StdStringStreamPrinter)
> +        libstdcxx_printer.add_version('std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter)
>
>      # std::regex components
>      libstdcxx_printer.add_version('std::__detail::', '_State',
> diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
> index 98bbc182551..3c6195591c5 100644
> --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
> +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
> @@ -29,6 +29,7 @@
>  #include <list>
>  #include <map>
>  #include <set>
> +#include <sstream>
>  #include <vector>
>  #include <ext/slist>
>
> @@ -110,6 +111,20 @@ main()
>    __gnu_cxx::slist<int>::iterator slliter = sll.begin();
>  // { dg-final { note-test slliter {47} } }
>
> +  std::stringstream sstream;
> +  sstream << "abc";
> +// { dg-final { note-test sstream "\"abc\"" } }
> +  std::stringstream ssin("input", std::ios::in);
> +// { dg-final { note-test ssin "\"input\"" } }
> +  std::istringstream ssin2("input");
> +// { dg-final { note-test ssin2 "\"input\"" } }
> +  std::ostringstream ssout;
> +  ssout << "out";
> +// { dg-final { note-test ssout "\"out\"" } }
> +  std::stringstream redirected("xxx");
> +  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
> +// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
> +
>    std::cout << "\n";
>    return 0;                    // Mark SPOT
>  }
> diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
> index 1f85775bff0..1609ae2c8db 100644
> --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
> +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
> @@ -30,6 +30,7 @@
>  #include <list>
>  #include <map>
>  #include <set>
> +#include <sstream>
>  #include <vector>
>  #include <ext/slist>
>
> @@ -169,6 +170,20 @@ main()
>    __gnu_cxx::slist<int>::iterator slliter0;
>  // { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } }
>
> +  std::stringstream sstream;
> +  sstream << "abc";
> +// { dg-final { note-test sstream "\"abc\"" } }
> +  std::stringstream ssin("input", std::ios::in);
> +// { dg-final { note-test ssin "\"input\"" } }
> +  std::istringstream ssin2("input");
> +// { dg-final { note-test ssin2 "\"input\"" } }
> +  std::ostringstream ssout;
> +  ssout << "out";
> +// { dg-final { note-test ssout "\"out\"" } }
> +  std::stringstream redirected("xxx");
> +  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
> +// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
> +
>    std::cout << "\n";
>    return 0;                    // Mark SPOT
>  }
> diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
> index 6f21675cf41..a4b82e30f9c 100644
> --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
> +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
> @@ -30,6 +30,7 @@
>  #include <list>
>  #include <map>
>  #include <set>
> +#include <sstream>
>  #include <vector>
>  #include <ext/slist>
>
> @@ -162,6 +163,20 @@ main()
>    __gnu_cxx::slist<int>::iterator slliter0;
>  // { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } }
>
> +  std::stringstream sstream;
> +  sstream << "abc";
> +// { dg-final { note-test sstream "\"abc\"" } }
> +  std::stringstream ssin("input", std::ios::in);
> +// { dg-final { note-test ssin "\"input\"" } }
> +  std::istringstream ssin2("input");
> +// { dg-final { note-test ssin2 "\"input\"" } }
> +  std::ostringstream ssout;
> +  ssout << "out";
> +// { dg-final { note-test ssout "\"out\"" } }
> +  std::stringstream redirected("xxx");
> +  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
> +// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
> +
>    std::cout << "\n";
>    return 0;                    // Mark SPOT
>  }
> --
> 2.37.3
>
  

Patch

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index d70c8d5d616..bd4289c1c62 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -969,6 +969,57 @@  class StdStringPrinter:
     def display_hint (self):
         return 'string'
 
+def access_streambuf_ptrs(streambuf):
+    "Access the streambuf put area pointers"
+    pbase = streambuf['_M_out_beg']
+    pptr = streambuf['_M_out_cur']
+    egptr = streambuf['_M_in_end']
+    return pbase, pptr, egptr
+
+class StdStringBufPrinter:
+    "Print a std::basic_stringbuf"
+
+    def __init__(self, _, val):
+        self.val = val
+
+    def to_string(self):
+        (pbase, pptr, egptr) = access_streambuf_ptrs(self.val)
+        # Logic from basic_stringbuf::_M_high_mark()
+        if pptr:
+            if not egptr or pptr > egptr:
+                return pbase.string(length = pptr - pbase)
+            else:
+                return pbase.string(length = egptr - pbase)
+        return self.val['_M_string']
+
+    def display_hint(self):
+        return 'string'
+
+class StdStringStreamPrinter:
+    "Print a std::basic_stringstream"
+
+    def __init__(self, typename, val):
+        self.val = val
+        self.typename = typename
+
+        # Check if the stream was redirected:
+        # This is essentially: val['_M_streambuf'] == val['_M_stringbuf'].address
+        # However, GDB can't resolve the virtual inheritance, so we do that manually
+        basetype = [f.type for f in val.type.fields() if f.is_base_class][0]
+        gdb.set_convenience_variable('__stream', val.cast(basetype).address)
+        self.streambuf = gdb.parse_and_eval('$__stream->rdbuf()')
+        self.was_redirected = self.streambuf != val['_M_stringbuf'].address
+
+    def to_string(self):
+        if self.was_redirected:
+            return "%s redirected to %s" % (self.typename, self.streambuf.dereference())
+        return self.val['_M_stringbuf']
+
+    def display_hint(self):
+        if self.was_redirected:
+            return None
+        return 'string'
+
 class Tr1HashtableIterator(Iterator):
     def __init__ (self, hashtable):
         self.buckets = hashtable['_M_buckets']
@@ -2232,6 +2283,11 @@  def build_libstdcxx_dictionary ():
     libstdcxx_printer.add_version('std::', 'initializer_list',
                                   StdInitializerListPrinter)
     libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
+    libstdcxx_printer.add_version('std::', 'basic_stringbuf', StdStringBufPrinter)
+    libstdcxx_printer.add_version('std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter)
+    for sstream in ('istringstream', 'ostringstream', 'stringstream'):
+        libstdcxx_printer.add_version('std::', 'basic_' + sstream, StdStringStreamPrinter)
+        libstdcxx_printer.add_version('std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter)
 
     # std::regex components
     libstdcxx_printer.add_version('std::__detail::', '_State',
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
index 98bbc182551..3c6195591c5 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/debug.cc
@@ -29,6 +29,7 @@ 
 #include <list>
 #include <map>
 #include <set>
+#include <sstream>
 #include <vector>
 #include <ext/slist>
 
@@ -110,6 +111,20 @@  main()
   __gnu_cxx::slist<int>::iterator slliter = sll.begin();
 // { dg-final { note-test slliter {47} } }
 
+  std::stringstream sstream;
+  sstream << "abc";
+// { dg-final { note-test sstream "\"abc\"" } }
+  std::stringstream ssin("input", std::ios::in);
+// { dg-final { note-test ssin "\"input\"" } }
+  std::istringstream ssin2("input");
+// { dg-final { note-test ssin2 "\"input\"" } }
+  std::ostringstream ssout;
+  ssout << "out";
+// { dg-final { note-test ssout "\"out\"" } }
+  std::stringstream redirected("xxx");
+  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
+// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
+
   std::cout << "\n";
   return 0;			// Mark SPOT
 }
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
index 1f85775bff0..1609ae2c8db 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple.cc
@@ -30,6 +30,7 @@ 
 #include <list>
 #include <map>
 #include <set>
+#include <sstream>
 #include <vector>
 #include <ext/slist>
 
@@ -169,6 +170,20 @@  main()
   __gnu_cxx::slist<int>::iterator slliter0;
 // { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } }
 
+  std::stringstream sstream;
+  sstream << "abc";
+// { dg-final { note-test sstream "\"abc\"" } }
+  std::stringstream ssin("input", std::ios::in);
+// { dg-final { note-test ssin "\"input\"" } }
+  std::istringstream ssin2("input");
+// { dg-final { note-test ssin2 "\"input\"" } }
+  std::ostringstream ssout;
+  ssout << "out";
+// { dg-final { note-test ssout "\"out\"" } }
+  std::stringstream redirected("xxx");
+  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
+// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
+
   std::cout << "\n";
   return 0;			// Mark SPOT
 }
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
index 6f21675cf41..a4b82e30f9c 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/simple11.cc
@@ -30,6 +30,7 @@ 
 #include <list>
 #include <map>
 #include <set>
+#include <sstream>
 #include <vector>
 #include <ext/slist>
 
@@ -162,6 +163,20 @@  main()
   __gnu_cxx::slist<int>::iterator slliter0;
 // { dg-final { note-test slliter0 {non-dereferenceable iterator for __gnu_cxx::slist} } }
 
+  std::stringstream sstream;
+  sstream << "abc";
+// { dg-final { note-test sstream "\"abc\"" } }
+  std::stringstream ssin("input", std::ios::in);
+// { dg-final { note-test ssin "\"input\"" } }
+  std::istringstream ssin2("input");
+// { dg-final { note-test ssin2 "\"input\"" } }
+  std::ostringstream ssout;
+  ssout << "out";
+// { dg-final { note-test ssout "\"out\"" } }
+  std::stringstream redirected("xxx");
+  static_cast<std::basic_ios<std::stringstream::char_type>&>(redirected).rdbuf(sstream.rdbuf());
+// { dg-final { regexp-test redirected {std::.*stringstream redirected to .*} } }
+
   std::cout << "\n";
   return 0;			// Mark SPOT
 }