402 lines
10 KiB
C++
402 lines
10 KiB
C++
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
// -*- Mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2021 Oracle, Inc.
|
|
//
|
|
// Author: Guillermo E. Martinez
|
|
|
|
/// @file
|
|
///
|
|
/// This file implement the CTF testsuite. It reads ELF binaries
|
|
/// containing CTF, save them in XML corpus files and diff the
|
|
/// corpus files against reference XML corpus files.
|
|
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include "abg-ctf-reader.h"
|
|
#include "test-read-common.h"
|
|
|
|
using std::string;
|
|
using std::cerr;
|
|
|
|
using abigail::tests::read_common::InOutSpec;
|
|
using abigail::tests::read_common::test_task;
|
|
using abigail::tests::read_common::display_usage;
|
|
using abigail::tests::read_common::options;
|
|
|
|
using abigail::ctf_reader::read_context_sptr;
|
|
using abigail::ctf_reader::create_read_context;
|
|
using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
|
|
using abigail::xml_writer::HASH_TYPE_ID_STYLE;
|
|
using abigail::tools_utils::emit_prefix;
|
|
|
|
static InOutSpec in_out_specs[] =
|
|
{
|
|
{
|
|
"data/test-read-ctf/test0",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test0.abi",
|
|
"output/test-read-ctf/test0.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test0",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test0.hash.abi",
|
|
"output/test-read-ctf/test0.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test1.so",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test1.so.abi",
|
|
"output/test-read-ctf/test1.so.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test1.so",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test1.so.hash.abi",
|
|
"output/test-read-ctf/test1.so.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test2.so",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test2.so.abi",
|
|
"output/test-read-ctf/test2.so.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test2.so",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test2.so.hash.abi",
|
|
"output/test-read-ctf/test2.so.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-common/test3.so",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test3.so.abi",
|
|
"output/test-read-ctf/test3.so.abi"
|
|
},
|
|
{
|
|
"data/test-read-common/test3.so",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test3.so.hash.abi",
|
|
"output/test-read-ctf/test3.so.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-enum-many.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-enum-many.o.hash.abi",
|
|
"output/test-read-ctf/test-enum-many.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-ambiguous-struct-A.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
|
|
"output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-ambiguous-struct-B.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
|
|
"output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-conflicting-type-syms-a.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
|
|
"output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-conflicting-type-syms-b.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
|
|
"output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-common/test4.so",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test4.so.abi",
|
|
"output/test-read-ctf/test4.so.abi"
|
|
},
|
|
{
|
|
"data/test-read-common/test4.so",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test4.so.hash.abi",
|
|
"output/test-read-ctf/test4.so.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test5.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test5.o.abi",
|
|
"output/test-read-ctf/test5.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test7.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test7.o.abi",
|
|
"output/test-read-ctf/test7.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test8.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test8.o.abi",
|
|
"output/test-read-ctf/test8.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test9.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test9.o.abi",
|
|
"output/test-read-ctf/test9.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-enum.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-enum.o.abi",
|
|
"output/test-read-ctf/test-enum.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-enum-symbol.o",
|
|
"",
|
|
"",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-enum-symbol.o.hash.abi",
|
|
"output/test-read-ctf/test-enum-symbol.o.hash.abi"
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-dynamic-array.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-dynamic-array.o.abi",
|
|
"output/test-read-ctf/test-dynamic-array.o.abi"
|
|
},
|
|
{
|
|
"data/test-read-common/PR27700/test-PR27700.o",
|
|
"",
|
|
"data/test-read-common/PR27700/pub-incdir",
|
|
HASH_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/PR27700/test-PR27700.abi",
|
|
"output/test-read-ctf/PR27700/test-PR27700.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-callback.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-callback.abi",
|
|
"output/test-read-ctf/test-callback.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-array-of-pointers.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-array-of-pointers.abi",
|
|
"output/test-read-ctf/test-array-of-pointers.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-functions-declaration.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-functions-declaration.abi",
|
|
"output/test-read-ctf/test-functions-declaration.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-forward-type-decl.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-forward-type-decl.abi",
|
|
"output/test-read-ctf/test-forward-type-decl.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-list-struct.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-list-struct.abi",
|
|
"output/test-read-ctf/test-list-struct.abi",
|
|
},
|
|
{
|
|
"data/test-read-ctf/test-callback2.o",
|
|
"",
|
|
"",
|
|
SEQUENCE_TYPE_ID_STYLE,
|
|
"data/test-read-ctf/test-callback2.abi",
|
|
"output/test-read-ctf/test-callback2.abi",
|
|
},
|
|
// This should be the last entry.
|
|
{NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
|
|
};
|
|
|
|
/// Task specialization to perform CTF tests.
|
|
struct test_task_ctf : public test_task
|
|
{
|
|
test_task_ctf(const InOutSpec &s,
|
|
string& a_out_abi_base,
|
|
string& a_in_elf_base,
|
|
string& a_in_abi_base);
|
|
virtual void
|
|
perform();
|
|
|
|
virtual
|
|
~test_task_ctf()
|
|
{}
|
|
}; // end struct test_task_ctf
|
|
|
|
/// Constructor.
|
|
///
|
|
/// Task to be executed for each CTF test entry in @ref
|
|
/// abigail::tests::read_common::InOutSpec.
|
|
/// @param InOutSpec the array containing set of tests.
|
|
///
|
|
/// @param a_out_abi_base the output base directory for abixml files.
|
|
///
|
|
/// @param a_in_elf_base the input base directory for object files.
|
|
///
|
|
/// @param a_in_elf_base the input base directory for expected
|
|
/// abixml files.
|
|
test_task_ctf::test_task_ctf(const InOutSpec &s,
|
|
string& a_out_abi_base,
|
|
string& a_in_elf_base,
|
|
string& a_in_abi_base)
|
|
: test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base)
|
|
{}
|
|
|
|
/// The thread function to execute each CTF test entry in @ref
|
|
/// abigail::tests::read_common::InOutSpec.
|
|
///
|
|
/// This reads the corpus into memory, saves it to disk, loads it
|
|
/// again and compares the new in-memory representation against the
|
|
void
|
|
test_task_ctf::perform()
|
|
{
|
|
abigail::ir::environment_sptr env;
|
|
|
|
set_in_elf_path();
|
|
set_in_suppr_spec_path();
|
|
|
|
env.reset(new abigail::ir::environment);
|
|
abigail::elf_reader::status status =
|
|
abigail::elf_reader::STATUS_UNKNOWN;
|
|
ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
|
|
|
|
read_context_sptr ctxt = create_read_context(in_elf_path,
|
|
env.get());
|
|
ABG_ASSERT(ctxt);
|
|
|
|
corpus_sptr corp = read_corpus(ctxt.get(), status);
|
|
// if there is no output and no input, assume that we do not care about the
|
|
// actual read result, just that it succeeded.
|
|
if (!spec.in_abi_path && !spec.out_abi_path)
|
|
{
|
|
// Phew! we made it here and we did not crash! yay!
|
|
return;
|
|
}
|
|
if (!corp)
|
|
{
|
|
error_message = string("failed to read ") + in_elf_path + "\n";
|
|
is_ok = false;
|
|
return;
|
|
}
|
|
corp->set_path(spec.in_elf_path);
|
|
// Do not take architecture names in comparison so that these
|
|
// test input binaries can come from whatever arch the
|
|
// programmer likes.
|
|
corp->set_architecture_name("");
|
|
|
|
if (!(is_ok = set_out_abi_path()))
|
|
return;
|
|
|
|
if (!(is_ok = serialize_corpus(out_abi_path, corp)))
|
|
return;
|
|
|
|
if (!(is_ok = run_abidw("--ctf ")))
|
|
return;
|
|
|
|
if (!(is_ok = run_diff()))
|
|
return;
|
|
}
|
|
|
|
/// Create a new CTF instance for task to be execute by the testsuite.
|
|
///
|
|
/// @param s the @ref abigail::tests::read_common::InOutSpec
|
|
/// tests container.
|
|
///
|
|
/// @param a_out_abi_base the output base directory for abixml files.
|
|
///
|
|
/// @param a_in_elf_base the input base directory for object files.
|
|
///
|
|
/// @param a_in_abi_base the input base directory for abixml files.
|
|
///
|
|
/// @return abigail::tests::read_common::test_task instance.
|
|
static test_task*
|
|
new_task(const InOutSpec* s, string& a_out_abi_base,
|
|
string& a_in_elf_base, string& a_in_abi_base)
|
|
{
|
|
return new test_task_ctf(*s, a_out_abi_base,
|
|
a_in_elf_base, a_in_abi_base);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
options opts;
|
|
if (!parse_command_line(argc, argv, opts))
|
|
{
|
|
if (!opts.wrong_option.empty())
|
|
emit_prefix(argv[0], cerr)
|
|
<< "unrecognized option: " << opts.wrong_option << "\n";
|
|
display_usage(argv[0], cerr);
|
|
return 1;
|
|
}
|
|
|
|
// compute number of tests to be executed.
|
|
const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1;
|
|
|
|
return run_tests(num_tests, in_out_specs, opts, new_task);
|
|
}
|