Add _GLIBCXX_DEBUG backtrace generation
Commit Message
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
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
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.
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
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
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;
}
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 ?
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.
@@ -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>
@@ -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>
@@ -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&
@@ -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: ");
@@ -60,6 +60,7 @@ libstdc___libbacktrace_la_SHORTNAME = $(obj_prefix)
libstdc___libbacktrace_la_SOURCES = \
atomic.c \
+ backtrace.c \
dwarf.c \
fileline.c \
posix.c \
@@ -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
@@ -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
@@ -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>