public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: "François Dumont" <frs.dumont@gmail.com>
To: Jonathan Wakely <jwakely@redhat.com>
Cc: "libstdc++@gcc.gnu.org" <libstdc++@gcc.gnu.org>,
	gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] Add _GLIBCXX_DEBUG backtrace generation
Date: Tue, 9 Aug 2022 10:07:06 +0200	[thread overview]
Message-ID: <eb9d510a-4b4f-2ffe-e7a7-58fcc01703d0@gmail.com> (raw)
In-Reply-To: <CACb0b4n2jTatPdLagmkX3MZgG5i=_ER=XFqQ1t6KLVBL-Ka3Zg@mail.gmail.com>

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

On 08/08/22 15:29, Jonathan Wakely wrote:
> On Wed, 13 Jul 2022 at 18:28, François Dumont via Libstdc++
> <libstdc++@gcc.gnu.org> wrote:
>> libstdc++: [_GLIBCXX_DEBUG] Add backtrace generation on demand
>>
>>     Add _GLIBCXX_DEBUG_BACKTRACE macro to activate backtrace generation
>> on _GLIBCXX_DEBUG assertions. Prerequisite is to have configure the lib
>> with:
>>
>>     --enable-libstdcxx-backtrace=yes
>>
>>     libstdc++-v3/ChangeLog:
>>
>>     * include/debug/formatter.h
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_state): Declare.
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_create_state): Declare.
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_full_callback): Define.
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_error_callback): Define.
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_full_func): Define.
>>     [_GLIBCXX_HAVE_STACKTRACE](__glibcxx_backtrace_full): Declare.
>>     [_GLIBCXX_HAVE_STACKTRACE](_Error_formatter::_M_backtrace_state): New.
>>     [_GLIBCXX_HAVE_STACKTRACE](_Error_formatter::_M_backtrace_full): New.
>>     * src/c++11/debug.cc (pretty_print): Rename into...
>>     (print_function): ...that.
> This does more than just rename it, what are the other changes for?

Nothing, I'm starting to remember what you did on this, reverted.


>
>
>>     [_GLIBCXX_HAVE_STACKTRACE](print_backtrace): New.
>>     (_Error_formatter::_M_error()): Adapt.
>>     * src/libbacktrace/Makefile.am: Add backtrace.c.
>>     * src/libbacktrace/Makefile.in: Regenerate.
>>     * src/libbacktrace/backtrace-rename.h (backtrace_full): New.
>>     * testsuite/23_containers/vector/debug/assign4_neg.cc: Add backtrace
>>       generation.
>>     * doc/xml/manual/debug_mode.xml: Document _GLIBCXX_DEBUG_BACKTRACE.
>>     * doc/xml/manual/using.xml: Likewise.
>>
>> Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes.
>>
>> Ok to commit ?
>
>> --- a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_neg.cc
>> @@ -16,6 +16,7 @@
>> // <http://www.gnu.org/licenses/>.
>> //
>> // { dg-do run { xfail *-*-* } }
>> +// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++_libbacktrace" }
>>
>> #include <debug/vector>
>> #include <debug/checks.h>
> This will fail to link if the static lib isn't available.
>
Good point ! So I am introducing a new test case with the necessary dg 
directive.

It is a 'run' test case even if what is really tested is only the 
compilation/link part. For the run part someone has to look at the log file.

François

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

diff --git a/libstdc++-v3/doc/xml/manual/debug_mode.xml b/libstdc++-v3/doc/xml/manual/debug_mode.xml
index 988c4a93601..dadc0cd1bb4 100644
--- a/libstdc++-v3/doc/xml/manual/debug_mode.xml
+++ b/libstdc++-v3/doc/xml/manual/debug_mode.xml
@@ -161,6 +161,12 @@ which always works correctly.
   <code>GLIBCXX_DEBUG_MESSAGE_LENGTH</code> can be used to request a
   different length.</para>
 
+<para>Note that libstdc++ is able to produce backtraces on error.
+  It requires that you configure libstdc++ build with
+  <option>--enable-libstdcxx-backtrace=yes</option>.
+  Use <code>-D_GLIBCXX_DEBUG_BACKTRACE</code> to activate it.
+  You'll then have to link with libstdc++_libbacktrace static library
+  (<option>-lstdc++_libbacktrace</option>) to build your application.</para>
 </section>
 
 <section xml:id="debug_mode.using.specific" xreflabel="Using Specific"><info><title>Using a Specific Debug Container</title></info>
diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml
index 36b86702d22..26f14fae194 100644
--- a/libstdc++-v3/doc/xml/manual/using.xml
+++ b/libstdc++-v3/doc/xml/manual/using.xml
@@ -1129,6 +1129,15 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe
 	extensions and libstdc++-specific behavior into errors.
       </para>
     </listitem></varlistentry>
+    <varlistentry><term><code>_GLIBCXX_DEBUG_BACKTRACE</code></term>
+    <listitem>
+      <para>
+	Undefined by default. Considered only if libstdc++ has been configured with
+	<option>--enable-libstdcxx-backtrace=yes</option> and if <code>_GLIBCXX_DEBUG</code>
+	is defined. When defined display backtraces on
+	<link linkend="manual.ext.debug_mode">debug mode</link> assertions.
+      </para>
+    </listitem></varlistentry>
     <varlistentry><term><code>_GLIBCXX_PARALLEL</code></term>
     <listitem>
       <para>Undefined by default. When defined, compiles user code
@@ -1635,6 +1644,7 @@ A quick read of the relevant part of the GCC
       header will remain compatible between different GCC releases.
     </para>
     </section>
+
   </section>
 
   <section xml:id="manual.intro.using.concurrency" xreflabel="Concurrency"><info><title>Concurrency</title></info>
diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h
index 748d4fbfea4..b4b72383e22 100644
--- a/libstdc++-v3/include/debug/formatter.h
+++ b/libstdc++-v3/include/debug/formatter.h
@@ -31,6 +31,37 @@
 
 #include <bits/c++config.h>
 
+#if _GLIBCXX_HAVE_STACKTRACE
+struct __glibcxx_backtrace_state;
+
+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);
+
+  typedef int (*__glibcxx_backtrace_full_func) (
+    __glibcxx_backtrace_state*, int,
+    __glibcxx_backtrace_full_callback,
+    __glibcxx_backtrace_error_callback,
+    void*);
+
+  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)
@@ -576,6 +607,15 @@ namespace __gnu_debug
 		     const char* __function)
     : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
     , _M_function(__function)
+#if _GLIBCXX_HAVE_STACKTRACE
+# ifdef _GLIBCXX_DEBUG_BACKTRACE
+    , _M_backtrace_state(
+      __glibcxx_backtrace_create_state(nullptr, 0, nullptr, nullptr))
+    , _M_backtrace_full(&__glibcxx_backtrace_full)
+# else
+    , _M_backtrace_state()
+# endif
+#endif
     { }
 
 #if !_GLIBCXX_INLINE_VERSION
@@ -591,6 +631,10 @@ namespace __gnu_debug
     unsigned int	_M_num_parameters;
     const char*		_M_text;
     const char*		_M_function;
+#if _GLIBCXX_HAVE_STACKTRACE
+    __glibcxx_backtrace_state*		_M_backtrace_state;
+    __glibcxx_backtrace_full_func	_M_backtrace_full;
+#endif
 
   public:
     static _Error_formatter&
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 8ed61a69913..25129fe94dc 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -611,10 +611,12 @@ namespace
   void
   print_raw(PrintContext& ctx, const char* str, ptrdiff_t nbc = -1)
   {
-    if (nbc >= 0)
-      ctx._M_column += fprintf(stderr, "%.*s", (int)nbc, str);
-    else
-      ctx._M_column += fprintf(stderr, "%s", str);
+    if (nbc != 0)
+      {
+	ctx._M_column += (nbc > 0)
+	  ? fprintf(stderr, "%.*s", (int)nbc, str)
+	  : fprintf(stderr, "%s", str);
+      }
   }
 
   void
@@ -668,7 +670,7 @@ namespace
   }
 
   void
-  pretty_print(PrintContext& ctx, const char* str, _Print_func_t print_func)
+  print_function(PrintContext& ctx, const char* str, _Print_func_t print_func)
   {
     const char cxx1998[] = "cxx1998::";
     for (;;)
@@ -680,7 +682,7 @@ namespace
 
 	    pos += 2; // advance past "__"
 	    if (memcmp(pos, cxx1998, 9) == 0)
-	      pos += 9; // advance part "cxx1998::"
+	      pos += 9; // advance past "cxx1998::"
 
 	    str = pos;
 	  }
@@ -706,7 +708,7 @@ 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());
 	  free(demangled_name);
@@ -737,7 +739,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>
@@ -1093,6 +1095,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
@@ -1133,12 +1187,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_backtrace_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
new file mode 100644
index 00000000000..b28c9164365
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 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/>.
+//
+// { dg-do run { xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++_libbacktrace" }
+// { dg-require-effective-target stacktrace }
+
+#include <debug/vector>
+#include <debug/checks.h>
+
+void test01()
+{
+  __gnu_test::check_assign1<__gnu_debug::vector<int> >();
+}
+
+int main()
+{
+  test01();
+  return 0;
+}

  reply	other threads:[~2022-08-09  8:07 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-13 17:26 François Dumont
2022-08-04 20:46 ` François Dumont
2022-08-08 13:29 ` Jonathan Wakely
2022-08-09  8:07   ` François Dumont [this message]
2022-08-31  5:05     ` François Dumont
2022-08-31 10:11       ` Jonathan Wakely
2022-08-31 19:33         ` François Dumont
2022-08-31 20:07           ` Jonathan Wakely

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=eb9d510a-4b4f-2ffe-e7a7-58fcc01703d0@gmail.com \
    --to=frs.dumont@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jwakely@redhat.com \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).