• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2022-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This file is part of the BTF testsuite. It reads ELF binaries
11 /// containing BTF, 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-btf-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::btf::create_reader;
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-btf/test0.o",
41     "",
42     "",
43     SEQUENCE_TYPE_ID_STYLE,
44     "data/test-read-btf/test0.o.abi",
45     "output/test-read-btf/test0.o.abi",
46     "--btf",
47   },
48   {
49     "data/test-read-btf/test1.o",
50     "",
51     "",
52     SEQUENCE_TYPE_ID_STYLE,
53     "data/test-read-btf/test1.o.abi",
54     "output/test-read-btf/test1.o.abi",
55     "--btf",
56   },
57   // This should be the last entry.
58   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL}
59 };
60 
61 /// Task specialization to perform BTF tests.
62 struct test_task_btf : public test_task
63 {
64   test_task_btf(const InOutSpec &s,
65                 string& a_out_abi_base,
66                 string& a_in_elf_base,
67                 string& a_in_abi_base);
68   virtual void
69   perform();
70 
71   virtual
~test_task_btftest_task_btf72   ~test_task_btf()
73   {}
74 }; // end struct test_task_btf
75 
76 /// Constructor.
77 ///
78 /// Task to be executed for each BTF test entry in @ref
79 /// abigail::tests::read_common::InOutSpec.
80 /// @param InOutSpec the array containing set of tests.
81 ///
82 /// @param a_out_abi_base the output base directory for abixml files.
83 ///
84 /// @param a_in_elf_base the input base directory for object files.
85 ///
86 /// @param a_in_elf_base the input base directory for expected
87 /// abixml files.
test_task_btf(const InOutSpec & s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)88 test_task_btf::test_task_btf(const InOutSpec &s,
89                              string& a_out_abi_base,
90                              string& a_in_elf_base,
91                              string& a_in_abi_base)
92         : test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base)
93   {}
94 
95 /// The thread function to execute each BTF test entry in @ref
96 /// abigail::tests::read_common::InOutSpec.
97 ///
98 /// This reads the corpus into memory, saves it to disk, loads it
99 /// again and compares the new in-memory representation against the
100 void
perform()101 test_task_btf::perform()
102 {
103   abigail::ir::environment env;
104 
105   set_in_elf_path();
106   set_in_suppr_spec_path();
107 
108   abigail::fe_iface::status status =
109     abigail::fe_iface::STATUS_UNKNOWN;
110   vector<char**> di_roots;
111   ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
112 
113   abigail::elf_based_reader_sptr rdr = abigail::btf::create_reader(in_elf_path,
114 								   di_roots, env);
115   ABG_ASSERT(rdr);
116 
117   corpus_sptr corp = rdr->read_corpus(status);
118 
119   // if there is no output and no input, assume that we do not care about the
120   // actual read result, just that it succeeded.
121   if (!spec.in_abi_path && !spec.out_abi_path)
122     {
123         // Phew! we made it here and we did not crash! yay!
124         return;
125     }
126   if (!corp)
127     {
128         error_message = string("failed to read ") + in_elf_path  + "\n";
129         is_ok = false;
130         return;
131     }
132   corp->set_path(spec.in_elf_path);
133   // Do not take architecture names in comparison so that these
134   // test input binaries can come from whatever arch the
135   // programmer likes.
136   corp->set_architecture_name("");
137 
138   if (!(is_ok = set_out_abi_path()))
139       return;
140 
141   if (!(is_ok = serialize_corpus(out_abi_path, corp)))
142        return;
143 
144   if (!(is_ok = run_abidw("--btf ")))
145     return;
146 
147   if (!(is_ok = run_diff()))
148       return;
149 }
150 
151 /// Create a new BTF instance for task to be execute by the testsuite.
152 ///
153 /// @param s the @ref abigail::tests::read_common::InOutSpec
154 /// tests container.
155 ///
156 /// @param a_out_abi_base the output base directory for abixml files.
157 ///
158 /// @param a_in_elf_base the input base directory for object files.
159 ///
160 /// @param a_in_abi_base the input base directory for abixml files.
161 ///
162 /// @return abigail::tests::read_common::test_task instance.
163 static test_task*
new_task(const InOutSpec * s,string & a_out_abi_base,string & a_in_elf_base,string & a_in_abi_base)164 new_task(const InOutSpec* s, string& a_out_abi_base,
165          string& a_in_elf_base, string& a_in_abi_base)
166 {
167   return new test_task_btf(*s, a_out_abi_base,
168                            a_in_elf_base, a_in_abi_base);
169 }
170 
171 int
main(int argc,char * argv[])172 main(int argc, char *argv[])
173 {
174   options opts;
175   if (!parse_command_line(argc, argv, opts))
176     {
177       if (!opts.wrong_option.empty())
178         emit_prefix(argv[0], cerr)
179           << "unrecognized option: " << opts.wrong_option << "\n";
180       display_usage(argv[0], cerr);
181       return 1;
182     }
183 
184   // compute number of tests to be executed.
185   const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1;
186 
187   return run_tests(num_tests, in_out_specs, opts, new_task);
188 }
189