]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/testsuite_abi.cc
re PR testsuite/21945 (gfortran testsuite dies on cygwin (again))
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / testsuite_abi.cc
CommitLineData
4b260c20
BK
1// -*- C++ -*-
2
56ffd9b3 3// Copyright (C) 2004, 2005 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
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, 59 Temple Place - Suite 330, Boston,
18// MA 02111-1307, 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 <sstream>
34#include <fstream>
35#include <iostream>
36
37using namespace std;
38
39void
40symbol::init(string& data)
41{
42 const char delim = ':';
43 const char version_delim = '@';
44 const string::size_type npos = string::npos;
45 string::size_type n = 0;
46
47 // Set the type.
48 if (data.find("FUNC") == 0)
49 type = symbol::function;
50 else if (data.find("OBJECT") == 0)
51 type = symbol::object;
52 else
53 type = symbol::error;
54 n = data.find_first_of(delim);
55 if (n != npos)
56 data.erase(data.begin(), data.begin() + n + 1);
57
58 // Iff object, get size info.
59 if (type == symbol::object)
60 {
61 n = data.find_first_of(delim);
62 if (n != npos)
63 {
64 string size(data.begin(), data.begin() + n);
65 istringstream iss(size);
66 int x;
67 iss >> x;
68 if (!iss.fail())
69 size = x;
70 data.erase(data.begin(), data.begin() + n + 1);
71 }
72 }
73
74 // Set the name.
75 n = data.find_first_of(version_delim);
76 if (n != npos)
77 {
78 // Found version string.
79 name = string(data.begin(), data.begin() + n);
80 n = data.find_last_of(version_delim);
81 data.erase(data.begin(), data.begin() + n + 1);
82
83 // Set version name.
84 version_name = data;
85 }
86 else
87 {
88 // No versioning info.
89 name = string(data.begin(), data.end());
90 data.erase(data.begin(), data.end());
91 }
92
93 // Set the demangled name.
94 demangled_name = demangle(name);
95}
96
97void
98symbol::print() const
99{
100 const char tab = '\t';
101 cout << tab << name << endl;
102 cout << tab << demangled_name << endl;
103 cout << tab << version_name << endl;
104
105 string type_string;
106 switch (type)
107 {
108 case none:
109 type_string = "none";
110 break;
111 case function:
112 type_string = "function";
113 break;
114 case object:
115 type_string = "object";
116 break;
117 case error:
118 type_string = "error";
119 break;
120 default:
121 type_string = "<default>";
122 }
123 cout << tab << type_string << endl;
124
125 if (type == object)
126 cout << tab << size << endl;
127
128 string status_string;
129 switch (status)
130 {
131 case unknown:
132 status_string = "unknown";
133 break;
134 case added:
135 status_string = "added";
136 break;
137 case subtracted:
138 status_string = "subtracted";
139 break;
140 case compatible:
141 status_string = "compatible";
142 break;
143 case incompatible:
144 status_string = "incompatible";
145 break;
146 default:
147 status_string = "<default>";
148 }
149 cout << tab << status_string << endl;
150}
151
152
153bool
154check_version(const symbol& test, bool added)
155{
156 typedef std::vector<std::string> compat_list;
157 static compat_list known_versions;
158 if (known_versions.empty())
159 {
160 known_versions.push_back("GLIBCPP_3.2"); // base version
161 known_versions.push_back("GLIBCPP_3.2.1");
162 known_versions.push_back("GLIBCPP_3.2.2");
163 known_versions.push_back("GLIBCPP_3.2.3"); // gcc-3.3.0
164 known_versions.push_back("GLIBCXX_3.4");
7c9fee34 165 known_versions.push_back("GLIBCXX_3.4.1");
9e802114 166 known_versions.push_back("GLIBCXX_3.4.2");
0e98ac62 167 known_versions.push_back("GLIBCXX_3.4.3");
fcb94d10 168 known_versions.push_back("GLIBCXX_3.4.4");
36b72d8d 169 known_versions.push_back("GLIBCXX_3.4.5");
4b260c20
BK
170 known_versions.push_back("CXXABI_1.2");
171 known_versions.push_back("CXXABI_1.2.1");
172 known_versions.push_back("CXXABI_1.3");
44dd2da2 173 known_versions.push_back("CXXABI_1.3.1");
4b260c20
BK
174 }
175 compat_list::iterator begin = known_versions.begin();
176 compat_list::iterator end = known_versions.end();
177
178 // Check version names for compatibility...
179 compat_list::iterator it1 = find(begin, end, test.version_name);
180
181 // Check for weak label.
182 compat_list::iterator it2 = find(begin, end, test.name);
183
184 // Check that added symbols aren't added in the base version.
185 bool compat = true;
186 if (added && test.version_name == known_versions[0])
187 compat = false;
188
189 if (it1 == end && it2 == end)
190 compat = false;
191
192 return compat;
193}
194
195bool
196check_compatible(const symbol& lhs, const symbol& rhs, bool verbose)
197{
198 bool ret = true;
199 const char tab = '\t';
200
201 // Check to see if symbol_objects are compatible.
202 if (lhs.type != rhs.type)
203 {
204 ret = false;
205 if (verbose)
206 cout << tab << "incompatible types" << endl;
207 }
208
209 if (lhs.name != rhs.name)
210 {
211 ret = false;
212 if (verbose)
213 cout << tab << "incompatible names" << endl;
214 }
215
216 if (lhs.size != rhs.size)
217 {
218 ret = false;
219 if (verbose)
220 {
221 cout << tab << "incompatible sizes" << endl;
222 cout << tab << lhs.size << endl;
223 cout << tab << rhs.size << endl;
224 }
225 }
226
227 if (lhs.version_name != rhs.version_name
228 && !check_version(lhs) && !check_version(rhs))
229 {
230 ret = false;
231 if (verbose)
232 {
233 cout << tab << "incompatible versions" << endl;
234 cout << tab << lhs.version_name << endl;
235 cout << tab << rhs.version_name << endl;
236 }
237 }
238
239 if (verbose)
240 cout << endl;
241
242 return ret;
243}
244
245
246bool
247has_symbol(const string& mangled, const symbols& s) throw()
248{
249 const symbol_names& names = s.first;
250 symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
251 return i != names.end();
252}
253
254symbol&
255get_symbol(const string& mangled, const symbols& s)
256{
257 const symbol_names& names = s.first;
258 symbol_names::const_iterator i = find(names.begin(), names.end(), mangled);
259 if (i != names.end())
260 {
261 symbol_objects objects = s.second;
262 return objects[mangled];
263 }
264 else
265 {
266 ostringstream os;
267 os << "get_symbol failed for symbol " << mangled;
56ffd9b3 268 __throw_logic_error(os.str().c_str());
4b260c20
BK
269 }
270}
271
272void
273examine_symbol(const char* name, const char* file)
274{
275 try
276 {
277 symbols s = create_symbols(file);
278 symbol& sym = get_symbol(name, s);
279 sym.print();
280 }
281 catch(...)
d98fd134 282 { __throw_exception_again; }
4b260c20
BK
283}
284
fdbba6bc 285int
4b260c20
BK
286compare_symbols(const char* baseline_file, const char* test_file,
287 bool verbose)
288{
289 // Input both lists of symbols into container.
290 symbols baseline = create_symbols(baseline_file);
291 symbols test = create_symbols(test_file);
292 symbol_names& baseline_names = baseline.first;
293 symbol_objects& baseline_objects = baseline.second;
294 symbol_names& test_names = test.first;
295 symbol_objects& test_objects = test.second;
296
297 // Sanity check results.
298 const symbol_names::size_type baseline_size = baseline_names.size();
299 const symbol_names::size_type test_size = test_names.size();
300 if (!baseline_size || !test_size)
301 {
302 cerr << "Problems parsing the list of exported symbols." << endl;
303 exit(2);
304 }
305
306 // Sort out names.
307 // Assuming baseline_names, test_names are both unique w/ no duplicates.
308 //
309 // The names added to missing_names are baseline_names not found in
310 // test_names
311 // -> symbols that have been deleted.
312 //
313 // The names added to added_names are test_names are names not in
314 // baseline_names
315 // -> symbols that have been added.
316 symbol_names shared_names;
317 symbol_names missing_names;
318 symbol_names added_names = test_names;
319 for (size_t i = 0; i < baseline_size; ++i)
320 {
321 string what(baseline_names[i]);
322 symbol_names::iterator end = added_names.end();
323 symbol_names::iterator it = find(added_names.begin(), end, what);
324 if (it != end)
325 {
326 // Found.
327 shared_names.push_back(what);
328 added_names.erase(it);
329 }
330 else
331 missing_names.push_back(what);
332 }
333
334 // Check missing names for compatibility.
335 typedef pair<symbol, symbol> symbol_pair;
336 vector<symbol_pair> incompatible;
95b147fe 337 for (size_t j = 0; j < missing_names.size(); ++j)
4b260c20 338 {
95b147fe 339 symbol base = baseline_objects[missing_names[j]];
4b260c20
BK
340 incompatible.push_back(symbol_pair(base, base));
341 }
342
343 // Check shared names for compatibility.
95b147fe 344 for (size_t k = 0; k < shared_names.size(); ++k)
4b260c20 345 {
95b147fe
SM
346 symbol base = baseline_objects[shared_names[k]];
347 symbol test = test_objects[shared_names[k]];
4b260c20
BK
348 if (!check_compatible(base, test))
349 incompatible.push_back(symbol_pair(base, test));
350 }
351
352 // Check added names for compatibility.
95b147fe 353 for (size_t l = 0; l < added_names.size(); ++l)
4b260c20 354 {
95b147fe 355 symbol test = test_objects[added_names[l]];
4b260c20
BK
356 if (!check_version(test, true))
357 incompatible.push_back(symbol_pair(test, test));
358 }
359
360 // Report results.
361 if (verbose && added_names.size())
362 {
363 cout << added_names.size() << " added symbols " << endl;
364 for (size_t j = 0; j < added_names.size() ; ++j)
365 test_objects[added_names[j]].print();
366 }
367
368 if (verbose && missing_names.size())
369 {
370 cout << missing_names.size() << " missing symbols " << endl;
371 for (size_t j = 0; j < missing_names.size() ; ++j)
372 baseline_objects[missing_names[j]].print();
373 }
374
375 if (verbose && incompatible.size())
376 {
377 cout << incompatible.size() << " incompatible symbols " << endl;
378 for (size_t j = 0; j < incompatible.size() ; ++j)
379 {
380 // First, report name.
381 const symbol& base = incompatible[j].first;
382 const symbol& test = incompatible[j].second;
383 test.print();
384
385 // Second, report reason or reasons incompatible.
386 check_compatible(base, test, true);
387 }
388 }
389
390 cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl;
391 cout << endl;
392 cout << "# of added symbols:\t\t " << added_names.size() << endl;
393 cout << "# of missing symbols:\t\t " << missing_names.size() << endl;
394 cout << "# of incompatible symbols:\t " << incompatible.size() << endl;
395 cout << endl;
396 cout << "using: " << baseline_file << endl;
fdbba6bc
MM
397
398 return !(missing_names.size() || incompatible.size());
4b260c20
BK
399}
400
401
402symbols
403create_symbols(const char* file)
404{
405 symbols s;
406 ifstream ifs(file);
407 if (ifs.is_open())
408 {
409 // Organize file data into container of symbol objects.
410 symbol_names& names = s.first;
411 symbol_objects& objects = s.second;
412 const string empty;
413 string line = empty;
414 while (getline(ifs, line).good())
415 {
416 symbol tmp;
417 tmp.init(line);
418 objects[tmp.name] = tmp;
419 names.push_back(tmp.name);
420 line = empty;
421 }
422 }
423 else
424 {
425 ostringstream os;
426 os << "create_symbols failed for file " << file;
56ffd9b3 427 __throw_runtime_error(os.str().c_str());
4b260c20
BK
428 }
429 return s;
430}
431
432
433const char*
434demangle(const std::string& mangled)
435{
436 const char* name;
437 if (mangled[0] != '_' || mangled[1] != 'Z')
438 {
439 // This is not a mangled symbol, thus has "C" linkage.
440 name = mangled.c_str();
441 }
442 else
443 {
444 // Use __cxa_demangle to demangle.
445 int status = 0;
446 name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);
447 if (!name)
448 {
449 switch (status)
450 {
451 case 0:
452 name = "error code = 0: success";
453 break;
454 case -1:
455 name = "error code = -1: memory allocation failure";
456 break;
457 case -2:
458 name = "error code = -2: invalid mangled name";
459 break;
460 case -3:
461 name = "error code = -3: invalid arguments";
462 break;
463 default:
464 name = "error code unknown - who knows what happened";
465 }
466 }
467 }
468 return name;
469}
470