From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by sourceware.org (Postfix) with ESMTPS id D1E2F393D037; Sat, 24 Apr 2021 13:46:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D1E2F393D037 Received: by mail-wm1-x336.google.com with SMTP id d200-20020a1c1dd10000b02901384767d4a5so2672211wmd.3; Sat, 24 Apr 2021 06:46:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:cc:message-id:date:user-agent :mime-version:content-language; bh=m78Xci4KQG5Et4uRS9wJWJga+dftllQXBFsipPCPrWI=; b=j5ON00b/GfBKQccQZxc7ZQOxkt/oWOiCn08mqZUV2p20ytHyuvDBL8UC+f5V7CSuaE PihF0w1Cel8icdlQh81ESaMkw0CmeXUkGhAdL+iWB+sSeIyhKBYb+R1I02kLM94Ro4Bo w95Bjmzx5ijUD/CtpQdUAVw4B4CGIFpQT5dPII+wjxs3LN2YjtuZoWwB//akRQmatf73 PIeU63Hv4LoxylNJZSUUwvyV+sOIwGEnpnFndVWE2EljBxjQW0q13X2jqnxb3976KrZ2 7iSS5e/WgBiyuQA3mxc0EOqj8QrIVgd0Tj7Yt976bBfY6qFDXOpPaMgZdtfiGqZJg2R/ Apdg== X-Gm-Message-State: AOAM531W1XC3OZckiN0kCbq6xaYWUtSLz9m20+/el5TH/IMdEET+LnKJ F16dnLo/K6xbdJY1H0xVAiEbwyLS015lZQ== X-Google-Smtp-Source: ABdhPJx3brJMxAjRk57CVq/WBkixvsZhhcHUYNb9omT47pUSGeUadTPaIRppv117YOTmEh5eNannMQ== X-Received: by 2002:a05:600c:4282:: with SMTP id v2mr10630871wmc.101.1619272004363; Sat, 24 Apr 2021 06:46:44 -0700 (PDT) Received: from ?IPv6:2a01:e0a:1dc:b1c0:ed23:303b:ae5a:813c? ([2a01:e0a:1dc:b1c0:ed23:303b:ae5a:813c]) by smtp.googlemail.com with ESMTPSA id h1sm13659474wml.38.2021.04.24.06.46.42 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 24 Apr 2021 06:46:42 -0700 (PDT) From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= Subject: [PATCH][_GLIBCXX_DEBUG] libbacktrace integration To: "libstdc++@gcc.gnu.org" Cc: gcc-patches Message-ID: Date: Sat, 24 Apr 2021 15:46:41 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------1755651C59E507A23DE7F245" Content-Language: fr X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 24 Apr 2021 13:46:48 -0000 This is a multi-part message in MIME format. --------------1755651C59E507A23DE7F245 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Hi     Here is the patch to add backtrace generation on _GLIBCXX_DEBUG assertions thanks to libbacktrace.     In addition to this integration I am also improving the generation of the assertion message thanks to the "%.*s" printf format, it avoids an intermediate buffer most of the time. I am also removing the "__" used for uglification to get a nicer output. I can propose it in a dedicated patch if you prefer.     I am adding GLIBCXX_3.4.30 abi version to properly export the 2 new weak symbols. Let me know if it isn't necessary.     libstdc++: [_GLIBCXX_DEBUG] Add backtrace generation thanks to libbacktrace       Add _GLIBCXX_DEBUG_BACKTRACE macro to activate backtrace generation on     _GLIBCXX_DEBUG assertions using libbacktrace.             * config/abi/pre/gnu.ver: Add GLIBCXX_3.4.30 version and new exports.             * include/debug/formatter.h [_GLIBCXX_DEBUG_BACKTRACE]:             Include .             [_GLIBCXX_DEBUG_BACKTRACE && BACKTRACE_SUPPORTED]:             Include .             [(!_GLIBCXX_DEBUG_BACKTRACE || !BACKTRACE_SUPPORTED) &&             _GLIBCXX_USE_C99_STDINT_TR1]: Include .             [_GLIBCXX_DEBUG_USE_LIBBACKTRACE]             (__gnu_debug::__create_backtrace_state): New.             [_GLIBCXX_DEBUG_USE_LIBBACKTRACE]             (__gnu_debug::__render_backtrace): New. [_GLIBCXX_DEBUG_USE_LIBBACKTRACE](_Error_formatter::_M_print_backtrace):             New. [_GLIBCXX_DEBUG_USE_LIBBACKTRACE](_Error_formatter::_M_backtrace_state):             New.             (_Error_formatter::_Error_formatter): Outline definition.             * src/c++11/debug.cc: Include .             (_Print_func_t): New.             (print_word): Use '%.*s' format in fprintf to render only expected             number of chars.             (print_raw(PrintContext&, const char*, ptrdiff_t)): New.             (print_function(PrintContext&, const char*, _Print_func_t)): New.             (print_type): Use latter.             (print_string(PrintContext&, const char*, const _Parameter*, size_t)):             Change signature to...             (print_string(PrintContext&, const char*, ptrdiff_t, const _Parameter*,             size_t)): ...this and adapt. Remove intermediate buffer to render input             string.             (print_string(PrintContext&, const char*, ptrdiff_t)): New.             [_GLIBCXX_DEBUG_USE_LIBBACKTRACE]             (print_backtrace(void*, uintptr_t, const char*, int, const char*)): New.             (_Error_formatter::_M_error()): Adapt.             [_GLIBCXX_DEBUG_USE_LIBBACKTRACE]             (__gnu_debug::__create_backtrace_state): New, weak symbol.             [_GLIBCXX_DEBUG_USE_LIBBACKTRACE]             (__gnu_debug::__render_backtrace): New, weak symbol.             * testsuite/util/testsuite_abi.cc: Add new symbol version.             * doc/xml/manual/debug_mode.xml: Document _GLIBCXX_DEBUG_BACKTRACE.             * doc/xml/manual/using.xml: Likewise. Tested under Linux x86_64. Ok to commit ? François --------------1755651C59E507A23DE7F245 Content-Type: text/x-patch; charset=UTF-8; name="libbacktrace.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="libbacktrace.patch" diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 5323c7f0604..2606d67d8a9 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2397,6 +2397,15 @@ GLIBCXX_3.4.29 { } GLIBCXX_3.4.28; +GLIBCXX_3.4.30 { + + # __gnu_debug::__create_backtrace + _ZN11__gnu_debug24__create_backtrace_stateEv; + _ZN11__gnu_debug18__render_backtraceEPvPFiS0_mPKciS2_ES0_; + +} GLIBCXX_3.4.29; + + # Symbols in the support library (libsupc++) have their own tag. CXXABI_1.3 { diff --git a/libstdc++-v3/doc/xml/manual/debug_mode.xml b/libstdc++-v3/doc/xml/manual/debug_mode.xml index 883e8cb4f03..931b09710f3 100644 --- a/libstdc++-v3/doc/xml/manual/debug_mode.xml +++ b/libstdc++-v3/doc/xml/manual/debug_mode.xml @@ -160,6 +160,12 @@ which always works correctly. GLIBCXX_DEBUG_MESSAGE_LENGTH can be used to request a different length. +Note that libstdc++ is able to use + libbacktrace + to produce backtraces on error. Use -D_GLIBCXX_DEBUG_BACKTRACE to + activate it. You'll also have to link with libbacktrace + () to build your application.
Using a Specific Debug Container diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml index 24543e9526e..9bd0da8c1c5 100644 --- a/libstdc++-v3/doc/xml/manual/using.xml +++ b/libstdc++-v3/doc/xml/manual/using.xml @@ -1128,6 +1128,16 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe extensions and libstdc++-specific behavior into errors. + _GLIBCXX_DEBUG_BACKTRACE + + + Undefined by default. Considered only if _GLIBCXX_DEBUG + is defined. When defined, checks for libbacktrace + support and use it to display backtraces on + debug mode assertions. + + _GLIBCXX_PARALLEL Undefined by default. When defined, compiles user code @@ -1634,6 +1644,17 @@ A quick read of the relevant part of the GCC header will remain compatible between different GCC releases.
+ +
External Libraries + + + libstdc++ debug mode is able to + produce backtraces thanks to libbacktrace. + To use the library you should define _GLIBCXX_DEBUG_BACKTRACE along + with _GLIBCXX_DEBUG and link with . + +
Concurrency diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index 7140fed5e83..ec0984e438f 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -31,6 +31,31 @@ #include +#if defined(_GLIBCXX_DEBUG_BACKTRACE) +# if !defined(BACKTRACE_SUPPORTED) +# include +# endif +#endif + +#if defined(_GLIBCXX_DEBUG_BACKTRACE) && BACKTRACE_SUPPORTED +# define _GLIBCXX_DEBUG_USE_LIBBACKTRACE 1 +# include + +namespace __gnu_debug +{ + typedef backtrace_full_callback __backtrace_full_cb; +} +#elif defined (_GLIBCXX_USE_C99_STDINT_TR1) +# define _GLIBCXX_DEBUG_USE_LIBBACKTRACE 0 +# include // For uintptr_t. + +namespace __gnu_debug +{ + typedef int (*__backtrace_full_cb) (void*, uintptr_t, const char*, + int, const char*); +} +#endif + #if __cpp_rtti # include # define _GLIBCXX_TYPEID(_Type) &typeid(_Type) @@ -155,6 +180,16 @@ namespace __gnu_debug __msg_irreflexive_ordering }; +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + + void* + __create_backtrace_state(); + + void + __render_backtrace(void*, __backtrace_full_cb, void*); + +#endif + class _Error_formatter { // Tags denoting the type of parameter for construction @@ -558,12 +593,14 @@ namespace __gnu_debug _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED; #endif +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + void + _M_print_backtrace(__backtrace_full_cb __cb, void* __data) const; +#endif + private: _Error_formatter(const char* __file, unsigned int __line, - const char* __function) - : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0) - , _M_function(__function) - { } + const char* __function); #if !_GLIBCXX_INLINE_VERSION void @@ -578,6 +615,9 @@ namespace __gnu_debug unsigned int _M_num_parameters; const char* _M_text; const char* _M_function; +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + void* _M_backtrace_state; +#endif public: static _Error_formatter& @@ -587,6 +627,36 @@ namespace __gnu_debug return __formatter; } }; + +#if _GLIBCXX_DEBUG_USE_LIBBACKTRACE + + void* + __create_backtrace_state() + { return backtrace_create_state(NULL, 0, NULL, NULL); } + + void + __render_backtrace(void* __bt, __backtrace_full_cb __cb, void* __data) + { backtrace_full((backtrace_state*)__bt, 1, __cb, 0, __data); } + +#endif + + _Error_formatter:: + _Error_formatter(const char* __file, unsigned int __line, + const char* __function) + : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0) + , _M_function(__function) +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + , _M_backtrace_state(__create_backtrace_state()) +#endif + { } + +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + void + _Error_formatter:: + _M_print_backtrace(__backtrace_full_cb __cb, void* __data) const + { __render_backtrace(_M_backtrace_state, __cb, __data); } +#endif + } // namespace __gnu_debug #undef _GLIBCXX_TYPEID diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 5a642097d17..790810fdab4 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -34,16 +34,12 @@ #include #include -#include // for std::isspace +#include // for std::isspace. +#include // for std::strstr. -#include // for std::min +#include // for std::min. -#include // for __cxa_demangle - -// libstdc++/85768 -#if 0 // defined _GLIBCXX_HAVE_EXECINFO_H -# include // for backtrace -#endif +#include // for __cxa_demangle. #include "mutex_pool.h" @@ -574,7 +570,7 @@ namespace struct PrintContext { PrintContext() - : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) + : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) { get_max_length(_M_max_length); } std::size_t _M_max_length; @@ -584,16 +580,17 @@ namespace bool _M_wordwrap; }; + typedef void (*_Print_func_t) (PrintContext&, const char*, ptrdiff_t); + template void print_literal(PrintContext& ctx, const char(&word)[Length]) { print_word(ctx, word, Length - 1); } void - print_word(PrintContext& ctx, const char* word, - std::ptrdiff_t count = -1) + print_word(PrintContext& ctx, const char* word, ptrdiff_t nbc = -1) { - size_t length = count >= 0 ? count : __builtin_strlen(word); + size_t length = nbc >= 0 ? nbc : __builtin_strlen(word); if (length == 0) return; @@ -619,15 +616,12 @@ namespace // If this isn't the first line, indent if (ctx._M_column == 1 && !ctx._M_first_line) { - char spacing[ctx._M_indent + 1]; - for (int i = 0; i < ctx._M_indent; ++i) - spacing[i] = ' '; - spacing[ctx._M_indent] = '\0'; + const char spacing[ctx._M_indent + 1] = " "; fprintf(stderr, "%s", spacing); ctx._M_column += ctx._M_indent; } - int written = fprintf(stderr, "%s", word); + int written = fprintf(stderr, "%.*s", (int)length, word); if (word[length - 1] == '\n') { @@ -640,7 +634,57 @@ namespace else { print_literal(ctx, "\n"); - print_word(ctx, word, count); + print_word(ctx, word, nbc); + } + } + + void + print_raw(PrintContext&, const char* str, ptrdiff_t nbc) + { + if (nbc >= 0) + fprintf(stderr, "%.*s", (int)nbc, str); + else + fprintf(stderr, "%s", str); + } + + void + print_function(PrintContext& ctx, const char* func, + _Print_func_t print_func) + { + const char cxx1998[] = "__cxx1998::"; + const char uglification[] = "__"; + for (;;) + { + auto idx1 = strstr(func, cxx1998); + auto idx2 = strstr(func, uglification); + if (idx1 || idx2) + { + if (idx1 && (!idx2 || idx1 <= idx2)) + { + if (idx1 != func) + print_func(ctx, func, idx1 - func); + + func = idx1 + sizeof(cxx1998) - 1; + } + else if (idx2) + { + if (idx2 != func) + print_func(ctx, func, idx2 - func); + + func = idx2 + sizeof(uglification) - 1; + } + + while (*func && isspace(*func)) + ++func; + + if (!*func) + break; + } + else + { + print_func(ctx, func, -1); + break; + } } } @@ -657,7 +701,10 @@ namespace int status; char* demangled_name = __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status); - print_word(ctx, status == 0 ? demangled_name : info->name()); + if (status == 0) + print_function(ctx, demangled_name, &print_word); + else + print_word(ctx, info->name(), -1); free(demangled_name); } } @@ -925,61 +972,62 @@ namespace } void - print_string(PrintContext& ctx, const char* string, + print_string(PrintContext& ctx, const char* str, ptrdiff_t nbc, const _Parameter* parameters, std::size_t num_parameters) { - const char* start = string; - const int bufsize = 128; - char buf[bufsize]; - int bufindex = 0; + const char* start = str; + const char* end = nbc >= 0 ? start + nbc : nullptr; + char buf[64]; - while (*start) + while ((end && str != end) || (!end && *str)) { - if (isspace(*start)) + if (isspace(*str)) { - buf[bufindex++] = *start++; - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); - bufindex = 0; + ++str; + print_word(ctx, start, str - start); + start = str; continue; } - if (!num_parameters || *start != '%') + if (!parameters || *str != '%') { // Normal char or no parameter to look for. - buf[bufindex++] = *start++; + ++str; continue; } - if (*++start == '%') + if (*++str == '%') { // Escaped '%' - buf[bufindex++] = *start++; + print_word(ctx, start, str - start); + ++str; + start = str; continue; } // We are on a parameter property reference, we need to flush buffer // first. - if (bufindex != 0) + if (str != start) { - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); - bufindex = 0; + // Avoid to print the '%'. + if (str - start > 1) + print_word(ctx, start, str - start - 1); + start = str; } // Get the parameter number - assert(*start >= '1' && *start <= '9'); - size_t param_index = *start - '0' - 1; + assert(*str >= '1' && *str <= '9'); + size_t param_index = *str - '0' - 1; assert(param_index < num_parameters); const auto& param = parameters[param_index]; // '.' separates the parameter number from the field // name, if there is one. - ++start; - if (*start != '.') + ++str; + if (*str != '.') { - assert(*start == ';'); - ++start; + assert(*str == ';'); + ++str; if (param._M_kind == _Parameter::__integer) { int written @@ -988,8 +1036,9 @@ namespace print_word(ctx, buf, written); } else if (param._M_kind == _Parameter::__string) - print_string(ctx, param._M_variant._M_string._M_value, + print_string(ctx, param._M_variant._M_string._M_value, -1, parameters, num_parameters); + start = str; continue; } @@ -997,26 +1046,80 @@ namespace const int max_field_len = 16; char field[max_field_len]; int field_idx = 0; - ++start; - while (*start != ';') + ++str; + while (*str != ';') { - assert(*start); + assert(*str); assert(field_idx < max_field_len - 1); - field[field_idx++] = *start++; + field[field_idx++] = *str++; } - ++start; + ++str; field[field_idx] = '\0'; print_field(ctx, param, field); + start = str; } // Might need to flush. - if (bufindex) + if (str != start) + print_word(ctx, start, str - start); + } + + void + print_string(PrintContext& ctx, const char* str, ptrdiff_t nbc) + { print_string(ctx, str, nbc, nullptr, 0); } + +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + int + print_backtrace(void* data, uintptr_t pc, const char* filename, + int lineno, const char* function) + { + const int bufsize = 64; + char buf[bufsize]; + + PrintContext& ctx = *static_cast(data); + + int written = __builtin_sprintf(buf, "%p ", (void*)pc); + print_word(ctx, buf, written); + + int ret = 0; + if (function) { - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); + 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 @@ -1058,41 +1161,27 @@ namespace __gnu_debug if (_M_function) { print_literal(ctx, "In function:\n"); - print_string(ctx, _M_function, nullptr, 0); + print_function(ctx, _M_function, &print_string); print_literal(ctx, "\n"); ctx._M_first_line = true; print_literal(ctx, "\n"); } -// libstdc++/85768 -#if 0 //defined _GLIBCXX_HAVE_EXECINFO_H - { - void* stack[32]; - int nb = backtrace(stack, 32); - - // Note that we skip current method symbol. - if (nb > 1) - { - print_literal(ctx, "Backtrace:\n"); - auto symbols = backtrace_symbols(stack, nb); - for (int i = 1; i < nb; ++i) - { - print_word(ctx, symbols[i]); - print_literal(ctx, "\n"); - } - - free(symbols); - ctx._M_first_line = true; - print_literal(ctx, "\n"); - } - } +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + if (_M_backtrace_state) + { + print_literal(ctx, "Backtrace:\n"); + _M_print_backtrace(print_backtrace, &ctx); + ctx._M_first_line = true; + print_literal(ctx, "\n"); + } #endif print_literal(ctx, "Error: "); // Print the error message assert(_M_text); - print_string(ctx, _M_text, _M_parameters, _M_num_parameters); + print_string(ctx, _M_text, -1, _M_parameters, _M_num_parameters); print_literal(ctx, ".\n"); // Emit descriptions of the objects involved in the operation @@ -1123,6 +1212,18 @@ namespace __gnu_debug abort(); } +#ifdef _GLIBCXX_DEBUG_USE_LIBBACKTRACE + + _GLIBCXX_WEAK_DEFINITION void* + __create_backtrace_state() + { return nullptr; } + + _GLIBCXX_WEAK_DEFINITION void + __render_backtrace(void*, __backtrace_full_cb, void*) + { } + +#endif + #if !_GLIBCXX_INLINE_VERSION // Deprecated methods kept for backward compatibility. void diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc index 3af5dc593c2..2c3204e57a5 100644 --- a/libstdc++-v3/testsuite/util/testsuite_abi.cc +++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc @@ -210,6 +210,7 @@ check_version(symbol& test, bool added) known_versions.push_back("GLIBCXX_3.4.27"); known_versions.push_back("GLIBCXX_3.4.28"); known_versions.push_back("GLIBCXX_3.4.29"); + known_versions.push_back("GLIBCXX_3.4.30"); known_versions.push_back("GLIBCXX_LDBL_3.4.29"); known_versions.push_back("GLIBCXX_IEEE128_3.4.29"); known_versions.push_back("CXXABI_1.3"); --------------1755651C59E507A23DE7F245--