public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* WIP _GLIBCXX_DEBUG backtrace
@ 2022-07-04 17:20 François Dumont
  2022-07-04 19:52 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: François Dumont @ 2022-07-04 17:20 UTC (permalink / raw)
  To: libstdc++

[-- Attachment #1: Type: text/plain, Size: 1866 bytes --]

Hi

Here is the patch to add backtrace to _GLIBCXX_DEBUG mode. It is using 
the recently introduced _GLIBCXX_HAS_STACKTRACE.

It is only WIP because for the moment I had to add:

// { dg-options "-lstdc++_libbacktrace" }

to avoid unresolved symbols.

How should I handle this ?

1. Ask the user to define _GLIBCXX_DEBUG_STACKTRACE to get the backtrace 
and so also require to add this linker option.

2. Is it possible to add something in formatter.h to automagically link 
libstdc++_libbacktrace ?

3. Add symbols to libstdc++.so ?

Output sample:

/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:264:
In function:
     void std::debug::vector<_Tp, _Allocator>::assign(_InputIterator,
     _InputIterator) [with _InputIterator = const int*;
     <template-parameter-2-2> = void; _Tp = int; _Allocator =
     std::allocator<int>]

Backtrace:
     0x40284a void std::debug::vector<int, std::allocator<int> 
 >::assign<int const*, void>(int const*, int const*)
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:264
     0x402bed void gnu_test::check_assign1<std::debug::vector<int, 
std::allocator<int> > >()
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/util/debug/checks.h:111
     0x40246c test01()
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc:26
     0x40246c main
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc:31

Error: function requires a valid iterator range [first, last).

Objects involved in the operation:
     iterator "first" @ 0x7ffe09e62fd8 {
       type = int const* (constant iterator);
     }
     iterator "last" @ 0x7ffe09e62fd0 {
       type = int const* (constant iterator);
     }
XFAIL: 23_containers/vector/debug/assign4_neg.cc execution test

François


[-- Attachment #2: debug_backtrace.patch --]
[-- Type: text/x-patch, Size: 11410 bytes --]

diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index 80e8ba46d1e..f77912c3fd2 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -31,6 +31,30 @@
 
 #include <bits/c++config.h>
 
+struct __glibcxx_backtrace_state;
+
+#if _GLIBCXX_HAVE_STACKTRACE
+extern "C"
+{
+  __glibcxx_backtrace_state*
+  __glibcxx_backtrace_create_state(const char*, int,
+				   void(*)(void*, const char*, int),
+				   void*);
+
+  typedef int (*__glibcxx_backtrace_full_callback) (
+    void*, __UINTPTR_TYPE__, const char *, int, const char*);
+
+  typedef void (*__glibcxx_backtrace_error_callback) (
+    void*, const char*, int);
+
+  int
+  __glibcxx_backtrace_full(__glibcxx_backtrace_state*, int,
+	   __glibcxx_backtrace_full_callback,
+	   __glibcxx_backtrace_error_callback,
+	   void*);
+}
+#endif
+
 #if __cpp_rtti
 # include <typeinfo>
 # define _GLIBCXX_TYPEID(_Type) &typeid(_Type)
@@ -560,11 +584,25 @@ namespace __gnu_debug
     _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED;
 #endif
 
+#if _GLIBCXX_HAVE_STACKTRACE
+    int
+    _M_backtrace_full(__glibcxx_backtrace_state* __st, int __skip,
+		      __glibcxx_backtrace_full_callback __cb,
+		      __glibcxx_backtrace_error_callback __ecb,
+		      void* __data) const;
+#endif
+
   private:
     _Error_formatter(const char* __file, unsigned int __line,
 		     const char* __function)
     : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
     , _M_function(__function)
+#if _GLIBCXX_HAVE_STACKTRACE
+    , _M_backtrace_state(
+      __glibcxx_backtrace_create_state(nullptr, 0, nullptr, nullptr))
+#else
+    , _M_backtrace_state()
+#endif
     { }
 
 #if !_GLIBCXX_INLINE_VERSION
@@ -580,6 +618,7 @@ namespace __gnu_debug
     unsigned int	_M_num_parameters;
     const char*		_M_text;
     const char*		_M_function;
+    __glibcxx_backtrace_state*	_M_backtrace_state;
 
   public:
     static _Error_formatter&
@@ -589,6 +628,16 @@ namespace __gnu_debug
       return __formatter;
     }
   };
+
+#if _GLIBCXX_HAVE_STACKTRACE
+  int
+  _Error_formatter::_M_backtrace_full(__glibcxx_backtrace_state* __st, int __skip,
+				      __glibcxx_backtrace_full_callback __cb,
+				      __glibcxx_backtrace_error_callback __ecb,
+				      void* __data) const
+  { return __glibcxx_backtrace_full(__st, __skip, __cb, __ecb, __data); }
+#endif
+
 } // namespace __gnu_debug
 
 #undef _GLIBCXX_TYPEID
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 4706defedf1..39ecc7817b7 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -607,12 +607,12 @@ namespace
     { print_word(ctx, word, Length - 1); }
 
   void
-  print_raw(PrintContext& ctx, const char* str, ptrdiff_t nbc = -1)
+  print_raw(PrintContext&, const char* str, ptrdiff_t nbc)
   {
     if (nbc >= 0)
-      ctx._M_column += fprintf(stderr, "%.*s", (int)nbc, str);
+      fprintf(stderr, "%.*s", (int)nbc, str);
     else
-      ctx._M_column += fprintf(stderr, "%s", str);
+      fprintf(stderr, "%s", str);
   }
 
   void
@@ -646,6 +646,7 @@ namespace
 	  {
 	    const char spacing[PrintContext::_S_indent + 1] = "    ";
 	    print_raw(ctx, spacing, PrintContext::_S_indent);
+	    ctx._M_column += PrintContext::_S_indent;
 	  }
 
 	int written = fprintf(stderr, "%.*s", (int)length, word);
@@ -666,25 +667,35 @@ namespace
   }
 
   void
-  pretty_print(PrintContext& ctx, const char* str, _Print_func_t print_func)
+  print_function(PrintContext& ctx, const char* func, _Print_func_t print_func)
   {
-    const char cxx1998[] = "cxx1998::";
+    const char cxx1998[] = "__cxx1998::";
+    const char uglification[] = "__";
     for (;;)
       {
-	if (auto pos = strstr(str, "__"))
+	size_t offset;
+	auto idx = strstr(func, cxx1998);
+	if (idx)
+	  offset = sizeof(cxx1998) - 1;
+	else if ((idx = strstr(func, uglification)))
+	  offset = sizeof(uglification) - 1;
+
+	if (idx)
 	  {
-	    if (pos != str)
-	      print_func(ctx, str, pos - str);
+	    if (idx != func)
+	      print_func(ctx, func, idx - func);
 
-	    pos += 2; // advance past "__"
-	    if (memcmp(pos, cxx1998, 9) == 0)
-	      pos += 9; // advance part "cxx1998::"
+	    func = idx + offset;
 
-	    str = pos;
+	    while (*func && isspace((unsigned char)*func))
+	      ++func;
+
+	    if (!*func)
+	      break;
 	  }
 	else
 	  {
-	    print_func(ctx, str, -1);
+	    print_func(ctx, func, -1);
 	    break;
 	  }
       }
@@ -704,9 +715,9 @@ namespace
 	  char* demangled_name =
 	    __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status);
 	  if (status == 0)
-	    pretty_print(ctx, demangled_name, &print_word);
+	    print_function(ctx, demangled_name, &print_word);
 	  else
-	    print_word(ctx, info->name());
+	    print_word(ctx, info->name(), -1);
 	  free(demangled_name);
 	}
     }
@@ -735,7 +746,7 @@ namespace
   print_named_name(PrintContext& ctx, const _Parameter::_Named& named)
   {
     assert(named._M_name);
-    pretty_print(ctx, named._M_name, print_word);
+    print_function(ctx, named._M_name, print_word);
   }
 
   template<typename _Iterator>
@@ -1036,7 +1047,7 @@ namespace
 	// first.
 	if (str != start)
 	  {
-	    // Avoid printing the '%'.
+	    // Avoid to print the '%'.
 	    if (str - start > 1)
 	      print_word(ctx, start, str - start - 1);
 	    start = str;
@@ -1090,6 +1101,58 @@ namespace
   void
   print_string(PrintContext& ctx, const char* str, ptrdiff_t nbc)
   { print_string(ctx, str, nbc, nullptr, 0); }
+
+#if _GLIBCXX_HAVE_STACKTRACE
+  int
+  print_backtrace(void* data, __UINTPTR_TYPE__ pc, const char* filename,
+		  int lineno, const char* function)
+  {
+    const int bufsize = 64;
+    char buf[bufsize];
+
+    PrintContext& ctx = *static_cast<PrintContext*>(data);
+
+    int written = __builtin_sprintf(buf, "%p ", (void*)pc);
+    print_word(ctx, buf, written);
+
+    int ret = 0;
+    if (function)
+      {
+	int status;
+	char* demangled_name =
+	  __cxxabiv1::__cxa_demangle(function, NULL, NULL, &status);
+	if (status == 0)
+	  print_function(ctx, demangled_name, &print_raw);
+	else
+	  print_word(ctx, function);
+
+	free(demangled_name);
+	ret = strstr(function, "main") ? 1 : 0;
+      }
+
+    print_literal(ctx, "\n");
+
+    if (filename)
+      {
+	bool wordwrap = false;
+	swap(wordwrap, ctx._M_wordwrap);
+	print_word(ctx, filename);
+
+	if (lineno)
+	  {
+	    written = __builtin_sprintf(buf, ":%u\n", lineno);
+	    print_word(ctx, buf, written);
+	  }
+	else
+	  print_literal(ctx, "\n");
+	swap(wordwrap, ctx._M_wordwrap);
+      }
+    else
+      print_literal(ctx, "???:0\n");
+
+    return ret;
+  }
+#endif
 }
 
 namespace __gnu_debug
@@ -1109,7 +1172,7 @@ namespace __gnu_debug
     PrintContext ctx;
     if (_M_file)
       {
-	print_raw(ctx, _M_file);
+	print_raw(ctx, _M_file, -1);
 	print_literal(ctx, ":");
 	go_to_next_line = true;
       }
@@ -1130,12 +1193,23 @@ namespace __gnu_debug
     if (_M_function)
       {
 	print_literal(ctx, "In function:\n");
-	pretty_print(ctx, _M_function, &print_string);
+	print_function(ctx, _M_function, &print_string);
 	print_literal(ctx, "\n");
 	ctx._M_first_line = true;
 	print_literal(ctx, "\n");
       }
 
+#if _GLIBCXX_HAVE_STACKTRACE
+    if (_M_backtrace_state)
+      {
+	print_literal(ctx, "Backtrace:\n");
+	_M_backtrace_full(
+	  _M_backtrace_state, 1, print_backtrace, nullptr, &ctx);
+	ctx._M_first_line = true;
+	print_literal(ctx, "\n");
+      }
+#endif
+
     print_literal(ctx, "Error: ");
 
     // Print the error message
diff --git a/libstdc++-v3/src/libbacktrace/Makefile.am b/libstdc++-v3/src/libbacktrace/Makefile.am
index 0f1143507f3..52d8f81b97b 100644
--- a/libstdc++-v3/src/libbacktrace/Makefile.am
+++ b/libstdc++-v3/src/libbacktrace/Makefile.am
@@ -60,6 +60,7 @@ libstdc___libbacktrace_la_SHORTNAME = $(obj_prefix)
 
 libstdc___libbacktrace_la_SOURCES = \
 	atomic.c \
+	backtrace.c \
 	dwarf.c \
 	fileline.c \
 	posix.c \
diff --git a/libstdc++-v3/src/libbacktrace/Makefile.in b/libstdc++-v3/src/libbacktrace/Makefile.in
index 7545894d59a..5c6b4dd1a0c 100644
--- a/libstdc++-v3/src/libbacktrace/Makefile.in
+++ b/libstdc++-v3/src/libbacktrace/Makefile.in
@@ -181,10 +181,10 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 am_libstdc___libbacktrace_la_OBJECTS = $(obj_prefix)-atomic.lo \
-	$(obj_prefix)-dwarf.lo $(obj_prefix)-fileline.lo \
-	$(obj_prefix)-posix.lo $(obj_prefix)-sort.lo \
-	$(obj_prefix)-simple.lo $(obj_prefix)-state.lo \
-	$(obj_prefix)-cp-demangle.lo
+	$(obj_prefix)-backtrace.lo $(obj_prefix)-dwarf.lo \
+	$(obj_prefix)-fileline.lo $(obj_prefix)-posix.lo \
+	$(obj_prefix)-sort.lo $(obj_prefix)-simple.lo \
+	$(obj_prefix)-state.lo $(obj_prefix)-cp-demangle.lo
 libstdc___libbacktrace_la_OBJECTS =  \
 	$(am_libstdc___libbacktrace_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -507,6 +507,7 @@ obj_prefix = std_stacktrace
 libstdc___libbacktrace_la_SHORTNAME = $(obj_prefix)
 libstdc___libbacktrace_la_SOURCES = \
 	atomic.c \
+	backtrace.c \
 	dwarf.c \
 	fileline.c \
 	posix.c \
@@ -647,6 +648,9 @@ distclean-compile:
 $(obj_prefix)-atomic.lo: atomic.c
 	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstdc___libbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o $(obj_prefix)-atomic.lo `test -f 'atomic.c' || echo '$(srcdir)/'`atomic.c
 
+$(obj_prefix)-backtrace.lo: backtrace.c
+	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstdc___libbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o $(obj_prefix)-backtrace.lo `test -f 'backtrace.c' || echo '$(srcdir)/'`backtrace.c
+
 $(obj_prefix)-dwarf.lo: dwarf.c
 	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstdc___libbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o $(obj_prefix)-dwarf.lo `test -f 'dwarf.c' || echo '$(srcdir)/'`dwarf.c
 
diff --git a/libstdc++-v3/src/libbacktrace/backtrace-rename.h b/libstdc++-v3/src/libbacktrace/backtrace-rename.h
index 7a59f166e62..79bdef6309f 100644
--- a/libstdc++-v3/src/libbacktrace/backtrace-rename.h
+++ b/libstdc++-v3/src/libbacktrace/backtrace-rename.h
@@ -4,6 +4,7 @@
 #define backtrace_create_state __glibcxx_backtrace_create_state
 #define backtrace_dwarf_add __glibcxx_backtrace_dwarf_add
 #define backtrace_free __glibcxx_backtrace_free
+#define backtrace_full __glibcxx_backtrace_full
 #define backtrace_get_view __glibcxx_backtrace_get_view
 #define backtrace_initialize __glibcxx_backtrace_initialize
 #define backtrace_open __glibcxx_backtrace_open
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc
index 7ab658d0ba1..83dd67b352a 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc
@@ -15,6 +15,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 //
+// { dg-options "-lstdc++_libbacktrace" }
 // { dg-do run { xfail *-*-* } }
 
 #include <debug/vector>

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: WIP _GLIBCXX_DEBUG backtrace
  2022-07-04 17:20 WIP _GLIBCXX_DEBUG backtrace François Dumont
@ 2022-07-04 19:52 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2022-07-04 19:52 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++

On Mon, 4 Jul 2022, 18:21 François Dumont via Libstdc++, <
libstdc++@gcc.gnu.org> wrote:

> Hi
>
> Here is the patch to add backtrace to _GLIBCXX_DEBUG mode. It is using
> the recently introduced _GLIBCXX_HAS_STACKTRACE.
>
> It is only WIP because for the moment I had to add:
>
> // { dg-options "-lstdc++_libbacktrace" }
>
> to avoid unresolved symbols.
>
> How should I handle this ?
>
> 1. Ask the user to define _GLIBCXX_DEBUG_STACKTRACE to get the backtrace
> and so also require to add this linker option.
>

For now, I think this is the best option. Even when the symbols are in the
library I think the backtraces should be optional. Controlled by a
compile-time macro and/or an environment variable.


> 2. Is it possible to add something in formatter.h to automagically link
> libstdc++_libbacktrace ?
>

Not possible, GCC and Unix linkers don't support doing that.


> 3. Add symbols to libstdc++.so ?
>

The symbols from libstdc++_libbacktrace.a will move to the .so at some
point, once the C++23 std::stacktrace implementation is stable. I don't
know if that will happen for GCC 13 though, it might be GCC 14.



> Output sample:
>
>
> /home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:264:
> In function:
>      void std::debug::vector<_Tp, _Allocator>::assign(_InputIterator,
>      _InputIterator) [with _InputIterator = const int*;
>      <template-parameter-2-2> = void; _Tp = int; _Allocator =
>      std::allocator<int>]
>
> Backtrace:
>      0x40284a void std::debug::vector<int, std::allocator<int>
>  >::assign<int const*, void>(int const*, int const*)
>
> /home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/vector:264
>      0x402bed void gnu_test::check_assign1<std::debug::vector<int,
> std::allocator<int> > >()
> /home/fdt/dev/gcc/git/libstdc++-v3/testsuite/util/debug/checks.h:111
>      0x40246c test01()
>
> /home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc:26
>      0x40246c main
>
> /home/fdt/dev/gcc/git/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc:31
>
> Error: function requires a valid iterator range [first, last).
>
> Objects involved in the operation:
>      iterator "first" @ 0x7ffe09e62fd8 {
>        type = int const* (constant iterator);
>      }
>      iterator "last" @ 0x7ffe09e62fd0 {
>        type = int const* (constant iterator);
>      }
> XFAIL: 23_containers/vector/debug/assign4_neg.cc execution test
>
> François
>
>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-07-04 19:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-04 17:20 WIP _GLIBCXX_DEBUG backtrace François Dumont
2022-07-04 19:52 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).