libabigail/tests/test-read-dwarf.cc

307 lines
8.7 KiB
C++
Raw Normal View History

// -*- Mode: C++ -*-
//
Use worker threads pattern to speed up some tests We are going to need to speed up more and more tests, and coding directly with libpthread for that can be tedious and bug-prone. So I devised an implementation for the worker threads design pattern instead, and used it to speed up some tests. * include/Makefile.am: Add the new abg-workers.h to source distribution. * include/abg-workers.h: New file. * src/Makefile.am: Add the new abg-worker.cc to source distribution. * src/abg-workers.cc: New file. * tests/test-utils.cc: Update copyright. Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. Make that const char reside in thread local storage, so that two concurrent threads can safely call these functions in parallel, without any race. * tests/test-utils.h: Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. * tests/test-abicompat.cc: Update copyright. Adjust for get_src_dir() and get_build_dir() change. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-diff-dwarf-abixml.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-pkg.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-types-stability.cc: Likewise. Use the new task queue type to run these tests in parallel. * tests/test-diff-filter.cc: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2016-01-15 12:34:16 +00:00
// Copyright (C) 2013-2016 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 <unistd.h>
#include <pthread.h>
#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;
using abigail::dwarf_reader::read_corpus_from_elf;
/// 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"
},
Initial support for DW_TAG_partial_unit * src/abg-dwarf-reader.cc (read_context::cur_tu_die_): New member. (read_context::read_context): Initialize the new member. (read_context::cur_tu_die): New accessors. (find_last_import_unit_point_before_die): New static function. (get_parent_die): Take a logical current die offset parameter. If the die we want the parent for is a partial unit, then find the last DW_TAG_imported_unit that imports that partial unit before the logical current die and return the parent of that DW_TAG_imported_unit die. (get_scope_for_die): Take a logical current die offset parameter. Adjust. (build_translation_unit_and_add_to_ir): Set/unset the current translation unit DIE in the context. Adjust. (build_namespace_decl_and_add_to_ir) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_typedef_type) (build_var_decl, build_function_decl, build_ir_node_from_die): Take a logical current die offset parameter. Adjust. (build_corpus): Accept that we can have DIE that are not DW_TAG_compile_unit at the top level, because, well, we can now have DW_TAG_partial_unit too. * tests/data/test-read-dwarf/test2-{0,1}.cc: New test source files. * tests/data/test-read-dwarf/test2.h: Likewise. * tests/data/test-read-dwarf/test2.so: New input binary to read. * tests/data/test-read-dwarf/test2.so.abi: New reference test to compare against. * tests/test-read-dwarf.cc: Adjust to launch the new test. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2014-05-19 15:26:40 +00:00
{
"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"
},
Support C and C++ array type. * include/abg-comparison.h (array_diff): Declare new class. (array_diff_sptr): Shared pointer to type array_diff. (compute_diff): Overload the function to take type array_diff_sptr as the first two arguments. * include/abg-fwd.h (array_type_def): Declare new class. (subrange_type): Likewise. (is_array_def): Declare new function. * include/abg-ir.h (array_type_def_sptr): Shared pointer to type array_type_def. (array_type_def): Declare new class. (ir_node_visitor::visit): Declare a new virtual function taking a pointer to type array_type_def as an argument. * src/abg-comparison.cc (compute_diff_for_types): Add try_to_diff for two instances of type array_type_def. (array_diff::priv): declare struct for holding private members of type array_diff. (array_diff::array_diff): Define constructor. (array_diff::{first,second}_array):Define new member functions. (array_diff::element_type_diff): Likewise. (array_diff::{length,report,traverse}): Likewise. (compute_diff): Define function overloaded in include/abg-comparison.h. * src/abg-dwarf-reader.cc (build_array_type): Define new function. Handle DW_TAG_array_type and DW_TAG_subrange type. (build_ir_node_from_die): Amend case DW_TAG_array_type with a call to build_array_type. * src/abg-hash.cc (array_type_def::hash): Declare new struct. (type_base::dynamic_hash::operator()): Attempt to dynamic_cast the argument to type array_type_def as well. (array_type_def::hash): Declare new struct. * src/abg-ir.cc (array_type_def::array_type_def): Define constructors. (array_type_def::priv): declare struct for holding private members of type array_type_def. (array_type_def::operator==(const decl_base&): Define new operator. (array_type_def::operator==(const type_base&): Likewise. (array_type_def::append_subrange{,s}): Define new functions. (array_type_def::{set,get}_size_in_bits): Likewise. (array_type_def::get_dimension_count): Likewise. (array_type_def::get_qualified_name): Likewise. (array_type_def::get_pretty_representation): Likewise. (array_type_def::get_subrange_representation): Likewise. (array_type_def::traverse): Likewise. (array_type_def::get_{element_type,location,subranges}): Likewise. (array_type_def::is_infinite): Likewise. (array_type_def::~array_type_def): Define destructor. (ir_node_visitor::visit): Define function, taking pointer to array_type_def as an argument. * src/abg-reader.cc (map_id_and_node): Check if node is an array. (is_array_def): Check if object is an array. (handle_element_node): Handle array_type_def as well. (build_subrange_type): Define new function. (build_array_type_def): Likewise. (build_type): Build type array_type_def as well. (build_type_composition): Likewise. (handle_array_type_def): Define new function. * src/abg-writer.cc: (write_decl): Output arrays as well. (write_member_type): Likewise. (write_type_composition): Likewise. (write_array_type_def): Define new function. * tests/data/test-diff-dwarf/test{10,11}-v{0,1}.{cc,o}: New test source files * tests/data/test-diff-dwarf/test{10,11}-report.txt: Likewise. * tests/data/test-diff-dwarf/test10-report.txt: New test input. * tests/data/test-read-dwarf/test7.cc: New test source file. * tests/data/test-read-dwarf/test7.so: New input binary to read. * tests/data/test-read-dwarf/test7.so.abi: New reference test to compare against. * tests/data/test-read-write/test25.xml: New test source file. * tests/test-diff-dwarf.cc: Adjust to launch the new test. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * test/Makefile.am: Add the new test inputs to the source distribution. Signed-off-by: Ondrej Oprala <ooprala@redhat.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2014-08-18 09:56:43 +00:00
{
"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"
},
Bug 18818 - abidw aborts on a class with a non-complete base class On some binaries with debug info emitted by "Ubuntu clang version 3.6.0-2ubuntu1" and "GNU C++ 4.9.2" (as the value of the DW_AT_producer property), it seems some classes can have a base class that is not complete. E.g, the debug info (that I have extracted using the command eu-readelf --debug-dump=info <the-binary-attached-to-the-bug>) has these relevant pieces: [...] [ 5ff7] class_type containing_type (ref4) [ 7485] name (strp) "system_error" byte_size (data1) 40 decl_file (data1) 46 decl_line (data1) 22 [ 6003] inheritance type (ref4) [ 7480] [...] Here, we are looking at the type system_error (actually boost::system::system_error) that inherits the type which DIE is referred to as offset '7480'. Then the definition of the DIE at offset 7480 is: [...] [ 7480] class_type name (strp) "runtime_error" declaration (flag_present) [ 7485] class_type name (strp) "exception" declaration (flag_present) [...] You can see that the type "runtime_error" (actually std::runtime_error) has the flag DW_AT_declaration set, marking it as a declaration (with no definition yet). And no other DIE in the same translation unit (src/third_party/boost-1.56.0/libs/filesystem/src/codecvt_error_category.cpp) or in the same DSO provides the definition for that declaration. I believe this is ill-formed. A base class should be defined and have a layout completed expressed and accessible from the translation unit it's used in. The patch I am proposing detects that the base class is still incomplete when we finish loading the current binary. In that case, the base class is made complete with a size of 1. Meaning it's an empty class (with no data member and no base class). This works as a viable work-around *if* the producer only omitted definitions for empty classes. We'll need to fix the producers eventually. * src/abg-dwarf-reader.cc (read_context::decl_only_classes_to_force_defined_map_): New data member. (read_context::declaration_only_classes_to_force_defined): New accessors. (read_context::schedule_declaration_only_class_for_forced_resolution): New member function. (build_class_type_and_add_to_ir): If a base class is a declaration-only class then mark it as needing to be force-defined *if* it's still not defined at the end of the abi corpus loading. (read_context::resolve_declaration_only_classes): If declaration-only classes that need to force-defined are present and not defined (when we reach the end of the ABI corpus) then force-define them as empty classes. * tests/data/test-read-dwarf/test10-pr18818-gcc.so: New test binary input file. This comes from a user binary submitted to bug https://sourceware.org/bugzilla/show_bug.cgi?id=18818. The original URL to the binary is https://sourceware.org/bugzilla/attachment.cgi?id=8518. * tests/data/test-read-dwarf/test9-pr18818-clang.so: New binary input file. This comes from the same bug report as above. The original URL to the binary is https://sourceware.org/bugzilla/attachment.cgi?id=8511. * tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: New reference output file. * tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Likewise. * tests/data/Makefile.am: Add the new files above to the source distribution. * tests/test-read-dwarf.cc (in_out_specs): Add the test inputs above the set of tests input this harness has to run over. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-08-12 21:55:18 +00:00
{
"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",
Bug 18893 - type degradation from dwarf to abixml on libGLU.so abidiff-ing libGLU.so against the result of 'abidw libGLU.so' does not yield the empty set. This is because hashing certain types when they are read (de-serialized) from DWARF doesn't give the same result as when they are de-serialized from abixml. I call this type degradation. And it leads to spurious comparison differences. This is due to several issues. 1/ The logical link between a class declaration and its definition -- that is built when reading types from DWARF is not preserved in abixml. So, for example, when a class S refers to itself via a pointer to its declaration, that type might hash differently when read from DWARF and when read from abixml. When read from abixml it's a pointer to S itself. But then that 'self' can be a copy of S that is defined in another file because abixml doesn't enforce the One Definition Rule from C++ either. 2/ As the result of hashing is kept in a cache for var_decl and function_decl, hashing those decl before their types are completely built caches a value that becomes wrong when their type become completely built. 3/ In DWARF, a class which has a virtual member function can still be considered as being declaration-only. And its definition can come later in the DWARF info. Our DWARF reader removes the "declaration-only" flag from a class as soon as it sees virtual member functions in that class; that makes us consider that class as a definition. And then later when we read the real definition of the class we have two classes of the same name, with different layouts/size in the system. This leads to spurious comparison differences too. This patch addresses issues 1, 2 and 3. * src/abg-dwarf-reader.cc (build_class_type_and_add_to_ir): Do not consider that virtual member functions disqualify a class from being declaration-only. * src/abg-hash.cc (var_decl::hash::operator()): Do not cache the result of hashing before we are done building the type of the var_decl. (function_decl::hash::operator()): Likewise, do not cache the result of hashing before we are done building the type of the function_decl. * src/abg-reader.cc (build_class_decl): Build the link between a class declaration and its definition. If there are several definitions of a class in the corpus, keep just one. * src/abg-writer.cc (write_class_is_declaration_only): Emit the link between a class declaration and its definition. (write_class_decl): Emit a class declaration even if it has a definition. The definition is going to be emitted separately. * tests/data/test-read-dwarf/test14-pr18893.so: New binary test input. * tests/data/test-read-dwarf/test14-pr18893.so.abi: New test reference output. * tests/data/Makefile.am: Add the new test input files to source distribution. * tests/test-read-dwarf.cc (in_out_specs): Run the new tests. * tests/data/test-abidiff/test-PR18791-report0.txt: Adjust. * tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Likewise. * tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: Likewise. * tests/data/test-read-dwarf/test11-pr18828.so.abi: Likewise. * tests/data/test-read-dwarf/test12-pr18844.so.abi: Likewise. * tests/data/test-read-dwarf/test13-pr18894.so.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-08-30 14:19:50 +00:00
},
{
Bug 18893 - type degradation from dwarf to abixml on libGLU.so abidiff-ing libGLU.so against the result of 'abidw libGLU.so' does not yield the empty set. This is because hashing certain types when they are read (de-serialized) from DWARF doesn't give the same result as when they are de-serialized from abixml. I call this type degradation. And it leads to spurious comparison differences. This is due to several issues. 1/ The logical link between a class declaration and its definition -- that is built when reading types from DWARF is not preserved in abixml. So, for example, when a class S refers to itself via a pointer to its declaration, that type might hash differently when read from DWARF and when read from abixml. When read from abixml it's a pointer to S itself. But then that 'self' can be a copy of S that is defined in another file because abixml doesn't enforce the One Definition Rule from C++ either. 2/ As the result of hashing is kept in a cache for var_decl and function_decl, hashing those decl before their types are completely built caches a value that becomes wrong when their type become completely built. 3/ In DWARF, a class which has a virtual member function can still be considered as being declaration-only. And its definition can come later in the DWARF info. Our DWARF reader removes the "declaration-only" flag from a class as soon as it sees virtual member functions in that class; that makes us consider that class as a definition. And then later when we read the real definition of the class we have two classes of the same name, with different layouts/size in the system. This leads to spurious comparison differences too. This patch addresses issues 1, 2 and 3. * src/abg-dwarf-reader.cc (build_class_type_and_add_to_ir): Do not consider that virtual member functions disqualify a class from being declaration-only. * src/abg-hash.cc (var_decl::hash::operator()): Do not cache the result of hashing before we are done building the type of the var_decl. (function_decl::hash::operator()): Likewise, do not cache the result of hashing before we are done building the type of the function_decl. * src/abg-reader.cc (build_class_decl): Build the link between a class declaration and its definition. If there are several definitions of a class in the corpus, keep just one. * src/abg-writer.cc (write_class_is_declaration_only): Emit the link between a class declaration and its definition. (write_class_decl): Emit a class declaration even if it has a definition. The definition is going to be emitted separately. * tests/data/test-read-dwarf/test14-pr18893.so: New binary test input. * tests/data/test-read-dwarf/test14-pr18893.so.abi: New test reference output. * tests/data/Makefile.am: Add the new test input files to source distribution. * tests/test-read-dwarf.cc (in_out_specs): Run the new tests. * tests/data/test-abidiff/test-PR18791-report0.txt: Adjust. * tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Likewise. * tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: Likewise. * tests/data/test-read-dwarf/test11-pr18828.so.abi: Likewise. * tests/data/test-read-dwarf/test12-pr18844.so.abi: Likewise. * tests/data/test-read-dwarf/test13-pr18894.so.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-08-30 14:19:50 +00:00
"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",
},
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::hash::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::hash::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 11:41:34 +00:00
{
"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",
},
Bug 19037 - Make ABI corpus support several functions with same symbol It turns out that, in DWARF, there can be function template instantiations foo<int>(int) and foo<TypedefOfInt>(TypedefOfInt) which have the same symbol name, if TypedefOfInt is a typedef of int. An ABI corpus retains only one function declaration per symbol name. So in the example of the bug the input DWARF has the two instantiations, but libabigail is just keeping one of the two; so the abixml only has one of the two template instantiations. This patch changes the ABI corpus model so that it represents the fact that there can be several function declarations for a given symbol. The patch then adjust the comparison engine to make it know about this new model. * include/abg-corpus.h (corpus::exported_decls_builder::str_{fn,var}_ptr_map_type): Remove these typedefs from here as they only used internally in abg-corpus.cc. So we move them there instead. * src/abg-corpus.cc (str_fn_ptrs_map_type): New typedef. (str_var_ptr_map_type): Moved the typedef that was in corpus::exported_decls_builder here. (corpus::exported_decls_builder::id_fns_map_): Rename the fns_ data member into this. Make it have a str_fn_ptrs_map_type as a type. (corpus::exported_decls_builder::id_fns_map): Renamed the fns_map() accessor into this one. (corpus::exported_decls_builder::{fn_id_is_in_id_fns_map, fn_is_in_fns}): New member functions. (corpus::exported_decls_builder::fn_is_in_id_fns_map): Rename fn_is_in_map into this. (corpus::exported_decls_builder::add_fn_to_id_fns_map): Rename add_fn_to_map into this. (corpus::exported_decls_builder::add_fn_to_exported): Adjust. (corpus::exported_decls_builder::maybe_add_fn_to_exported_fns): Adjust. * src/abg-comparison.cc (function_decl_diff::report): Emit reports about function name changes (for a given function ID) only if there are sub-type changes to be reported for the function. In that case, do not forget to emit the sub-type changes after the name changes have been reported. (corpus_diff::priv::ensure_lookup_tables_populated): Several functions of the same ID can be removed or added from/to the corpus. * tests/data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so: New test input binary. * tests/data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi: New test output reference. * tests/data/Makefile.am: Add the new test materials to the source distribution. * tests/test-read-dwarf.cc (in_out_specs): Adjust to add the new test inputs above. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-10-06 10:01:20 +00:00
{
"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",
},
Bug 19025 - abixml writer forgets to emit some member types When a member type (a type that is a member of a class) M is referenced by some types emitted by abixml, but the context of M (the class type which M is a member of) is not itself referenced by any ABI artifact, then abixml forgets to emit the context of M and thus M itself. With this patch, when the abixml writer has emitted almost all ABI artifacts for the current translation unit, it looks for types that have been referenced by the emitted ABI artifacts, but that haven't been emitted themselves. It then emits those referenced-but-not-emitted types, and makes sure their contexts are emitted as well. * include/abg-fwd.h (is_namespace): Fix prototype. * src/abg-writer.cc (struct type_ptr_comp_functor): New internal type. (sort_type_ptr_map): New static function. (write_context::m_referenced_types_map): Renamed m_referenced_fntypes_map data member into this. (write_context::get_referenced_types): New member function. (write_context::record_type_as_referenced): Renamed record_fntype_as_referenced member function into this. Adjust. (write_context::type_is_referenced): Renamed fntype_is_referenced into this. (write_context::clear_referenced_types_map): Renamed clear_referenced_fntypes_map member function into this. Adjust. (write_decl_in_scope): New static function. (write_translation_unit): Use it here to emit types that are referenced by other types in the TU, but that are not emitted. Adjust. (write_pointer_type_def, write_reference_type_def) (write_typedef_decl): Record the underlying types referenced by the emitted types as being, well, referenced. * tests/data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so: New test binary input. * tests/data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi: New reference output of the binary input above. * tests/data/Makefile.am: Add the new test material above to the source distribution. * tests/test-read-dwarf.cc (in_out_spec): Add the new test inputs. * tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Adjust. * tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: Likewise. * tests/data/test-read-dwarf/test12-pr18844.so.abi: Likewise. * 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. * tests/data/test-read-dwarf/test16-pr18904.so.abi: Likewise. * tests/data/test-read-dwarf/test17-pr19027.so.abi: Likewise. * tests/data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi: Likewise. * tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-10-08 10:57:04 +00:00
{
"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",
},
Adjust regression tests reference output for the current patch set This is the last patch of a series of patches which aims at fixing bug libabigail/19097. The short titles of the patches of the set are, including this one: Don't canonicalize types not added to their context in abixml reader Support updating a class in the abixml reader Fix emitting of referenced type in abixml writer Use abidw --abidiff in test-read-dwarf.cc Adjust regression tests reference output for the current patch set Below is the cover letter of the last patch of the set. The current patch set needs big reference output adjustments, that we are doing at the end, here. * tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so: New test input binary. * tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi: New test reference output. * tests/data/Makefile.am: Add the new test files above to the source distribution. * tests/test-read-dwarf.cc (in_out_specs): Add the two new test files above to the set of test input files. * tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: Adjust. * tests/data/test-read-dwarf/test12-pr18844.so.abi: Adjust. * tests/data/test-read-dwarf/test13-pr18894.so.abi: Adjust. * tests/data/test-read-dwarf/test14-pr18893.so.abi: Adjust. * tests/data/test-read-dwarf/test15-pr18892.so.abi: Adjust. * tests/data/test-read-dwarf/test16-pr18904.so.abi: Adjust. * tests/data/test-read-dwarf/test17-pr19027.so.abi: Adjust. * tests/data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi: Adjust. * tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi: Adjust. * tests/data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi: Adjust. * tests/data/test-read-dwarf/test21-pr19092.so.abi: Adjust. * tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Adjust. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-10-17 13:03:41 +00:00
{
"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",
},
// This should be the last entry.
{NULL, NULL, NULL}
};
// The global pointer to the testsuite paths.
InOutSpec *iospec = in_out_specs;
// Lock to help atomically increment iospec.
pthread_mutex_t spec_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
// No lock needed here, since is_ok is only ever re-set to false.
bool is_ok = true;
// These prefixes don't change during the program's lifetime, so
// we only get them once.
Use worker threads pattern to speed up some tests We are going to need to speed up more and more tests, and coding directly with libpthread for that can be tedious and bug-prone. So I devised an implementation for the worker threads design pattern instead, and used it to speed up some tests. * include/Makefile.am: Add the new abg-workers.h to source distribution. * include/abg-workers.h: New file. * src/Makefile.am: Add the new abg-worker.cc to source distribution. * src/abg-workers.cc: New file. * tests/test-utils.cc: Update copyright. Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. Make that const char reside in thread local storage, so that two concurrent threads can safely call these functions in parallel, without any race. * tests/test-utils.h: Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. * tests/test-abicompat.cc: Update copyright. Adjust for get_src_dir() and get_build_dir() change. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-diff-dwarf-abixml.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-pkg.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-types-stability.cc: Likewise. Use the new task queue type to run these tests in parallel. * tests/test-diff-filter.cc: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2016-01-15 12:34:16 +00:00
const string out_abi_base = string(get_build_dir()) + "/tests/";
const string in_elf_base = string(abigail::tests::get_src_dir()) + "/tests/";
const string in_abi_base = in_elf_base;
void
handle_in_out_spec(void)
{
string in_elf_path, in_abi_path, out_abi_path;
Introduce the concept of environment There are resources needed by the type system and other artifacts of libabigail. Today, when the life time of those resources need to be greater than all of artifacts of Abigail, then said resources are made global. But then global resources are not great, if anything because they complicate the future use of the library in concurrent computing setups. As I was in the need to add one resource to be used by the type system, I decided to sit down and first overhaul how these long lived resources needed to be handled. And here comes the concept of "environment". An environment is a place where one can put resources that need to live longer than all the other artifacts of the Abigail system. And so, the code that creates Abigail artifacts needs and environment of for said artifacts to use. In other words, artifacts now use an environment. This has interesting and strong implications. We can only compare two artifacts if they use the same environment. This is quite a strong requirement. But then when this requirement is fulfilled, comparing two types amounts to just comparing two pointer values; hash values for types can also be cached. Now *that* is great for speed of comparison, is it not? This patch introduce the concept environment (which is basically a new abigail::ir::environment type), removes the global variables and uses the environment instead. Each ABI artifact (either type or decl) now has a ::get_environment() member function to get its environment. This patch also disables the caching of hash values because the caching must happen only *after* all types have been canonicalized. We were not respecting that requirement until now, and that introduces wrong hash values. A subsequent patch is going to re-introduce hash value caching again, once the infrastructure is in place to set a flag in the environment (hah!) once type canonicalization is done, and then later read that flag when some client code requests a hash value, to know if we should look in the hash value cache or not. The patch obviously changes the output of numerous regression tests (if anything b/c it disables hash value caching) so 'make check' yields regressions. But then, it's only the subsequent patch that updates the tests. * include/abg-ir.h: Adjust note about memory management. (class environment): Declare new class. (translation_unit::translation_unit): Take an environment in parameter. (translation_unit::{g,s}et_environment): Declare new member functions. (type_or_decl_base::{g,s}et_environment): Likewise. (type_or_decl_base::{get_cached_hash_value, set_cached_hash_value}): Change the name of decl_base::peek_hash_value() and decl_base::set_hash() here into these and move them here. (type_or_decl_base::hashing_started): Move decl_base::hashing_started() here. ({g,s}et_environment_for_artifact): Declare new functions. (class decl_base): Move member functions hashing_started(), peek_hash_value() and set_hash() on to the type_or_decl_base base class. (scope_decl::scope_decl): Initialize the virtual member type_or_decl_base(). (type_decl::{get_void_type_decl, get_variadic_parameter_type_decl}): Remove these static member functions. They are now non-static member functions of the new environment type. * src/abg-ir.cc (class environment_setter): New internal class. (get_canonical_types_map): Remove. This now becomes a member function of the environment type. (class usage_watchdog): Remove. (usage_watchdog_{s,w}ptr): Remove these typedefs. (get_usage_watchdog_wptr, ref_usage_watchdog) (maybe_cleanup_type_system_data): Remove these functions. (translation_unit::priv::usage_watchdog_): Remove data member. (translation_unit::priv::env_): New data member. (translation_unit::priv::priv): Take an environment and initialize the new env_ data member. Do not initialize the removed usage_watchdog_. (translation_unit::translation_unit): Take an environment parameter. (translation_unit::get_global_scope): Set the environment of a new global scope. (translation_unit::{g,s}et_environment): New accessors. (translation_unit::bind_function_type_life_time): Set the environment of the function type. (struct environment::priv): New class. (environment::{environment, ~environment, get_canonical_types_map, get_variadic_parameter_type_decl, canonicalization_is_done}): New member functions. (struct type_or_decl_base::priv): New class. (type_or_decl_base::{type_or_decl_base, hashing_started, get_cached_hash_value, set_cached_hash_value, set_environment, get_environment, traverse}): New member functions. ({s,g}get_environment_for_artifact): New functions. (decl_base::priv::{hash_, hashing_started}): Remove. (decl_base::priv::priv): Adjust. (decl_base::decl_base): In the copy constructor, initialize the virtual base type_or_decl_base. Do not initialize hash_ and hashing_started data member that got removed. (decl_base::{hashing_started, peek_hash_value, set_hash}): Remove member functions. (strip_typedef): Set the environment of the new type which has its typedefs stripped off. Adjust the call to type_or_void(). (scope_decl::{add, insert}_member_decl): Set the environment of the new member decl to the environment of its scope. (synthesize_type_from_translation_unit) (synthesize_function_type_from_translation_unit): Set the environment for the newly synthesized type. Adjust calls to type_or_void(). (type_or_void): Take an environment in parameter. Get the void type from the environment. (get_canonical_types_map): Remove. (type_base::get_canonical_type_for): Get the canonical types map from the environment, not from a global variable. (type_decl::{get_void_type_decl, get_variadic_parameter_type_decl}): Remove. (pointer_type_def::pointer_type_def): Adjust call to type_or_void. (reference_type_def::reference_type_def): Likewise. (function_decl::parameter::get_pretty_representation): Get the variadic parameter type decl from the environment. (class_decl::priv::classes_being_compared_): Remove static data member. (class_decl::priv::{mark_as_being_compared, unmark_as_being_compared, comparison_started): Use the "classes being compared" map from the environment. (class_decl::base_spec::get_hash): Adjust. (keep_type_alive): Get the alive types array from the environment) not from a global variable anymore. (get_next_string): Put the counter in thread-local storage. * src/abg-hash.cc (scope_decl::hash::operator()) (function_decl::hash::operator()): Do not handle caching (here). * include/abg-corpus.h (corpus::{g,s}et_environment): Declare new accessors. * src/abg-corpus.cc (corpus::priv::env): New data member. (corpus::priv::priv): Initialize it. (corpus::corpus): Take an environment in parameter. (corpus::{g,s}et_environment): Define new member functions (corpus::add): Set the environment of the newly added translation unit, if it's not set already set. In any case, assert that the translation unit must use the same environment as the corpus. * include/abg-dwarf-reader.h (create_read_context) (read_corpus_from_elf): Take an environment parameter. ({s,g}et_debug_info_root_path, {s,g}et_environment): Declare new functions. * src/abg-dwarf-reader.cc (read_context::{env_, offline_callbacks_}): New data members. (read_context::read_context): Initialize them. (read_context::clear_per_translation_unit_data): Do not touch the void type declaration, it doesn't belong to the translation unit. (read_context::{env, offline_callbacks}): New accessors. (read_context::{create_default_dwfl}): New member function. (read_context::dwfl_handle): Add a setter overload. ({s,g}et_debug_info_root_path): Define new accessors. (create_default_dwfl, create_dwfl_sptr, create_default_dwfl_sptr): Remove these. (build_translation_unit_and_add_to_ir): Adjust to pass the environment to the newly created translation unit. (build_function_decl): Adjust to pass the environment to the created function and parameter types. Get variadic parameter type node from the current environment, not from a global variable. And do not try to canonicalize function types here. (read_debug_info_into_corpus): Set the environment of the newly created corpus. (build_ir_node_for_void_type): Get the void type node from the current environment, rather than from a global variable. (create_read_context): Take the environment in parameter. Create the default dwarf front end library handle using the new member function of the read context. Set the current environment used by the reader. (read_corpus_from_elf): Take an environment in parameter. Overhaul. This is now simpler. (has_alt_debug_info): Adjust the call to create_read_context() to make it pass an empty environment. * include/abg-fwd.h (class environment): Forward declare. * include/abg-reader.h (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream) (read_corpus_from_native_xml): Take an environment in parameter. * src/abg-reader.cc (read_context::m_env): New data member. (read_context::read_context): Initialize it. (read_context::{get_environment, set_environment}): New data member. (read_translation_unit): Set environment of the new translation unit. (read_corpus_from_input): Set the environment of the new corpus. (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream, read_corpus_from_native_xml): Take an environment in parameter. (build_function_parameter): Get variadic parameter type from the environment. * src/abg-comparison.cc (compute_diff): Add asserts in all the overloads to ensure that the artifact being compared come from the same environment. * tests/print-diff-tree.cc (main): Create an env for the ABI artifacts to use. * tests/test-abidiff.cc (main): Likewise. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-ir-walker.cc (main): Likewise. * tests/test-read-dwarf.cc (main): Likewise. * tests/test-read-write.cc (main): Likewise. * tools/abicompat.cc (main): Likewise. * tools/abidiff.cc (main): Likewise. * tools/abidw.cc (main): Likewise. * tools/abilint.cc (main): Likewise. * tools/abipkgdiff.cc (main): Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-09-07 20:27:50 +00:00
abigail::ir::environment_sptr env;
InOutSpec *s;
while (true)
{
pthread_mutex_lock(&spec_lock);
if (iospec->in_elf_path)
s = iospec++;
else
s = NULL;
pthread_mutex_unlock(&spec_lock);
if (!s)
pthread_exit(NULL);
in_elf_path = in_elf_base + s->in_elf_path;
env.reset(new abigail::ir::environment);
abigail::dwarf_reader::status status =
abigail::dwarf_reader::STATUS_UNKNOWN;
abigail::corpus_sptr corp =
read_corpus_from_elf(in_elf_path,
/*debug_info_root_path=*/0,
env.get(),
/*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 = out_abi_base + s->out_abi_path;
if (!abigail::tools_utils::ensure_parent_dir_created(out_abi_path))
{
cerr << "Could not create parent directory for " << out_abi_path;
is_ok = false;
exit(1);
}
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;
}
pthread_mutex_lock(&write_lock);
is_ok =
abigail::xml_writer::write_corpus_to_native_xml(corp,
/*indent=*/0,
of);
pthread_mutex_unlock(&write_lock);
of.close();
Use worker threads pattern to speed up some tests We are going to need to speed up more and more tests, and coding directly with libpthread for that can be tedious and bug-prone. So I devised an implementation for the worker threads design pattern instead, and used it to speed up some tests. * include/Makefile.am: Add the new abg-workers.h to source distribution. * include/abg-workers.h: New file. * src/Makefile.am: Add the new abg-worker.cc to source distribution. * src/abg-workers.cc: New file. * tests/test-utils.cc: Update copyright. Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. Make that const char reside in thread local storage, so that two concurrent threads can safely call these functions in parallel, without any race. * tests/test-utils.h: Make get_src_dir() and get_build_dir() return a const char*, as opposed to returning a string. * tests/test-abicompat.cc: Update copyright. Adjust for get_src_dir() and get_build_dir() change. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-diff-dwarf-abixml.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-pkg.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-types-stability.cc: Likewise. Use the new task queue type to run these tests in parallel. * tests/test-diff-filter.cc: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2016-01-15 12:34:16 +00:00
string abidw = string(get_build_dir()) + "/tools/abidw";
string cmd = abidw + " --abidiff " + in_elf_path;
if (system(cmd.c_str()))
{
cerr << "ABIs differ:\n"
<< in_elf_path
<< "\nand:\n"
<< out_abi_path
<< "\n";
is_ok = false;
}
in_abi_path = in_abi_base + s->in_abi_path;
cmd = "diff -u " + in_abi_path + " " + out_abi_path;
if (system(cmd.c_str()))
is_ok = false;
}
}
int
main(int argc, char *argv[])
{
// Number of currently online processors in the system.
size_t nprocs = sysconf(_SC_NPROCESSORS_ONLN);
// All the pthread_ts we've created.
pthread_t *pthr = new pthread_t[nprocs];
if (argc == 2)
{
if (argv[1] == string("--no-parallel"))
nprocs = 1;
else
{
cerr << "unrecognized option\n";
cerr << "usage: " << argv[0] << " [--no-parallel]\n" ;
return 1;
}
}
assert(nprocs >= 1);
for (size_t i = 0; i < nprocs; ++i)
pthread_create(&pthr[i], NULL,
(void*(*)(void*))handle_in_out_spec,
NULL);
for (size_t i = 0; i < nprocs; ++i)
pthread_join(pthr[i], NULL);
delete pthr;
return !is_ok;
}