Update concepts branch to revision 131834
[official-gcc.git] / libstdc++-v3 / testsuite / util / testsuite_abi.cc
blob6466fbabcd80b037aa64e3127bba6302f7fab151
1 // -*- C++ -*-
3 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2, or (at
8 // your option) any later version.
10 // This library is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this library; see the file COPYING. If not, write to
17 // the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 // MA 02110-1301, USA.
20 // As a special exception, you may use this file as part of a free
21 // software library without restriction. Specifically, if other files
22 // instantiate templates or use macros or inline functions from this
23 // file, or you compile this file and link it with other files to
24 // produce an executable, this file does not by itself cause the
25 // resulting executable to be covered by the GNU General Public
26 // License. This exception does not however invalidate any other
27 // reasons why the executable file might be covered by the GNU General
28 // Public License.
30 // Benjamin Kosnik <bkoz@redhat.com>
32 #include "testsuite_abi.h"
33 #include <cstdlib>
34 #include <sstream>
35 #include <fstream>
36 #include <iostream>
37 #include <vector>
38 #include <algorithm>
40 using namespace std;
42 void
43 symbol::init(string& data)
45 const char delim = ':';
46 const char version_delim = '@';
47 const string::size_type npos = string::npos;
48 string::size_type n = 0;
50 // Set the type.
51 if (data.find("FUNC") == 0)
52 type = symbol::function;
53 else if (data.find("OBJECT") == 0)
54 type = symbol::object;
56 n = data.find_first_of(delim);
57 if (n != npos)
58 data.erase(data.begin(), data.begin() + n + 1);
60 // Iff object, get size info.
61 if (type == symbol::object)
63 n = data.find_first_of(delim);
64 if (n != npos)
66 string objectsize(data.begin(), data.begin() + n);
67 istringstream iss(objectsize);
68 int x;
69 iss >> x;
70 if (!iss.fail())
71 size = x;
72 data.erase(data.begin(), data.begin() + n + 1);
76 // Set the name and raw_name.
77 raw_name = string(data.begin(), data.end());
78 n = data.find_first_of(version_delim);
79 if (n != npos)
81 // Found version string.
82 name = string(data.begin(), data.begin() + n);
83 n = data.find_last_of(version_delim);
84 data.erase(data.begin(), data.begin() + n + 1);
86 // Set version name.
87 version_name = data;
89 else
91 // No versioning info.
92 name = string(data.begin(), data.end());
93 version_status = symbol::none;
96 // Set the demangled name.
97 demangled_name = demangle(name);
100 void
101 symbol::print() const
103 const char tab = '\t';
104 cout << name << endl;
106 if (demangled_name != name)
107 cout << demangled_name << endl;
109 string vers;
110 switch (version_status)
112 case none:
113 vers = "none";
114 break;
115 case compatible:
116 vers = "compatible";
117 break;
118 case incompatible:
119 vers = "incompatible";
120 break;
121 case unversioned:
122 vers = "unversioned";
123 break;
124 default:
125 vers = "<default>";
127 cout << "version status: " << vers << endl;
129 if (version_name.size()
130 && (version_status == compatible || version_status == incompatible))
131 cout << version_name << endl;
133 string type_string;
134 switch (type)
136 case function:
137 type_string = "function";
138 break;
139 case object:
140 type_string = "object";
141 break;
142 case uncategorized:
143 type_string = "uncategorized";
144 break;
145 default:
146 type_string = "<default>";
148 cout << "type: " << type_string << endl;
150 if (type == object)
151 cout << "type size: " << size << endl;
153 string status_string;
154 switch (status)
156 case added:
157 status_string = "added";
158 break;
159 case subtracted:
160 status_string = "subtracted";
161 break;
162 case undesignated:
163 status_string = "undesignated";
164 break;
165 default:
166 status_string = "<default>";
168 cout << "status: " << status_string << endl;
170 cout << endl;
174 bool
175 check_version(symbol& test, bool added)
177 // Construct list of compatible versions.
178 typedef std::vector<std::string> compat_list;
179 static compat_list known_versions;
180 if (known_versions.empty())
182 // NB: First version here must be the default version for this
183 // version of DT_SONAME.
184 known_versions.push_back("GLIBCXX_3.4");
185 known_versions.push_back("GLIBCXX_3.4.1");
186 known_versions.push_back("GLIBCXX_3.4.2");
187 known_versions.push_back("GLIBCXX_3.4.3");
188 known_versions.push_back("GLIBCXX_3.4.4");
189 known_versions.push_back("GLIBCXX_3.4.5");
190 known_versions.push_back("GLIBCXX_3.4.6");
191 known_versions.push_back("GLIBCXX_3.4.7");
192 known_versions.push_back("GLIBCXX_3.4.8");
193 known_versions.push_back("GLIBCXX_3.4.9");
194 known_versions.push_back("GLIBCXX_3.4.10");
195 known_versions.push_back("GLIBCXX_3.4.11");
196 known_versions.push_back("GLIBCXX_LDBL_3.4");
197 known_versions.push_back("GLIBCXX_LDBL_3.4.7");
198 known_versions.push_back("GLIBCXX_LDBL_3.4.10");
199 known_versions.push_back("CXXABI_1.3");
200 known_versions.push_back("CXXABI_1.3.1");
201 known_versions.push_back("CXXABI_1.3.2");
202 known_versions.push_back("CXXABI_LDBL_1.3");
204 compat_list::iterator begin = known_versions.begin();
205 compat_list::iterator end = known_versions.end();
207 // Check for compatible version.
208 if (test.version_name.size())
210 compat_list::iterator it1 = find(begin, end, test.version_name);
211 compat_list::iterator it2 = find(begin, end, test.name);
212 if (it1 != end)
213 test.version_status = symbol::compatible;
214 else
215 test.version_status = symbol::incompatible;
217 // Check that added symbols aren't added in the base version.
218 if (added && test.version_name == known_versions[0])
219 test.version_status = symbol::incompatible;
221 // Check that long double compatibility symbols demangled as
222 // __float128 are put into some _LDBL_ version name.
223 if (added && test.demangled_name.find("__float128") != std::string::npos)
225 // Has to be in _LDBL_ version name.
226 if (test.version_name.find("_LDBL_") == std::string::npos)
227 test.version_status = symbol::incompatible;
230 // Check for weak label.
231 if (it1 == end && it2 == end)
232 test.version_status = symbol::incompatible;
234 // Check that
235 // GLIBCXX_3.4
236 // GLIBCXX_3.4.5
237 // version as compatible
238 // XXX
240 else
242 if (added)
244 // New version labels are ok. The rest are not.
245 compat_list::iterator it2 = find(begin, end, test.name);
246 if (it2 != end)
247 test.version_status = symbol::compatible;
248 else
249 test.version_status = symbol::incompatible;
252 return test.version_status == symbol::compatible;
255 bool
256 check_compatible(symbol& lhs, symbol& rhs, bool verbose)
258 bool ret = true;
259 const char tab = '\t';
261 // Check to see if symbol_objects are compatible.
262 if (lhs.type != rhs.type)
264 ret = false;
265 if (verbose)
266 cout << tab << "incompatible types" << endl;
269 if (lhs.name != rhs.name)
271 ret = false;
272 if (verbose)
273 cout << tab << "incompatible names" << endl;
276 if (lhs.size != rhs.size)
278 ret = false;
279 if (verbose)
281 cout << tab << "incompatible sizes" << endl;
282 cout << tab << lhs.size << endl;
283 cout << tab << rhs.size << endl;
287 if (lhs.version_name != rhs.version_name
288 && !check_version(lhs) && !check_version(rhs))
290 ret = false;
291 if (verbose)
293 cout << tab << "incompatible versions" << endl;
294 cout << tab << lhs.version_name << endl;
295 cout << tab << rhs.version_name << endl;
299 if (verbose)
300 cout << endl;
302 return ret;
306 inline bool
307 has_symbol(const string& name, const symbols& s) throw()
308 { return s.find(name) != s.end(); }
310 const symbol&
311 get_symbol(const string& name, const symbols& s)
313 symbols::const_iterator i = s.find(name);
314 if (i != s.end())
316 return i->second;
318 else
320 ostringstream os;
321 os << "get_symbol failed for symbol " << name;
322 __throw_logic_error(os.str().c_str());
326 void
327 examine_symbol(const char* name, const char* file)
331 symbols s = create_symbols(file);
332 const symbol& sym = get_symbol(name, s);
333 sym.print();
335 catch(...)
336 { __throw_exception_again; }
340 compare_symbols(const char* baseline_file, const char* test_file,
341 bool verbose)
343 // Input both lists of symbols into container.
344 symbols baseline = create_symbols(baseline_file);
345 symbols test = create_symbols(test_file);
347 // Sanity check results.
348 if (!baseline.size() || !test.size())
350 cerr << "Problems parsing the list of exported symbols." << endl;
351 exit(2);
354 // Check to see if any long double compatibility symbols are produced.
355 bool ld_version_found(false);
356 symbols::iterator li(test.begin());
357 while (!ld_version_found && li != test.end())
359 if (li->second.version_name.find("_LDBL_") != std::string::npos)
360 ld_version_found = true;
361 ++li;
364 // Sort out names.
365 // Assuming all baseline names and test names are both unique w/ no
366 // duplicates.
368 // The names added to missing_names are baseline names not found in
369 // test names
370 // -> symbols that have been deleted.
372 // The names added to added_names are test names not in
373 // baseline names
374 // -> symbols that have been added.
375 typedef std::vector<std::string> symbol_names;
376 symbol_names shared_names;
377 symbol_names missing_names;
378 symbol_names added_names;
379 for (li = test.begin(); li != test.end(); ++li)
380 added_names.push_back(li->first);
382 for (symbols::iterator i = baseline.begin(); i != baseline.end(); ++i)
384 string name(i->first);
385 symbol_names::iterator end = added_names.end();
386 symbol_names::iterator it = find(added_names.begin(), end, name);
387 if (it != end)
389 // Found.
390 shared_names.push_back(name);
391 added_names.erase(it);
393 else
395 // Iff no test long double compatibility symbols at all and the symbol
396 // missing is a baseline long double compatibility symbol, skip.
397 string version_name(i->second.version_name);
398 bool base_ld(version_name.find("_LDBL_") != std::string::npos);
399 if (!base_ld || base_ld && ld_version_found)
400 missing_names.push_back(name);
404 // Fill out list of incompatible symbols.
405 typedef pair<symbol, symbol> symbol_pair;
406 vector<symbol_pair> incompatible;
408 // Check missing names for compatibility.
409 for (size_t j = 0; j < missing_names.size(); ++j)
411 symbol& sbase = baseline[missing_names[j]];
412 sbase.status = symbol::subtracted;
413 incompatible.push_back(symbol_pair(sbase, sbase));
416 // Check shared names for compatibility.
417 const symbol_names::size_type shared_size = shared_names.size();
418 for (size_t k = 0; k < shared_size; ++k)
420 symbol& sbase = baseline[shared_names[k]];
421 symbol& stest = test[shared_names[k]];
422 stest.status = symbol::existing;
423 if (!check_compatible(sbase, stest))
424 incompatible.push_back(symbol_pair(sbase, stest));
427 // Check added names for compatibility.
428 const symbol_names::size_type added_size = added_names.size();
429 for (size_t l = 0; l < added_size; ++l)
431 symbol& stest = test[added_names[l]];
432 stest.status = symbol::added;
433 if (!check_version(stest, true))
434 incompatible.push_back(symbol_pair(stest, stest));
437 // Report results.
438 if (verbose && added_names.size())
440 cout << endl << added_names.size() << " added symbols " << endl;
441 for (size_t j = 0; j < added_names.size() ; ++j)
443 cout << j << endl;
444 test[added_names[j]].print();
448 if (verbose && missing_names.size())
450 cout << endl << missing_names.size() << " missing symbols " << endl;
451 for (size_t j = 0; j < missing_names.size() ; ++j)
453 cout << j << endl;
454 baseline[missing_names[j]].print();
458 if (verbose && incompatible.size())
460 cout << endl << incompatible.size() << " incompatible symbols " << endl;
461 for (size_t j = 0; j < incompatible.size() ; ++j)
463 // First, print index.
464 cout << j << endl;
466 // Second, report name.
467 symbol& sbase = incompatible[j].first;
468 symbol& stest = incompatible[j].second;
469 stest.print();
471 // Second, report reason or reasons incompatible.
472 check_compatible(sbase, stest, true);
476 cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
477 cout << endl;
478 cout << "# of added symbols:\t\t " << added_names.size() << endl;
479 cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
480 cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
481 cout << endl;
482 cout << "using: " << baseline_file << endl;
484 return !(missing_names.size() || incompatible.size());
488 symbols
489 create_symbols(const char* file)
491 symbols s;
492 ifstream ifs(file);
493 if (ifs.is_open())
495 // Organize file data into an associated container (symbols) of symbol
496 // objects mapped to mangled names without versioning
497 // information.
498 const string empty;
499 string line = empty;
500 while (getline(ifs, line).good())
502 symbol tmp;
503 tmp.init(line);
504 s[tmp.name] = tmp;
505 line = empty;
508 else
510 ostringstream os;
511 os << "create_symbols failed for file " << file;
512 __throw_runtime_error(os.str().c_str());
514 return s;
518 const char*
519 demangle(const std::string& mangled)
521 const char* name;
522 if (mangled[0] != '_' || mangled[1] != 'Z')
524 // This is not a mangled symbol, thus has "C" linkage.
525 name = mangled.c_str();
527 else
529 // Use __cxa_demangle to demangle.
530 int status = 0;
531 name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
532 if (!name)
534 switch (status)
536 case 0:
537 name = "error code = 0: success";
538 break;
539 case -1:
540 name = "error code = -1: memory allocation failure";
541 break;
542 case -2:
543 name = "error code = -2: invalid mangled name";
544 break;
545 case -3:
546 name = "error code = -3: invalid arguments";
547 break;
548 default:
549 name = "error code unknown - who knows what happened";
553 return name;