diff options
author | François Dumont <fdumont@gcc.gnu.org> | 2020-01-21 19:33:15 +0100 |
---|---|---|
committer | François Dumont <fdumont@gcc.gnu.org> | 2022-08-31 20:51:10 +0200 |
commit | 4d5660907c2b4c301fcbdc3dc713879fa31afec0 (patch) | |
tree | f2e5a68fb76ea8103414dad8202aefe25c85a60e | |
parent | de9805c08121a84ce368dccfe043a3f44c3ff13b (diff) | |
download | gcc-4d5660907c2b4c301fcbdc3dc713879fa31afec0.zip gcc-4d5660907c2b4c301fcbdc3dc713879fa31afec0.tar.gz gcc-4d5660907c2b4c301fcbdc3dc713879fa31afec0.tar.bz2 |
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.
-rw-r--r-- | libstdc++-v3/doc/xml/manual/debug_mode.xml | 6 | ||||
-rw-r--r-- | libstdc++-v3/doc/xml/manual/using.xml | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/debug/formatter.h | 44 | ||||
-rw-r--r-- | libstdc++-v3/src/c++11/debug.cc | 75 | ||||
-rw-r--r-- | libstdc++-v3/src/libbacktrace/Makefile.am | 1 | ||||
-rw-r--r-- | libstdc++-v3/src/libbacktrace/Makefile.in | 12 | ||||
-rw-r--r-- | libstdc++-v3/src/libbacktrace/backtrace-rename.h | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc | 17 |
8 files changed, 157 insertions, 9 deletions
diff --git a/libstdc++-v3/doc/xml/manual/debug_mode.xml b/libstdc++-v3/doc/xml/manual/debug_mode.xml index 988c4a9..dadc0cd 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 0b9a0c9..0acdba6 100644 --- a/libstdc++-v3/doc/xml/manual/using.xml +++ b/libstdc++-v3/doc/xml/manual/using.xml @@ -1144,6 +1144,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 @@ -1650,6 +1659,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 748d4fb..b4b7238 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 8ed61a6..abc4124 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 @@ -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; } @@ -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) + pretty_print(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 @@ -1139,6 +1193,17 @@ namespace __gnu_debug 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 0f11435..52d8f81 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 7545894..5c6b4dd 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 7a59f16..79bdef6 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 0000000..520788d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc @@ -0,0 +1,17 @@ +// { 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; +} |