1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7
8 /// @file
9 ///
10 /// This program tests that the representation of types by the
11 /// internal representation of libabigail is stable through reading
12 /// from ELF/DWARF, constructing an internal represenation, saving that
13 /// internal presentation to the abixml format, reading from that
14 /// abixml format and constructing an internal representation from it
15 /// again.
16 ///
17 /// This program thus compares the internal representation that is
18 /// built from reading from ELF/DWARF and the one that is built from
19 /// the abixml (which itself results from the serialization of the
20 /// first internal representation to abixml).
21 ///
22 /// The comparison is expected to yield the empty set.
23
24 #include <cstdlib>
25 #include <fstream>
26 #include <iostream>
27 #include <memory>
28 #include <string>
29 #include "abg-tools-utils.h"
30 #include "test-utils.h"
31 #include "abg-dwarf-reader.h"
32 #include "abg-comparison.h"
33 #include "abg-workers.h"
34
35 using std::string;
36 using std::ofstream;
37 using std::cerr;
38
39 // A set of elf files to test type stability for.
40 const char* elf_paths[] =
41 {
42 "data/test-types-stability/pr19434-elf0",
43 "data/test-types-stability/pr19139-DomainNeighborMapInst.o",
44 "data/test-types-stability/pr19202-libmpi_gpfs.so.5.0",
45 "data/test-types-stability/pr19026-libvtkIOSQL-6.1.so.1",
46 "data/test-types-stability/pr19138-elf0",
47 "data/test-types-stability/pr19433-custom0",
48 "data/test-types-stability/pr19141-get5d.o",
49 "data/test-types-stability/pr19142-topo.o",
50 "data/test-types-stability/pr19204-libtcmalloc.so.4.2.6-xlc",
51 "data/test-types-stability/PR27165-libzmq.so.5.2.3",
52 "data/test-types-stability/pr27980-libc.so",
53 "data/test-types-stability/PR27086-libstdc++.so.6.0.26",
54 "data/test-types-stability/PR28450-libepetra.so.13.0",
55 // The below should always be the last element of array.
56 0
57 };
58
59 /// A task which launches abidw --abidiff on a binary
60 /// passed to the constructor of the task.
61 struct test_task : public abigail::workers::task
62 {
63 const string path;
64 const bool no_default_sizes;
65 string error_message;
66 bool is_ok;
67
68 /// The constructor of the test task.
69 ///
70 /// @param elf_path the path to the elf binary on which we are
71 /// supposed to launch abidw --abidiff.
test_tasktest_task72 test_task(const string& elf_path, bool no_default_sizes)
73 : path(elf_path),
74 no_default_sizes(no_default_sizes),
75 is_ok(true)
76 {}
77
78 /// This virtual function overload actually performs the job of the task.
79 ///
80 /// It calls abidw --abidiff on the binary refered to by the task.
81 /// It thus stores a flag saying if the result of abidw --abidiff is
82 /// OK or not.
83 virtual void
performtest_task84 perform()
85 {
86 using abigail::tests::get_src_dir;
87 using abigail::tests::get_build_dir;
88
89 string abidw = string(get_build_dir()) + "/tools/abidw";
90 string elf_path = string(get_src_dir()) + "/tests/" + path;
91 string cmd = abidw + " --abidiff "
92 + (no_default_sizes ? "--no-write-default-sizes " : "")
93 + elf_path;
94 if (system(cmd.c_str()))
95 {
96 error_message =
97 "IR stability issue detected for binary " + elf_path
98 + (no_default_sizes ? " with --no-write-default-sizes" : "");
99 is_ok = false;
100 }
101 }
102 }; // end struct test_task
103
104 /// A convenience typedef for a shared_ptr to @ref test_task.
105 typedef shared_ptr<test_task> test_task_sptr;
106
107 int
main()108 main()
109 {
110 using std::vector;
111 using std::dynamic_pointer_cast;
112 using abigail::workers::queue;
113 using abigail::workers::task;
114 using abigail::workers::task_sptr;
115 using abigail::workers::get_number_of_threads;
116
117 /// Create a task queue. The max number of worker threads of the
118 /// queue is the number of the concurrent threads supported by the
119 /// processor of the machine this code runs on.
120 const size_t num_tests = (sizeof(elf_paths) / sizeof(char*) - 1) * 2;
121 size_t num_workers = std::min(get_number_of_threads(), num_tests);
122 queue task_queue(num_workers);
123
124 /// Create one task per binary registered for this test, and push
125 /// them to the task queue. Pushing a task to the queue triggers
126 /// a worker thread that starts working on the task.
127 for (const char** p = elf_paths; p && *p; ++p)
128 {
129 test_task_sptr t(new test_task(*p, false));
130 ABG_ASSERT(task_queue.schedule_task(t));
131
132 t.reset(new test_task(*p, true));
133 ABG_ASSERT(task_queue.schedule_task(t));
134 }
135
136 /// Wait for all worker threads to finish their job, and wind down.
137 task_queue.wait_for_workers_to_complete();
138
139 // Now walk the results and print whatever error messages need to be
140 // printed.
141
142 const vector<task_sptr>& completed_tasks =
143 task_queue.get_completed_tasks();
144
145 ABG_ASSERT(completed_tasks.size () == num_tests);
146
147 bool is_ok = true;
148 for (vector<task_sptr>::const_iterator ti = completed_tasks.begin();
149 ti != completed_tasks.end();
150 ++ti)
151 {
152 test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
153 if (!t->is_ok)
154 {
155 is_ok = false;
156 cerr << t->error_message << "\n";
157 }
158 }
159
160 return !is_ok;
161 }
162