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