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