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
23using std::string;
24using std::cerr;
25using std::vector;
26
27using abigail::tests::read_common::InOutSpec;
28using abigail::tests::read_common::test_task;
29using abigail::tests::read_common::display_usage;
30using abigail::tests::read_common::options;
31
32using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
33using abigail::xml_writer::HASH_TYPE_ID_STYLE;
34using abigail::tools_utils::emit_prefix;
35
36using namespace abigail;
37
38static 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.
398struct 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
408  ~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.
424test_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
436void
437test_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.
499static test_task*
500new_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
507int
508main(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