]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/util/testsuite_abi.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / util / testsuite_abi.cc
CommitLineData
4b260c20
BK
1// -*- C++ -*-
2
8d9254fc 3// Copyright (C) 2004-2020 Free Software Foundation, Inc.
4b260c20
BK
4
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
748086b7 7// published by the Free Software Foundation; either version 3, or (at
4b260c20
BK
8// your option) any later version.
9
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.
14
15// You should have received a copy of the GNU General Public License
748086b7
JJ
16// along with this library; see the file COPYING3. If not see
17// <http://www.gnu.org/licenses/>.
4b260c20 18
4b260c20
BK
19
20// Benjamin Kosnik <bkoz@redhat.com>
21
22#include "testsuite_abi.h"
0c3de900 23#include <cstdlib>
4b260c20
BK
24#include <sstream>
25#include <fstream>
26#include <iostream>
0c3de900 27#include <vector>
4f39bf5c 28#include <algorithm>
4b260c20
BK
29
30using namespace std;
31
c9fd7c7b 32void
4b260c20
BK
33symbol::init(string& data)
34{
35 const char delim = ':';
36 const char version_delim = '@';
37 const string::size_type npos = string::npos;
38 string::size_type n = 0;
39
40 // Set the type.
41 if (data.find("FUNC") == 0)
42 type = symbol::function;
43 else if (data.find("OBJECT") == 0)
44 type = symbol::object;
bf718682
BK
45 else if (data.find("TLS") == 0)
46 type = symbol::tls;
bb2b2a24 47
4b260c20
BK
48 n = data.find_first_of(delim);
49 if (n != npos)
50 data.erase(data.begin(), data.begin() + n + 1);
51
bf718682
BK
52 // Iff object or TLS, get size info.
53 if (type == symbol::object || type == symbol::tls)
4b260c20
BK
54 {
55 n = data.find_first_of(delim);
56 if (n != npos)
57 {
69240fc2
SW
58 string objectsize(data.begin(), data.begin() + n);
59 istringstream iss(objectsize);
4b260c20
BK
60 int x;
61 iss >> x;
62 if (!iss.fail())
63 size = x;
64 data.erase(data.begin(), data.begin() + n + 1);
65 }
66 }
67
bb2b2a24
BK
68 // Set the name and raw_name.
69 raw_name = string(data.begin(), data.end());
4b260c20
BK
70 n = data.find_first_of(version_delim);
71 if (n != npos)
72 {
73 // Found version string.
74 name = string(data.begin(), data.begin() + n);
75 n = data.find_last_of(version_delim);
76 data.erase(data.begin(), data.begin() + n + 1);
77
78 // Set version name.
79 version_name = data;
80 }
81 else
82 {
83 // No versioning info.
84 name = string(data.begin(), data.end());
bb2b2a24 85 version_status = symbol::none;
4b260c20
BK
86 }
87
88 // Set the demangled name.
89 demangled_name = demangle(name);
90}
91
92void
93symbol::print() const
94{
95 const char tab = '\t';
bb2b2a24 96 cout << name << endl;
4b260c20 97
bb2b2a24
BK
98 if (demangled_name != name)
99 cout << demangled_name << endl;
100
101 string vers;
102 switch (version_status)
4b260c20
BK
103 {
104 case none:
bb2b2a24
BK
105 vers = "none";
106 break;
107 case compatible:
108 vers = "compatible";
109 break;
110 case incompatible:
111 vers = "incompatible";
112 break;
113 case unversioned:
114 vers = "unversioned";
4b260c20 115 break;
bb2b2a24
BK
116 default:
117 vers = "<default>";
118 }
119 cout << "version status: " << vers << endl;
120
c9fd7c7b 121 if (version_name.size()
bb2b2a24 122 && (version_status == compatible || version_status == incompatible))
c9fd7c7b 123 cout << version_name << endl;
bb2b2a24
BK
124
125 string type_string;
126 switch (type)
127 {
4b260c20
BK
128 case function:
129 type_string = "function";
130 break;
131 case object:
132 type_string = "object";
133 break;
bf718682
BK
134 case tls:
135 type_string = "tls";
136 break;
bb2b2a24
BK
137 case uncategorized:
138 type_string = "uncategorized";
4b260c20
BK
139 break;
140 default:
141 type_string = "<default>";
142 }
bb2b2a24 143 cout << "type: " << type_string << endl;
c9fd7c7b 144
bf718682 145 if (type == object || type == tls)
bb2b2a24 146 cout << "type size: " << size << endl;
4b260c20
BK
147
148 string status_string;
149 switch (status)
150 {
4b260c20
BK
151 case added:
152 status_string = "added";
153 break;
154 case subtracted:
155 status_string = "subtracted";
156 break;
bb2b2a24
BK
157 case undesignated:
158 status_string = "undesignated";
4b260c20
BK
159 break;
160 default:
161 status_string = "<default>";
162 }
bb2b2a24
BK
163 cout << "status: " << status_string << endl;
164
165 cout << endl;
4b260c20
BK
166}
167
168
169bool
bb2b2a24 170check_version(symbol& test, bool added)
4b260c20 171{
bb2b2a24 172 // Construct list of compatible versions.
4b260c20
BK
173 typedef std::vector<std::string> compat_list;
174 static compat_list known_versions;
175 if (known_versions.empty())
176 {
bb2b2a24
BK
177 // NB: First version here must be the default version for this
178 // version of DT_SONAME.
4b260c20 179 known_versions.push_back("GLIBCXX_3.4");
fb7f649d 180 known_versions.push_back("GLIBCXX_LDBL_3.4");
7c9fee34 181 known_versions.push_back("GLIBCXX_3.4.1");
9e802114 182 known_versions.push_back("GLIBCXX_3.4.2");
0e98ac62 183 known_versions.push_back("GLIBCXX_3.4.3");
c9fd7c7b 184 known_versions.push_back("GLIBCXX_3.4.4");
36b72d8d 185 known_versions.push_back("GLIBCXX_3.4.5");
bb2b2a24 186 known_versions.push_back("GLIBCXX_3.4.6");
18c75543 187 known_versions.push_back("GLIBCXX_3.4.7");
fb7f649d 188 known_versions.push_back("GLIBCXX_LDBL_3.4.7");
45f388bb 189 known_versions.push_back("GLIBCXX_3.4.8");
0efaed01 190 known_versions.push_back("GLIBCXX_3.4.9");
5dddb7e5 191 known_versions.push_back("GLIBCXX_3.4.10");
fb7f649d 192 known_versions.push_back("GLIBCXX_LDBL_3.4.10");
31908b79 193 known_versions.push_back("GLIBCXX_3.4.11");
efdb7347 194 known_versions.push_back("GLIBCXX_3.4.12");
95bfca5e 195 known_versions.push_back("GLIBCXX_3.4.13");
41bc3c4a 196 known_versions.push_back("GLIBCXX_3.4.14");
1e2c0906 197 known_versions.push_back("GLIBCXX_3.4.15");
07703a37 198 known_versions.push_back("GLIBCXX_3.4.16");
43653c33 199 known_versions.push_back("GLIBCXX_3.4.17");
90a75549 200 known_versions.push_back("GLIBCXX_3.4.18");
2d500828 201 known_versions.push_back("GLIBCXX_3.4.19");
2e8a9734 202 known_versions.push_back("GLIBCXX_3.4.20");
a8218d79 203 known_versions.push_back("GLIBCXX_3.4.21");
34a2b755 204 known_versions.push_back("GLIBCXX_LDBL_3.4.21");
62589e99
JW
205 known_versions.push_back("GLIBCXX_3.4.22");
206 known_versions.push_back("GLIBCXX_3.4.23");
78aa76df 207 known_versions.push_back("GLIBCXX_3.4.24");
4317778a 208 known_versions.push_back("GLIBCXX_3.4.25");
cda121ac 209 known_versions.push_back("GLIBCXX_3.4.26");
67699bf6 210 known_versions.push_back("GLIBCXX_3.4.27");
d02a0412 211 known_versions.push_back("GLIBCXX_3.4.28");
4b260c20 212 known_versions.push_back("CXXABI_1.3");
fb7f649d 213 known_versions.push_back("CXXABI_LDBL_1.3");
44dd2da2 214 known_versions.push_back("CXXABI_1.3.1");
9b4fc32c 215 known_versions.push_back("CXXABI_1.3.2");
c466b2cd 216 known_versions.push_back("CXXABI_1.3.3");
fae927d3 217 known_versions.push_back("CXXABI_1.3.4");
67275575 218 known_versions.push_back("CXXABI_1.3.5");
50da34bb 219 known_versions.push_back("CXXABI_1.3.6");
f5220359 220 known_versions.push_back("CXXABI_1.3.7");
fb7f649d 221 known_versions.push_back("CXXABI_1.3.8");
e4012a04 222 known_versions.push_back("CXXABI_1.3.9");
7573116b 223 known_versions.push_back("CXXABI_1.3.10");
27abac26 224 known_versions.push_back("CXXABI_1.3.11");
c124af93 225 known_versions.push_back("CXXABI_1.3.12");
c9fd7c7b 226 known_versions.push_back("CXXABI_TM_1");
bb59f396 227 known_versions.push_back("CXXABI_FLOAT128");
4b260c20
BK
228 }
229 compat_list::iterator begin = known_versions.begin();
230 compat_list::iterator end = known_versions.end();
231
bb2b2a24
BK
232 // Check for compatible version.
233 if (test.version_name.size())
234 {
235 compat_list::iterator it1 = find(begin, end, test.version_name);
236 compat_list::iterator it2 = find(begin, end, test.name);
237 if (it1 != end)
238 test.version_status = symbol::compatible;
239 else
240 test.version_status = symbol::incompatible;
c9fd7c7b
BK
241
242 // Check that added symbols are added in the latest pre-release version.
d02a0412 243 bool latestp = (test.version_name == "GLIBCXX_3.4.28"
c124af93 244 || test.version_name == "CXXABI_1.3.12"
bb59f396 245 || test.version_name == "CXXABI_FLOAT128"
c9fd7c7b
BK
246 || test.version_name == "CXXABI_TM_1");
247 if (added && !latestp)
bb2b2a24 248 test.version_status = symbol::incompatible;
c75bd36b 249
0c312c2d 250 // Check that long double compatibility symbols demangled as
bb59f396
MG
251 // __float128 and regular __float128 symbols are put into some _LDBL_
252 // or _FLOAT128 version name.
34a2b755
JW
253 if (added && test.demangled_name.find("__float128") != std::string::npos
254 && test.demangled_name.find("std::__cxx11::") != 0)
0c312c2d 255 {
bb59f396
MG
256 if (test.version_name.find("_LDBL_") == std::string::npos
257 && test.version_name.find("_FLOAT128") == std::string::npos)
0c312c2d
BK
258 test.version_status = symbol::incompatible;
259 }
260
bb2b2a24
BK
261 // Check for weak label.
262 if (it1 == end && it2 == end)
263 test.version_status = symbol::incompatible;
c9fd7c7b
BK
264
265 // Check that
bb2b2a24
BK
266 // GLIBCXX_3.4
267 // GLIBCXX_3.4.5
268 // version as compatible
269 // XXX
270 }
271 else
272 {
273 if (added)
274 {
275 // New version labels are ok. The rest are not.
276 compat_list::iterator it2 = find(begin, end, test.name);
277 if (it2 != end)
6defecc2 278 test.version_status = symbol::compatible;
bb2b2a24
BK
279 else
280 test.version_status = symbol::incompatible;
281 }
282 }
283 return test.version_status == symbol::compatible;
4b260c20
BK
284}
285
c9fd7c7b 286bool
bb2b2a24 287check_compatible(symbol& lhs, symbol& rhs, bool verbose)
4b260c20
BK
288{
289 bool ret = true;
290 const char tab = '\t';
291
292 // Check to see if symbol_objects are compatible.
293 if (lhs.type != rhs.type)
294 {
295 ret = false;
296 if (verbose)
297 cout << tab << "incompatible types" << endl;
298 }
c9fd7c7b 299
4b260c20
BK
300 if (lhs.name != rhs.name)
301 {
302 ret = false;
303 if (verbose)
304 cout << tab << "incompatible names" << endl;
305 }
306
307 if (lhs.size != rhs.size)
308 {
309 ret = false;
310 if (verbose)
311 {
312 cout << tab << "incompatible sizes" << endl;
313 cout << tab << lhs.size << endl;
314 cout << tab << rhs.size << endl;
315 }
316 }
317
c9fd7c7b 318 if (lhs.version_name != rhs.version_name
4b260c20
BK
319 && !check_version(lhs) && !check_version(rhs))
320 {
321 ret = false;
322 if (verbose)
323 {
324 cout << tab << "incompatible versions" << endl;
325 cout << tab << lhs.version_name << endl;
326 cout << tab << rhs.version_name << endl;
327 }
328 }
329
330 if (verbose)
331 cout << endl;
332
333 return ret;
334}
335
336
0c312c2d
BK
337inline bool
338has_symbol(const string& name, const symbols& s) throw()
339{ return s.find(name) != s.end(); }
4b260c20 340
0c312c2d
BK
341const symbol&
342get_symbol(const string& name, const symbols& s)
4b260c20 343{
0c312c2d
BK
344 symbols::const_iterator i = s.find(name);
345 if (i != s.end())
4b260c20 346 {
0c312c2d 347 return i->second;
4b260c20
BK
348 }
349 else
350 {
351 ostringstream os;
0c312c2d 352 os << "get_symbol failed for symbol " << name;
56ffd9b3 353 __throw_logic_error(os.str().c_str());
4b260c20
BK
354 }
355}
356
c9fd7c7b 357void
4b260c20
BK
358examine_symbol(const char* name, const char* file)
359{
360 try
361 {
362 symbols s = create_symbols(file);
0c312c2d 363 const symbol& sym = get_symbol(name, s);
4b260c20
BK
364 sym.print();
365 }
366 catch(...)
d98fd134 367 { __throw_exception_again; }
4b260c20
BK
368}
369
fdbba6bc 370int
c9fd7c7b 371compare_symbols(const char* baseline_file, const char* test_file,
4b260c20
BK
372 bool verbose)
373{
374 // Input both lists of symbols into container.
375 symbols baseline = create_symbols(baseline_file);
376 symbols test = create_symbols(test_file);
4b260c20
BK
377
378 // Sanity check results.
0c312c2d 379 if (!baseline.size() || !test.size())
4b260c20
BK
380 {
381 cerr << "Problems parsing the list of exported symbols." << endl;
382 exit(2);
383 }
384
4a49c70b
BK
385 // Check to see if any long double compatibility symbols are produced.
386 bool ld_version_found(false);
0c312c2d
BK
387 symbols::iterator li(test.begin());
388 while (!ld_version_found && li != test.end())
4a49c70b 389 {
0c312c2d 390 if (li->second.version_name.find("_LDBL_") != std::string::npos)
4a49c70b
BK
391 ld_version_found = true;
392 ++li;
393 }
394
4b260c20 395 // Sort out names.
0c312c2d
BK
396 // Assuming all baseline names and test names are both unique w/ no
397 // duplicates.
4b260c20 398 //
0c312c2d 399 // The names added to missing_names are baseline names not found in
c9fd7c7b 400 // test names
4b260c20
BK
401 // -> symbols that have been deleted.
402 //
0c312c2d
BK
403 // The names added to added_names are test names not in
404 // baseline names
4b260c20 405 // -> symbols that have been added.
0c312c2d 406 typedef std::vector<std::string> symbol_names;
4b260c20
BK
407 symbol_names shared_names;
408 symbol_names missing_names;
0c312c2d
BK
409 symbol_names added_names;
410 for (li = test.begin(); li != test.end(); ++li)
411 added_names.push_back(li->first);
412
413 for (symbols::iterator i = baseline.begin(); i != baseline.end(); ++i)
4b260c20 414 {
0c312c2d 415 string name(i->first);
4b260c20 416 symbol_names::iterator end = added_names.end();
0c312c2d 417 symbol_names::iterator it = find(added_names.begin(), end, name);
4b260c20
BK
418 if (it != end)
419 {
420 // Found.
0c312c2d 421 shared_names.push_back(name);
4b260c20
BK
422 added_names.erase(it);
423 }
0c312c2d
BK
424 else
425 {
426 // Iff no test long double compatibility symbols at all and the symbol
427 // missing is a baseline long double compatibility symbol, skip.
428 string version_name(i->second.version_name);
429 bool base_ld(version_name.find("_LDBL_") != std::string::npos);
430 if (!base_ld || base_ld && ld_version_found)
431 missing_names.push_back(name);
432 }
4b260c20
BK
433 }
434
0c312c2d 435 // Fill out list of incompatible symbols.
4b260c20
BK
436 typedef pair<symbol, symbol> symbol_pair;
437 vector<symbol_pair> incompatible;
0c312c2d 438
c9fd7c7b
BK
439 // Fill out list of undesignated symbols.
440 vector<symbol> undesignated;
441
0c312c2d
BK
442 // Check missing names for compatibility.
443 for (size_t j = 0; j < missing_names.size(); ++j)
4b260c20 444 {
0c312c2d
BK
445 symbol& sbase = baseline[missing_names[j]];
446 sbase.status = symbol::subtracted;
447 incompatible.push_back(symbol_pair(sbase, sbase));
4b260c20
BK
448 }
449
450 // Check shared names for compatibility.
6defecc2
JJ
451 const symbol_names::size_type shared_size = shared_names.size();
452 for (size_t k = 0; k < shared_size; ++k)
4b260c20 453 {
0c312c2d
BK
454 symbol& sbase = baseline[shared_names[k]];
455 symbol& stest = test[shared_names[k]];
456 stest.status = symbol::existing;
457 if (!check_compatible(sbase, stest))
458 incompatible.push_back(symbol_pair(sbase, stest));
4b260c20
BK
459 }
460
461 // Check added names for compatibility.
6defecc2
JJ
462 const symbol_names::size_type added_size = added_names.size();
463 for (size_t l = 0; l < added_size; ++l)
4b260c20 464 {
0c312c2d 465 symbol& stest = test[added_names[l]];
c9fd7c7b
BK
466
467 // Mark TLS as undesignated, remove from added.
468 if (stest.type == symbol::tls)
469 {
470 stest.status = symbol::undesignated;
471 if (!check_version(stest, false))
472 incompatible.push_back(symbol_pair(stest, stest));
473 else
474 undesignated.push_back(stest);
475 }
476 else
477 {
478 stest.status = symbol::added;
479 if (!check_version(stest, true))
480 incompatible.push_back(symbol_pair(stest, stest));
481 }
4b260c20
BK
482 }
483
c9fd7c7b
BK
484 // Normalize added names and undesignated names.
485 const size_t undesignated_size = undesignated.size();
486 for (size_t l = 0; l < undesignated_size; ++l)
487 {
488 symbol& sundes = undesignated[l];
489 symbol_names::iterator end = added_names.end();
490 symbol_names::iterator it = find(added_names.begin(), end, sundes.name);
491 if (it != end)
492 {
493 // Found.
494 added_names.erase(it);
495 }
496 else
497 __throw_runtime_error(sundes.name.c_str());
498 }
499
500
4b260c20
BK
501 // Report results.
502 if (verbose && added_names.size())
503 {
bb2b2a24 504 cout << endl << added_names.size() << " added symbols " << endl;
4b260c20 505 for (size_t j = 0; j < added_names.size() ; ++j)
bb2b2a24
BK
506 {
507 cout << j << endl;
0c312c2d 508 test[added_names[j]].print();
bb2b2a24 509 }
4b260c20 510 }
c9fd7c7b 511
4b260c20
BK
512 if (verbose && missing_names.size())
513 {
bb2b2a24 514 cout << endl << missing_names.size() << " missing symbols " << endl;
4b260c20 515 for (size_t j = 0; j < missing_names.size() ; ++j)
bb2b2a24
BK
516 {
517 cout << j << endl;
0c312c2d 518 baseline[missing_names[j]].print();
bb2b2a24 519 }
4b260c20 520 }
c9fd7c7b
BK
521
522 if (verbose && undesignated.size())
523 {
524 cout << endl << undesignated.size() << " undesignated symbols " << endl;
525 for (size_t j = 0; j < undesignated.size() ; ++j)
526 {
527 // First, print index.
528 cout << j << endl;
529
530 // Second, report name.
531 symbol& s = undesignated[j];
532 s.print();
533 }
534 }
535
4b260c20
BK
536 if (verbose && incompatible.size())
537 {
bb2b2a24 538 cout << endl << incompatible.size() << " incompatible symbols " << endl;
4b260c20
BK
539 for (size_t j = 0; j < incompatible.size() ; ++j)
540 {
bb2b2a24
BK
541 // First, print index.
542 cout << j << endl;
543
544 // Second, report name.
0c312c2d
BK
545 symbol& sbase = incompatible[j].first;
546 symbol& stest = incompatible[j].second;
547 stest.print();
c9fd7c7b
BK
548
549 // Third, report reason or reasons incompatible.
0c312c2d 550 check_compatible(sbase, stest, true);
4b260c20
BK
551 }
552 }
c9fd7c7b 553
332781bb 554 cout << "\n\t\t==== libstdc++-v3 check-abi Summary ====" << endl;
4b260c20
BK
555 cout << endl;
556 cout << "# of added symbols:\t\t " << added_names.size() << endl;
557 cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
c9fd7c7b 558 cout << "# of undesignated symbols:\t " << undesignated.size() << endl;
4b260c20
BK
559 cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
560 cout << endl;
561 cout << "using: " << baseline_file << endl;
fdbba6bc
MM
562
563 return !(missing_names.size() || incompatible.size());
4b260c20
BK
564}
565
566
567symbols
568create_symbols(const char* file)
569{
570 symbols s;
571 ifstream ifs(file);
572 if (ifs.is_open())
573 {
0c312c2d
BK
574 // Organize file data into an associated container (symbols) of symbol
575 // objects mapped to mangled names without versioning
576 // information.
4b260c20
BK
577 const string empty;
578 string line = empty;
579 while (getline(ifs, line).good())
580 {
581 symbol tmp;
582 tmp.init(line);
0c312c2d 583 s[tmp.name] = tmp;
4b260c20
BK
584 line = empty;
585 }
586 }
587 else
588 {
589 ostringstream os;
590 os << "create_symbols failed for file " << file;
56ffd9b3 591 __throw_runtime_error(os.str().c_str());
4b260c20
BK
592 }
593 return s;
594}
595
596
4f7c2c7f 597std::string
4b260c20
BK
598demangle(const std::string& mangled)
599{
4f7c2c7f 600 std::string name;
4b260c20
BK
601 if (mangled[0] != '_' || mangled[1] != 'Z')
602 {
603 // This is not a mangled symbol, thus has "C" linkage.
4f7c2c7f 604 name = mangled;
4b260c20
BK
605 }
606 else
607 {
608 // Use __cxa_demangle to demangle.
609 int status = 0;
4f7c2c7f
JW
610 char* ptr = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
611 if (ptr)
612 {
613 name = ptr;
614 free(ptr);
615 }
616 else
4b260c20
BK
617 {
618 switch (status)
619 {
620 case 0:
621 name = "error code = 0: success";
622 break;
623 case -1:
624 name = "error code = -1: memory allocation failure";
625 break;
626 case -2:
627 name = "error code = -2: invalid mangled name";
628 break;
629 case -3:
630 name = "error code = -3: invalid arguments";
631 break;
632 default:
633 name = "error code unknown - who knows what happened";
634 }
635 }
636 }
637 return name;
638}