diff options
author | bkoz <bkoz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 12:50:53 +0000 |
---|---|---|
committer | bkoz <bkoz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 12:50:53 +0000 |
commit | e2585cd835ae2dfa42f12b9ff4bbb56d339a83c9 (patch) | |
tree | 63b5caca1dfe3a1f87e96af76329f6f1565e7266 /libstdc++-v3/testsuite | |
parent | 578377eba22f40aa2699b0451be8f385125de557 (diff) | |
download | gcc-e2585cd835ae2dfa42f12b9ff4bbb56d339a83c9.tar.gz |
2004-05-13 Benjamin Kosnik <bkoz@redhat.com>
* docs/html/abi.html: New.
* docs/html/abi.txt: Remove.
* docs/html/documentation.html: Add link.
* testsuite/Makefile.am: Add files.
* testsuite/Makefile.in: Regenerated.
* testsuite/abi_check.cc: Move and modify code into...
* testsuite/testsuite_abi.cc: Add.
* testsuite/testsuite_abi.h: Add.
* docs/html/17_intro/TODO: Update.
* include/bits/stl_pair.h: Format.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81781 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r-- | libstdc++-v3/testsuite/Makefile.am | 23 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/Makefile.in | 17 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/abi_check.cc | 489 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/testsuite_abi.cc | 462 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/testsuite_abi.h | 129 |
5 files changed, 679 insertions, 441 deletions
diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am index c58d008d00c..9e11ac30ae9 100644 --- a/libstdc++-v3/testsuite/Makefile.am +++ b/libstdc++-v3/testsuite/Makefile.am @@ -39,18 +39,14 @@ GLIBCXX_DIR=${glibcxx_builddir}/src/.libs CXXLINK = \ $(LIBTOOL) --tag=CXX --mode=link $(CXX) \ -R $(GLIBGCC_DIR) -R $(GLIBCXX_DIR) \ - $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ - -# Generated lists of files to run. All of these names are valid make -# targets, if you wish to generate a list manually. -lists_of_files = \ - testsuite_files \ - testsuite_files_interactive \ - testsuite_files_performance + $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -lv3test -L. -o $@ ## Build support library. noinst_LIBRARIES = libv3test.a -libv3test_a_SOURCES = testsuite_hooks.cc testsuite_allocator.cc +libv3test_a_SOURCES = \ + testsuite_abi.cc \ + testsuite_allocator.cc \ + testsuite_hooks.cc ## Build support utilities. if GLIBCXX_TEST_ABI @@ -59,6 +55,7 @@ else noinst_PROGRAMS = endif abi_check_SOURCES = abi_check.cc +abi_check_DEPENDENCIES = libv3test.a all-local: stamp_wchar testsuite_files @@ -70,6 +67,14 @@ else stamp_wchar: endif +# Generated lists of files to run. All of these names are valid make +# targets, if you wish to generate a list manually. +lists_of_files = \ + testsuite_files \ + testsuite_files_interactive \ + testsuite_files_performance + + # We need more things in site.exp, but automake completely controls the # creation of that file; there's no way to append to it without messing up # the dependancy chains. So we overrule automake. This rule is exactly diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in index bd006066bf2..b74f2b36cdb 100644 --- a/libstdc++-v3/testsuite/Makefile.in +++ b/libstdc++-v3/testsuite/Makefile.in @@ -58,8 +58,8 @@ ARFLAGS = cru LIBRARIES = $(noinst_LIBRARIES) libv3test_a_AR = $(AR) $(ARFLAGS) libv3test_a_LIBADD = -am_libv3test_a_OBJECTS = testsuite_hooks.$(OBJEXT) \ - testsuite_allocator.$(OBJEXT) +am_libv3test_a_OBJECTS = testsuite_abi.$(OBJEXT) \ + testsuite_allocator.$(OBJEXT) testsuite_hooks.$(OBJEXT) libv3test_a_OBJECTS = $(am_libv3test_a_OBJECTS) PROGRAMS = $(noinst_PROGRAMS) am_abi_check_OBJECTS = abi_check.$(OBJEXT) @@ -272,8 +272,16 @@ GLIBCXX_DIR = ${glibcxx_builddir}/src/.libs CXXLINK = \ $(LIBTOOL) --tag=CXX --mode=link $(CXX) \ -R $(GLIBGCC_DIR) -R $(GLIBCXX_DIR) \ - $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ + $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -lv3test -L. -o $@ +noinst_LIBRARIES = libv3test.a +libv3test_a_SOURCES = \ + testsuite_abi.cc \ + testsuite_allocator.cc \ + testsuite_hooks.cc + +abi_check_SOURCES = abi_check.cc +abi_check_DEPENDENCIES = libv3test.a # Generated lists of files to run. All of these names are valid make # targets, if you wish to generate a list manually. @@ -282,9 +290,6 @@ lists_of_files = \ testsuite_files_interactive \ testsuite_files_performance -noinst_LIBRARIES = libv3test.a -libv3test_a_SOURCES = testsuite_hooks.cc testsuite_allocator.cc -abi_check_SOURCES = abi_check.cc baseline_file = ${baseline_dir}/baseline_symbols.txt extract_symvers = $(glibcxx_srcdir)/scripts/extract_symvers diff --git a/libstdc++-v3/testsuite/abi_check.cc b/libstdc++-v3/testsuite/abi_check.cc index 2116f7a6b30..18c8b7be9b6 100644 --- a/libstdc++-v3/testsuite/abi_check.cc +++ b/libstdc++-v3/testsuite/abi_check.cc @@ -1,311 +1,38 @@ -// Utility for libstdc++ ABI analysis -*- C++ -*- - -// Copyright (C) 2002, 2003 Free Software Foundation, Inc. -// -// This file is part of the GNU ISO C++ Library. This library is free -// software; you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the -// Free Software Foundation; either version 2, or (at your option) -// any later version. - -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License along -// with this library; see the file COPYING. If not, write to the Free -// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -// USA. - -// As a special exception, you may use this file as part of a free software -// library without restriction. Specifically, if other files instantiate -// templates or use macros or inline functions from this file, or you compile -// this file and link it with other files to produce an executable, this -// file does not by itself cause the resulting executable to be covered by -// the GNU General Public License. This exception does not however -// invalidate any other reasons why the executable file might be covered by -// the GNU General Public License. +// -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2, or (at +// your option) any later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. // Benjamin Kosnik <bkoz@redhat.com> // Blame subsequent hacks on Loren J. Rittle <ljrittle@acm.org>, Phil // Edwards <pme@gcc.gnu.org>, and a cast of dozens at libstdc++@gcc.gnu.org. - -#include <string> -#include <ext/hash_map> -#include <deque> -#include <sstream> -#include <fstream> + +#include "testsuite_abi.h" #include <iostream> -#include <cxxabi.h> -#include <stdlib.h> // for system(3) -#include <unistd.h> // for access(2) - -struct symbol_info -{ - enum category { none, function, object, error }; - category type; - std::string name; - std::string demangled_name; - int size; - std::string version_name; - - symbol_info() : type(none), size(0) { } - - symbol_info(const symbol_info& other) - : type(other.type), name(other.name), demangled_name(other.demangled_name), - size(other.size), version_name(other.version_name) { } -}; - -namespace __gnu_cxx -{ - using namespace std; - - template<> - struct hash<string> - { - size_t operator()(const string& s) const - { - const collate<char>& c = use_facet<collate<char> >(locale::classic()); - return c.hash(s.c_str(), s.c_str() + s.size()); - } - }; -} - -typedef std::deque<std::string> symbol_names; -typedef __gnu_cxx::hash_map<std::string, symbol_info> symbol_infos; - - -bool -check_version(const symbol_info& test, bool added = false) -{ - typedef std::vector<std::string> compat_list; - static compat_list known_versions; - if (known_versions.empty()) - { - known_versions.push_back("GLIBCPP_3.2"); // base version - known_versions.push_back("GLIBCPP_3.2.1"); - known_versions.push_back("GLIBCPP_3.2.2"); - known_versions.push_back("GLIBCPP_3.2.3"); // gcc-3.3.0 - known_versions.push_back("GLIBCXX_3.4"); - known_versions.push_back("CXXABI_1.2"); - known_versions.push_back("CXXABI_1.2.1"); - known_versions.push_back("CXXABI_1.3"); - } - compat_list::iterator begin = known_versions.begin(); - compat_list::iterator end = known_versions.end(); - - // Check version names for compatibility... - compat_list::iterator it1 = find(begin, end, test.version_name); - - // Check for weak label. - compat_list::iterator it2 = find(begin, end, test.name); - - // Check that added symbols aren't added in the base version. - bool compat = true; - if (added && test.version_name == known_versions[0]) - compat = false; - - if (it1 == end && it2 == end) - compat = false; - - return compat; -} - -bool -check_compatible(const symbol_info& lhs, const symbol_info& rhs, - bool verbose = false) -{ - using namespace std; - bool ret = true; - const char tab = '\t'; - - // Check to see if symbol_infos are compatible. - if (lhs.type != rhs.type) - { - ret = false; - if (verbose) - { - cout << tab << "incompatible types" << endl; - } - } - - if (lhs.name != rhs.name) - { - ret = false; - if (verbose) - { - cout << tab << "incompatible names" << endl; - } - } - - if (lhs.size != rhs.size) - { - ret = false; - if (verbose) - { - cout << tab << "incompatible sizes" << endl; - cout << tab << lhs.size << endl; - cout << tab << rhs.size << endl; - } - } - - if (lhs.version_name != rhs.version_name - && !check_version(lhs) && !check_version(rhs)) - { - ret = false; - if (verbose) - { - cout << tab << "incompatible versions" << endl; - cout << tab << lhs.version_name << endl; - cout << tab << rhs.version_name << endl; - } - } - - if (verbose) - cout << endl; - - return ret; -} - -const char* -demangle(const std::string& mangled) -{ - const char* name; - if (mangled[0] != '_' || mangled[1] != 'Z') - { - // This is not a mangled symbol, thus has "C" linkage. - name = mangled.c_str(); - } - else - { - // Use __cxa_demangle to demangle. - int status = 0; - name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status); - if (!name) - { - switch (status) - { - case 0: - name = "error code = 0: success"; - break; - case -1: - name = "error code = -1: memory allocation failure"; - break; - case -2: - name = "error code = -2: invalid mangled name"; - break; - case -3: - name = "error code = -3: invalid arguments"; - break; - default: - name = "error code unknown - who knows what happened"; - } - } - } - return name; -} - -void -line_to_symbol_info(std::string& input, symbol_info& output) -{ - using namespace std; - const char delim = ':'; - const char version_delim = '@'; - const string::size_type npos = string::npos; - string::size_type n = 0; - - // Set the type. - if (input.find("FUNC") == 0) - output.type = symbol_info::function; - else if (input.find("OBJECT") == 0) - output.type = symbol_info::object; - else - output.type = symbol_info::error; - n = input.find_first_of(delim); - if (n != npos) - input.erase(input.begin(), input.begin() + n + 1); - - // Iff object, get size info. - if (output.type == symbol_info::object) - { - n = input.find_first_of(delim); - if (n != npos) - { - string size(input.begin(), input.begin() + n); - istringstream iss(size); - int x; - iss >> x; - if (!iss.fail()) - output.size = x; - input.erase(input.begin(), input.begin() + n + 1); - } - } - - // Set the name. - n = input.find_first_of(version_delim); - if (n != npos) - { - // Found version string. - output.name = string(input.begin(), input.begin() + n); - n = input.find_last_of(version_delim); - input.erase(input.begin(), input.begin() + n + 1); - - // Set version name. - output.version_name = input; - } - else - { - // No versioning info. - output.name = string(input.begin(), input.end()); - input.erase(input.begin(), input.end()); - } - - // Set the demangled name. - output.demangled_name = demangle(output.name); -} - -void -create_symbol_data(const char* file, symbol_infos& symbols, - symbol_names& names) -{ - // Parse list of symbols in file into vectors of symbol_info. - // For 3.2.0 on x86/linux, this usually is - // 947 non-weak symbols - // 2084 weak symbols - using namespace std; - ifstream ifs(file); - if (ifs.is_open()) - { - // Organize input into container of symbol_info objects. - const string empty; - string line = empty; - while (getline(ifs, line).good()) - { - symbol_info symbol; - line_to_symbol_info(line, symbol); - symbols[symbol.name] = symbol; - names.push_back(symbol.name); - line = empty; - } - } -} - -void -report_symbol_info(const symbol_info& symbol, std::size_t n, bool ret = true) -{ - using namespace std; - const char tab = '\t'; - - // Add any other information to display here. - cout << tab << symbol.demangled_name << endl; - cout << tab << symbol.name << endl; - cout << tab << symbol.version_name << endl; - - if (ret) - cout << endl; -} - int main(int argc, char** argv) @@ -313,144 +40,54 @@ main(int argc, char** argv) using namespace std; // Get arguments. (Heading towards getopt_long, I can feel it.) - bool verbose = false; string argv1 = argc > 1 ? argv[1] : ""; if (argv1 == "--help" || argc < 4) { cerr << "usage: abi_check --check current baseline\n" " --check-verbose current baseline\n" - " --help\n\n" - "Where CURRENT is a file containing the current results from\n" - "extract_symvers, and BASELINE is one from config/abi.\n" + " --examine symbol current\n" + " --help\n" + "\n" + "All arguments are string literals.\n" + "CURRENT is a file generated byextract_symvers.\n" + "BASELINE is a file from config/abi.\n" + "SYMBOL is a mangled name.\n" << endl; exit(1); } - else if (argv1 == "--check-verbose") - verbose = true; - - // Quick sanity/setup check for arguments. - const char* test_file = argv[2]; - const char* baseline_file = argv[3]; - if (access(test_file, R_OK) != 0) - { - cerr << "Cannot read symbols file " << test_file - << ", did you forget to build first?" << endl; - exit(1); - } - if (access(baseline_file, R_OK) != 0) - { - cerr << "Cannot read baseline file " << baseline_file << endl; - exit(1); - } - - // Input both lists of symbols into container. - symbol_infos baseline_symbols; - symbol_names baseline_names; - symbol_infos test_symbols; - symbol_names test_names; - create_symbol_data(baseline_file, baseline_symbols, baseline_names); - create_symbol_data(test_file, test_symbols, test_names); - - // Sanity check results. - const symbol_names::size_type baseline_size = baseline_names.size(); - const symbol_names::size_type test_size = test_names.size(); - if (!baseline_size || !test_size) - { - cerr << "Problems parsing the list of exported symbols." << endl; - exit(2); - } - - // Sort out names. - // Assuming baseline_names, test_names are both unique w/ no duplicates. - // - // The names added to missing_names are baseline_names not found in - // test_names - // -> symbols that have been deleted. - // - // The names added to added_names are test_names are names not in - // baseline_names - // -> symbols that have been added. - symbol_names shared_names; - symbol_names missing_names; - symbol_names added_names = test_names; - for (size_t i = 0; i < baseline_size; ++i) - { - string what(baseline_names[i]); - symbol_names::iterator end = added_names.end(); - symbol_names::iterator it = find(added_names.begin(), end, what); - if (it != end) + + if (argv1.find("--check") != string::npos) + { + bool verbose = false; + if (argv1 == "--check-verbose") + verbose = true; + + // Quick sanity/setup check for arguments. + const char* test_file = argv[2]; + const char* baseline_file = argv[3]; + if (access(test_file, R_OK) != 0) { - // Found. - shared_names.push_back(what); - added_names.erase(it); + cerr << "Cannot read symbols file " << test_file + << ", did you forget to build first?" << endl; + exit(1); } - else - missing_names.push_back(what); - } - - // Check missing names for compatibility. - typedef pair<symbol_info, symbol_info> symbol_pair; - vector<symbol_pair> incompatible; - for (size_t i = 0; i < missing_names.size(); ++i) - { - symbol_info base = baseline_symbols[missing_names[i]]; - incompatible.push_back(symbol_pair(base, base)); - } - - // Check shared names for compatibility. - for (size_t i = 0; i < shared_names.size(); ++i) - { - symbol_info base = baseline_symbols[shared_names[i]]; - symbol_info test = test_symbols[shared_names[i]]; - if (!check_compatible(base, test)) - incompatible.push_back(symbol_pair(base, test)); - } - - // Check added names for compatibility. - for (size_t i = 0; i < added_names.size(); ++i) - { - symbol_info test = test_symbols[added_names[i]]; - if (!check_version(test, true)) - incompatible.push_back(symbol_pair(test, test)); - } - - // Report results. - if (verbose && added_names.size()) - { - cout << added_names.size() << " added symbols " << endl; - for (size_t j = 0; j < added_names.size() ; ++j) - report_symbol_info(test_symbols[added_names[j]], j + 1); - } - - if (verbose && missing_names.size()) - { - cout << missing_names.size() << " missing symbols " << endl; - for (size_t j = 0; j < missing_names.size() ; ++j) - report_symbol_info(baseline_symbols[missing_names[j]], j + 1); + if (access(baseline_file, R_OK) != 0) + { + cerr << "Cannot read baseline file " << baseline_file << endl; + exit(1); + } + compare_symbols(baseline_file, test_file, verbose); } - if (verbose && incompatible.size()) + if (argv1 == "--examine") { - cout << incompatible.size() << " incompatible symbols " << endl; - for (size_t j = 0; j < incompatible.size() ; ++j) + const char* file = argv[3]; + if (access(file, R_OK) != 0) { - // First, report name. - const symbol_info& base = incompatible[j].first; - const symbol_info& test = incompatible[j].second; - report_symbol_info(test, j + 1, false); - - // Second, report reason or reasons incompatible. - check_compatible(base, test, true); + cerr << "Cannot read symbol file " << file << endl; + exit(1); } + examine_symbol(argv[2], file); } - - cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl; - cout << endl; - cout << "# of added symbols:\t\t " << added_names.size() << endl; - cout << "# of missing symbols:\t\t " << missing_names.size() << endl; - cout << "# of incompatible symbols:\t " << incompatible.size() << endl; - cout << endl; - cout << "using: " << baseline_file << endl; - return 0; } diff --git a/libstdc++-v3/testsuite/testsuite_abi.cc b/libstdc++-v3/testsuite/testsuite_abi.cc new file mode 100644 index 00000000000..552da1bca0e --- /dev/null +++ b/libstdc++-v3/testsuite/testsuite_abi.cc @@ -0,0 +1,462 @@ +// -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2, or (at +// your option) any later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +// Benjamin Kosnik <bkoz@redhat.com> + +#include "testsuite_abi.h" +#include <sstream> +#include <fstream> +#include <iostream> + +using namespace std; + +void +symbol::init(string& data) +{ + const char delim = ':'; + const char version_delim = '@'; + const string::size_type npos = string::npos; + string::size_type n = 0; + + // Set the type. + if (data.find("FUNC") == 0) + type = symbol::function; + else if (data.find("OBJECT") == 0) + type = symbol::object; + else + type = symbol::error; + n = data.find_first_of(delim); + if (n != npos) + data.erase(data.begin(), data.begin() + n + 1); + + // Iff object, get size info. + if (type == symbol::object) + { + n = data.find_first_of(delim); + if (n != npos) + { + string size(data.begin(), data.begin() + n); + istringstream iss(size); + int x; + iss >> x; + if (!iss.fail()) + size = x; + data.erase(data.begin(), data.begin() + n + 1); + } + } + + // Set the name. + n = data.find_first_of(version_delim); + if (n != npos) + { + // Found version string. + name = string(data.begin(), data.begin() + n); + n = data.find_last_of(version_delim); + data.erase(data.begin(), data.begin() + n + 1); + + // Set version name. + version_name = data; + } + else + { + // No versioning info. + name = string(data.begin(), data.end()); + data.erase(data.begin(), data.end()); + } + + // Set the demangled name. + demangled_name = demangle(name); +} + +void +symbol::print() const +{ + const char tab = '\t'; + cout << tab << name << endl; + cout << tab << demangled_name << endl; + cout << tab << version_name << endl; + + string type_string; + switch (type) + { + case none: + type_string = "none"; + break; + case function: + type_string = "function"; + break; + case object: + type_string = "object"; + break; + case error: + type_string = "error"; + break; + default: + type_string = "<default>"; + } + cout << tab << type_string << endl; + + if (type == object) + cout << tab << size << endl; + + string status_string; + switch (status) + { + case unknown: + status_string = "unknown"; + break; + case added: + status_string = "added"; + break; + case subtracted: + status_string = "subtracted"; + break; + case compatible: + status_string = "compatible"; + break; + case incompatible: + status_string = "incompatible"; + break; + default: + status_string = "<default>"; + } + cout << tab << status_string << endl; +} + + +bool +check_version(const symbol& test, bool added) +{ + typedef std::vector<std::string> compat_list; + static compat_list known_versions; + if (known_versions.empty()) + { + known_versions.push_back("GLIBCPP_3.2"); // base version + known_versions.push_back("GLIBCPP_3.2.1"); + known_versions.push_back("GLIBCPP_3.2.2"); + known_versions.push_back("GLIBCPP_3.2.3"); // gcc-3.3.0 + known_versions.push_back("GLIBCXX_3.4"); + known_versions.push_back("CXXABI_1.2"); + known_versions.push_back("CXXABI_1.2.1"); + known_versions.push_back("CXXABI_1.3"); + } + compat_list::iterator begin = known_versions.begin(); + compat_list::iterator end = known_versions.end(); + + // Check version names for compatibility... + compat_list::iterator it1 = find(begin, end, test.version_name); + + // Check for weak label. + compat_list::iterator it2 = find(begin, end, test.name); + + // Check that added symbols aren't added in the base version. + bool compat = true; + if (added && test.version_name == known_versions[0]) + compat = false; + + if (it1 == end && it2 == end) + compat = false; + + return compat; +} + +bool +check_compatible(const symbol& lhs, const symbol& rhs, bool verbose) +{ + bool ret = true; + const char tab = '\t'; + + // Check to see if symbol_objects are compatible. + if (lhs.type != rhs.type) + { + ret = false; + if (verbose) + cout << tab << "incompatible types" << endl; + } + + if (lhs.name != rhs.name) + { + ret = false; + if (verbose) + cout << tab << "incompatible names" << endl; + } + + if (lhs.size != rhs.size) + { + ret = false; + if (verbose) + { + cout << tab << "incompatible sizes" << endl; + cout << tab << lhs.size << endl; + cout << tab << rhs.size << endl; + } + } + + if (lhs.version_name != rhs.version_name + && !check_version(lhs) && !check_version(rhs)) + { + ret = false; + if (verbose) + { + cout << tab << "incompatible versions" << endl; + cout << tab << lhs.version_name << endl; + cout << tab << rhs.version_name << endl; + } + } + + if (verbose) + cout << endl; + + return ret; +} + + +bool +has_symbol(const string& mangled, const symbols& s) throw() +{ + const symbol_names& names = s.first; + symbol_names::const_iterator i = find(names.begin(), names.end(), mangled); + return i != names.end(); +} + +symbol& +get_symbol(const string& mangled, const symbols& s) +{ + const symbol_names& names = s.first; + symbol_names::const_iterator i = find(names.begin(), names.end(), mangled); + if (i != names.end()) + { + symbol_objects objects = s.second; + return objects[mangled]; + } + else + { + ostringstream os; + os << "get_symbol failed for symbol " << mangled; + throw symbol_error(os.str()); + } +} + +void +examine_symbol(const char* name, const char* file) +{ + try + { + symbols s = create_symbols(file); + symbol& sym = get_symbol(name, s); + sym.print(); + } + catch(...) + { throw; } +} + +void +compare_symbols(const char* baseline_file, const char* test_file, + bool verbose) +{ + // Input both lists of symbols into container. + symbols baseline = create_symbols(baseline_file); + symbols test = create_symbols(test_file); + symbol_names& baseline_names = baseline.first; + symbol_objects& baseline_objects = baseline.second; + symbol_names& test_names = test.first; + symbol_objects& test_objects = test.second; + + // Sanity check results. + const symbol_names::size_type baseline_size = baseline_names.size(); + const symbol_names::size_type test_size = test_names.size(); + if (!baseline_size || !test_size) + { + cerr << "Problems parsing the list of exported symbols." << endl; + exit(2); + } + + // Sort out names. + // Assuming baseline_names, test_names are both unique w/ no duplicates. + // + // The names added to missing_names are baseline_names not found in + // test_names + // -> symbols that have been deleted. + // + // The names added to added_names are test_names are names not in + // baseline_names + // -> symbols that have been added. + symbol_names shared_names; + symbol_names missing_names; + symbol_names added_names = test_names; + for (size_t i = 0; i < baseline_size; ++i) + { + string what(baseline_names[i]); + symbol_names::iterator end = added_names.end(); + symbol_names::iterator it = find(added_names.begin(), end, what); + if (it != end) + { + // Found. + shared_names.push_back(what); + added_names.erase(it); + } + else + missing_names.push_back(what); + } + + // Check missing names for compatibility. + typedef pair<symbol, symbol> symbol_pair; + vector<symbol_pair> incompatible; + for (size_t i = 0; i < missing_names.size(); ++i) + { + symbol base = baseline_objects[missing_names[i]]; + incompatible.push_back(symbol_pair(base, base)); + } + + // Check shared names for compatibility. + for (size_t i = 0; i < shared_names.size(); ++i) + { + symbol base = baseline_objects[shared_names[i]]; + symbol test = test_objects[shared_names[i]]; + if (!check_compatible(base, test)) + incompatible.push_back(symbol_pair(base, test)); + } + + // Check added names for compatibility. + for (size_t i = 0; i < added_names.size(); ++i) + { + symbol test = test_objects[added_names[i]]; + if (!check_version(test, true)) + incompatible.push_back(symbol_pair(test, test)); + } + + // Report results. + if (verbose && added_names.size()) + { + cout << added_names.size() << " added symbols " << endl; + for (size_t j = 0; j < added_names.size() ; ++j) + test_objects[added_names[j]].print(); + } + + if (verbose && missing_names.size()) + { + cout << missing_names.size() << " missing symbols " << endl; + for (size_t j = 0; j < missing_names.size() ; ++j) + baseline_objects[missing_names[j]].print(); + } + + if (verbose && incompatible.size()) + { + cout << incompatible.size() << " incompatible symbols " << endl; + for (size_t j = 0; j < incompatible.size() ; ++j) + { + // First, report name. + const symbol& base = incompatible[j].first; + const symbol& test = incompatible[j].second; + test.print(); + + // Second, report reason or reasons incompatible. + check_compatible(base, test, true); + } + } + + cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl; + cout << endl; + cout << "# of added symbols:\t\t " << added_names.size() << endl; + cout << "# of missing symbols:\t\t " << missing_names.size() << endl; + cout << "# of incompatible symbols:\t " << incompatible.size() << endl; + cout << endl; + cout << "using: " << baseline_file << endl; +} + + +symbols +create_symbols(const char* file) +{ + symbols s; + ifstream ifs(file); + if (ifs.is_open()) + { + // Organize file data into container of symbol objects. + symbol_names& names = s.first; + symbol_objects& objects = s.second; + const string empty; + string line = empty; + while (getline(ifs, line).good()) + { + symbol tmp; + tmp.init(line); + objects[tmp.name] = tmp; + names.push_back(tmp.name); + line = empty; + } + } + else + { + ostringstream os; + os << "create_symbols failed for file " << file; + throw runtime_error(os.str()); + } + return s; +} + + +const char* +demangle(const std::string& mangled) +{ + const char* name; + if (mangled[0] != '_' || mangled[1] != 'Z') + { + // This is not a mangled symbol, thus has "C" linkage. + name = mangled.c_str(); + } + else + { + // Use __cxa_demangle to demangle. + int status = 0; + name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status); + if (!name) + { + switch (status) + { + case 0: + name = "error code = 0: success"; + break; + case -1: + name = "error code = -1: memory allocation failure"; + break; + case -2: + name = "error code = -2: invalid mangled name"; + break; + case -3: + name = "error code = -3: invalid arguments"; + break; + default: + name = "error code unknown - who knows what happened"; + } + } + } + return name; +} + diff --git a/libstdc++-v3/testsuite/testsuite_abi.h b/libstdc++-v3/testsuite/testsuite_abi.h new file mode 100644 index 00000000000..ebacb6a46e8 --- /dev/null +++ b/libstdc++-v3/testsuite/testsuite_abi.h @@ -0,0 +1,129 @@ +// -*- C++ -*- + +// Copyright (C) 2004 Free Software Foundation, Inc. + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2, or (at +// your option) any later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +// Benjamin Kosnik <bkoz@redhat.com> + +#include <string> +#include <stdexcept> +#include <deque> +#include <ext/hash_map> +#include <cxxabi.h> + +// Encapsulates symbol characteristics. +struct symbol +{ + enum category { none, function, object, error }; + enum designation { unknown, added, subtracted, compatible, incompatible }; + enum compatibility + { + compat_type = 1, + compat_name = 2, + compat_size = 4, + compat_version = 8 + }; + + category type; + std::string name; + std::string demangled_name; + int size; + std::string version_name; + designation status; + + symbol() : type(none), size(0), status(unknown) { } + + symbol(const symbol& other) + : type(other.type), name(other.name), demangled_name(other.demangled_name), + size(other.size), version_name(other.version_name), + status(other.status) { } + + void + print() const; + + void + init(std::string& data); +}; + +struct symbol_error : public std::logic_error +{ + explicit symbol_error(const std::string& s) : std::logic_error(s) { } +}; + + +typedef __gnu_cxx::hash_map<std::string, symbol> symbol_objects; + +typedef std::deque<std::string> symbol_names; + +typedef std::pair<symbol_names, symbol_objects> symbols; + + +// Check. +bool +check_version(const symbol& test, bool added = false); + +bool +check_compatible(const symbol& lhs, const symbol& rhs, bool verbose = false); + + +// Examine. +bool +has_symbol(const std::string& mangled, const symbols& list) throw(); + +symbol& +get_symbol(const std::string& mangled, const symbols& list); + +extern "C" void +examine_symbol(const char* name, const char* file); + +extern "C" void +compare_symbols(const char* baseline_file, const char* test_file, bool verb); + + +// Util. +symbols +create_symbols(const char* file); + +const char* +demangle(const std::string& mangled); + + +// Specialization. +namespace __gnu_cxx +{ + using namespace std; + + template<> + struct hash<string> + { + size_t operator()(const string& s) const + { + const collate<char>& c = use_facet<collate<char> >(locale::classic()); + return c.hash(s.c_str(), s.c_str() + s.size()); + } + }; +} |