2008-01-25 Douglas Gregor <doug.gregor@gmail.com>
[official-gcc.git] / libstdc++-v3 / testsuite / util / testsuite_abi.cc
blobcec3ae2f3f9ca9f3ddc46db85255804489d7eeae
1 // -*- C++ -*-
3 // Copyright (C) 2004, 2005, 2006, 2007 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_LDBL_3.4");
196 known_versions.push_back("GLIBCXX_LDBL_3.4.7");
197 known_versions.push_back("CXXABI_1.3");
198 known_versions.push_back("CXXABI_1.3.1");
199 known_versions.push_back("CXXABI_1.3.2");
200 known_versions.push_back("CXXABI_LDBL_1.3");
202 compat_list::iterator begin = known_versions.begin();
203 compat_list::iterator end = known_versions.end();
205 // Check for compatible version.
206 if (test.version_name.size())
208 compat_list::iterator it1 = find(begin, end, test.version_name);
209 compat_list::iterator it2 = find(begin, end, test.name);
210 if (it1 != end)
211 test.version_status = symbol::compatible;
212 else
213 test.version_status = symbol::incompatible;
215 // Check that added symbols aren't added in the base version.
216 if (added && test.version_name == known_versions[0])
217 test.version_status = symbol::incompatible;
219 // Check for weak label.
220 if (it1 == end && it2 == end)
221 test.version_status = symbol::incompatible;
223 // Check that
224 // GLIBCXX_3.4
225 // GLIBCXX_3.4.5
226 // version as compatible
227 // XXX
229 else
231 if (added)
233 // New version labels are ok. The rest are not.
234 compat_list::iterator it2 = find(begin, end, test.name);
235 if (it2 != end)
236 test.version_status = symbol::compatible;
237 else
238 test.version_status = symbol::incompatible;
241 return test.version_status == symbol::compatible;
244 bool
245 check_compatible(symbol& lhs, symbol& rhs, bool verbose)
247 bool ret = true;
248 const char tab = '\t';
250 // Check to see if symbol_objects are compatible.
251 if (lhs.type != rhs.type)
253 ret = false;
254 if (verbose)
255 cout << tab << "incompatible types" << endl;
258 if (lhs.name != rhs.name)
260 ret = false;
261 if (verbose)
262 cout << tab << "incompatible names" << endl;
265 if (lhs.size != rhs.size)
267 ret = false;
268 if (verbose)
270 cout << tab << "incompatible sizes" << endl;
271 cout << tab << lhs.size << endl;
272 cout << tab << rhs.size << endl;
276 if (lhs.version_name != rhs.version_name
277 && !check_version(lhs) && !check_version(rhs))
279 ret = false;
280 if (verbose)
282 cout << tab << "incompatible versions" << endl;
283 cout << tab << lhs.version_name << endl;
284 cout << tab << rhs.version_name << endl;
288 if (verbose)
289 cout << endl;
291 return ret;
295 bool
296 has_symbol(const string& mangled, const symbols& s) throw()
298 const symbol_names& names = s.first;
299 symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
300 return i != names.end();
303 symbol&
304 get_symbol(const string& mangled, const symbols& s)
306 const symbol_names& names = s.first;
307 symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
308 if (i != names.end())
310 symbol_objects objects = s.second;
311 return objects[mangled];
313 else
315 ostringstream os;
316 os << "get_symbol failed for symbol " << mangled;
317 __throw_logic_error(os.str().c_str());
321 void
322 examine_symbol(const char* name, const char* file)
326 symbols s = create_symbols(file);
327 symbol& sym = get_symbol(name, s);
328 sym.print();
330 catch(...)
331 { __throw_exception_again; }
335 compare_symbols(const char* baseline_file, const char* test_file,
336 bool verbose)
338 // Input both lists of symbols into container.
339 symbols baseline = create_symbols(baseline_file);
340 symbols test = create_symbols(test_file);
341 symbol_names& baseline_names = baseline.first;
342 symbol_objects& baseline_objects = baseline.second;
343 symbol_names& test_names = test.first;
344 symbol_objects& test_objects = test.second;
346 // Sanity check results.
347 const symbol_names::size_type baseline_size = baseline_names.size();
348 const symbol_names::size_type test_size = test_names.size();
349 if (!baseline_size || !test_size)
351 cerr << "Problems parsing the list of exported symbols." << endl;
352 exit(2);
355 // Sort out names.
356 // Assuming baseline_names, test_names are both unique w/ no duplicates.
358 // The names added to missing_names are baseline_names not found in
359 // test_names
360 // -> symbols that have been deleted.
362 // The names added to added_names are test_names not in
363 // baseline_names
364 // -> symbols that have been added.
365 symbol_names shared_names;
366 symbol_names missing_names;
367 symbol_names added_names = test_names;
368 for (size_t i = 0; i < baseline_size; ++i)
370 string what(baseline_names[i]);
371 symbol_names::iterator end = added_names.end();
372 symbol_names::iterator it = find(added_names.begin(), end, what);
373 if (it != end)
375 // Found.
376 shared_names.push_back(what);
377 added_names.erase(it);
379 else
380 missing_names.push_back(what);
383 // Check missing names for compatibility.
384 typedef pair<symbol, symbol> symbol_pair;
385 vector<symbol_pair> incompatible;
386 const symbol_names::size_type missing_size = missing_names.size();
387 for (size_t j = 0; j < missing_size; ++j)
389 symbol& base = baseline_objects[missing_names[j]];
390 base.status = symbol::subtracted;
391 incompatible.push_back(symbol_pair(base, base));
394 // Check shared names for compatibility.
395 const symbol_names::size_type shared_size = shared_names.size();
396 for (size_t k = 0; k < shared_size; ++k)
398 symbol& base = baseline_objects[shared_names[k]];
399 symbol& test = test_objects[shared_names[k]];
400 test.status = symbol::existing;
401 if (!check_compatible(base, test))
402 incompatible.push_back(symbol_pair(base, test));
405 // Check added names for compatibility.
406 const symbol_names::size_type added_size = added_names.size();
407 for (size_t l = 0; l < added_size; ++l)
409 symbol& test = test_objects[added_names[l]];
410 test.status = symbol::added;
411 if (!check_version(test, true))
412 incompatible.push_back(symbol_pair(test, test));
415 // Report results.
416 if (verbose && added_names.size())
418 cout << endl << added_names.size() << " added symbols " << endl;
419 for (size_t j = 0; j < added_names.size() ; ++j)
421 cout << j << endl;
422 test_objects[added_names[j]].print();
426 if (verbose && missing_names.size())
428 cout << endl << missing_names.size() << " missing symbols " << endl;
429 for (size_t j = 0; j < missing_names.size() ; ++j)
431 cout << j << endl;
432 baseline_objects[missing_names[j]].print();
436 if (verbose && incompatible.size())
438 cout << endl << incompatible.size() << " incompatible symbols " << endl;
439 for (size_t j = 0; j < incompatible.size() ; ++j)
441 // First, print index.
442 cout << j << endl;
444 // Second, report name.
445 symbol& base = incompatible[j].first;
446 symbol& test = incompatible[j].second;
447 test.print();
449 // Second, report reason or reasons incompatible.
450 check_compatible(base, test, true);
454 cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
455 cout << endl;
456 cout << "# of added symbols:\t\t " << added_names.size() << endl;
457 cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
458 cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
459 cout << endl;
460 cout << "using: " << baseline_file << endl;
462 return !(missing_names.size() || incompatible.size());
466 symbols
467 create_symbols(const char* file)
469 symbols s;
470 ifstream ifs(file);
471 if (ifs.is_open())
473 // Organize file data into container of symbol objects, and a
474 // container of mangled names without versioning information.
475 symbol_names& names = s.first;
476 symbol_objects& objects = s.second;
477 const string empty;
478 string line = empty;
479 while (getline(ifs, line).good())
481 symbol tmp;
482 tmp.init(line);
483 objects[tmp.name] = tmp;
484 names.push_back(tmp.name);
485 line = empty;
488 else
490 ostringstream os;
491 os << "create_symbols failed for file " << file;
492 __throw_runtime_error(os.str().c_str());
494 return s;
498 const char*
499 demangle(const std::string& mangled)
501 const char* name;
502 if (mangled[0] != '_' || mangled[1] != 'Z')
504 // This is not a mangled symbol, thus has "C" linkage.
505 name = mangled.c_str();
507 else
509 // Use __cxa_demangle to demangle.
510 int status = 0;
511 name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
512 if (!name)
514 switch (status)
516 case 0:
517 name = "error code = 0: success";
518 break;
519 case -1:
520 name = "error code = -1: memory allocation failure";
521 break;
522 case -2:
523 name = "error code = -2: invalid mangled name";
524 break;
525 case -3:
526 name = "error code = -3: invalid arguments";
527 break;
528 default:
529 name = "error code unknown - who knows what happened";
533 return name;