• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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