Add _GLIBCXX_DEBUG backtrace generation

Message ID a1afcbea-4657-d356-a3ec-519188298bb3@gmail.com
State New, archived
Headers
Series Add _GLIBCXX_DEBUG backtrace generation |

Commit Message

François Dumont July 13, 2022, 5:26 p.m. UTC
  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.
   [_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 ?

François
  

Comments

François Dumont Aug. 4, 2022, 8:46 p.m. UTC | #1
Gentle reminder.

On 13/07/22 19:26, François Dumont 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.
>   [_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 ?
>
> François
  
Jonathan Wakely Aug. 8, 2022, 1:29 p.m. UTC | #2
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?


>    [_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.
  
François Dumont Aug. 9, 2022, 8:07 a.m. UTC | #3
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
  
François Dumont Aug. 31, 2022, 5:05 a.m. UTC | #4
After a second thought here is an even cleaner version. No more function 
rename, current pretty_print is fine.

     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 
[_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_backtrace_neg.cc: New test.
             * doc/xml/manual/debug_mode.xml: Document 
_GLIBCXX_DEBUG_BACKTRACE.
             * doc/xml/manual/using.xml: Likewise.
Ok to commit ?

François

On 09/08/22 10:07, François Dumont wrote:
> 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
  
Jonathan Wakely Aug. 31, 2022, 10:11 a.m. UTC | #5
On Wed, 31 Aug 2022 at 06:05, François Dumont <frs.dumont@gmail.com> wrote:
>
> After a second thought here is an even cleaner version. No more function
> rename, current pretty_print is fine.
>
>      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
> [_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_backtrace_neg.cc: New test.
>              * doc/xml/manual/debug_mode.xml: Document
> _GLIBCXX_DEBUG_BACKTRACE.
>              * doc/xml/manual/using.xml: Likewise.
> Ok to commit ?

OK for trunk, thanks.

The small change to print_raw in this patch makes me wonder whether
that function is actually useful.

It supports two modes, print with max precision, and print without.
The only time we use it to print with max precision we pass a string
of exactly the right length, so the precision is not needed (but the
caller has to get the string length correct: if we increase _S_indent
and do not increase the "    " literal passed to print_raw, the
effects would be wrong).

Wouldn't it be better to just use fprintf directly when we want to
print without precision, and use a minimum field width instead of
precision for indenting? i.e. ...

--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -608,15 +608,6 @@ namespace
    print_literal(PrintContext& ctx, const char(&word)[Length])
    { print_word(ctx, word, Length - 1); }

-  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);
-  }
-
  void
  print_word(PrintContext& ctx, const char* word, ptrdiff_t nbc = -1)
  {
@@ -643,12 +634,9 @@ namespace
       || (ctx._M_column + visual_length < ctx._M_max_length)
       || (visual_length >= ctx._M_max_length && ctx._M_column == 1))
      {
-       // If this isn't the first line, indent
+       // If this isn't the first line, indent.
       if (ctx._M_column == 1 && !ctx._M_first_line)
-         {
-           const char spacing[PrintContext::_S_indent + 1] = "    ";
-           print_raw(ctx, spacing, PrintContext::_S_indent);
-         }
+         ctx._M_column += fprintf(stderr, "%*c", PrintContext::_S_indent, ' ');

       int written = fprintf(stderr, "%.*s", (int)length, word);

@@ -1112,7 +1100,7 @@ namespace __gnu_debug
    PrintContext ctx;
    if (_M_file)
      {
-       print_raw(ctx, _M_file);
+       ctx._M_column += fprintf(stderr, "%s", _M_file);
       print_literal(ctx, ":");
       go_to_next_line = true;
      }
  
François Dumont Aug. 31, 2022, 7:33 p.m. UTC | #6
On 31/08/22 12:11, Jonathan Wakely wrote:
> On Wed, 31 Aug 2022 at 06:05, François Dumont <frs.dumont@gmail.com> wrote:
>> After a second thought here is an even cleaner version. No more function
>> rename, current pretty_print is fine.
>>
>>       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
>> [_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_backtrace_neg.cc: New test.
>>               * doc/xml/manual/debug_mode.xml: Document
>> _GLIBCXX_DEBUG_BACKTRACE.
>>               * doc/xml/manual/using.xml: Likewise.
>> Ok to commit ?
> OK for trunk, thanks.
>
> The small change to print_raw in this patch makes me wonder whether
> that function is actually useful.
>
> It supports two modes, print with max precision, and print without.
> The only time we use it to print with max precision we pass a string
> of exactly the right length, so the precision is not needed (but the
> caller has to get the string length correct: if we increase _S_indent
> and do not increase the "    " literal passed to print_raw, the
> effects would be wrong).
>
> Wouldn't it be better to just use fprintf directly when we want to
> print without precision, and use a minimum field width instead of
> precision for indenting? i.e. ...
>
> --- a/libstdc++-v3/src/c++11/debug.cc
> +++ b/libstdc++-v3/src/c++11/debug.cc
> @@ -608,15 +608,6 @@ namespace
>      print_literal(PrintContext& ctx, const char(&word)[Length])
>      { print_word(ctx, word, Length - 1); }
>
> -  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);
> -  }
> -
>    void
>    print_word(PrintContext& ctx, const char* word, ptrdiff_t nbc = -1)
>    {
> @@ -643,12 +634,9 @@ namespace
>         || (ctx._M_column + visual_length < ctx._M_max_length)
>         || (visual_length >= ctx._M_max_length && ctx._M_column == 1))
>        {
> -       // If this isn't the first line, indent
> +       // If this isn't the first line, indent.
>         if (ctx._M_column == 1 && !ctx._M_first_line)
> -         {
> -           const char spacing[PrintContext::_S_indent + 1] = "    ";
> -           print_raw(ctx, spacing, PrintContext::_S_indent);
> -         }
> +         ctx._M_column += fprintf(stderr, "%*c", PrintContext::_S_indent, ' ');
I did not know this syntax, it looks definitely better.
>
>         int written = fprintf(stderr, "%.*s", (int)length, word);
>
> @@ -1112,7 +1100,7 @@ namespace __gnu_debug
>      PrintContext ctx;
>      if (_M_file)
>        {
> -       print_raw(ctx, _M_file);
> +       ctx._M_column += fprintf(stderr, "%s", _M_file);
>         print_literal(ctx, ":");
>         go_to_next_line = true;
>        }
>
Do you take care or you prefer I do ?
  
Jonathan Wakely Aug. 31, 2022, 8:07 p.m. UTC | #7
On Wed, 31 Aug 2022 at 20:33, François Dumont <frs.dumont@gmail.com> wrote:
>
> On 31/08/22 12:11, Jonathan Wakely wrote:
> > On Wed, 31 Aug 2022 at 06:05, François Dumont <frs.dumont@gmail.com> wrote:
> >> After a second thought here is an even cleaner version. No more function
> >> rename, current pretty_print is fine.
> >>
> >>       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
> >> [_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_backtrace_neg.cc: New test.
> >>               * doc/xml/manual/debug_mode.xml: Document
> >> _GLIBCXX_DEBUG_BACKTRACE.
> >>               * doc/xml/manual/using.xml: Likewise.
> >> Ok to commit ?
> > OK for trunk, thanks.
> >
> > The small change to print_raw in this patch makes me wonder whether
> > that function is actually useful.
> >
> > It supports two modes, print with max precision, and print without.
> > The only time we use it to print with max precision we pass a string
> > of exactly the right length, so the precision is not needed (but the
> > caller has to get the string length correct: if we increase _S_indent
> > and do not increase the "    " literal passed to print_raw, the
> > effects would be wrong).
> >
> > Wouldn't it be better to just use fprintf directly when we want to
> > print without precision, and use a minimum field width instead of
> > precision for indenting? i.e. ...
> >
> > --- a/libstdc++-v3/src/c++11/debug.cc
> > +++ b/libstdc++-v3/src/c++11/debug.cc
> > @@ -608,15 +608,6 @@ namespace
> >      print_literal(PrintContext& ctx, const char(&word)[Length])
> >      { print_word(ctx, word, Length - 1); }
> >
> > -  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);
> > -  }
> > -
> >    void
> >    print_word(PrintContext& ctx, const char* word, ptrdiff_t nbc = -1)
> >    {
> > @@ -643,12 +634,9 @@ namespace
> >         || (ctx._M_column + visual_length < ctx._M_max_length)
> >         || (visual_length >= ctx._M_max_length && ctx._M_column == 1))
> >        {
> > -       // If this isn't the first line, indent
> > +       // If this isn't the first line, indent.
> >         if (ctx._M_column == 1 && !ctx._M_first_line)
> > -         {
> > -           const char spacing[PrintContext::_S_indent + 1] = "    ";
> > -           print_raw(ctx, spacing, PrintContext::_S_indent);
> > -         }
> > +         ctx._M_column += fprintf(stderr, "%*c", PrintContext::_S_indent, ' ');
> I did not know this syntax, it looks definitely better.
> >
> >         int written = fprintf(stderr, "%.*s", (int)length, word);
> >
> > @@ -1112,7 +1100,7 @@ namespace __gnu_debug
> >      PrintContext ctx;
> >      if (_M_file)
> >        {
> > -       print_raw(ctx, _M_file);
> > +       ctx._M_column += fprintf(stderr, "%s", _M_file);
> >         print_literal(ctx, ":");
> >         go_to_next_line = true;
> >        }
> >
> Do you take care or you prefer I do ?


I can do it.
  

Patch

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 80e8ba46d1e..f31b44d184a 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)
@@ -565,6 +596,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
@@ -580,6 +620,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 4706defedf1..3e45433be22 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -609,10 +609,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
@@ -666,25 +668,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);
+
+	    func = idx + offset;
 
-	    pos += 2; // advance past "__"
-	    if (memcmp(pos, cxx1998, 9) == 0)
-	      pos += 9; // advance part "cxx1998::"
+	    while (*func && isspace((unsigned char)*func))
+	      ++func;
 
-	    str = pos;
+	    if (!*func)
+	      break;
 	  }
 	else
 	  {
-	    print_func(ctx, str, -1);
+	    print_func(ctx, func, -1);
 	    break;
 	  }
       }
@@ -704,7 +716,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);
@@ -735,7 +747,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>
@@ -1090,6 +1102,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
@@ -1130,11 +1194,22 @@  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: ");
 
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..cb1b1740cfe 100644
--- 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>