libabigail/tests/test-read-dwarf.cc
Matthias Maennich beededda29 Add compatibility layer for C++11 mode
Introduce a compatibility layer for C++11 code by adding
include/abg-cxx-compat.h. abg-cxx-compat defines a new namespace
abg_compat and defines
	abg_compat::hash
	abg_compat::shared_ptr
	abg_compat::weak_ptr
	abg_compat::dynamic_pointer_cast
	abg_compat::static_pointer_cast
	abg_compat::unordered_map
	abg_compat::unordered_set
based on definitions from std::tr1 (std=gnu++98) or std:: (std=gnu++11).

I decided for introducing abg_compat:: rather than polluting abigail::
to allow an easier transition to C++11 at a later time and to not subtly
break existing code.

As the shared_ptr in C++11 defines shared_ptr::operator bool() explicit,
some locations where a shared_ptr is assigned to boolean, needed to be
adjusted to explicitly cast to bool.

	* include/abg-cxx-compat.h: new file introducing the abg_compat
	  namespace to provide C++11 functionality from either std::tr1
	  or std::
	* include/Makefile.am: Add the new abg-cxx-compat.h to source
	  distribution.
	* include/abg-comparison.h: replace std::tr1 usage by abg_compat
	  and adjust includes accordingly: likewise
	* include/abg-diff-utils.h: likewise
	* include/abg-fwd.h: likewise
	* include/abg-ini.h: likewise
	* include/abg-interned-str.h: likewise
	* include/abg-ir.h: likewise
	* include/abg-libxml-utils.h: likewise
	* include/abg-libzip-utils.h: likewise
	* include/abg-reporter.h: likewise
	* include/abg-sptr-utils.h: likewise
	* include/abg-suppression.h: likewise
	* include/abg-tools-utils.h: likewise
	* include/abg-workers.h: likewise
	* src/abg-comp-filter.cc: likewise
	* src/abg-comparison-priv.h: likewise
	* src/abg-corpus.cc: likewise
	* src/abg-dwarf-reader.cc: likewise
	* src/abg-hash.cc: likewise
	* src/abg-ir.cc: likewise
	* src/abg-reader.cc: likewise
	* src/abg-suppression.cc: likewise
	* src/abg-tools-utils.cc: likewise
	* src/abg-writer.cc: likewise
	* tests/test-diff-filter.cc: likewise
	* tests/test-diff-pkg.cc: likewise
	* tests/test-read-dwarf.cc: likewise
	* tests/test-read-write.cc: likewise
	* tests/test-types-stability.cc: likewise
	* tests/test-write-read-archive.cc: likewise
	* tools/abicompat.cc: likewise
	* tools/abidiff.cc: likewise
	* tools/abidw.cc: likewise
	* tools/abilint.cc: likewise
	* tools/abipkgdiff.cc: likewise

Signed-off-by: Matthias Maennich <maennich@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2019-07-09 18:05:28 +02:00

434 lines
12 KiB
C++

// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2019 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
// Author: Dodji Seketeli
/// @file read ELF binaries containing DWARF, save them in XML corpus
/// files and diff the corpus files against reference XML corpus
/// files.
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
#include <cstdlib>
#include "abg-ir.h"
#include "abg-dwarf-reader.h"
#include "abg-workers.h"
#include "abg-writer.h"
#include "abg-tools-utils.h"
#include "test-utils.h"
using std::vector;
using std::string;
using std::ofstream;
using std::cerr;
using abg_compat::dynamic_pointer_cast;
using abigail::tests::get_build_dir;
using abigail::dwarf_reader::read_corpus_from_elf;
using abigail::dwarf_reader::read_context;
using abigail::dwarf_reader::read_context_sptr;
using abigail::dwarf_reader::create_read_context;
using abigail::xml_writer::create_write_context;
using abigail::xml_writer::write_context_sptr;
using abigail::xml_writer::write_corpus;
/// This is an aggregate that specifies where a test shall get its
/// input from, and where it shall write its ouput to.
struct InOutSpec
{
const char* in_elf_path;
const char* in_suppr_spec_path;
const char* in_abi_path;
const char* out_abi_path;
};// end struct InOutSpec
InOutSpec in_out_specs[] =
{
{
"data/test-read-dwarf/test0",
"",
"data/test-read-dwarf/test0.abi",
"output/test-read-dwarf/test0.abi"
},
{
"data/test-read-dwarf/test1",
"",
"data/test-read-dwarf/test1.abi",
"output/test-read-dwarf/test1.abi"
},
{
"data/test-read-dwarf/test2.so",
"",
"data/test-read-dwarf/test2.so.abi",
"output/test-read-dwarf/test2.so.abi"
},
{
"data/test-read-dwarf/test3.so",
"",
"data/test-read-dwarf/test3.so.abi",
"output/test-read-dwarf/test3.so.abi"
},
{
"data/test-read-dwarf/test4.so",
"",
"data/test-read-dwarf/test4.so.abi",
"output/test-read-dwarf/test4.so.abi"
},
{
"data/test-read-dwarf/test5.o",
"",
"data/test-read-dwarf/test5.o.abi",
"output/test-read-dwarf/test5.o.abi"
},
{
"data/test-read-dwarf/test6.so",
"",
"data/test-read-dwarf/test6.so.abi",
"output/test-read-dwarf/test6.so.abi"
},
{
"data/test-read-dwarf/test7.so",
"",
"data/test-read-dwarf/test7.so.abi",
"output/test-read-dwarf/test7.so.abi"
},
{
"data/test-read-dwarf/test8-qualified-this-pointer.so",
"",
"data/test-read-dwarf/test8-qualified-this-pointer.so.abi",
"output/test-read-dwarf/test8-qualified-this-pointer.so.abi"
},
{
"data/test-read-dwarf/test9-pr18818-clang.so",
"",
"data/test-read-dwarf/test9-pr18818-clang.so.abi",
"output/test-read-dwarf/test9-pr18818-clang.so.abi"
},
{
"data/test-read-dwarf/test10-pr18818-gcc.so",
"",
"data/test-read-dwarf/test10-pr18818-gcc.so.abi",
"output/test-read-dwarf/test10-pr18818-gcc.so.abi"
},
{
"data/test-read-dwarf/test11-pr18828.so",
"",
"data/test-read-dwarf/test11-pr18828.so.abi",
"output/test-read-dwarf/test11-pr18828.so.abi",
},
{
"data/test-read-dwarf/test12-pr18844.so",
"",
"data/test-read-dwarf/test12-pr18844.so.abi",
"output/test-read-dwarf/test12-pr18844.so.abi",
},
{
"data/test-read-dwarf/test13-pr18894.so",
"",
"data/test-read-dwarf/test13-pr18894.so.abi",
"output/test-read-dwarf/test13-pr18894.so.abi",
},
{
"data/test-read-dwarf/test14-pr18893.so",
"",
"data/test-read-dwarf/test14-pr18893.so.abi",
"output/test-read-dwarf/test14-pr18893.so.abi",
},
{
"data/test-read-dwarf/test15-pr18892.so",
"",
"data/test-read-dwarf/test15-pr18892.so.abi",
"output/test-read-dwarf/test15-pr18892.so.abi",
},
{
"data/test-read-dwarf/test16-pr18904.so",
"",
"data/test-read-dwarf/test16-pr18904.so.abi",
"output/test-read-dwarf/test16-pr18904.so.abi",
},
{
"data/test-read-dwarf/test17-pr19027.so",
"",
"data/test-read-dwarf/test17-pr19027.so.abi",
"output/test-read-dwarf/test17-pr19027.so.abi",
},
{
"data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so",
"",
"data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
"output/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
},
{
"data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so",
"",
"data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
"output/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
},
{
"data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so",
"",
"data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
"output/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
},
{
"data/test-read-dwarf/test21-pr19092.so",
"",
"data/test-read-dwarf/test21-pr19092.so.abi",
"output/test-read-dwarf/test21-pr19092.so.abi",
},
{
"data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so",
"",
"data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
"output/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
},
{
"data/test-read-dwarf/libtest23.so",
"",
"data/test-read-dwarf/libtest23.so.abi",
"output/test-read-dwarf/libtest23.so.abi",
},
{
"data/test-read-dwarf/libtest24-drop-fns.so",
"data/test-read-dwarf/test24-drop-fns-0.suppr",
"data/test-read-dwarf/libtest24-drop-fns.so.abi",
"output/test-read-dwarf/libtest24-drop-fns.so.abi",
},
{
"data/test-read-dwarf/libtest24-drop-fns.so",
"",
"data/test-read-dwarf/libtest24-drop-fns-2.so.abi",
"output/test-read-dwarf/libtest24-drop-fns-2.so.abi",
},
{
"data/test-read-dwarf/PR22015-libboost_iostreams.so",
"",
"data/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
"output/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
},
{
"data/test-read-dwarf/PR22122-libftdc.so",
"",
"data/test-read-dwarf/PR22122-libftdc.so.abi",
"output/test-read-dwarf/PR22122-libftdc.so.abi",
},
{
"data/test-read-dwarf/PR24378-fn-is-not-scope.o",
"",
"data/test-read-dwarf/PR24378-fn-is-not-scope.abi",
"output/test-read-dwarf/PR24378-fn-is-not-scope.abi",
},
// This should be the last entry.
{NULL, NULL, NULL, NULL}
};
using abigail::suppr::suppression_sptr;
using abigail::suppr::suppressions_type;
using abigail::suppr::read_suppressions;
/// Set the suppression specification to use when reading the ELF binary.
///
/// @param read_ctxt the context used to read the ELF binary.
///
/// @param path the path to the suppression specification to read.
static void
set_suppressions(read_context& read_ctxt, const string& path)
{
suppressions_type supprs;
read_suppressions(path, supprs);
add_read_context_suppressions(read_ctxt, supprs);
}
/// The task that peforms the tests.
struct test_task : public abigail::workers::task
{
bool is_ok;
InOutSpec spec;
string error_message;
string out_abi_base;
string in_elf_base;
string in_abi_base;
test_task(const InOutSpec &s,
string& a_out_abi_base,
string& a_in_elf_base,
string& a_in_abi_base)
: is_ok(true),
spec(s),
out_abi_base(a_out_abi_base),
in_elf_base(a_in_elf_base),
in_abi_base(a_in_abi_base)
{}
/// The actual test.
///
/// This reads the corpus into memory, saves it to disk, loads it
/// again and compares the new in-memory representation against the
/// saved one.
virtual void
perform()
{
string in_elf_path, in_abi_path, in_suppr_spec_path, out_abi_path;
abigail::ir::environment_sptr env;
in_elf_path = in_elf_base + spec.in_elf_path;
if (spec.in_suppr_spec_path)
in_suppr_spec_path = in_elf_base + spec.in_suppr_spec_path;
else
in_suppr_spec_path.clear();
env.reset(new abigail::ir::environment);
abigail::dwarf_reader::status status =
abigail::dwarf_reader::STATUS_UNKNOWN;
vector<char**> di_roots;
read_context_sptr ctxt = create_read_context(in_elf_path,
di_roots,
env.get());
ABG_ASSERT(ctxt);
if (!in_suppr_spec_path.empty())
set_suppressions(*ctxt, in_suppr_spec_path);
abigail::corpus_sptr corp = read_corpus_from_elf(*ctxt, status);
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("");
out_abi_path = out_abi_base + spec.out_abi_path;
if (!abigail::tools_utils::ensure_parent_dir_created(out_abi_path))
{
error_message =
string("Could not create parent directory for ") + out_abi_path;
is_ok = false;
return;
}
ofstream of(out_abi_path.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
error_message = string("failed to read ") + out_abi_path + "\n";
is_ok = false;
return;
}
const write_context_sptr write_ctxt
= create_write_context(corp->get_environment(), of);
is_ok = write_corpus(*write_ctxt, corp, /*indent=*/0);
of.close();
string abidw = string(get_build_dir()) + "/tools/abidw";
string cmd = abidw + " --abidiff " + in_elf_path;
if (system(cmd.c_str()))
{
error_message = string("ABIs differ:\n")
+ in_elf_path
+ "\nand:\n"
+ out_abi_path
+ "\n";
is_ok = false;
}
in_abi_path = in_abi_base + spec.in_abi_path;
cmd = "diff -u " + in_abi_path + " " + out_abi_path;
if (system(cmd.c_str()))
is_ok = false;
}
}; // end struct test_task
typedef shared_ptr<test_task> test_task_sptr;
int
main(int argc, char *argv[])
{
bool no_parallel = false;
if (argc == 2)
{
if (argv[1] == string("--no-parallel"))
no_parallel = true;
else
{
cerr << "unrecognized option\n";
cerr << "usage: " << argv[0] << " [--no-parallel]\n" ;
return 1;
}
}
/// Create a task queue. The max number of worker threads of the
/// queue is the number of the concurrent threads supported by the
/// processor of the machine this code runs on. But if
/// --no-parallel was provided then the number of worker threads
/// equals 1.
const size_t num_tests = sizeof(in_out_specs) / sizeof (InOutSpec) - 1;
size_t num_workers = (no_parallel
? 1
: std::min(abigail::workers::get_number_of_threads(),
num_tests));
abigail::workers::queue task_queue(num_workers);
bool is_ok = true;
string out_abi_base = string(get_build_dir()) + "/tests/";
string in_elf_base = string(abigail::tests::get_src_dir()) + "/tests/";
string in_abi_base = in_elf_base;
for (InOutSpec *s = in_out_specs; s->in_elf_path; ++s)
{
test_task_sptr t(new test_task(*s, out_abi_base,
in_elf_base,
in_abi_base));
ABG_ASSERT(task_queue.schedule_task(t));
}
/// Wait for all worker threads to finish their job, and wind down.
task_queue.wait_for_workers_to_complete();
// Now walk the results and print whatever error messages need to be
// printed.
const vector<abigail::workers::task_sptr>& completed_tasks =
task_queue.get_completed_tasks();
ABG_ASSERT(completed_tasks.size() == num_tests);
for (vector<abigail::workers::task_sptr>::const_iterator ti =
completed_tasks.begin();
ti != completed_tasks.end();
++ti)
{
test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
if (!t->is_ok)
{
is_ok = false;
if (!t->error_message.empty())
cerr << t->error_message << '\n';
}
}
return !is_ok;
}