1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 2// -*- Mode: C++ -*- 3// 4// Copyright (C) 2021-2022 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 23using std::string; 24using std::cerr; 25using std::vector; 26 27using abigail::tests::read_common::InOutSpec; 28using abigail::tests::read_common::test_task; 29using abigail::tests::read_common::display_usage; 30using abigail::tests::read_common::options; 31 32using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE; 33using abigail::xml_writer::HASH_TYPE_ID_STYLE; 34using abigail::tools_utils::emit_prefix; 35 36using namespace abigail; 37 38static InOutSpec in_out_specs[] = 39{ 40 { 41 "data/test-read-ctf/test0", 42 "", 43 "", 44 SEQUENCE_TYPE_ID_STYLE, 45 "data/test-read-ctf/test0.abi", 46 "output/test-read-ctf/test0.abi", 47 "--ctf" 48 }, 49 { 50 "data/test-read-ctf/test0", 51 "", 52 "", 53 HASH_TYPE_ID_STYLE, 54 "data/test-read-ctf/test0.hash.abi", 55 "output/test-read-ctf/test0.hash.abi", 56 "--ctf" 57 }, 58 { 59 "data/test-read-ctf/test1.so", 60 "", 61 "", 62 SEQUENCE_TYPE_ID_STYLE, 63 "data/test-read-ctf/test1.so.abi", 64 "output/test-read-ctf/test1.so.abi", 65 "--ctf" 66 }, 67 { 68 "data/test-read-ctf/test1.so", 69 "", 70 "", 71 HASH_TYPE_ID_STYLE, 72 "data/test-read-ctf/test1.so.hash.abi", 73 "output/test-read-ctf/test1.so.hash.abi", 74 "--ctf" 75 }, 76 { 77 "data/test-read-ctf/test2.so", 78 "", 79 "", 80 SEQUENCE_TYPE_ID_STYLE, 81 "data/test-read-ctf/test2.so.abi", 82 "output/test-read-ctf/test2.so.abi", 83 "--ctf" 84 }, 85 { 86 "data/test-read-ctf/test2.so", 87 "", 88 "", 89 HASH_TYPE_ID_STYLE, 90 "data/test-read-ctf/test2.so.hash.abi", 91 "output/test-read-ctf/test2.so.hash.abi", 92 "--ctf" 93 }, 94 { 95 "data/test-read-common/test3.so", 96 "", 97 "", 98 SEQUENCE_TYPE_ID_STYLE, 99 "data/test-read-ctf/test3.so.abi", 100 "output/test-read-ctf/test3.so.abi", 101 "--ctf" 102 }, 103 { 104 "data/test-read-common/test3.so", 105 "", 106 "", 107 HASH_TYPE_ID_STYLE, 108 "data/test-read-ctf/test3.so.hash.abi", 109 "output/test-read-ctf/test3.so.hash.abi", 110 "--ctf" 111 }, 112 { 113 "data/test-read-ctf/test-enum-many.o", 114 "", 115 "", 116 HASH_TYPE_ID_STYLE, 117 "data/test-read-ctf/test-enum-many.o.hash.abi", 118 "output/test-read-ctf/test-enum-many.o.hash.abi", 119 "--ctf" 120 }, 121 { 122 "data/test-read-ctf/test-ambiguous-struct-A.o", 123 "", 124 "", 125 HASH_TYPE_ID_STYLE, 126 "data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi", 127 "output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi", 128 "--ctf" 129 }, 130 { 131 "data/test-read-ctf/test-ambiguous-struct-B.o", 132 "", 133 "", 134 HASH_TYPE_ID_STYLE, 135 "data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi", 136 "output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi", 137 "--ctf" 138 }, 139 { 140 "data/test-read-ctf/test-conflicting-type-syms-a.o", 141 "", 142 "", 143 HASH_TYPE_ID_STYLE, 144 "data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi", 145 "output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi", 146 "--ctf" 147 }, 148 { 149 "data/test-read-ctf/test-conflicting-type-syms-b.o", 150 "", 151 "", 152 HASH_TYPE_ID_STYLE, 153 "data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi", 154 "output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi", 155 "--ctf" 156 }, 157 { 158 "data/test-read-common/test4.so", 159 "", 160 "", 161 SEQUENCE_TYPE_ID_STYLE, 162 "data/test-read-ctf/test4.so.abi", 163 "output/test-read-ctf/test4.so.abi", 164 "--ctf" 165 }, 166 { 167 "data/test-read-common/test4.so", 168 "", 169 "", 170 HASH_TYPE_ID_STYLE, 171 "data/test-read-ctf/test4.so.hash.abi", 172 "output/test-read-ctf/test4.so.hash.abi", 173 "--ctf" 174 }, 175 { 176 "data/test-read-ctf/test5.o", 177 "", 178 "", 179 SEQUENCE_TYPE_ID_STYLE, 180 "data/test-read-ctf/test5.o.abi", 181 "output/test-read-ctf/test5.o.abi", 182 "--ctf" 183 }, 184 { 185 "data/test-read-ctf/test7.o", 186 "", 187 "", 188 SEQUENCE_TYPE_ID_STYLE, 189 "data/test-read-ctf/test7.o.abi", 190 "output/test-read-ctf/test7.o.abi", 191 "--ctf" 192 }, 193 { 194 "data/test-read-ctf/test8.o", 195 "", 196 "", 197 SEQUENCE_TYPE_ID_STYLE, 198 "data/test-read-ctf/test8.o.abi", 199 "output/test-read-ctf/test8.o.abi", 200 "--ctf" 201 }, 202 { 203 "data/test-read-ctf/test9.o", 204 "", 205 "", 206 SEQUENCE_TYPE_ID_STYLE, 207 "data/test-read-ctf/test9.o.abi", 208 "output/test-read-ctf/test9.o.abi", 209 "--ctf" 210 }, 211 { 212 "data/test-read-ctf/test-enum.o", 213 "", 214 "", 215 SEQUENCE_TYPE_ID_STYLE, 216 "data/test-read-ctf/test-enum.o.abi", 217 "output/test-read-ctf/test-enum.o.abi", 218 "--ctf" 219 }, 220 { 221 "data/test-read-ctf/test-enum-symbol.o", 222 "", 223 "", 224 HASH_TYPE_ID_STYLE, 225 "data/test-read-ctf/test-enum-symbol.o.hash.abi", 226 "output/test-read-ctf/test-enum-symbol.o.hash.abi", 227 "--ctf" 228 }, 229 { 230 "data/test-read-ctf/test-dynamic-array.o", 231 "", 232 "", 233 SEQUENCE_TYPE_ID_STYLE, 234 "data/test-read-ctf/test-dynamic-array.o.abi", 235 "output/test-read-ctf/test-dynamic-array.o.abi", 236 "--ctf" 237 }, 238 { 239 "data/test-read-ctf/test-anonymous-fields.o", 240 "", 241 "", 242 SEQUENCE_TYPE_ID_STYLE, 243 "data/test-read-ctf/test-anonymous-fields.o.abi", 244 "output/test-read-ctf/test-anonymous-fields.o.abi", 245 "--ctf" 246 }, 247 { 248 "data/test-read-common/PR27700/test-PR27700.o", 249 "", 250 "data/test-read-common/PR27700/pub-incdir", 251 HASH_TYPE_ID_STYLE, 252 "data/test-read-ctf/PR27700/test-PR27700.abi", 253 "output/test-read-ctf/PR27700/test-PR27700.abi", 254 "--ctf" 255 }, 256 { 257 "data/test-read-ctf/test-callback.o", 258 "", 259 "", 260 SEQUENCE_TYPE_ID_STYLE, 261 "data/test-read-ctf/test-callback.abi", 262 "output/test-read-ctf/test-callback.abi", 263 "--ctf" 264 }, 265 { 266 "data/test-read-ctf/test-array-of-pointers.o", 267 "", 268 "", 269 SEQUENCE_TYPE_ID_STYLE, 270 "data/test-read-ctf/test-array-of-pointers.abi", 271 "output/test-read-ctf/test-array-of-pointers.abi", 272 "--ctf" 273 }, 274 { 275 "data/test-read-ctf/test-functions-declaration.o", 276 "", 277 "", 278 SEQUENCE_TYPE_ID_STYLE, 279 "data/test-read-ctf/test-functions-declaration.abi", 280 "output/test-read-ctf/test-functions-declaration.abi", 281 "--ctf" 282 }, 283 { 284 "data/test-read-ctf/test-forward-type-decl.o", 285 "", 286 "", 287 SEQUENCE_TYPE_ID_STYLE, 288 "data/test-read-ctf/test-forward-type-decl.abi", 289 "output/test-read-ctf/test-forward-type-decl.abi", 290 "--ctf" 291 }, 292 { 293 "data/test-read-ctf/test-list-struct.o", 294 "", 295 "", 296 SEQUENCE_TYPE_ID_STYLE, 297 "data/test-read-ctf/test-list-struct.abi", 298 "output/test-read-ctf/test-list-struct.abi", 299 "--ctf" 300 }, 301 { 302 "data/test-read-common/test-PR26568-1.o", 303 "", 304 "", 305 SEQUENCE_TYPE_ID_STYLE, 306 "data/test-read-ctf/test-PR26568-1.o.abi", 307 "output/test-read-ctf/test-PR26568-1.o.abi", 308 "--ctf" 309 }, 310 { 311 "data/test-read-common/test-PR26568-2.o", 312 "", 313 "", 314 SEQUENCE_TYPE_ID_STYLE, 315 "data/test-read-ctf/test-PR26568-2.o.abi", 316 "output/test-read-ctf/test-PR26568-2.o.abi", 317 "--ctf" 318 }, 319 { 320 "data/test-read-ctf/test-callback2.o", 321 "", 322 "", 323 SEQUENCE_TYPE_ID_STYLE, 324 "data/test-read-ctf/test-callback2.abi", 325 "output/test-read-ctf/test-callback2.abi", 326 "--ctf" 327 }, 328 // out-of-tree kernel module. 329 { 330 "data/test-read-ctf/test-linux-module.ko", 331 "", 332 "", 333 SEQUENCE_TYPE_ID_STYLE, 334 "data/test-read-ctf/test-linux-module.abi", 335 "output/test-read-ctf/test-linux-module.abi", 336 "--ctf" 337 }, 338 // CTF fallback feature. 339 { 340 "data/test-read-ctf/test-fallback.o", 341 "", 342 "", 343 SEQUENCE_TYPE_ID_STYLE, 344 "data/test-read-ctf/test-fallback.abi", 345 "output/test-read-ctf/test-fallback.abi", 346 NULL, 347 }, 348 { 349 "data/test-read-ctf/test-bitfield.o", 350 "", 351 "", 352 SEQUENCE_TYPE_ID_STYLE, 353 "data/test-read-ctf/test-bitfield.abi", 354 "output/test-read-ctf/test-bitfield.abi", 355 "--ctf", 356 }, 357 { 358 "data/test-read-ctf/test-bitfield-enum.o", 359 "", 360 "", 361 SEQUENCE_TYPE_ID_STYLE, 362 "data/test-read-ctf/test-bitfield-enum.abi", 363 "output/test-read-ctf/test-bitfield-enum.abi", 364 "--ctf", 365 }, 366 { 367 "data/test-read-ctf/test-const-array.o", 368 "", 369 "", 370 SEQUENCE_TYPE_ID_STYLE, 371 "data/test-read-ctf/test-const-array.abi", 372 "output/test-read-ctf/test-const-array.abi", 373 "--ctf", 374 }, 375 { 376 "data/test-read-ctf/test-array-mdimension.o", 377 "", 378 "", 379 SEQUENCE_TYPE_ID_STYLE, 380 "data/test-read-ctf/test-array-mdimension.abi", 381 "output/test-read-ctf/test-array-mdimension.abi", 382 "--ctf", 383 }, 384 { 385 "data/test-read-ctf/test-array-size.o", 386 "", 387 "", 388 SEQUENCE_TYPE_ID_STYLE, 389 "data/test-read-ctf/test-array-size.abi", 390 "output/test-read-ctf/test-array-size.abi", 391 "--ctf", 392 }, 393 // This should be the last entry. 394 {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL} 395}; 396 397/// Task specialization to perform CTF tests. 398struct test_task_ctf : public test_task 399{ 400 test_task_ctf(const InOutSpec &s, 401 string& a_out_abi_base, 402 string& a_in_elf_base, 403 string& a_in_abi_base); 404 virtual void 405 perform(); 406 407 virtual 408 ~test_task_ctf() 409 {} 410}; // end struct test_task_ctf 411 412/// Constructor. 413/// 414/// Task to be executed for each CTF test entry in @ref 415/// abigail::tests::read_common::InOutSpec. 416/// @param InOutSpec the array containing set of tests. 417/// 418/// @param a_out_abi_base the output base directory for abixml files. 419/// 420/// @param a_in_elf_base the input base directory for object files. 421/// 422/// @param a_in_elf_base the input base directory for expected 423/// abixml files. 424test_task_ctf::test_task_ctf(const InOutSpec &s, 425 string& a_out_abi_base, 426 string& a_in_elf_base, 427 string& a_in_abi_base) 428 : test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base) 429 {} 430 431/// The thread function to execute each CTF test entry in @ref 432/// abigail::tests::read_common::InOutSpec. 433/// 434/// This reads the corpus into memory, saves it to disk, loads it 435/// again and compares the new in-memory representation against the 436void 437test_task_ctf::perform() 438{ 439 abigail::ir::environment env; 440 441 set_in_elf_path(); 442 set_in_suppr_spec_path(); 443 444 abigail::fe_iface::status status = 445 abigail::fe_iface::STATUS_UNKNOWN; 446 vector<char**> di_roots; 447 ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path)); 448 449 abigail::elf_based_reader_sptr rdr = ctf::create_reader(in_elf_path, 450 di_roots, env); 451 ABG_ASSERT(rdr); 452 453 corpus_sptr corp = rdr->read_corpus(status); 454 455 // if there is no output and no input, assume that we do not care about the 456 // actual read result, just that it succeeded. 457 if (!spec.in_abi_path && !spec.out_abi_path) 458 { 459 // Phew! we made it here and we did not crash! yay! 460 return; 461 } 462 if (!corp) 463 { 464 error_message = string("failed to read ") + in_elf_path + "\n"; 465 is_ok = false; 466 return; 467 } 468 corp->set_path(spec.in_elf_path); 469 // Do not take architecture names in comparison so that these 470 // test input binaries can come from whatever arch the 471 // programmer likes. 472 corp->set_architecture_name(""); 473 474 if (!(is_ok = set_out_abi_path())) 475 return; 476 477 if (!(is_ok = serialize_corpus(out_abi_path, corp))) 478 return; 479 480 if (!(is_ok = run_abidw())) 481 return; 482 483 if (!(is_ok = run_diff())) 484 return; 485} 486 487/// Create a new CTF instance for task to be execute by the testsuite. 488/// 489/// @param s the @ref abigail::tests::read_common::InOutSpec 490/// tests container. 491/// 492/// @param a_out_abi_base the output base directory for abixml files. 493/// 494/// @param a_in_elf_base the input base directory for object files. 495/// 496/// @param a_in_abi_base the input base directory for abixml files. 497/// 498/// @return abigail::tests::read_common::test_task instance. 499static test_task* 500new_task(const InOutSpec* s, string& a_out_abi_base, 501 string& a_in_elf_base, string& a_in_abi_base) 502{ 503 return new test_task_ctf(*s, a_out_abi_base, 504 a_in_elf_base, a_in_abi_base); 505} 506 507int 508main(int argc, char *argv[]) 509{ 510 options opts; 511 if (!parse_command_line(argc, argv, opts)) 512 { 513 if (!opts.wrong_option.empty()) 514 emit_prefix(argv[0], cerr) 515 << "unrecognized option: " << opts.wrong_option << "\n"; 516 display_usage(argv[0], cerr); 517 return 1; 518 } 519 520 // compute number of tests to be executed. 521 const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1; 522 523 return run_tests(num_tests, in_out_specs, opts, new_task); 524} 525