libabigail/tests/test-read-dwarf.cc
Dodji Seketeli 3b6bada297 More type degradation fixes (from DWARF to abixml)
The series of fixes to make

 "abidw foo > foo.abi && abidiff foo foo.abi"
work continues.

On a binary submitted as part of bug 18904, I am still seeing type
degradation.  This patch addresses the different cases of degradation
that are happening.

	* include/abg-fwd.h (get_type_scope): Declare new function.
	* src/abg-hash.cc (var_decl:#️⃣:operator()): Do not cache the
	hash because that can alter the hash computing of a larger type
	which embeds a var decl as a member declaration.  This is
	especially true if the var decl indirectly references the larger
	type.  The only way to cache the value of a var decl would be to
	wait after all canonical types have been computed.  We'd then seal
	all types.  After that sealing happens, we can cache var decls
	starting from the top-level ones.
	(function_decl:#️⃣:operator()): Likewise.
	* src/abg-ir.cc (get_type_scope): Define new functions.
	* src/abg-reader.cc (read_is_declaration_only): Declare this
	function earlier.
	(typedef const_types_map_it): Adjust this to make it point to a
	map of string and vector of types, as opposed to a map to string
	and type as it was before.
	(typedef types_map_it): New typedef.
	(read_context::map_id_and_node): Map a type id to the last
	xmlNodePtr that represent a *declaration*.  That gives more leeway
	to the declaration resolution code to choose the right definition
	later.  Otherwise, there are cases where the wrong definition.  By
	wrong definition, I mean a definition that is different from the
	one chosen by the DWARF reading code, for a given declaration.
	Basically for a given ABI corpus, a type declaration resolve to
	the first definition seen in the corpus.
	(read_context::get_all_type_decls): Define new member function.
	(read_context::types_equal): Use qualified names only if both
	types have a scope.
	(read_context::key_type_decl): Now a given ID is associated to
	*all* the declarations and definition that have that ID.
	(read_translation_unit_from_input): Make sure the current corpus
	node points to the right node.
	(build_class_decl): Resolve class declarations to the first
	definition seen in the corpus.  Key a type decl before reading its
	members as a reading a member can request the current decl.  No
	need to try and canonicalize a member type, as build_class_decl()
	does that already.
	* tests/data/test-read-dwarf/test16-pr18904.so: New test binary
	input.
	* tests/data/test-read-dwarf/test16-pr18904.so.abi: New test
	output reference.
	* tests/test-read-dwarf.cc: Run the test above.
	* tests/data/Makefile.am: Add the new test input to source
	distribution.
	* tests/data/test-abidiff/test-PR18791-report0.txt: Adjust.
	* tests/data/test-read-dwarf/test13-pr18894.so.abi: Likewise.
	* tests/data/test-read-dwarf/test14-pr18893.so.abi: Likewise.
	* tests/data/test-read-dwarf/test15-pr18892.so.abi: Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-09-02 14:15:58 +02:00

232 lines
6.4 KiB
C++

// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2015 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 <cstdlib>
#include "abg-ir.h"
#include "abg-dwarf-reader.h"
#include "abg-writer.h"
#include "abg-tools-utils.h"
#include "test-utils.h"
using std::string;
using std::ofstream;
using std::cerr;
using abigail::tests::get_build_dir;
/// 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_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",
},
// This should be the last entry.
{NULL, NULL, NULL}
};
int
main()
{
unsigned result = 1;
bool is_ok = true;
string in_elf_path, in_abi_path, out_abi_path;
abigail::corpus_sptr corp;
for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s)
{
in_elf_path = abigail::tests::get_src_dir() + "/tests/" + s->in_elf_path;
abigail::dwarf_reader::status status =
abigail::dwarf_reader::STATUS_UNKNOWN;
corp = abigail::dwarf_reader::read_corpus_from_elf(in_elf_path,
/*debug_info_root_path=*/0,
/*load_all_types=*/false,
status);
if (!corp)
{
cerr << "failed to read " << in_elf_path << "\n";
is_ok = false;
continue;
}
corp->set_path(s->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 = get_build_dir() + "/tests/" + s->out_abi_path;
if (!abigail::tools_utils::ensure_parent_dir_created(out_abi_path))
{
cerr << "Could not create parent director for " << out_abi_path;
is_ok = false;
return result;
}
ofstream of(out_abi_path.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
cerr << "failed to read " << out_abi_path << "\n";
is_ok = false;
continue;
}
bool r =
abigail::xml_writer::write_corpus_to_native_xml(corp,
/*indent=*/0,
of);
is_ok = (is_ok && r);
of.close();
string abilint = get_build_dir() + "/tools/abilint";
abilint += " --noout";
string cmd = abilint + " " + out_abi_path;
if (system(cmd.c_str()))
{
cerr << "output file doesn't pass abilint: " << out_abi_path << "\n";
r = false;
}
is_ok = (is_ok && r);
in_elf_path = abigail::tests::get_src_dir() + "/tests/" + s->in_elf_path;
string abidiff = get_build_dir() + "/tools/abidiff";
cmd = abidiff + " --no-architecture " + in_elf_path + " " + out_abi_path;
r = true;
if (system(cmd.c_str()))
{
cerr << "ABIs differ:\n"
<< in_elf_path
<< "\nand:\n"
<< out_abi_path
<< "\n";
r = false;
}
is_ok = (is_ok && r);
in_abi_path = abigail::tests::get_src_dir() + "/tests/" + s->in_abi_path;
cmd = "diff -u " + in_abi_path + " " + out_abi_path;
r = true;
if (system(cmd.c_str()))
r = false;
is_ok = (is_ok && r);
}
return !is_ok;
}