• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2021 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::ctf_reader::read_context_sptr;
33 using abigail::ctf_reader::create_read_context;
34 using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
35 using abigail::xml_writer::HASH_TYPE_ID_STYLE;
36 using abigail::tools_utils::emit_prefix;
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   },
48   {
49     "data/test-read-ctf/test0",
50     "",
51     "",
52     HASH_TYPE_ID_STYLE,
53     "data/test-read-ctf/test0.hash.abi",
54     "output/test-read-ctf/test0.hash.abi"
55   },
56   {
57     "data/test-read-ctf/test1.so",
58     "",
59     "",
60     SEQUENCE_TYPE_ID_STYLE,
61     "data/test-read-ctf/test1.so.abi",
62     "output/test-read-ctf/test1.so.abi"
63   },
64   {
65     "data/test-read-ctf/test1.so",
66     "",
67     "",
68     HASH_TYPE_ID_STYLE,
69     "data/test-read-ctf/test1.so.hash.abi",
70     "output/test-read-ctf/test1.so.hash.abi"
71   },
72   {
73     "data/test-read-ctf/test2.so",
74     "",
75     "",
76     SEQUENCE_TYPE_ID_STYLE,
77     "data/test-read-ctf/test2.so.abi",
78     "output/test-read-ctf/test2.so.abi"
79   },
80   {
81     "data/test-read-ctf/test2.so",
82     "",
83     "",
84     HASH_TYPE_ID_STYLE,
85     "data/test-read-ctf/test2.so.hash.abi",
86     "output/test-read-ctf/test2.so.hash.abi"
87   },
88   {
89     "data/test-read-common/test3.so",
90     "",
91     "",
92     SEQUENCE_TYPE_ID_STYLE,
93     "data/test-read-ctf/test3.so.abi",
94     "output/test-read-ctf/test3.so.abi"
95   },
96   {
97     "data/test-read-common/test3.so",
98     "",
99     "",
100     HASH_TYPE_ID_STYLE,
101     "data/test-read-ctf/test3.so.hash.abi",
102     "output/test-read-ctf/test3.so.hash.abi"
103   },
104   {
105     "data/test-read-ctf/test-enum-many.o",
106     "",
107     "",
108     HASH_TYPE_ID_STYLE,
109     "data/test-read-ctf/test-enum-many.o.hash.abi",
110     "output/test-read-ctf/test-enum-many.o.hash.abi"
111   },
112   {
113     "data/test-read-ctf/test-ambiguous-struct-A.o",
114     "",
115     "",
116     HASH_TYPE_ID_STYLE,
117     "data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
118     "output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi"
119   },
120   {
121     "data/test-read-ctf/test-ambiguous-struct-B.o",
122     "",
123     "",
124     HASH_TYPE_ID_STYLE,
125     "data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
126     "output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi"
127   },
128   {
129     "data/test-read-ctf/test-conflicting-type-syms-a.o",
130     "",
131     "",
132     HASH_TYPE_ID_STYLE,
133     "data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
134     "output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi"
135   },
136   {
137     "data/test-read-ctf/test-conflicting-type-syms-b.o",
138     "",
139     "",
140     HASH_TYPE_ID_STYLE,
141     "data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
142     "output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi"
143   },
144   {
145     "data/test-read-common/test4.so",
146     "",
147     "",
148     SEQUENCE_TYPE_ID_STYLE,
149     "data/test-read-ctf/test4.so.abi",
150     "output/test-read-ctf/test4.so.abi"
151   },
152   {
153     "data/test-read-common/test4.so",
154     "",
155     "",
156     HASH_TYPE_ID_STYLE,
157     "data/test-read-ctf/test4.so.hash.abi",
158     "output/test-read-ctf/test4.so.hash.abi"
159   },
160   {
161     "data/test-read-ctf/test5.o",
162     "",
163     "",
164     SEQUENCE_TYPE_ID_STYLE,
165     "data/test-read-ctf/test5.o.abi",
166     "output/test-read-ctf/test5.o.abi"
167   },
168   {
169     "data/test-read-ctf/test7.o",
170     "",
171     "",
172     SEQUENCE_TYPE_ID_STYLE,
173     "data/test-read-ctf/test7.o.abi",
174     "output/test-read-ctf/test7.o.abi"
175   },
176   {
177     "data/test-read-ctf/test8.o",
178     "",
179     "",
180     SEQUENCE_TYPE_ID_STYLE,
181     "data/test-read-ctf/test8.o.abi",
182     "output/test-read-ctf/test8.o.abi"
183   },
184   {
185     "data/test-read-ctf/test9.o",
186     "",
187     "",
188     SEQUENCE_TYPE_ID_STYLE,
189     "data/test-read-ctf/test9.o.abi",
190     "output/test-read-ctf/test9.o.abi"
191   },
192   {
193     "data/test-read-ctf/test-enum.o",
194     "",
195     "",
196     SEQUENCE_TYPE_ID_STYLE,
197     "data/test-read-ctf/test-enum.o.abi",
198     "output/test-read-ctf/test-enum.o.abi"
199   },
200   {
201     "data/test-read-ctf/test-enum-symbol.o",
202     "",
203     "",
204     HASH_TYPE_ID_STYLE,
205     "data/test-read-ctf/test-enum-symbol.o.hash.abi",
206     "output/test-read-ctf/test-enum-symbol.o.hash.abi"
207   },
208   {
209     "data/test-read-ctf/test-dynamic-array.o",
210     "",
211     "",
212     SEQUENCE_TYPE_ID_STYLE,
213     "data/test-read-ctf/test-dynamic-array.o.abi",
214     "output/test-read-ctf/test-dynamic-array.o.abi"
215   },
216   {
217     "data/test-read-ctf/test-anonymous-fields.o",
218     "",
219     "",
220     SEQUENCE_TYPE_ID_STYLE,
221     "data/test-read-ctf/test-anonymous-fields.o.abi",
222     "output/test-read-ctf/test-anonymous-fields.o.abi"
223   },
224   {
225     "data/test-read-common/PR27700/test-PR27700.o",
226     "",
227     "data/test-read-common/PR27700/pub-incdir",
228     HASH_TYPE_ID_STYLE,
229     "data/test-read-ctf/PR27700/test-PR27700.abi",
230     "output/test-read-ctf/PR27700/test-PR27700.abi",
231   },
232   {
233     "data/test-read-ctf/test-callback.o",
234     "",
235     "",
236     SEQUENCE_TYPE_ID_STYLE,
237     "data/test-read-ctf/test-callback.abi",
238     "output/test-read-ctf/test-callback.abi",
239   },
240   {
241     "data/test-read-ctf/test-array-of-pointers.o",
242     "",
243     "",
244     SEQUENCE_TYPE_ID_STYLE,
245     "data/test-read-ctf/test-array-of-pointers.abi",
246     "output/test-read-ctf/test-array-of-pointers.abi",
247   },
248   {
249     "data/test-read-ctf/test-functions-declaration.o",
250     "",
251     "",
252     SEQUENCE_TYPE_ID_STYLE,
253     "data/test-read-ctf/test-functions-declaration.abi",
254     "output/test-read-ctf/test-functions-declaration.abi",
255   },
256   {
257     "data/test-read-ctf/test-forward-type-decl.o",
258     "",
259     "",
260     SEQUENCE_TYPE_ID_STYLE,
261     "data/test-read-ctf/test-forward-type-decl.abi",
262     "output/test-read-ctf/test-forward-type-decl.abi",
263   },
264   {
265     "data/test-read-ctf/test-list-struct.o",
266     "",
267     "",
268     SEQUENCE_TYPE_ID_STYLE,
269     "data/test-read-ctf/test-list-struct.abi",
270     "output/test-read-ctf/test-list-struct.abi",
271   },
272   {
273     "data/test-read-common/test-PR26568-1.o",
274     "",
275     "",
276     SEQUENCE_TYPE_ID_STYLE,
277     "data/test-read-ctf/test-PR26568-1.o.abi",
278     "output/test-read-ctf/test-PR26568-1.o.abi",
279   },
280   {
281     "data/test-read-common/test-PR26568-2.o",
282     "",
283     "",
284     SEQUENCE_TYPE_ID_STYLE,
285     "data/test-read-ctf/test-PR26568-2.o.abi",
286     "output/test-read-ctf/test-PR26568-2.o.abi",
287   },
288   {
289     "data/test-read-ctf/test-callback2.o",
290     "",
291     "",
292     SEQUENCE_TYPE_ID_STYLE,
293     "data/test-read-ctf/test-callback2.abi",
294     "output/test-read-ctf/test-callback2.abi",
295   },
296   // This should be the last entry.
297   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
298 };
299 
300 /// Task specialization to perform CTF tests.
301 struct test_task_ctf : public test_task
302 {
303   test_task_ctf(const InOutSpec &s,
304                 string& a_out_abi_base,
305                 string& a_in_elf_base,
306                 string& a_in_abi_base);
307   virtual void
308   perform();
309 
310   virtual
~test_task_ctftest_task_ctf311   ~test_task_ctf()
312   {}
313 }; // end struct test_task_ctf
314 
315 /// Constructor.
316 ///
317 /// Task to be executed for each CTF test entry in @ref
318 /// abigail::tests::read_common::InOutSpec.
319 /// @param InOutSpec the array containing set of tests.
320 ///
321 /// @param a_out_abi_base the output base directory for abixml files.
322 ///
323 /// @param a_in_elf_base the input base directory for object files.
324 ///
325 /// @param a_in_elf_base the input base directory for expected
326 /// abixml files.
test_task_ctf(const InOutSpec & s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)327 test_task_ctf::test_task_ctf(const InOutSpec &s,
328                              string& a_out_abi_base,
329                              string& a_in_elf_base,
330                              string& a_in_abi_base)
331         : test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base)
332   {}
333 
334 /// The thread function to execute each CTF test entry in @ref
335 /// abigail::tests::read_common::InOutSpec.
336 ///
337 /// This reads the corpus into memory, saves it to disk, loads it
338 /// again and compares the new in-memory representation against the
339 void
perform()340 test_task_ctf::perform()
341 {
342   abigail::ir::environment_sptr env;
343 
344   set_in_elf_path();
345   set_in_suppr_spec_path();
346 
347   env.reset(new abigail::ir::environment);
348   abigail::elf_reader::status status =
349     abigail::elf_reader::STATUS_UNKNOWN;
350   vector<char**> di_roots;
351   ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
352 
353   read_context_sptr ctxt = create_read_context(in_elf_path,
354                                                di_roots,
355                                                env.get());
356   ABG_ASSERT(ctxt);
357 
358   corpus_sptr corp = read_corpus(ctxt.get(), status);
359   // if there is no output and no input, assume that we do not care about the
360   // actual read result, just that it succeeded.
361   if (!spec.in_abi_path && !spec.out_abi_path)
362     {
363         // Phew! we made it here and we did not crash! yay!
364         return;
365     }
366   if (!corp)
367     {
368         error_message = string("failed to read ") + in_elf_path  + "\n";
369         is_ok = false;
370         return;
371     }
372   corp->set_path(spec.in_elf_path);
373   // Do not take architecture names in comparison so that these
374   // test input binaries can come from whatever arch the
375   // programmer likes.
376   corp->set_architecture_name("");
377 
378   if (!(is_ok = set_out_abi_path()))
379       return;
380 
381   if (!(is_ok = serialize_corpus(out_abi_path, corp)))
382        return;
383 
384   if (!(is_ok = run_abidw("--ctf ")))
385     return;
386 
387   if (!(is_ok = run_diff()))
388       return;
389 }
390 
391 /// Create a new CTF instance for task to be execute by the testsuite.
392 ///
393 /// @param s the @ref abigail::tests::read_common::InOutSpec
394 /// tests container.
395 ///
396 /// @param a_out_abi_base the output base directory for abixml files.
397 ///
398 /// @param a_in_elf_base the input base directory for object files.
399 ///
400 /// @param a_in_abi_base the input base directory for abixml files.
401 ///
402 /// @return abigail::tests::read_common::test_task instance.
403 static test_task*
new_task(const InOutSpec * s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)404 new_task(const InOutSpec* s, string& a_out_abi_base,
405          string& a_in_elf_base, string& a_in_abi_base)
406 {
407   return new test_task_ctf(*s, a_out_abi_base,
408                            a_in_elf_base, a_in_abi_base);
409 }
410 
411 int
main(int argc,char * argv[])412 main(int argc, char *argv[])
413 {
414   options opts;
415   if (!parse_command_line(argc, argv, opts))
416     {
417       if (!opts.wrong_option.empty())
418         emit_prefix(argv[0], cerr)
419           << "unrecognized option: " << opts.wrong_option << "\n";
420       display_usage(argv[0], cerr);
421       return 1;
422     }
423 
424   // compute number of tests to be executed.
425   const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1;
426 
427   return run_tests(num_tests, in_out_specs, opts, new_task);
428 }
429