c-common.c (c_stddef_cpp_builtins): Define __CHAR16_TYPE__ and __CHAR32_TYPE__.
[gcc.git] / libstdc++-v3 / testsuite / util / testsuite_abi.cc
1 // -*- C++ -*-
2
3 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
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
7 // published by the Free Software Foundation; either version 2, or (at
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
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.
19
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.
29
30 // Benjamin Kosnik <bkoz@redhat.com>
31
32 #include "testsuite_abi.h"
33 #include <cstdlib>
34 #include <sstream>
35 #include <fstream>
36 #include <iostream>
37 #include <vector>
38 #include <algorithm>
39
40 using namespace std;
41
42 void
43 symbol::init(string& data)
44 {
45 const char delim = ':';
46 const char version_delim = '@';
47 const string::size_type npos = string::npos;
48 string::size_type n = 0;
49
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;
55
56 n = data.find_first_of(delim);
57 if (n != npos)
58 data.erase(data.begin(), data.begin() + n + 1);
59
60 // Iff object, get size info.
61 if (type == symbol::object)
62 {
63 n = data.find_first_of(delim);
64 if (n != npos)
65 {
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);
73 }
74 }
75
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)
80 {
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);
85
86 // Set version name.
87 version_name = data;
88 }
89 else
90 {
91 // No versioning info.
92 name = string(data.begin(), data.end());
93 version_status = symbol::none;
94 }
95
96 // Set the demangled name.
97 demangled_name = demangle(name);
98 }
99
100 void
101 symbol::print() const
102 {
103 const char tab = '\t';
104 cout << name << endl;
105
106 if (demangled_name != name)
107 cout << demangled_name << endl;
108
109 string vers;
110 switch (version_status)
111 {
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>";
126 }
127 cout << "version status: " << vers << endl;
128
129 if (version_name.size()
130 && (version_status == compatible || version_status == incompatible))
131 cout << version_name << endl;
132
133 string type_string;
134 switch (type)
135 {
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>";
147 }
148 cout << "type: " << type_string << endl;
149
150 if (type == object)
151 cout << "type size: " << size << endl;
152
153 string status_string;
154 switch (status)
155 {
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>";
167 }
168 cout << "status: " << status_string << endl;
169
170 cout << endl;
171 }
172
173
174 bool
175 check_version(symbol& test, bool added)
176 {
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())
181 {
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_1.3.3");
203 known_versions.push_back("CXXABI_LDBL_1.3");
204 }
205 compat_list::iterator begin = known_versions.begin();
206 compat_list::iterator end = known_versions.end();
207
208 // Check for compatible version.
209 if (test.version_name.size())
210 {
211 compat_list::iterator it1 = find(begin, end, test.version_name);
212 compat_list::iterator it2 = find(begin, end, test.name);
213 if (it1 != end)
214 test.version_status = symbol::compatible;
215 else
216 test.version_status = symbol::incompatible;
217
218 // Check that added symbols aren't added in the base version.
219 if (added && test.version_name == known_versions[0])
220 test.version_status = symbol::incompatible;
221
222 // Check that long double compatibility symbols demangled as
223 // __float128 are put into some _LDBL_ version name.
224 if (added && test.demangled_name.find("__float128") != std::string::npos)
225 {
226 // Has to be in _LDBL_ version name.
227 if (test.version_name.find("_LDBL_") == std::string::npos)
228 test.version_status = symbol::incompatible;
229 }
230
231 // Check for weak label.
232 if (it1 == end && it2 == end)
233 test.version_status = symbol::incompatible;
234
235 // Check that
236 // GLIBCXX_3.4
237 // GLIBCXX_3.4.5
238 // version as compatible
239 // XXX
240 }
241 else
242 {
243 if (added)
244 {
245 // New version labels are ok. The rest are not.
246 compat_list::iterator it2 = find(begin, end, test.name);
247 if (it2 != end)
248 test.version_status = symbol::compatible;
249 else
250 test.version_status = symbol::incompatible;
251 }
252 }
253 return test.version_status == symbol::compatible;
254 }
255
256 bool
257 check_compatible(symbol& lhs, symbol& rhs, bool verbose)
258 {
259 bool ret = true;
260 const char tab = '\t';
261
262 // Check to see if symbol_objects are compatible.
263 if (lhs.type != rhs.type)
264 {
265 ret = false;
266 if (verbose)
267 cout << tab << "incompatible types" << endl;
268 }
269
270 if (lhs.name != rhs.name)
271 {
272 ret = false;
273 if (verbose)
274 cout << tab << "incompatible names" << endl;
275 }
276
277 if (lhs.size != rhs.size)
278 {
279 ret = false;
280 if (verbose)
281 {
282 cout << tab << "incompatible sizes" << endl;
283 cout << tab << lhs.size << endl;
284 cout << tab << rhs.size << endl;
285 }
286 }
287
288 if (lhs.version_name != rhs.version_name
289 && !check_version(lhs) && !check_version(rhs))
290 {
291 ret = false;
292 if (verbose)
293 {
294 cout << tab << "incompatible versions" << endl;
295 cout << tab << lhs.version_name << endl;
296 cout << tab << rhs.version_name << endl;
297 }
298 }
299
300 if (verbose)
301 cout << endl;
302
303 return ret;
304 }
305
306
307 inline bool
308 has_symbol(const string& name, const symbols& s) throw()
309 { return s.find(name) != s.end(); }
310
311 const symbol&
312 get_symbol(const string& name, const symbols& s)
313 {
314 symbols::const_iterator i = s.find(name);
315 if (i != s.end())
316 {
317 return i->second;
318 }
319 else
320 {
321 ostringstream os;
322 os << "get_symbol failed for symbol " << name;
323 __throw_logic_error(os.str().c_str());
324 }
325 }
326
327 void
328 examine_symbol(const char* name, const char* file)
329 {
330 try
331 {
332 symbols s = create_symbols(file);
333 const symbol& sym = get_symbol(name, s);
334 sym.print();
335 }
336 catch(...)
337 { __throw_exception_again; }
338 }
339
340 int
341 compare_symbols(const char* baseline_file, const char* test_file,
342 bool verbose)
343 {
344 // Input both lists of symbols into container.
345 symbols baseline = create_symbols(baseline_file);
346 symbols test = create_symbols(test_file);
347
348 // Sanity check results.
349 if (!baseline.size() || !test.size())
350 {
351 cerr << "Problems parsing the list of exported symbols." << endl;
352 exit(2);
353 }
354
355 // Check to see if any long double compatibility symbols are produced.
356 bool ld_version_found(false);
357 symbols::iterator li(test.begin());
358 while (!ld_version_found && li != test.end())
359 {
360 if (li->second.version_name.find("_LDBL_") != std::string::npos)
361 ld_version_found = true;
362 ++li;
363 }
364
365 // Sort out names.
366 // Assuming all baseline names and test names are both unique w/ no
367 // duplicates.
368 //
369 // The names added to missing_names are baseline names not found in
370 // test names
371 // -> symbols that have been deleted.
372 //
373 // The names added to added_names are test names not in
374 // baseline names
375 // -> symbols that have been added.
376 typedef std::vector<std::string> symbol_names;
377 symbol_names shared_names;
378 symbol_names missing_names;
379 symbol_names added_names;
380 for (li = test.begin(); li != test.end(); ++li)
381 added_names.push_back(li->first);
382
383 for (symbols::iterator i = baseline.begin(); i != baseline.end(); ++i)
384 {
385 string name(i->first);
386 symbol_names::iterator end = added_names.end();
387 symbol_names::iterator it = find(added_names.begin(), end, name);
388 if (it != end)
389 {
390 // Found.
391 shared_names.push_back(name);
392 added_names.erase(it);
393 }
394 else
395 {
396 // Iff no test long double compatibility symbols at all and the symbol
397 // missing is a baseline long double compatibility symbol, skip.
398 string version_name(i->second.version_name);
399 bool base_ld(version_name.find("_LDBL_") != std::string::npos);
400 if (!base_ld || base_ld && ld_version_found)
401 missing_names.push_back(name);
402 }
403 }
404
405 // Fill out list of incompatible symbols.
406 typedef pair<symbol, symbol> symbol_pair;
407 vector<symbol_pair> incompatible;
408
409 // Check missing names for compatibility.
410 for (size_t j = 0; j < missing_names.size(); ++j)
411 {
412 symbol& sbase = baseline[missing_names[j]];
413 sbase.status = symbol::subtracted;
414 incompatible.push_back(symbol_pair(sbase, sbase));
415 }
416
417 // Check shared names for compatibility.
418 const symbol_names::size_type shared_size = shared_names.size();
419 for (size_t k = 0; k < shared_size; ++k)
420 {
421 symbol& sbase = baseline[shared_names[k]];
422 symbol& stest = test[shared_names[k]];
423 stest.status = symbol::existing;
424 if (!check_compatible(sbase, stest))
425 incompatible.push_back(symbol_pair(sbase, stest));
426 }
427
428 // Check added names for compatibility.
429 const symbol_names::size_type added_size = added_names.size();
430 for (size_t l = 0; l < added_size; ++l)
431 {
432 symbol& stest = test[added_names[l]];
433 stest.status = symbol::added;
434 if (!check_version(stest, true))
435 incompatible.push_back(symbol_pair(stest, stest));
436 }
437
438 // Report results.
439 if (verbose && added_names.size())
440 {
441 cout << endl << added_names.size() << " added symbols " << endl;
442 for (size_t j = 0; j < added_names.size() ; ++j)
443 {
444 cout << j << endl;
445 test[added_names[j]].print();
446 }
447 }
448
449 if (verbose && missing_names.size())
450 {
451 cout << endl << missing_names.size() << " missing symbols " << endl;
452 for (size_t j = 0; j < missing_names.size() ; ++j)
453 {
454 cout << j << endl;
455 baseline[missing_names[j]].print();
456 }
457 }
458
459 if (verbose && incompatible.size())
460 {
461 cout << endl << incompatible.size() << " incompatible symbols " << endl;
462 for (size_t j = 0; j < incompatible.size() ; ++j)
463 {
464 // First, print index.
465 cout << j << endl;
466
467 // Second, report name.
468 symbol& sbase = incompatible[j].first;
469 symbol& stest = incompatible[j].second;
470 stest.print();
471
472 // Second, report reason or reasons incompatible.
473 check_compatible(sbase, stest, true);
474 }
475 }
476
477 cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
478 cout << endl;
479 cout << "# of added symbols:\t\t " << added_names.size() << endl;
480 cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
481 cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
482 cout << endl;
483 cout << "using: " << baseline_file << endl;
484
485 return !(missing_names.size() || incompatible.size());
486 }
487
488
489 symbols
490 create_symbols(const char* file)
491 {
492 symbols s;
493 ifstream ifs(file);
494 if (ifs.is_open())
495 {
496 // Organize file data into an associated container (symbols) of symbol
497 // objects mapped to mangled names without versioning
498 // information.
499 const string empty;
500 string line = empty;
501 while (getline(ifs, line).good())
502 {
503 symbol tmp;
504 tmp.init(line);
505 s[tmp.name] = tmp;
506 line = empty;
507 }
508 }
509 else
510 {
511 ostringstream os;
512 os << "create_symbols failed for file " << file;
513 __throw_runtime_error(os.str().c_str());
514 }
515 return s;
516 }
517
518
519 const char*
520 demangle(const std::string& mangled)
521 {
522 const char* name;
523 if (mangled[0] != '_' || mangled[1] != 'Z')
524 {
525 // This is not a mangled symbol, thus has "C" linkage.
526 name = mangled.c_str();
527 }
528 else
529 {
530 // Use __cxa_demangle to demangle.
531 int status = 0;
532 name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
533 if (!name)
534 {
535 switch (status)
536 {
537 case 0:
538 name = "error code = 0: success";
539 break;
540 case -1:
541 name = "error code = -1: memory allocation failure";
542 break;
543 case -2:
544 name = "error code = -2: invalid mangled name";
545 break;
546 case -3:
547 name = "error code = -3: invalid arguments";
548 break;
549 default:
550 name = "error code unknown - who knows what happened";
551 }
552 }
553 }
554 return name;
555 }
556