1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2021-2022 Oracle, Inc.
5 //
6 // Author: Guillermo E. Martinez
7
8 /// @file
9 ///
10 /// This file implement the CTF testsuite. It reads ELF binaries
11 /// containing CTF, save them in XML corpus files and diff the
12 /// corpus files against reference XML corpus files.
13
14 #include <cstdlib>
15 #include <fstream>
16 #include <iostream>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include "abg-ctf-reader.h"
21 #include "test-read-common.h"
22
23 using std::string;
24 using std::cerr;
25 using std::vector;
26
27 using abigail::tests::read_common::InOutSpec;
28 using abigail::tests::read_common::test_task;
29 using abigail::tests::read_common::display_usage;
30 using abigail::tests::read_common::options;
31
32 using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
33 using abigail::xml_writer::HASH_TYPE_ID_STYLE;
34 using abigail::tools_utils::emit_prefix;
35
36 using namespace abigail;
37
38 static InOutSpec in_out_specs[] =
39 {
40 {
41 "data/test-read-ctf/test0",
42 "",
43 "",
44 SEQUENCE_TYPE_ID_STYLE,
45 "data/test-read-ctf/test0.abi",
46 "output/test-read-ctf/test0.abi",
47 "--ctf"
48 },
49 {
50 "data/test-read-ctf/test0",
51 "",
52 "",
53 HASH_TYPE_ID_STYLE,
54 "data/test-read-ctf/test0.hash.abi",
55 "output/test-read-ctf/test0.hash.abi",
56 "--ctf"
57 },
58 {
59 "data/test-read-ctf/test1.so",
60 "",
61 "",
62 SEQUENCE_TYPE_ID_STYLE,
63 "data/test-read-ctf/test1.so.abi",
64 "output/test-read-ctf/test1.so.abi",
65 "--ctf"
66 },
67 {
68 "data/test-read-ctf/test1.so",
69 "",
70 "",
71 HASH_TYPE_ID_STYLE,
72 "data/test-read-ctf/test1.so.hash.abi",
73 "output/test-read-ctf/test1.so.hash.abi",
74 "--ctf"
75 },
76 {
77 "data/test-read-ctf/test2.so",
78 "",
79 "",
80 SEQUENCE_TYPE_ID_STYLE,
81 "data/test-read-ctf/test2.so.abi",
82 "output/test-read-ctf/test2.so.abi",
83 "--ctf"
84 },
85 {
86 "data/test-read-ctf/test2.so",
87 "",
88 "",
89 HASH_TYPE_ID_STYLE,
90 "data/test-read-ctf/test2.so.hash.abi",
91 "output/test-read-ctf/test2.so.hash.abi",
92 "--ctf"
93 },
94 {
95 "data/test-read-common/test3.so",
96 "",
97 "",
98 SEQUENCE_TYPE_ID_STYLE,
99 "data/test-read-ctf/test3.so.abi",
100 "output/test-read-ctf/test3.so.abi",
101 "--ctf"
102 },
103 {
104 "data/test-read-common/test3.so",
105 "",
106 "",
107 HASH_TYPE_ID_STYLE,
108 "data/test-read-ctf/test3.so.hash.abi",
109 "output/test-read-ctf/test3.so.hash.abi",
110 "--ctf"
111 },
112 {
113 "data/test-read-ctf/test-enum-many.o",
114 "",
115 "",
116 HASH_TYPE_ID_STYLE,
117 "data/test-read-ctf/test-enum-many.o.hash.abi",
118 "output/test-read-ctf/test-enum-many.o.hash.abi",
119 "--ctf"
120 },
121 {
122 "data/test-read-ctf/test-ambiguous-struct-A.o",
123 "",
124 "",
125 HASH_TYPE_ID_STYLE,
126 "data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
127 "output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
128 "--ctf"
129 },
130 {
131 "data/test-read-ctf/test-ambiguous-struct-B.o",
132 "",
133 "",
134 HASH_TYPE_ID_STYLE,
135 "data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
136 "output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
137 "--ctf"
138 },
139 {
140 "data/test-read-ctf/test-conflicting-type-syms-a.o",
141 "",
142 "",
143 HASH_TYPE_ID_STYLE,
144 "data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
145 "output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
146 "--ctf"
147 },
148 {
149 "data/test-read-ctf/test-conflicting-type-syms-b.o",
150 "",
151 "",
152 HASH_TYPE_ID_STYLE,
153 "data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
154 "output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
155 "--ctf"
156 },
157 {
158 "data/test-read-common/test4.so",
159 "",
160 "",
161 SEQUENCE_TYPE_ID_STYLE,
162 "data/test-read-ctf/test4.so.abi",
163 "output/test-read-ctf/test4.so.abi",
164 "--ctf"
165 },
166 {
167 "data/test-read-common/test4.so",
168 "",
169 "",
170 HASH_TYPE_ID_STYLE,
171 "data/test-read-ctf/test4.so.hash.abi",
172 "output/test-read-ctf/test4.so.hash.abi",
173 "--ctf"
174 },
175 {
176 "data/test-read-ctf/test5.o",
177 "",
178 "",
179 SEQUENCE_TYPE_ID_STYLE,
180 "data/test-read-ctf/test5.o.abi",
181 "output/test-read-ctf/test5.o.abi",
182 "--ctf"
183 },
184 {
185 "data/test-read-ctf/test7.o",
186 "",
187 "",
188 SEQUENCE_TYPE_ID_STYLE,
189 "data/test-read-ctf/test7.o.abi",
190 "output/test-read-ctf/test7.o.abi",
191 "--ctf"
192 },
193 {
194 "data/test-read-ctf/test8.o",
195 "",
196 "",
197 SEQUENCE_TYPE_ID_STYLE,
198 "data/test-read-ctf/test8.o.abi",
199 "output/test-read-ctf/test8.o.abi",
200 "--ctf"
201 },
202 {
203 "data/test-read-ctf/test9.o",
204 "",
205 "",
206 SEQUENCE_TYPE_ID_STYLE,
207 "data/test-read-ctf/test9.o.abi",
208 "output/test-read-ctf/test9.o.abi",
209 "--ctf"
210 },
211 {
212 "data/test-read-ctf/test-enum.o",
213 "",
214 "",
215 SEQUENCE_TYPE_ID_STYLE,
216 "data/test-read-ctf/test-enum.o.abi",
217 "output/test-read-ctf/test-enum.o.abi",
218 "--ctf"
219 },
220 {
221 "data/test-read-ctf/test-enum-symbol.o",
222 "",
223 "",
224 HASH_TYPE_ID_STYLE,
225 "data/test-read-ctf/test-enum-symbol.o.hash.abi",
226 "output/test-read-ctf/test-enum-symbol.o.hash.abi",
227 "--ctf"
228 },
229 {
230 "data/test-read-ctf/test-dynamic-array.o",
231 "",
232 "",
233 SEQUENCE_TYPE_ID_STYLE,
234 "data/test-read-ctf/test-dynamic-array.o.abi",
235 "output/test-read-ctf/test-dynamic-array.o.abi",
236 "--ctf"
237 },
238 {
239 "data/test-read-ctf/test-anonymous-fields.o",
240 "",
241 "",
242 SEQUENCE_TYPE_ID_STYLE,
243 "data/test-read-ctf/test-anonymous-fields.o.abi",
244 "output/test-read-ctf/test-anonymous-fields.o.abi",
245 "--ctf"
246 },
247 {
248 "data/test-read-common/PR27700/test-PR27700.o",
249 "",
250 "data/test-read-common/PR27700/pub-incdir",
251 HASH_TYPE_ID_STYLE,
252 "data/test-read-ctf/PR27700/test-PR27700.abi",
253 "output/test-read-ctf/PR27700/test-PR27700.abi",
254 "--ctf"
255 },
256 {
257 "data/test-read-ctf/test-callback.o",
258 "",
259 "",
260 SEQUENCE_TYPE_ID_STYLE,
261 "data/test-read-ctf/test-callback.abi",
262 "output/test-read-ctf/test-callback.abi",
263 "--ctf"
264 },
265 {
266 "data/test-read-ctf/test-array-of-pointers.o",
267 "",
268 "",
269 SEQUENCE_TYPE_ID_STYLE,
270 "data/test-read-ctf/test-array-of-pointers.abi",
271 "output/test-read-ctf/test-array-of-pointers.abi",
272 "--ctf"
273 },
274 {
275 "data/test-read-ctf/test-functions-declaration.o",
276 "",
277 "",
278 SEQUENCE_TYPE_ID_STYLE,
279 "data/test-read-ctf/test-functions-declaration.abi",
280 "output/test-read-ctf/test-functions-declaration.abi",
281 "--ctf"
282 },
283 {
284 "data/test-read-ctf/test-forward-type-decl.o",
285 "",
286 "",
287 SEQUENCE_TYPE_ID_STYLE,
288 "data/test-read-ctf/test-forward-type-decl.abi",
289 "output/test-read-ctf/test-forward-type-decl.abi",
290 "--ctf"
291 },
292 {
293 "data/test-read-ctf/test-list-struct.o",
294 "",
295 "",
296 SEQUENCE_TYPE_ID_STYLE,
297 "data/test-read-ctf/test-list-struct.abi",
298 "output/test-read-ctf/test-list-struct.abi",
299 "--ctf"
300 },
301 {
302 "data/test-read-common/test-PR26568-1.o",
303 "",
304 "",
305 SEQUENCE_TYPE_ID_STYLE,
306 "data/test-read-ctf/test-PR26568-1.o.abi",
307 "output/test-read-ctf/test-PR26568-1.o.abi",
308 "--ctf"
309 },
310 {
311 "data/test-read-common/test-PR26568-2.o",
312 "",
313 "",
314 SEQUENCE_TYPE_ID_STYLE,
315 "data/test-read-ctf/test-PR26568-2.o.abi",
316 "output/test-read-ctf/test-PR26568-2.o.abi",
317 "--ctf"
318 },
319 {
320 "data/test-read-ctf/test-callback2.o",
321 "",
322 "",
323 SEQUENCE_TYPE_ID_STYLE,
324 "data/test-read-ctf/test-callback2.abi",
325 "output/test-read-ctf/test-callback2.abi",
326 "--ctf"
327 },
328 // out-of-tree kernel module.
329 {
330 "data/test-read-ctf/test-linux-module.ko",
331 "",
332 "",
333 SEQUENCE_TYPE_ID_STYLE,
334 "data/test-read-ctf/test-linux-module.abi",
335 "output/test-read-ctf/test-linux-module.abi",
336 "--ctf"
337 },
338 // CTF fallback feature.
339 {
340 "data/test-read-ctf/test-fallback.o",
341 "",
342 "",
343 SEQUENCE_TYPE_ID_STYLE,
344 "data/test-read-ctf/test-fallback.abi",
345 "output/test-read-ctf/test-fallback.abi",
346 NULL,
347 },
348 {
349 "data/test-read-ctf/test-bitfield.o",
350 "",
351 "",
352 SEQUENCE_TYPE_ID_STYLE,
353 "data/test-read-ctf/test-bitfield.abi",
354 "output/test-read-ctf/test-bitfield.abi",
355 "--ctf",
356 },
357 {
358 "data/test-read-ctf/test-bitfield-enum.o",
359 "",
360 "",
361 SEQUENCE_TYPE_ID_STYLE,
362 "data/test-read-ctf/test-bitfield-enum.abi",
363 "output/test-read-ctf/test-bitfield-enum.abi",
364 "--ctf",
365 },
366 {
367 "data/test-read-ctf/test-const-array.o",
368 "",
369 "",
370 SEQUENCE_TYPE_ID_STYLE,
371 "data/test-read-ctf/test-const-array.abi",
372 "output/test-read-ctf/test-const-array.abi",
373 "--ctf",
374 },
375 {
376 "data/test-read-ctf/test-array-mdimension.o",
377 "",
378 "",
379 SEQUENCE_TYPE_ID_STYLE,
380 "data/test-read-ctf/test-array-mdimension.abi",
381 "output/test-read-ctf/test-array-mdimension.abi",
382 "--ctf",
383 },
384 {
385 "data/test-read-ctf/test-array-size.o",
386 "",
387 "",
388 SEQUENCE_TYPE_ID_STYLE,
389 "data/test-read-ctf/test-array-size.abi",
390 "output/test-read-ctf/test-array-size.abi",
391 "--ctf",
392 },
393 // This should be the last entry.
394 {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL}
395 };
396
397 /// Task specialization to perform CTF tests.
398 struct test_task_ctf : public test_task
399 {
400 test_task_ctf(const InOutSpec &s,
401 string& a_out_abi_base,
402 string& a_in_elf_base,
403 string& a_in_abi_base);
404 virtual void
405 perform();
406
407 virtual
~test_task_ctftest_task_ctf408 ~test_task_ctf()
409 {}
410 }; // end struct test_task_ctf
411
412 /// Constructor.
413 ///
414 /// Task to be executed for each CTF test entry in @ref
415 /// abigail::tests::read_common::InOutSpec.
416 /// @param InOutSpec the array containing set of tests.
417 ///
418 /// @param a_out_abi_base the output base directory for abixml files.
419 ///
420 /// @param a_in_elf_base the input base directory for object files.
421 ///
422 /// @param a_in_elf_base the input base directory for expected
423 /// abixml files.
test_task_ctf(const InOutSpec & s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)424 test_task_ctf::test_task_ctf(const InOutSpec &s,
425 string& a_out_abi_base,
426 string& a_in_elf_base,
427 string& a_in_abi_base)
428 : test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base)
429 {}
430
431 /// The thread function to execute each CTF test entry in @ref
432 /// abigail::tests::read_common::InOutSpec.
433 ///
434 /// This reads the corpus into memory, saves it to disk, loads it
435 /// again and compares the new in-memory representation against the
436 void
perform()437 test_task_ctf::perform()
438 {
439 abigail::ir::environment env;
440
441 set_in_elf_path();
442 set_in_suppr_spec_path();
443
444 abigail::fe_iface::status status =
445 abigail::fe_iface::STATUS_UNKNOWN;
446 vector<char**> di_roots;
447 ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
448
449 abigail::elf_based_reader_sptr rdr = ctf::create_reader(in_elf_path,
450 di_roots, env);
451 ABG_ASSERT(rdr);
452
453 corpus_sptr corp = rdr->read_corpus(status);
454
455 // if there is no output and no input, assume that we do not care about the
456 // actual read result, just that it succeeded.
457 if (!spec.in_abi_path && !spec.out_abi_path)
458 {
459 // Phew! we made it here and we did not crash! yay!
460 return;
461 }
462 if (!corp)
463 {
464 error_message = string("failed to read ") + in_elf_path + "\n";
465 is_ok = false;
466 return;
467 }
468 corp->set_path(spec.in_elf_path);
469 // Do not take architecture names in comparison so that these
470 // test input binaries can come from whatever arch the
471 // programmer likes.
472 corp->set_architecture_name("");
473
474 if (!(is_ok = set_out_abi_path()))
475 return;
476
477 if (!(is_ok = serialize_corpus(out_abi_path, corp)))
478 return;
479
480 if (!(is_ok = run_abidw()))
481 return;
482
483 if (!(is_ok = run_diff()))
484 return;
485 }
486
487 /// Create a new CTF instance for task to be execute by the testsuite.
488 ///
489 /// @param s the @ref abigail::tests::read_common::InOutSpec
490 /// tests container.
491 ///
492 /// @param a_out_abi_base the output base directory for abixml files.
493 ///
494 /// @param a_in_elf_base the input base directory for object files.
495 ///
496 /// @param a_in_abi_base the input base directory for abixml files.
497 ///
498 /// @return abigail::tests::read_common::test_task instance.
499 static test_task*
new_task(const InOutSpec * s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)500 new_task(const InOutSpec* s, string& a_out_abi_base,
501 string& a_in_elf_base, string& a_in_abi_base)
502 {
503 return new test_task_ctf(*s, a_out_abi_base,
504 a_in_elf_base, a_in_abi_base);
505 }
506
507 int
main(int argc,char * argv[])508 main(int argc, char *argv[])
509 {
510 options opts;
511 if (!parse_command_line(argc, argv, opts))
512 {
513 if (!opts.wrong_option.empty())
514 emit_prefix(argv[0], cerr)
515 << "unrecognized option: " << opts.wrong_option << "\n";
516 display_usage(argv[0], cerr);
517 return 1;
518 }
519
520 // compute number of tests to be executed.
521 const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1;
522
523 return run_tests(num_tests, in_out_specs, opts, new_task);
524 }
525