libabigail/tests/test-ir-walker.cc

181 lines
4.1 KiB
C++
Raw Normal View History

Re-license the project to Apache v2 With LLVM Exception Thanks to the previous work done, changing the license is just a matter of changing the SPDX identifer from "LGPL-3.0-or-later" to "Apache-2.0 WITH LLVM-exception". Note that for the abigail.m4, tests/test-dot.cc and tests/test-svg.cc the change was from "GPL-3.0-or-later WITH GCC-exception-3.1" to "Apache-2.0 WITH LLVM-exception". include/abg-cxx-compat.h was changed from "LGPL-2.0-or-later" to "Apache-2.0 WITH LLVM-exception". Source code of programs (as opposed to source code of the library) where generally licensed under GPL-3.0-or-later; they are also now licensed "Apache-2.0 WITH LLVM-exception". This is what this patch does. * abigail.m4: Change the SPDX identifier from "GPL-3.0-or-later WITH GCC-exception-3.1" to "Apache-2.0 WITH LLVM-exception" * include/abg-cxx-compat.h: Change the SPDX identifier from "LGPL-2.0-or-later" to "Apache-2.0 WITH LLVM-exception". * .clang-format: Change the SPDX identifier from "LGPL-3.0-or-later" to "Apache-2.0 WITH LLVM-exception". * Makefile.am: Likewise. * bash-completion/Makefile.am: Likewise. * bash-completion/abicompat: Likewise. * bash-completion/abidiff: Likewise. * bash-completion/abidw: Likewise. * bash-completion/abilint: Likewise. * bash-completion/abinilint: Likewise. * bash-completion/abipkgdiff: Likewise. * bash-completion/abisym: Likewise. * bash-completion/fedabipkgdiff: Likewise. * configure.ac: Likewise. * default.abignore: Likewise. * doc/Makefile.am: Likewise. * doc/api/libabigail.doxy: Likewise. * doc/manuals/Makefile.am: Likewise. * doc/website/libabigail-website.doxy: Likewise. * include/Makefile.am: Likewise. * include/abg-comp-filter.h: Likewise. * include/abg-comparison.h: Likewise. * include/abg-config.h: Likewise. * include/abg-corpus.h: Likewise. * include/abg-diff-utils.h: Likewise. * include/abg-dwarf-reader.h: Likewise. * include/abg-fwd.h: Likewise. * include/abg-hash.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-reader.h: Likewise. * include/abg-regex.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-traverse.h: Likewise. * include/abg-version.h.in: Likewise. * include/abg-viz-common.h: Likewise. * include/abg-viz-dot.h: Likewise. * include/abg-viz-svg.h: Likewise. * include/abg-workers.h: Likewise. * include/abg-writer.h: Likewise. * scripts/dot_to_png.sh: Likewise. * scripts/dot_to_svg.sh: Likewise. * scripts/make-verbose.sh: Likewise. * scripts/svg_to_plain_svg.sh: Likewise. * scripts/svg_to_png_and_pdf.sh: Likewise. * src/Makefile.am: Likewise. * src/abg-comp-filter.cc: Likewise. * src/abg-comparison-priv.h: Likewise. * src/abg-comparison.cc: Likewise. * src/abg-config.cc: Likewise. * src/abg-corpus-priv.h: Likewise. * src/abg-corpus.cc: Likewise. * src/abg-default-reporter.cc: Likewise. * src/abg-diff-utils.cc: Likewise. * src/abg-dwarf-reader.cc: Likewise. * src/abg-elf-helpers.cc: Likewise. * src/abg-elf-helpers.h: Likewise. * src/abg-hash.cc: Likewise. * src/abg-ini.cc: Likewise. * src/abg-internal.h: Likewise. * src/abg-ir-priv.h: Likewise. * src/abg-ir.cc: Likewise. * src/abg-leaf-reporter.cc: Likewise. * src/abg-libxml-utils.cc: Likewise. * src/abg-libzip-utils.cc: Likewise. * src/abg-reader.cc: Likewise. * src/abg-regex.cc: Likewise. * src/abg-reporter-priv.cc: Likewise. * src/abg-reporter-priv.h: Likewise. * src/abg-suppression-priv.h: Likewise. * src/abg-suppression.cc: Likewise. * src/abg-tools-utils.cc: Likewise. * src/abg-traverse.cc: Likewise. * src/abg-viz-common.cc: Likewise. * src/abg-viz-dot.cc: Likewise. * src/abg-viz-svg.cc: Likewise. * src/abg-workers.cc: Likewise. * src/abg-writer.cc: Likewise. * tests/Makefile.am: Likewise. * tests/data/Makefile.am: Likewise. * tests/lib/catch.cc: Likewise. * tests/mockfedabipkgdiff.in: Likewise. * tests/print-diff-tree.cc: Likewise. * tests/runtestcanonicalizetypes.sh.in: Likewise. * tests/runtestdefaultsupprs.py.in: Likewise. * tests/runtestdefaultsupprspy3.sh.in: Likewise. * tests/runtestfedabipkgdiff.py.in: Likewise. * tests/runtestfedabipkgdiffpy3.sh.in: Likewise. * tests/test-abicompat.cc: Likewise. * tests/test-abidiff-exit.cc: Likewise. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-annotate.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-cxx-compat.cc: Likewise. * tests/test-diff-dwarf-abixml.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-filter.cc: Likewise. * tests/test-diff-pkg.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-diff2.cc: Likewise. * tests/test-dot.cc: Change the SPDX identifier from "GPL-3.0-or-later WITH GCC-exception-3.1" to "Apache-2.0 WITH LLVM-exception" * tests/test-elf-helpers.cc: Change the SPDX identifier from "LGPL-3.0-or-later" to "Apache-2.0 WITH LLVM-exception" * tests/test-ini.cc: Likewise. * tests/test-ir-walker.cc: Likewise. * tests/test-kmi-whitelist.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-svg.cc: Change the SPDX identifier from "GPL-3.0-or-later WITH GCC-exception-3.1" to "Apache-2.0 WITH LLVM-exception". * tests/test-symtab.cc: Change the SPDX identifier from "LGPL-3.0-or-later" to "Apache-2.0 WITH LLVM-exception" * tests/test-tools-utils.cc: Likewise. * tests/test-types-stability.cc: Likewise. * tests/test-utils.cc: Likewise. * tests/test-utils.h: Likewise. * tests/test-write-read-archive.cc: Likewise. * tests/update-test-output.py: Likewise. * tools/Makefile.am: Likewise. * tools/abiar.cc: Likewise. * tools/abicompat.cc: Likewise. * tools/abidiff.cc: Likewise. * tools/abidw.cc: Likewise. * tools/abilint.cc: Likewise. * tools/abipkgdiff.cc: Likewise. * tools/abisym.cc: Likewise. * tools/binilint.cc: Likewise. * tools/fedabipkgdiff: Likewise. * tools/kmidiff.cc: Likewise. * update-copyright.sh: Likewise. Signed-off-by: Benjamin De Kosnik <bkoz@gnu.org> Signed-off-by: Ben Woodard <woodard@redhat.com> Signed-off-by: Chenxiong Qi <cqi@redhat.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com> Signed-off-by: Giuliano Procida <gprocida@google.com> Signed-off-by: Jan Engelhardt <jengelh@inai.de> Signed-off-by: Jessica Yu <jeyu@kernel.org> Signed-off-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Mark Wielaard <mark@klomp.org> Signed-off-by: Matthias Klose <doko@ubuntu.com> Signed-off-by: Matthias Maennich <maennich@google.com> Signed-off-by: Ondrej Oprala <ondrej.oprala@gmail.com> Signed-off-by: Roland McGrath <roland@hack.frob.com> Signed-off-by: Sinny Kumari <ksinny@gmail.com> Signed-off-by: Slava Barinov <v.barinov@samsung.com>
2020-05-29 14:26:04 +00:00
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
Update Copyright for year 2024 * update-copyright.sh: Update the date in this script. Running the script then yields the changes below. * include/abg-btf-reader.h: Update copyright year as a result of running update-copyright.sh above. * include/abg-comp-filter.h: Likewise. * include/abg-comparison.h: Likewise. * include/abg-config.h: Likewise. * include/abg-corpus.h: Likewise. * include/abg-ctf-reader.h: Likewise. * include/abg-cxx-compat.h: Likewise. * include/abg-diff-utils.h: Likewise. * include/abg-dwarf-reader.h: Likewise. * include/abg-elf-based-reader.h: Likewise. * include/abg-elf-reader.h: Likewise. * include/abg-fe-iface.h: Likewise. * include/abg-fwd.h: Likewise. * include/abg-hash.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-reader.h: Likewise. * include/abg-regex.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-traverse.h: Likewise. * include/abg-viz-common.h: Likewise. * include/abg-viz-dot.h: Likewise. * include/abg-viz-svg.h: Likewise. * include/abg-workers.h: Likewise. * include/abg-writer.h: Likewise. * src/abg-btf-reader.cc: Likewise. * src/abg-comp-filter.cc: Likewise. * src/abg-comparison-priv.h: Likewise. * src/abg-comparison.cc: Likewise. * src/abg-config.cc: Likewise. * src/abg-corpus-priv.h: Likewise. * src/abg-corpus.cc: Likewise. * src/abg-ctf-reader.cc: Likewise. * src/abg-default-reporter.cc: Likewise. * src/abg-diff-utils.cc: Likewise. * src/abg-dwarf-reader.cc: Likewise. * src/abg-elf-based-reader.cc: Likewise. * src/abg-elf-helpers.cc: Likewise. * src/abg-elf-helpers.h: Likewise. * src/abg-elf-reader.cc: Likewise. * src/abg-fe-iface.cc: Likewise. * src/abg-hash.cc: Likewise. * src/abg-ini.cc: Likewise. * src/abg-internal.h: Likewise. * src/abg-ir-priv.h: Likewise. * src/abg-ir.cc: Likewise. * src/abg-leaf-reporter.cc: Likewise. * src/abg-libxml-utils.cc: Likewise. * src/abg-reader.cc: Likewise. * src/abg-regex.cc: Likewise. * src/abg-reporter-priv.cc: Likewise. * src/abg-reporter-priv.h: Likewise. * src/abg-suppression-priv.h: Likewise. * src/abg-suppression.cc: Likewise. * src/abg-symtab-reader.cc: Likewise. * src/abg-symtab-reader.h: Likewise. * src/abg-tools-utils.cc: Likewise. * src/abg-traverse.cc: Likewise. * src/abg-viz-common.cc: Likewise. * src/abg-viz-dot.cc: Likewise. * src/abg-viz-svg.cc: Likewise. * src/abg-workers.cc: Likewise. * src/abg-writer.cc: Likewise. * tests/print-diff-tree.cc: Likewise. * tests/test-abicompat.cc: Likewise. * tests/test-abidiff-exit.cc: Likewise. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-cxx-compat.cc: Likewise. * tests/test-diff-dwarf-abixml.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-filter.cc: Likewise. * tests/test-diff-pkg.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-diff2.cc: Likewise. * tests/test-dot.cc: Likewise. * tests/test-elf-helpers.cc: Likewise. * tests/test-ini.cc: Likewise. * tests/test-ir-walker.cc: Likewise. * tests/test-kmi-whitelist.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-btf.cc: Likewise. * tests/test-read-ctf.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-svg.cc: Likewise. * tests/test-symtab-reader.cc: Likewise. * tests/test-symtab.cc: Likewise. * tests/test-tools-utils.cc: Likewise. * tests/test-types-stability.cc: Likewise. * tests/test-utils.cc: Likewise. * tests/test-utils.h: Likewise. * tools/abicompat.cc: Likewise. * tools/abidiff.cc: Likewise. * tools/abidw.cc: Likewise. * tools/abilint.cc: Likewise. * tools/abipkgdiff.cc: Likewise. * tools/abisym.cc: Likewise. * tools/binilint.cc: Likewise. * tools/fedabipkgdiff: Likewise. * tools/kmidiff.cc: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2024-04-26 13:29:50 +00:00
// Copyright (C) 2013-2024 Red Hat, Inc.
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "abg-dwarf-reader.h"
#include "test-utils.h"
using std::string;
using std::ofstream;
using std::cerr;
using std::cout;
Make Front Ends first class citizens This patch is a reorganization of the code to better support the need for having several different front-ends. In the libabigail pipeline of operation, a front-end is the part of the pipeline that analyses the input file. For instance, to analyse an ELF file, there is going to be one front-end. To analyse an ABIXML file, there is going to be another front-end. The middle-end is the part of the pipeline that interacts with the internal representation of ABIs. The middle-end knows how to analyse, compare ABI corpora provide an internal representation of the comparison result and analyse it as well. The back-end would be the part of the front-end that knows how to serialize internal representations of ABIs and ABI comparison results. One could thus imagine a front-end that understands the DWARF debug info format embedded in an ELF file. Another front-end would be dedicated to the CTF debug info format, and so on. Front-ends can share capabilities. For instance, DWARF and CTF front-ends are ELF based front end. As such, they share capabilities to understand the ELF format. They don't share much with the ABIXML front-end, however, as it's based on XML, which has almost nothing in common with ELF. To support this organization of concepts, this patch introduces a new hierarchy of types in the form of C++ classes. All front-ends implements the "Front End Interface". As such, they all inherit the abigail::fe_iface class. That class provides properties and behaviours that are shared by all front-ends that libabigail supports today. Namely, that class provides access to some of the options that are relevant to operating the front-end, to the ABI corpus or corpus group being constructed and to the suppression specifications that are considered. It also provides an abstract interface to perform the actual loading of the ABI corpus. That abstract interface has to be implemented by every single concrete front-end that is provided in libabigail. Then, there is the "ELF Reader" front-end. Its class name is abigail::elf::reader. It inherits the abigail::fe_iface class and implements the fe_iface::load_corpus() so that the ELF properties of the ELF file be loaded and exposed in the ABI corpus as returned by the fe_iface::corpus() accessor. This ELF reader front-end also provides lots of capabilities that are specific to accessing ELF content. Then, there is a common base class for ELF-based front-ends to come, named abigail::elf_based_reader, which inherits the abigail::elf::reader class. The purpose of this base class is to provide common properties and behaviours that are necessary to implement things like a DWARF or a CTF front-end, or any other front-end to support an ELF-based debug info format. Then, there is a CTF front-end which class is named abigail::ctf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the CTF-specific properties of the ELF file. To do this, abigail::ctf::reader::load_corpus() re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus. This reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Then, there is a DWARF front-end which class is named abigail::dwarf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the DWARF-specific properties of the ELF file. To do this, abigail::dwarf::reader re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus, just like what the CTF front-end does. And then, just like the CTF front-end, this reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Lastly, there is an ABIXML front-end which class is named abigail::abixml::reader. It inherits the abigail::fe_iface class directly. Note that unlike the two previous front-ends, this one doesn't inherit the elf_based_reader base class, for reasons that should be obvious to the astute reader by now. So, this front-end implements the abigail::fe_iface::load_corpus() abstract interface to load the properties for the ABI corpus represented in the ABIXML format, construct the internal representation and pass it to the middle-end for further analysis. The code of the tools got adapted to use these front-ends. The support of CTF is still guarded by #ifdef WITH_CTF pre-processor macros, but the one cool side effect is that the amount of guarded code is reduced. Basically, it's only the creation of the CTF front-end that is guarded. After its creation, what is returned is an instance of abigail::elf_based_reader::reader, exactly like what is returned by the creation of a DWARF front-end. Thus, the rest of the code is exactly the same, regardless of the kind of front-end. I believe this results in a more elegant and maintainable code. As a proof-of-concept, this patch also provides the create_best_elf_based_reader function. This function analyses the ELF file and depending on the kind of debug info it provides, returns the right front-end for it. Maybe at some point, all the #ifdef WITH_CTF guard pre-processing macros will be constrained in a single function like this one that will take the decision of instantiating the right front-end. The rest of the code will be as generic as it gets. The patch adjusts the reference abixml files produced by the CTF front-end because it now emits the <elf-needed> XML element which was not emitted before. This is done because the CTF front-end inherits the elf-reader which reads the "elf-needed" property from the binary, without explicit intervention from the CTF front-end. The patch passes 'make distcheck' on all the supported platforms. * include/abg-fwd.h (build_internal_underlying_enum_type_name): Move this here from src/abg-dwarf-reader.cc. * include/abg-elf-reader-common.h: Delete this file. Its content is going to be put in the new include/abg-elf-reader.h. * src/abg-elf-reader-common.cc: Likewise. * include/abg-{elf-based-reader, elf-reader, fe-iface}.h: Add new files. * src/abg-fe-iface.cc: Likewise. * include/Makefile.am: Add the new file abg-fe-iface.h, abg-elf-based-reader.h and abg-elf-reader.h to source distribution and remove include/abg-elf-reader-common.h from source distribution. * src/abg-ir.cc (build_internal_underlying_enum_type_name): Move this here from abg-dwarf-reader.cc so that it can be used by other readers. * include/abg-reader.h (abigail::abixml::reader): Rename the namespace abigail::xml_reader into this one. (read_context, create_native_xml_read_context) (read_context_get_path, read_corpus_from_native_xml) (read_corpus_from_native_xml_file) (read_corpus_group_from_native_xml) (read_corpus_group_from_native_xml_file): Remove. (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream) (read_translation_unit) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (load_canonical_type_ids): Take an fe_iface&, not a read_context. (create_reader): Declare new function that returns a fe_iface_sptr. (read_corpus_from_abixml, read_corpus_from_abixml_file) (read_corpus_group_from_abixml) (read_corpus_group_from_abixml_file): Declare new functions. * src/abg-reader.cc (namespace abixml): Rename the xml_reader namespace into this. (abixml::reader_sptr): New typedef. (abixml::reader): Rename read_context into this. Make it inherit the fe_iface interface. (abixml::reader::{m_path, m_env, m_corpus, m_corpus_group, m_exported_decls_builder, m_supprs}): Remove these data members that are now part of the fe_iface parent type. (abixml::reader::{set_environment, get_corpus, set_corpus, set_corpus_group, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls, maybe_check_abixml_canonical_type_stability, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name}): Remove. (read_corpus_from_input): Remove. Actually the code of this went into abixml::reader::read_context(). (abixml::reader::get_libxml_reader): Rename the get_reader member function into this. (abixml::add_reader_suppressions): Rename add_read_context_suppressions into this. (abixml::reader::read_corpus): Implement this virtual member function if the fe_iface parent interface. (maybe_set_naming_typedef, advance_cursor) (handle_version_attribute, walk_xml_node_to_map_type_ids) (read_elf_needed_from_input, read_symbol_db_from_input) (get_or_read_and_add_translation_unit, build_needed) (read_elf_needed_from_input, add_read_context_suppressions) (maybe_set_artificial_location, maybe_set_naming_typedef) (build_namespace_decl, build_elf_symbol) (build_elf_symbol_from_reference, build_elf_symbol_db) (build_function_parameter, build_function_decl) (build_function_decl_if_not_suppressed, function_is_suppressed) (type_is_suppressed, build_var_decl_if_not_suppressed) (variable_is_suppressed, variable_is_suppressed, build_var_decl) (build_type_decl, build_qualified_type_decl) (build_pointer_type_def, build_reference_type_def) (build_function_type, build_subrange_type, build_array_type_def) (build_enum_type_decl_if_not_suppressed, build_enum_type_decl) (build_typedef_decl, build_class_decl_if_not_suppressed) (build_union_decl_if_not_suppressed, build_class_decl) (build_union_decl, build_function_tdecl, build_class_tdecl) (build_type_tparameter, build_type_composition) (build_non_type_tparameter, build_non_type_tparameter) (build_template_tparameter, build_template_parameter, build_type) (handle_type_decl, handle_namespace_decl) (handle_qualified_type_decl, handle_pointer_type_def) (handle_reference_type_def, handle_function_type) (handle_array_type_def, handle_enum_type_decl) (handle_typedef_decl, handle_var_decl, handle_function_decl) (handle_class_decl, handle_union_decl, handle_function_tdecl) (read_translation_unit_from_istream): Take or use an abixml::reader rather than a read_context. (read_translation_unit, read_translation_unit_from_input) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (read_corpus_group_from_input, read_translation_unit) (handle_element_node, read_location, read_artificial_location) (load_canonical_type_ids) : Take an fe_iface&, not a read_context. (create_abixml_reader): Rename create_native_xml_read_context into this. Make it return a fe_iface_sptr. (read_corpus_from_abixml): Rename read_corpus_from_abixml into this. (read_corpus_from_abixml_file): Rename read_corpus_from_native_xml_file into this. (read_context_get_path): Remove. * include/abg-tools-utils.h (abigail::tools_utils::{file_has_dwarf_debug_info, file_has_ctf_debug_info}): Declare new functions. (create_best_elf_based_reader): Declare new function. * include/abg-corpus.h (corpus::add): Pass the translation unit by reference. (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. * src/abg-corpus-priv.h (corpus::exported_decls_builder::priv::add_{fn,var}_to_exported): Take a const parameter and adjust. * src/abg-corpus.cc (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. (corpus::add): Take a reference to translation_unit_sptr. * include/abg-suppression.h (abigail::fe_iface): Forward-declare this. (abigail::{suppression_sptr, suppressions_type}): Declare these types here. (abigail::suppr::{suppression_can_match, suppression_matches_function_name, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location, is_elf_symbol_suppressed, is_elf_symbol_suppressed, is_function_suppressed, is_variable_suppressed, is_type_suppressed}): Declare these functions here. * src/abg-suppression-priv.h (function_is_suppressed) (variable_is_suppressed, type_is_suppressed) (is_elf_symbol_suppressed): Remove these template functions. * src/abg-suppression.cc (suppression_matches_function_name) (suppression_matches_function_sym_name): Remove. (variable_is_suppressed, suppression_can_match) (suppression_matches_function_name) (suppression_matches_function_sym_name) (suppression_matches_variable_name) (suppression_matches_variable_sym_name) (suppression_matches_type_name_or_location) (is_elf_symbol_suppressed, is_elf_symbol_suppressed) (is_function_suppressed, is_variable_suppressed) (is_type_suppressed): New functions. * include/abg-ctf-reader.h (abigail::ctf::{read_context, create_read_context, read_corpus, read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group, reset_read_context, dic_type_key}): Remove. (ctf::{create_reader, reset_reader}): Declare new functions. * src/abg-ctf-reader.cc (read_context): Remove. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type) (process_ctf_enum_type, fill_ctf_section) (lookup_symbol_in_ctf_archive, dic_type_key): Forward-declare these static functions. (ctf::reader): New class that is the abstraction of the CTF reader. It extends the abigail::elf_based_reader class. This is a renaming of the abigail::ctf::read_context class. (ctf::reader::{elf_handler, elf_fd, elf_handler_dbg, elf_fd_dbg, symtab, debug_info_root_paths_, debug_info_root_paths_}): Remove these data members as they are now properties of the abigail::elf_reader class, which is a parent class of this abigail::ctf::reader class. (ctf::reader::{exported_decls_builder, maybe_add_fn_to_exported_decls, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group}): Remove these accessors that can now be used from the parent classes abigail::{elf_reader, elf_based_reader}. (ctf::reader::reader): This now delegates to the constructor of elf_based_reader. It doesn't pass any argument to initialize() anymore. (ctf::reader::initialize): Add an overload with no parameter. In the other overload, do not take a pointer to an environment as no new environment can be passed to the instance of reader that is being reset. Adjust the code of the initializer to reflect all the data members that got removed. (ctf::{env, find_ctfa_file, slurp_elf_info, process_ctf_archive, process_ctf_type, lookup_type, read_corpus, ~reader}): New member functions. Most of these were free-form functions that took ctf::read_context as first parameter. In read_corpus, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN origin as that is now done by elf::reader when it reads the binary. (lookup_type): Remove. These are now member functions of the ctf::reader class. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type): Take a ctf::reader rather an ctf::read_context. Adjust the content of the functions. (process_ctf_type, lookup_type, process_ctf_archive): Remove these and turn them into member functions of ctf::reader. (open_elf_handler, close_elf_handler, find_alt_debuginfo): Remove these ELF handling functions as ELF handling is now done by the elf_reader parent class. (fill_ctf_section): Take a const pointer to Elf_Scn. (slurp_elf_info, find_ctfa_file): Remove this and make it be a member of ctf::reader. Also, make it handle only CTF reader specific pieces. slurp_elf_info now delegates the reading of generic ELF properties to elf::reader by calling elf::reader::read_corpus(). (create_read_context, read_corpus, set_read_context_corpus_group) (read_and_add_corpus_to_group_from_elf): Remove these functions. (create_reader, reset_reader): Create new functions (dic_type_key): Make this static. * include/abg-dwarf-reader.h (abigail::dwarf::elf_type): Move this enum into the namespace abigail::elf_reader in the file include/abg-elf-reader.h. (abigail::dwarf::{read_context, read_context_sptr, create_read_context, read_context_get_path, reset_read_context, add_read_context_suppressions, set_read_context_corpus_group, read_corpus_from_elf, read_and_add_corpus_to_group_from_elf, read_and_add_corpus_to_group_from_elf, add_read_context_suppressions, refers_to_alt_debug_info, has_alt_debug_info, get_soname_of_elf_file, get_type_of_elf_file, set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_show_stats, set_drop_undefined_syms, set_do_log, set_environment, get_environment}): Remove. * src/abg-dwarf-reader.cc (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_type) (address_set_sptr): Delete these types. (read_context::options_type): Remove. The data members of this type got moved to struct fe_iface::options_type. (find_alt_debug_info_link, find_alt_debug_info_path) (find_alt_debug_info, lookup_data_tag_from_dynamic_segment) (elf_file_type, refers_to_alt_debug_info, has_alt_debug_info) (get_soname_of_elf_file, get_type_of_elf_file) : Remove these ELF specific functions from here; move them to the elf_reader namespace. (dwarf::reader): Create new class that extends elf_based_reader. dwarf::read_context is renamed into this type, actually. (dwarf::reader::die_source_dependant_container_set::get_container): Adjust. (dwarf::reader::{supprs_, dwarf_version_, offline_callbacks_, debug_info_root_paths_, handle_, dwarf_, alt_fd_, alt_dwarf_, alt_debug_info_path_, elf_module_, elf_handle_, elf_path_, symtab_section_, cur_corpus_group_, cur_corpus_, dt_needed_, dt_soname_, elf_architecture_, exported_decls_builder_, options_, drop_undefined_syms_}): Remove these ELF-related data members to move them into the elf_reader namespace. (maybe_propagate_canonical_type) (build_translation_unit_and_add_to_ir, build_ir_node_from_die) (add_or_update_class_type, add_or_update_union_type) (build_ir_node_for_void_type) (build_ir_node_for_variadic_parameter_type, build_function_decl) (function_is_suppressed, build_or_get_fn_decl_if_not_suppressed) (build_var_decl, build_or_get_var_decl_if_not_suppressed) (variable_is_suppressed) (propagate_canonical_type) (get_parent_die, get_scope_die, die_is_at_class_scope) (die_location, die_qualified_type_name, die_qualified_name) (die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_function_type_is_method_type) (die_pretty_print_type, die_pretty_print_decl, die_pretty_print) (maybe_canonicalize_type, build_subrange_type) (build_subranges_from_array_type_die, compare_dies, die_location) (die_loc_and_name, die_is_effectively_public_decl) (maybe_cache_type_comparison_result) (get_cached_type_comparison_result) (maybe_get_cached_type_comparison_result, die_is_at_class_scope) (die_function_type_is_method_type, die_member_offset) (die_qualified_type_name, die_qualified_decl_name) (die_qualified_name, die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_pretty_print_type) (die_pretty_print_decl, die_pretty_print) (at_least_one_decl_only_among_odr_relevant_dies) (compare_as_type_dies, compare_as_decl_and_type_dies) (fn_die_equal_by_linkage_name, try_canonical_die_comparison) (maybe_propagate_canonical_type, propagate_canonical_type) (compare_dies, compare_dies_during_canonicalization) (find_import_unit_point_between_dies, get_parent_die) (get_scope_die, find_lower_bound_in_imported_unit_points) (build_translation_unit_and_add_to_ir) (build_namespace_decl_and_add_to_ir, build_type_decl) (build_enum_underlying_type, build_enum_type) (finish_member_function_reading) (maybe_finish_function_decl_reading) (lookup_class_or_typedef_from_corpus) (is_function_for_die_a_member_of_class) (add_or_update_member_function, add_or_update_class_type) (add_or_update_union_type, build_qualified_type) (schedule_array_tree_for_late_canonicalization) (maybe_strip_qualification, build_pointer_type_def) (build_reference_type, build_function_type, build_subrange_type) (build_subranges_from_array_type_die, build_array_type) (build_typedef_type, build_or_get_var_decl_if_not_suppressed) (build_var_decl, function_is_suppressed) (build_or_get_fn_decl_if_not_suppressed, variable_is_suppressed) (type_is_suppressed, type_is_suppressed) (get_opaque_version_of_type, create_default_fn_sym) (build_function_decl, maybe_canonicalize_type) (build_ir_node_from_die) (build_ir_node_for_variadic_parameter_type): Take a reference to the new dwarf::reader rather than to the previous read_context. Adjust the function body. (return_comparison_result): Adjust. (dwarf::reader::reader): Adjust this from read_context::read_context. (dwarf::reader::initialize): Adjust from dwarf::read_context::initialize. (dwarf::reader::create): New factory static member function. (dwarf::reader::~reader): This doesn't have to clear anything for now. (dwarf::reader::read_corpus): New virtual member function which implements the fe_iface::read_corpus pure virtual interface. This now delegates the reading of the generic ELF properties to elf::reader by calling elf::reader::read_corpus(). Newer front-ends will be able to do the same. (dwarf::reader::reset_corpus): New member function. (dwarf::reader::read_debug_info_into_corpus): Adjust. This is now a member function. Also, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN here as it's now set by the elf::reader when it loads the binary. (dwarf::reader::{env, drop_undefined_syms, drop_undefined_syms, dwarf_elf_handle, dwarf_per_die_source, elf_path, compute_canonical_die_offset, get_die_source, get_die_from_offset, get_die_qualified_name, get_die_pretty_type_representation, get_die_qualified_type_name, get_die_pretty_representation, odr_is_relevant, set_canonical_die_offset, get_canonical_die_offset, erase_canonical_die_offset, die_wip_classes_map, die_wip_function_types_map, compare_before_canonicalisation, resolve_declaration_only_classes, resolve_declaration_only_enums, symbol_already_belongs_to_a_function, fixup_functions_with_no_symbols, canonicalize_types_scheduled, tu_die_imported_unit_points_map, die_parent_map, find_symbol_table_section, get_variable_address, exported_decls_builder, load_all_types, load_in_linux_kernel_mode, show_stats, do_log, build_die_parent_maps): Adjust. (offset_pairs_stack_type::rdr_): Changed the ctxt_ into this. (offset_pairs_stack_type::offset_pairs_stack_type): Adjust. (offset_pairs_stack_type::{erase_redundant_type_pair_entry, cancel_canonical_propagated_type}): Adjust. (dwarf::reader::{get_suppressions, offline_callbacks, create_default_dwfl, dwfl_handle, elf_module, elf_handle, add_debug_info_root_paths, add_debug_info_root_path, find_alt_debug_info, dwarf, alt_dwarf, alt_debug_info_path, current_corpus, reset_current_corpus, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group, function_symbol_is_exported, variable_symbol_is_exported, symtab, dt_needed, dt_soname, elf_architecture, is_elf_symbol_suppressed, load_dt_soname_and_needed, load_elf_architecture, load_elf_properties, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls}): Remove these member functions as they got moved into the elf_reader namespace or into the fe_iface class. (dwarf::read_context::{suppression_can_match, suppression_matches_function_sym_name, suppression_matches_function_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location}): Move these into the suppr namespace. Make it take an additional parameter that is reference fe_iface. (dwarf::reader::load_debug_info): Remove. This became merged into dwarf::read_debug_info_into_corpus. (dwarf::{set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_drop_undefined_syms, set_do_log}): Remove. (add_read_context_suppressions) (set_read_context_corpus_group, read_corpus_from_elf): Remove. (read_debug_info_into_corpus): This became a member function of dwarf::reader. (create_reader): Renamed create_read_context into this. Make it return an elf_based_reader_sptr, like the other front-end factory functions. Adjust. (reset_dwarf_reader): Renamed reset_read_context into this. Adjust. (read_corpus_from_elf): Adjust. * src/abg-elf-based-reader.cc: New file. * src/abg-elf-helpers.h (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_sptr): Move these types here from abg-dwarf-reader.cc (initialize_dwfl_callbacks, lookup_data_tag_from_dynamic_segment): * src/abg-elf-helpers.cc (lookup_data_tag_from_dynamic_segment) (lookup_data_tag_from_dynamic_segment, initialize_dwfl_callbacks) (create_new_dwfl_handle, get_soname_of_elf_file): New functions that got moved here from the factorizing of abg-dwarf-reader.cc and abg-ctf-reader.cc. * src/abg-tools-utils.cc (file_has_dwarf_debug_info) (file_has_ctf_debug_info): New functions. (load_generate_apply_suppressions): Take an elf_based_reader, not a dwarf::read_context. (maybe_load_vmlinux_dwarf_corpus): Adjust the body to use the new front-end types. * src/Makefile.am: Add the new files src/abg-{fe-iface, elf-based-reader, elf-reader}.cc to source distribution. Remove src/abg-elf-reader-common.cc. * tools/Makefile.am: Factorize linking to libabigail.so by using LDADD. * tools/abicompat.cc (read_corpus, main): Adjust. * tools/abidiff.cc (set_suppressions) (set_native_xml_reader_options, handle_error, main): Adjust. * tools/abidw.cc (set_suppressions, load_corpus_and_write_abixml) (load_kernel_corpus_group_and_write_abixml): Adjust. * tools/abilint.cc (build_type_use_tree, show_how_type_is_used) (set_suppressions, main): Adjust. * tools/abipkgdiff.cc (elf_file::type, compare, compare_to_self) (create_maps_of_package_content) (compare_prepared_userspace_packages) (self_compare_prepared_userspace_package): Adjust. * tools/abisym.cc: Adjust invocation to abigail::dwarf::lookup_symbol_from_elf, from abigail::dwarf_reader::lookup_symbol_from_elf. * tools/kmidiff.cc (main): Adjust. * tests/print-diff-tree.cc (main): Adjust. * tests/test-abidiff.cc (main): Likewise. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-ir-walker.cc (main): Likewise. * tests/test-read-ctf.cc (test_task_ctf::perform): Likewise. * tests/test-read-dwarf.cc: Remove the useless "using" statements. * tests/test-read-write.cc: Likewise. * tests/test-symtab.cc (read_corpus, TEST_CASE) (assert_symbol_count): Adjust. * tests/data/test-read-ctf/test0.abi: Adjust. * tests/data/test-read-ctf/test0.hash.abi: Likewise. * tests/data/test-read-ctf/test1.so.abi: Likewise. * tests/data/test-read-ctf/test1.so.hash.abi: Likewise. * tests/data/test-read-ctf/test2.so.abi: Likewise. * tests/data/test-read-ctf/test2.so.hash.abi: Likewise. * tests/data/test-read-ctf/test3.so.abi: Likewise. * tests/data/test-read-ctf/test3.so.hash.abi: Likewise. * tests/data/test-read-ctf/test4.so.abi: Likewise. * tests/data/test-read-ctf/test4.so.hash.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2022-11-15 16:26:37 +00:00
using namespace abigail;
///@file
///
/// This example shows how to walk the Internal Representation (IR)
/// graph of the ABI of a binary (called an ABI Corpus) and perform
/// actions on each node of the graph.
///
/// Basically, one has to define a "visitor" which carries member
/// functions that are called during the traversal of the graph.
///
/// On the visitor, there is potentially one member function pair per
/// type of node traversed. Each time a given node is visited, the
/// corresponding member function pair is called by the traversal
/// machinery. In other words, the visitor is notified each time a
/// node is traversed.
///
/// To define a visitor, one has to create a type which implements
/// (inherits) the abigail::ir_node_visitor interface. The visitor
/// must have a pair of node_begin() and node_end() function per type
/// of node that we wish to be notified for.
///
/// Once the visitor is defined, we can load an elf file and build an
/// ABI corpus out of it by using the
/// libabigail::dwarf_reader::read_corpus_from_elf() function, for
/// instance.
///
/// Then we enumerate the translation units comprised in
/// that ABI corpus and we invoke their "traverse()" method, using
/// and instance of the visitor that we just defined.
///
/// Enjoy!
struct name_printing_visitor : public abigail::ir_node_visitor
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
unsigned level_;
name_printing_visitor()
: level_()
Add option to avoid walking abigail::ir nodes twice When the ir_traversable_base::traverse() walks the IR graph, it happens that it can visit a type node that was already visited before. For instance, it visits the 'struct S' once and later, as part of its visit of struct S*, it can visit struct S again. There are use cases where we want the walker to avoid visiting a given type node again. This patch adds the option to do so. Basically the ir_node_visitor class can now be configured to tell the walker to avoid re-visiting a node. The test-ir-walker.cc example is amended to avoid re-visiting type nodes as well. * include/abg-ir.h (struct ir_node_visitor): Make this be a class. Add a private data member to it, following the 'pimpl' idiom. (ir_node_visitor::{allow_visiting_already_visited_type_node, mark_type_node_as_visited, forget_visited_type_nodes, type_node_has_been_visited}): Declare new member functions. * src/abg-ir.cc ({type_base, type_decl, scope_type_decl, qualified_type_decl, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, class_or_union, class_decl, union_decl}::traverse): Avoid re-visiting the type node if the visitor was configured as such. (struct ir_node_visitor::priv): Define new struct. (ir_node_visitor::{allow_visiting_already_visited_type_node, mark_type_node_as_visited, forget_visited_type_nodes, type_node_has_been_visited}): Define new member functions. * tests/test-ir-walker.cc (name_printing_visitor::name_printing_visitor): Avoid visiting a type node twice. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2018-09-03 09:10:25 +00:00
{
// Using this visitor, the IR walker will visit each type only
// once.
allow_visiting_already_visited_type_node(false);
}
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
void
build_level_prefix(string& str)
{
str.clear();
for (unsigned i = 0; i < level_; ++i)
str += ' ';
}
string
build_level_prefix()
{
string prefix;
build_level_prefix(prefix);
return prefix;
}
bool
visit_begin(abigail::namespace_decl* ns)
{
string prefix = build_level_prefix();
cout << prefix << ns->get_pretty_representation() << "\n"
<< prefix << "{\n";
++level_;
return true;
}
bool
visit_end(abigail::namespace_decl*)
{
string prefix = build_level_prefix();
cout << prefix << "}\n";
--level_;
return true;
}
bool
visit_begin(abigail::class_decl* klass)
{
string prefix = build_level_prefix();
cout << prefix << klass->get_pretty_representation() << "\n"
<< prefix << "{\n";
++level_;
return true;
}
bool
visit_end(abigail::class_decl*)
{
string prefix = build_level_prefix();
cout << prefix << "}\n";
--level_;
return true;
}
bool
visit_begin(abigail::function_decl* f)
{
string prefix = build_level_prefix();
cout << prefix << f->get_pretty_representation() << "\n";
++level_;
return true;
}
bool
visit_end(abigail::function_decl*)
{
--level_;
return true;
}
bool
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
visit_begin(abigail::var_decl* v)
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
string prefix = build_level_prefix();
cout << prefix << v->get_pretty_representation() << "\n";
++level_;
return true;
}
bool
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
visit_end(abigail::var_decl*)
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
--level_;
return true;
}
};
int
main(int argc, char **argv)
{
if (argc < 2)
return 0;
string file_name = argv[1];
Use environment by reference. This patch simplifies how the environment is created and passed around the functions that create front ends. With this change, the environment can simply be allocated on the stack and passed by reference to the libabigail pipeline. At the core of this change, type_or_decl_base::priv now carries a const reference to an environment rather than a pointer. The side effect is that type_or_decl_base can no longer be copied. This is not a problem because throughout the years I could see that the use case to copy ABI artifacts is just not there. Similarly, elf_symbol::priv carries a const reference to environment now, no more a pointer. Getters, setters and code that use the environment from the ABI artifacts are updated accordingly. The DWARF front-end can now be created by code that looks like this, for instance: vector<char**> debug_info_paths; abigail::ir::environment env; abigail::ctf_reader::read_context_sptr reader = abigail::dwarf_reader::create_read_context("elf/file/to/analyze", debug_info_paths, env); elf_reader::status reading_status; corpus_sptr abi_corpus = abigail::dwarf_reader::read_corpus_from_elf(reader, reading_status); /* then do something with the resulting abi_corpus*/ Note how, you don't need to use the "new" operator to instantiate the "env" object of type environment. It can sit on the stack and it's passed to the read_corpus_from_elf function by reference. In other words, the internal representation types have been changed to refer to the environment by reference, rather than requiring a pointer to it. * include/abg-corpus.h (corpus::corpus) (corpus_group::corpus_group): Take environment&, not environment* as parameter. (corpus::{get_environment, set_environment}): Take or return environment&, not environment*. * src/abg-corpus.cc (corpus::corpus): Likewise. (corpus::{get_environment, set_environment}): Likewise. (corpus::add): Don't update the environment of the translation unit. (corpus::{record_type_as_reachable_from_public_interfaces, type_is_reachable_from_public_interfaces, init_format_version, add_corpus}): Adjust for accessing a reference to environment, rather than a pointer. * include/abg-ctf-reader.h (create_read_context): Take or return environment&, not environment*. * src/abg-ctf-reader.cc (read_context::ir_env): Make this a reference to environment, not pointer anymore. (read_context::read_context): Initialize the reference to environment. (read_context::initialize): Do not re-set the environment. (process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_enum_type, read_corpus): Adjust for accessing a reference to environment, rather than a pointer. (create_read_context, reset_read_context): Take environment&, not environment*. * include/abg-dwarf-reader.h (create_read_context) (reset_read_context, read_corpus_from_elf) (lookup_symbol_from_elf, lookup_public_function_symbol_from_elf): Likewise. * src/abg-dwarf-reader.cc (lookup_symbol_from_sysv_hash_tab) (lookup_symbol_from_gnu_hash_tab) (lookup_symbol_from_elf_hash_tab, lookup_symbol_from_symtab) (lookup_symbol_from_elf, lookup_public_function_symbol_from_elf): Likewise. (read_context::options_type::env): Make this be a reference to environment, not a pointer. (read_context::options::options): Remove the default constructor. Add a new one to initialize the environment data member. (read_context::read_context): Take environment&, not environment*. Initialize the options_ data member. (read_context::initialize): Do not take or initialize an environment anymore. (read_context::env): Return or take environment&, not environment*. (read_context::{get_die_qualified_name, get_die_qualified_type_name, get_die_pretty_type_representation, get_die_pretty_representation, compare_before_canonicalisation}) (build_translation_unit_and_add_to_ir, build_function_type) (build_typedef_type, read_debug_info_into_corpus) (read_debug_info_into_corpus, build_ir_node_from_die) (build_ir_node_for_variadic_parameter_type, has_alt_debug_info): Adjust to use an environment&, not a pointer. (create_default_fn_sym, create_read_context) (read_corpus_from_elf, lookup_symbol_from_elf) (lookup_public_function_symbol_from_elf): Take environment&, not environment*. (reset_read_context): Do not take or reset environment* anymore. * include/abg-fwd.h (type_or_void): Likewise. * include/abg-ir.h (translation_unit::translation_unit): Likewise. (translation_unit::{get_environment, set_environment}): Likewise. (elf_symbol::elf_symbol): Likewise. (elf_symbol::create): Remove the overload that takes no parameter. Then for overload that take parameters then take environment&, not environment*. (elf_symbol::get_environment): Take environment&, not environment*. (type_or_decl_base::type_or_decl_base): Make the copy constructor and assignment operator private. (type_or_decl_base::{s,g}et_environment): Take or return environment& not environment*. (type_or_decl_base::set_environment_for_artifact): Erase these methods. (decl_base::decl_base): Make copy constructor private. Take or return environment&, not environment* for the other constructors. (scope_decl::scope_decl): Take or return environment&, not environment*. (type_base::type_base): Likewise. (scope_type_decl::scope_type_decl): Likewise. (namespace_decl::namespace_decl): Likewise. (qualified_type_def::qualified_type_def): Likewise. (pointer_type_def::pointer_type_def): Likewise. (reference_type_def::reference_type_def): Likewise. (array_type_def::subrange_type::subrange_type): Likewise. (enum_type_def::enumerator::enumerator): Likewise. (enum_type_def::enumerator::{get_name, get_qualified_name}): Return a string&, no more interned_string&. As the enumerator don't have an enumerator anymore, there is no way to intern the string anymore. Hopefully this won't incur a performance loss. (typedef_decl::typedef_decl, function_type::function_type) (method_type::method_type, template_decl::template_decl) (function_tdecl::function_tdecl, class_tdecl::class_tdecl) (class_or_union::class_or_union, class_decl::class_decl) (union_decl::union_decl): Take or return environment&, not environment*. * include/abg-reader.h (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream) (create_native_xml_read_context, create_native_xml_read_context) (read_corpus_from_native_xml, read_corpus_from_native_xml_file) (read_corpus_group_from_native_xml) (read_corpus_group_from_native_xml_file): Likewise. * include/abg-tools-utils.h (build_corpus_group_from_kernel_dist_under): Likewise. * src/abg-tools-utils.cc (maybe_load_vmlinux_dwarf_corpus) (maybe_load_vmlinux_ctf_corpus) (build_corpus_group_from_kernel_dist_under): Likewise. * include/abg-writer.h (create_write_context): Likewise. * src/abg-writer.cc (id_manager::m_env, id_manager::id_manager) (id_manager::get_environment, id_manager::get_id) (id_manager::get_id_with_prefix): Adjust. (write_context::m_env, write_context::write_context) (write_context::get_environment, write_context::get_config) (write_context::get_id_for_type, write_context::decl_is_emitted) (write_context::record_decl_as_emitted, create_write_context) (write_class_decl): Likewise. * src/abg-comparison.cc (compute_diff): Stop ensuring that the two artifacts being compare are in the same environment. Now that the environment is passed by reference, the potential for accendentally comparing artifacts coming from different environments is very low, given how the API is used in practice. This is in the overloads for decl_base_sptr, type_base_sptr, var_decl_sptr, pointer_type_def_sptr, array_type_def_sptr, reference_type_def_sptr, qualified_type_def_sptr, enum_type_decl_sptr, class_decl_sptr, class_decl::base_spec_sptr, union_decl_sptr, scope_decl_sptr, function_decl::parameter_sptr, function_type_sptr, function_decl_sptr, type_decl_sptr, typedef_decl_sptr, translation_unit_sptr, corpus_sptr. * src/abg-corpus-priv.h (corpus::priv::env): Make this be a reference to environments, not a pointer. (corpus::priv::priv): Pass environment&, not environment*. * src/abg-ir-priv.h (translation_unit::priv::env_): Make this an environment&, not an environment* anymore. (translation_unit::priv::priv): Take an environment&, not an environment*. (environment::priv::{confirm_ct_propagation_for_types_dependant_on, confirm_ct_propagation, cancel_ct_propagation_for_types_dependant_on, mark_as_being_compared, unmark_as_being_compared, comparison_started, mark_as_being_compared, comparison_started}): Adjust to use an environment&, not a pointer. * src/abg-ir.cc (class environment_setter): Remove this class. (push_composite_type_comparison_operands) (pop_composite_type_comparison_operands, try_canonical_compare) (return_comparison_result, translation_unit::{get_global_scope, bind_function_type_life_time}): Adjust. (translation_unit::{translation_unit, get_environment}): Take or get an environment&, not an environment*. Remove the getter that returns an environment*. (elf_symbol::priv::env_): Make this an environment&, not an environment*. (elf_symbol::priv::priv): Adjust. (elf_symbol::elf_symbol): Remove the default constructor. Change the one that takes an environment. (elf_symbol::create): Remove the default one. Adjust the one that takes an environment. (elf_symbol::get_environment): Adjust. (elf_symbol::set_environment_for_artifact): Remove. (environment::{get_void_type, get_variadic_parameter_type}): Adjust. (type_or_decl_base::priv::env_): Make this be a const environment&, not a const environment*. (type_or_decl_base::priv::priv): Adjust. (type_or_decl_base::type_or_decl_base): Remove the default and copy constructor. (type_or_decl_base::{set_environment, operator=}) (set_environment_for_artifact): Remove. (type_or_decl_base::get_environment): Adjust. (decl_base::{decl_base, set_name, set_naming_typedef, set_linkage_name}): Adjust. (get_decl_name_for_comparison, strip_typedef) (strip_useless_const_qualification): Adjust. (scope_decl::{scope_decl, add_member_decl, insert_member_decl}): Adjust. (get_generic_anonymous_internal_type_name, get_type_name) (get_name_of_pointer_to_type, get_name_of_reference_to_type) (get_name_of_qualified_type, get_function_type_name) (get_method_type_name, is_void_pointer_type, lookup_basic_type) (lookup_union_type, lookup_union_type_per_location) (lookup_enum_type, lookup_typedef_type, lookup_pointer_type) (lookup_type, lookup_basic_type_per_location) (lookup_basic_type_per_location, lookup_basic_type) (lookup_class_type, lookup_class_types) (lookup_class_type_per_location, lookup_union_type) (lookup_enum_type, lookup_enum_types) (lookup_enum_type_per_location, lookup_typedef_type) (lookup_typedef_type_per_location, maybe_update_types_lookup_map) (maybe_update_types_lookup_map) (synthesize_type_from_translation_unit) (synthesize_function_type_from_translation_unit) (demangle_cplus_mangled_name, type_or_void) (types_defined_same_linux_kernel_corpus_public) (compare_types_during_canonicalization) (type_base::get_canonical_type_for, type_base::type_base) (type_base::get_cached_pretty_representation) (type_decl::type_decl, type_decl::get_qualified_name): Adjust. (scope_type_decl::scope_type_decl) (namespace_decl::namespace_decl, qualified_type_def::build_name) (qualified_type_def::qualified_type_def) (qualified_type_def::get_qualified_name) (qualified_type_def::set_underlying_type) (pointer_type_def::pointer_type_def) (pointer_type_def::set_pointed_to_type) (reference_type_def::reference_type_def) (reference_type_def::set_pointed_to_type) (array_type_def::subrange_type::subrange_type) (array_type_def::array_type_def, array_type_def::update_size) (array_type_def::set_element_type) (array_type_def::append_subranges) (array_type_def::get_qualified_name, enum_has_non_name_change): Adjust. (enum_type_decl::enumerator::priv::env_): Remove this pointer to env. This is because the enumerator must be copy-able. As the enumerator doesn't have an env anymore, it can't intern strings. So the enumerator name and qualified name is not going to be interned. If that incurs a performance hit, we'll reconsider this decision. For now, it seems to work OK. As it simplifies things, I am keeping this for now. (enum_type_decl::enumerator::priv::{name, qualified_name}): Make this be string, not interned_string. (enum_type_decl::enumerator::get_environment): Remove. (enum_type_decl::enumerator::priv::priv): Adjust. (enum_type_decl::enumerator::enumerator) (enum_type_decl::enumerator::operator=) (enum_type_decl::enumerator::get_name) (enum_type_decl::enumerator::get_qualified_name) (enum_type_decl::enumerator::set_name): Likewise. (typedef_decl::typedef_decl): Adjust. (var_decl::get_id, var_decl::get_qualified_name): Adjust. (function_type::function_type, method_type::method_type) (function_decl::get_pretty_representation_of_declarator) (function_decl::set_symbol): Likewise. (function_decl::get_id, function_decl::parameter::get_type) (function_decl::parameter::get_type_name) (function_decl::parameter::get_type_pretty_representation) (function_decl::parameter::get_name_id) (class_or_union::class_or_union, class_decl::class_decl) (class_decl::add_base_specifier, union_decl::union_decl) (union_decl::union_decl, template_decl::template_decl) (class_tdecl::class_tdecl) (maybe_cancel_propagated_canonical_type) (dump_classes_being_compared) (dump_fn_types_being_compared, copy_member_function) (maybe_propagate_canonical_type, keep_type_alive) (is_non_canonicalized_type, qualified_name_setter::do_update): Likewise. (equals): Adjust the overloads for var_decl, function_type, class_or_union, class_decl, union_decl. * src/abg-reader.cc (read_context::m_env): Make this be an environment&, not an environment*. (read_context::read_context): Adjust (read_context::set_environment): Remove. (read_context::{get_environment, maybe_check_abixml_canonical_type_stability}): Adjust. (read_corpus_from_input, read_corpus_group_from_native_xml) (read_corpus_group_from_native_xml_file) (read_translation_unit_from_file) (read_translation_unit_from_buffer, read_translation_unit) (maybe_map_type_with_type_id, build_namespace_decl) (build_elf_symbol, build_function_parameter, build_function_decl) (build_function_type, build_enum_type_decl, build_class_decl) (build_union_decl, build_function_tdecl, build_class_tdecl) (build_type_tparameter, read_translation_unit_from_istream) (create_native_xml_read_context, read_corpus_from_native_xml): Likewise. * src/abg-symtab-reader.h (symtab::load): Likewise. * src/abg-symtab-reader.cc (symtab::load): Likewise. * tests/print-diff-tree.cc (main): Likewise. * tests/test-abidiff.cc (main): Likewise. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-ir-walker.cc (main): Likewise. * tests/test-read-ctf.cc (test_task_ctf::perform): Likewise. * tests/test-symtab.cc (read_corpus): Likewise. * tools/abicompat.cc (read_corpus, main): Likewise. * tools/abidiff.cc (main): Likewise. * tools/abidw.cc (load_corpus_and_write_abixml) (load_kernel_corpus_group_and_write_abixml, main): Likewise. * tools/abilint.cc (main): Likewise. * tools/abipkgdiff.cc (compare, compare_to_self) (compare_prepared_linux_kernel_packages, compare_task::perform): Likewise. * tools/abisym.cc (main): Likewise. * tools/kmidiff.cc (main): Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2022-11-10 11:00:44 +00:00
abigail::ir::environment env;
abigail::corpus_sptr c;
Make Front Ends first class citizens This patch is a reorganization of the code to better support the need for having several different front-ends. In the libabigail pipeline of operation, a front-end is the part of the pipeline that analyses the input file. For instance, to analyse an ELF file, there is going to be one front-end. To analyse an ABIXML file, there is going to be another front-end. The middle-end is the part of the pipeline that interacts with the internal representation of ABIs. The middle-end knows how to analyse, compare ABI corpora provide an internal representation of the comparison result and analyse it as well. The back-end would be the part of the front-end that knows how to serialize internal representations of ABIs and ABI comparison results. One could thus imagine a front-end that understands the DWARF debug info format embedded in an ELF file. Another front-end would be dedicated to the CTF debug info format, and so on. Front-ends can share capabilities. For instance, DWARF and CTF front-ends are ELF based front end. As such, they share capabilities to understand the ELF format. They don't share much with the ABIXML front-end, however, as it's based on XML, which has almost nothing in common with ELF. To support this organization of concepts, this patch introduces a new hierarchy of types in the form of C++ classes. All front-ends implements the "Front End Interface". As such, they all inherit the abigail::fe_iface class. That class provides properties and behaviours that are shared by all front-ends that libabigail supports today. Namely, that class provides access to some of the options that are relevant to operating the front-end, to the ABI corpus or corpus group being constructed and to the suppression specifications that are considered. It also provides an abstract interface to perform the actual loading of the ABI corpus. That abstract interface has to be implemented by every single concrete front-end that is provided in libabigail. Then, there is the "ELF Reader" front-end. Its class name is abigail::elf::reader. It inherits the abigail::fe_iface class and implements the fe_iface::load_corpus() so that the ELF properties of the ELF file be loaded and exposed in the ABI corpus as returned by the fe_iface::corpus() accessor. This ELF reader front-end also provides lots of capabilities that are specific to accessing ELF content. Then, there is a common base class for ELF-based front-ends to come, named abigail::elf_based_reader, which inherits the abigail::elf::reader class. The purpose of this base class is to provide common properties and behaviours that are necessary to implement things like a DWARF or a CTF front-end, or any other front-end to support an ELF-based debug info format. Then, there is a CTF front-end which class is named abigail::ctf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the CTF-specific properties of the ELF file. To do this, abigail::ctf::reader::load_corpus() re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus. This reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Then, there is a DWARF front-end which class is named abigail::dwarf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the DWARF-specific properties of the ELF file. To do this, abigail::dwarf::reader re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus, just like what the CTF front-end does. And then, just like the CTF front-end, this reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Lastly, there is an ABIXML front-end which class is named abigail::abixml::reader. It inherits the abigail::fe_iface class directly. Note that unlike the two previous front-ends, this one doesn't inherit the elf_based_reader base class, for reasons that should be obvious to the astute reader by now. So, this front-end implements the abigail::fe_iface::load_corpus() abstract interface to load the properties for the ABI corpus represented in the ABIXML format, construct the internal representation and pass it to the middle-end for further analysis. The code of the tools got adapted to use these front-ends. The support of CTF is still guarded by #ifdef WITH_CTF pre-processor macros, but the one cool side effect is that the amount of guarded code is reduced. Basically, it's only the creation of the CTF front-end that is guarded. After its creation, what is returned is an instance of abigail::elf_based_reader::reader, exactly like what is returned by the creation of a DWARF front-end. Thus, the rest of the code is exactly the same, regardless of the kind of front-end. I believe this results in a more elegant and maintainable code. As a proof-of-concept, this patch also provides the create_best_elf_based_reader function. This function analyses the ELF file and depending on the kind of debug info it provides, returns the right front-end for it. Maybe at some point, all the #ifdef WITH_CTF guard pre-processing macros will be constrained in a single function like this one that will take the decision of instantiating the right front-end. The rest of the code will be as generic as it gets. The patch adjusts the reference abixml files produced by the CTF front-end because it now emits the <elf-needed> XML element which was not emitted before. This is done because the CTF front-end inherits the elf-reader which reads the "elf-needed" property from the binary, without explicit intervention from the CTF front-end. The patch passes 'make distcheck' on all the supported platforms. * include/abg-fwd.h (build_internal_underlying_enum_type_name): Move this here from src/abg-dwarf-reader.cc. * include/abg-elf-reader-common.h: Delete this file. Its content is going to be put in the new include/abg-elf-reader.h. * src/abg-elf-reader-common.cc: Likewise. * include/abg-{elf-based-reader, elf-reader, fe-iface}.h: Add new files. * src/abg-fe-iface.cc: Likewise. * include/Makefile.am: Add the new file abg-fe-iface.h, abg-elf-based-reader.h and abg-elf-reader.h to source distribution and remove include/abg-elf-reader-common.h from source distribution. * src/abg-ir.cc (build_internal_underlying_enum_type_name): Move this here from abg-dwarf-reader.cc so that it can be used by other readers. * include/abg-reader.h (abigail::abixml::reader): Rename the namespace abigail::xml_reader into this one. (read_context, create_native_xml_read_context) (read_context_get_path, read_corpus_from_native_xml) (read_corpus_from_native_xml_file) (read_corpus_group_from_native_xml) (read_corpus_group_from_native_xml_file): Remove. (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream) (read_translation_unit) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (load_canonical_type_ids): Take an fe_iface&, not a read_context. (create_reader): Declare new function that returns a fe_iface_sptr. (read_corpus_from_abixml, read_corpus_from_abixml_file) (read_corpus_group_from_abixml) (read_corpus_group_from_abixml_file): Declare new functions. * src/abg-reader.cc (namespace abixml): Rename the xml_reader namespace into this. (abixml::reader_sptr): New typedef. (abixml::reader): Rename read_context into this. Make it inherit the fe_iface interface. (abixml::reader::{m_path, m_env, m_corpus, m_corpus_group, m_exported_decls_builder, m_supprs}): Remove these data members that are now part of the fe_iface parent type. (abixml::reader::{set_environment, get_corpus, set_corpus, set_corpus_group, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls, maybe_check_abixml_canonical_type_stability, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name}): Remove. (read_corpus_from_input): Remove. Actually the code of this went into abixml::reader::read_context(). (abixml::reader::get_libxml_reader): Rename the get_reader member function into this. (abixml::add_reader_suppressions): Rename add_read_context_suppressions into this. (abixml::reader::read_corpus): Implement this virtual member function if the fe_iface parent interface. (maybe_set_naming_typedef, advance_cursor) (handle_version_attribute, walk_xml_node_to_map_type_ids) (read_elf_needed_from_input, read_symbol_db_from_input) (get_or_read_and_add_translation_unit, build_needed) (read_elf_needed_from_input, add_read_context_suppressions) (maybe_set_artificial_location, maybe_set_naming_typedef) (build_namespace_decl, build_elf_symbol) (build_elf_symbol_from_reference, build_elf_symbol_db) (build_function_parameter, build_function_decl) (build_function_decl_if_not_suppressed, function_is_suppressed) (type_is_suppressed, build_var_decl_if_not_suppressed) (variable_is_suppressed, variable_is_suppressed, build_var_decl) (build_type_decl, build_qualified_type_decl) (build_pointer_type_def, build_reference_type_def) (build_function_type, build_subrange_type, build_array_type_def) (build_enum_type_decl_if_not_suppressed, build_enum_type_decl) (build_typedef_decl, build_class_decl_if_not_suppressed) (build_union_decl_if_not_suppressed, build_class_decl) (build_union_decl, build_function_tdecl, build_class_tdecl) (build_type_tparameter, build_type_composition) (build_non_type_tparameter, build_non_type_tparameter) (build_template_tparameter, build_template_parameter, build_type) (handle_type_decl, handle_namespace_decl) (handle_qualified_type_decl, handle_pointer_type_def) (handle_reference_type_def, handle_function_type) (handle_array_type_def, handle_enum_type_decl) (handle_typedef_decl, handle_var_decl, handle_function_decl) (handle_class_decl, handle_union_decl, handle_function_tdecl) (read_translation_unit_from_istream): Take or use an abixml::reader rather than a read_context. (read_translation_unit, read_translation_unit_from_input) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (read_corpus_group_from_input, read_translation_unit) (handle_element_node, read_location, read_artificial_location) (load_canonical_type_ids) : Take an fe_iface&, not a read_context. (create_abixml_reader): Rename create_native_xml_read_context into this. Make it return a fe_iface_sptr. (read_corpus_from_abixml): Rename read_corpus_from_abixml into this. (read_corpus_from_abixml_file): Rename read_corpus_from_native_xml_file into this. (read_context_get_path): Remove. * include/abg-tools-utils.h (abigail::tools_utils::{file_has_dwarf_debug_info, file_has_ctf_debug_info}): Declare new functions. (create_best_elf_based_reader): Declare new function. * include/abg-corpus.h (corpus::add): Pass the translation unit by reference. (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. * src/abg-corpus-priv.h (corpus::exported_decls_builder::priv::add_{fn,var}_to_exported): Take a const parameter and adjust. * src/abg-corpus.cc (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. (corpus::add): Take a reference to translation_unit_sptr. * include/abg-suppression.h (abigail::fe_iface): Forward-declare this. (abigail::{suppression_sptr, suppressions_type}): Declare these types here. (abigail::suppr::{suppression_can_match, suppression_matches_function_name, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location, is_elf_symbol_suppressed, is_elf_symbol_suppressed, is_function_suppressed, is_variable_suppressed, is_type_suppressed}): Declare these functions here. * src/abg-suppression-priv.h (function_is_suppressed) (variable_is_suppressed, type_is_suppressed) (is_elf_symbol_suppressed): Remove these template functions. * src/abg-suppression.cc (suppression_matches_function_name) (suppression_matches_function_sym_name): Remove. (variable_is_suppressed, suppression_can_match) (suppression_matches_function_name) (suppression_matches_function_sym_name) (suppression_matches_variable_name) (suppression_matches_variable_sym_name) (suppression_matches_type_name_or_location) (is_elf_symbol_suppressed, is_elf_symbol_suppressed) (is_function_suppressed, is_variable_suppressed) (is_type_suppressed): New functions. * include/abg-ctf-reader.h (abigail::ctf::{read_context, create_read_context, read_corpus, read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group, reset_read_context, dic_type_key}): Remove. (ctf::{create_reader, reset_reader}): Declare new functions. * src/abg-ctf-reader.cc (read_context): Remove. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type) (process_ctf_enum_type, fill_ctf_section) (lookup_symbol_in_ctf_archive, dic_type_key): Forward-declare these static functions. (ctf::reader): New class that is the abstraction of the CTF reader. It extends the abigail::elf_based_reader class. This is a renaming of the abigail::ctf::read_context class. (ctf::reader::{elf_handler, elf_fd, elf_handler_dbg, elf_fd_dbg, symtab, debug_info_root_paths_, debug_info_root_paths_}): Remove these data members as they are now properties of the abigail::elf_reader class, which is a parent class of this abigail::ctf::reader class. (ctf::reader::{exported_decls_builder, maybe_add_fn_to_exported_decls, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group}): Remove these accessors that can now be used from the parent classes abigail::{elf_reader, elf_based_reader}. (ctf::reader::reader): This now delegates to the constructor of elf_based_reader. It doesn't pass any argument to initialize() anymore. (ctf::reader::initialize): Add an overload with no parameter. In the other overload, do not take a pointer to an environment as no new environment can be passed to the instance of reader that is being reset. Adjust the code of the initializer to reflect all the data members that got removed. (ctf::{env, find_ctfa_file, slurp_elf_info, process_ctf_archive, process_ctf_type, lookup_type, read_corpus, ~reader}): New member functions. Most of these were free-form functions that took ctf::read_context as first parameter. In read_corpus, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN origin as that is now done by elf::reader when it reads the binary. (lookup_type): Remove. These are now member functions of the ctf::reader class. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type): Take a ctf::reader rather an ctf::read_context. Adjust the content of the functions. (process_ctf_type, lookup_type, process_ctf_archive): Remove these and turn them into member functions of ctf::reader. (open_elf_handler, close_elf_handler, find_alt_debuginfo): Remove these ELF handling functions as ELF handling is now done by the elf_reader parent class. (fill_ctf_section): Take a const pointer to Elf_Scn. (slurp_elf_info, find_ctfa_file): Remove this and make it be a member of ctf::reader. Also, make it handle only CTF reader specific pieces. slurp_elf_info now delegates the reading of generic ELF properties to elf::reader by calling elf::reader::read_corpus(). (create_read_context, read_corpus, set_read_context_corpus_group) (read_and_add_corpus_to_group_from_elf): Remove these functions. (create_reader, reset_reader): Create new functions (dic_type_key): Make this static. * include/abg-dwarf-reader.h (abigail::dwarf::elf_type): Move this enum into the namespace abigail::elf_reader in the file include/abg-elf-reader.h. (abigail::dwarf::{read_context, read_context_sptr, create_read_context, read_context_get_path, reset_read_context, add_read_context_suppressions, set_read_context_corpus_group, read_corpus_from_elf, read_and_add_corpus_to_group_from_elf, read_and_add_corpus_to_group_from_elf, add_read_context_suppressions, refers_to_alt_debug_info, has_alt_debug_info, get_soname_of_elf_file, get_type_of_elf_file, set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_show_stats, set_drop_undefined_syms, set_do_log, set_environment, get_environment}): Remove. * src/abg-dwarf-reader.cc (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_type) (address_set_sptr): Delete these types. (read_context::options_type): Remove. The data members of this type got moved to struct fe_iface::options_type. (find_alt_debug_info_link, find_alt_debug_info_path) (find_alt_debug_info, lookup_data_tag_from_dynamic_segment) (elf_file_type, refers_to_alt_debug_info, has_alt_debug_info) (get_soname_of_elf_file, get_type_of_elf_file) : Remove these ELF specific functions from here; move them to the elf_reader namespace. (dwarf::reader): Create new class that extends elf_based_reader. dwarf::read_context is renamed into this type, actually. (dwarf::reader::die_source_dependant_container_set::get_container): Adjust. (dwarf::reader::{supprs_, dwarf_version_, offline_callbacks_, debug_info_root_paths_, handle_, dwarf_, alt_fd_, alt_dwarf_, alt_debug_info_path_, elf_module_, elf_handle_, elf_path_, symtab_section_, cur_corpus_group_, cur_corpus_, dt_needed_, dt_soname_, elf_architecture_, exported_decls_builder_, options_, drop_undefined_syms_}): Remove these ELF-related data members to move them into the elf_reader namespace. (maybe_propagate_canonical_type) (build_translation_unit_and_add_to_ir, build_ir_node_from_die) (add_or_update_class_type, add_or_update_union_type) (build_ir_node_for_void_type) (build_ir_node_for_variadic_parameter_type, build_function_decl) (function_is_suppressed, build_or_get_fn_decl_if_not_suppressed) (build_var_decl, build_or_get_var_decl_if_not_suppressed) (variable_is_suppressed) (propagate_canonical_type) (get_parent_die, get_scope_die, die_is_at_class_scope) (die_location, die_qualified_type_name, die_qualified_name) (die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_function_type_is_method_type) (die_pretty_print_type, die_pretty_print_decl, die_pretty_print) (maybe_canonicalize_type, build_subrange_type) (build_subranges_from_array_type_die, compare_dies, die_location) (die_loc_and_name, die_is_effectively_public_decl) (maybe_cache_type_comparison_result) (get_cached_type_comparison_result) (maybe_get_cached_type_comparison_result, die_is_at_class_scope) (die_function_type_is_method_type, die_member_offset) (die_qualified_type_name, die_qualified_decl_name) (die_qualified_name, die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_pretty_print_type) (die_pretty_print_decl, die_pretty_print) (at_least_one_decl_only_among_odr_relevant_dies) (compare_as_type_dies, compare_as_decl_and_type_dies) (fn_die_equal_by_linkage_name, try_canonical_die_comparison) (maybe_propagate_canonical_type, propagate_canonical_type) (compare_dies, compare_dies_during_canonicalization) (find_import_unit_point_between_dies, get_parent_die) (get_scope_die, find_lower_bound_in_imported_unit_points) (build_translation_unit_and_add_to_ir) (build_namespace_decl_and_add_to_ir, build_type_decl) (build_enum_underlying_type, build_enum_type) (finish_member_function_reading) (maybe_finish_function_decl_reading) (lookup_class_or_typedef_from_corpus) (is_function_for_die_a_member_of_class) (add_or_update_member_function, add_or_update_class_type) (add_or_update_union_type, build_qualified_type) (schedule_array_tree_for_late_canonicalization) (maybe_strip_qualification, build_pointer_type_def) (build_reference_type, build_function_type, build_subrange_type) (build_subranges_from_array_type_die, build_array_type) (build_typedef_type, build_or_get_var_decl_if_not_suppressed) (build_var_decl, function_is_suppressed) (build_or_get_fn_decl_if_not_suppressed, variable_is_suppressed) (type_is_suppressed, type_is_suppressed) (get_opaque_version_of_type, create_default_fn_sym) (build_function_decl, maybe_canonicalize_type) (build_ir_node_from_die) (build_ir_node_for_variadic_parameter_type): Take a reference to the new dwarf::reader rather than to the previous read_context. Adjust the function body. (return_comparison_result): Adjust. (dwarf::reader::reader): Adjust this from read_context::read_context. (dwarf::reader::initialize): Adjust from dwarf::read_context::initialize. (dwarf::reader::create): New factory static member function. (dwarf::reader::~reader): This doesn't have to clear anything for now. (dwarf::reader::read_corpus): New virtual member function which implements the fe_iface::read_corpus pure virtual interface. This now delegates the reading of the generic ELF properties to elf::reader by calling elf::reader::read_corpus(). Newer front-ends will be able to do the same. (dwarf::reader::reset_corpus): New member function. (dwarf::reader::read_debug_info_into_corpus): Adjust. This is now a member function. Also, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN here as it's now set by the elf::reader when it loads the binary. (dwarf::reader::{env, drop_undefined_syms, drop_undefined_syms, dwarf_elf_handle, dwarf_per_die_source, elf_path, compute_canonical_die_offset, get_die_source, get_die_from_offset, get_die_qualified_name, get_die_pretty_type_representation, get_die_qualified_type_name, get_die_pretty_representation, odr_is_relevant, set_canonical_die_offset, get_canonical_die_offset, erase_canonical_die_offset, die_wip_classes_map, die_wip_function_types_map, compare_before_canonicalisation, resolve_declaration_only_classes, resolve_declaration_only_enums, symbol_already_belongs_to_a_function, fixup_functions_with_no_symbols, canonicalize_types_scheduled, tu_die_imported_unit_points_map, die_parent_map, find_symbol_table_section, get_variable_address, exported_decls_builder, load_all_types, load_in_linux_kernel_mode, show_stats, do_log, build_die_parent_maps): Adjust. (offset_pairs_stack_type::rdr_): Changed the ctxt_ into this. (offset_pairs_stack_type::offset_pairs_stack_type): Adjust. (offset_pairs_stack_type::{erase_redundant_type_pair_entry, cancel_canonical_propagated_type}): Adjust. (dwarf::reader::{get_suppressions, offline_callbacks, create_default_dwfl, dwfl_handle, elf_module, elf_handle, add_debug_info_root_paths, add_debug_info_root_path, find_alt_debug_info, dwarf, alt_dwarf, alt_debug_info_path, current_corpus, reset_current_corpus, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group, function_symbol_is_exported, variable_symbol_is_exported, symtab, dt_needed, dt_soname, elf_architecture, is_elf_symbol_suppressed, load_dt_soname_and_needed, load_elf_architecture, load_elf_properties, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls}): Remove these member functions as they got moved into the elf_reader namespace or into the fe_iface class. (dwarf::read_context::{suppression_can_match, suppression_matches_function_sym_name, suppression_matches_function_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location}): Move these into the suppr namespace. Make it take an additional parameter that is reference fe_iface. (dwarf::reader::load_debug_info): Remove. This became merged into dwarf::read_debug_info_into_corpus. (dwarf::{set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_drop_undefined_syms, set_do_log}): Remove. (add_read_context_suppressions) (set_read_context_corpus_group, read_corpus_from_elf): Remove. (read_debug_info_into_corpus): This became a member function of dwarf::reader. (create_reader): Renamed create_read_context into this. Make it return an elf_based_reader_sptr, like the other front-end factory functions. Adjust. (reset_dwarf_reader): Renamed reset_read_context into this. Adjust. (read_corpus_from_elf): Adjust. * src/abg-elf-based-reader.cc: New file. * src/abg-elf-helpers.h (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_sptr): Move these types here from abg-dwarf-reader.cc (initialize_dwfl_callbacks, lookup_data_tag_from_dynamic_segment): * src/abg-elf-helpers.cc (lookup_data_tag_from_dynamic_segment) (lookup_data_tag_from_dynamic_segment, initialize_dwfl_callbacks) (create_new_dwfl_handle, get_soname_of_elf_file): New functions that got moved here from the factorizing of abg-dwarf-reader.cc and abg-ctf-reader.cc. * src/abg-tools-utils.cc (file_has_dwarf_debug_info) (file_has_ctf_debug_info): New functions. (load_generate_apply_suppressions): Take an elf_based_reader, not a dwarf::read_context. (maybe_load_vmlinux_dwarf_corpus): Adjust the body to use the new front-end types. * src/Makefile.am: Add the new files src/abg-{fe-iface, elf-based-reader, elf-reader}.cc to source distribution. Remove src/abg-elf-reader-common.cc. * tools/Makefile.am: Factorize linking to libabigail.so by using LDADD. * tools/abicompat.cc (read_corpus, main): Adjust. * tools/abidiff.cc (set_suppressions) (set_native_xml_reader_options, handle_error, main): Adjust. * tools/abidw.cc (set_suppressions, load_corpus_and_write_abixml) (load_kernel_corpus_group_and_write_abixml): Adjust. * tools/abilint.cc (build_type_use_tree, show_how_type_is_used) (set_suppressions, main): Adjust. * tools/abipkgdiff.cc (elf_file::type, compare, compare_to_self) (create_maps_of_package_content) (compare_prepared_userspace_packages) (self_compare_prepared_userspace_package): Adjust. * tools/abisym.cc: Adjust invocation to abigail::dwarf::lookup_symbol_from_elf, from abigail::dwarf_reader::lookup_symbol_from_elf. * tools/kmidiff.cc (main): Adjust. * tests/print-diff-tree.cc (main): Adjust. * tests/test-abidiff.cc (main): Likewise. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-ir-walker.cc (main): Likewise. * tests/test-read-ctf.cc (test_task_ctf::perform): Likewise. * tests/test-read-dwarf.cc: Remove the useless "using" statements. * tests/test-read-write.cc: Likewise. * tests/test-symtab.cc (read_corpus, TEST_CASE) (assert_symbol_count): Adjust. * tests/data/test-read-ctf/test0.abi: Adjust. * tests/data/test-read-ctf/test0.hash.abi: Likewise. * tests/data/test-read-ctf/test1.so.abi: Likewise. * tests/data/test-read-ctf/test1.so.hash.abi: Likewise. * tests/data/test-read-ctf/test2.so.abi: Likewise. * tests/data/test-read-ctf/test2.so.hash.abi: Likewise. * tests/data/test-read-ctf/test3.so.abi: Likewise. * tests/data/test-read-ctf/test3.so.hash.abi: Likewise. * tests/data/test-read-ctf/test4.so.abi: Likewise. * tests/data/test-read-ctf/test4.so.hash.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2022-11-15 16:26:37 +00:00
abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
Support having several debuginfo search dirs for a binary There are use cases where the split debuginfo file of a given binary is under a given root directory and that the split debuginfo file itself depends on an alternate debuginfo file that is under another unrelated root directory. In that case, the dwarf reader must be able to look for the debuginfo files under several unrelated root directories. The tools abidiff and abidw must thus support having several occurences of the option --debug-info-dir1 (or --debug-info-dir2) meaning that the debuginfo files for the binary must be looked for under several root directories. This is what this patch does. * doc/manuals/abidiff.rst: Adjust doc for the --debug-info-dir{1,2} that can now be provided several times. * include/abg-dwarf-reader.h ({create, reset}_read_context) (read_corpus_from_elf): Take a vector of debug info root dirs. * include/abg-tools-utils.h (trim_leading_string) (find_file_under_dir, make_path_absolute_to_be_freed) (convert_char_stars_to_char_star_stars): Declare new functions. * src/abg-dwarf-reader.cc (find_alt_debug_info_link): Renamed find_alt_debug_info_location into this. (find_alt_debug_info_path): Define new static function. (find_alt_debug_info): Take a vector of debug info root dirs. Use the new find_alt_debug_info_path to look into the debug info root dirs for the alt debug info. (read_context::debug_info_root_paths_): Define new data member. (read_context::read_context): Take a vector of debug info root dirs and initialize the new read_context::debug_info_root_paths_. (read_context::{initialize, create_default_dwfl}): Take a vector of debug info root dirs and adjust. (read_context::{add_debug_info_root_paths, add_debug_info_root_path, find_alt_debug_info}): Define new member functions. (read_context::load_debug_info): Look into the debug info roots for split debug info files. (create_read_context, read_corpus_from_elf): Take a vector of debug info root dirs and adjust. (has_alt_debug_info): Adjust. * src/abg-tools-utils.cc (trim_leading_string) (make_path_absolute_to_be_freed, find_file_under_dir) (convert_char_stars_to_char_star_stars): Define new functions. (entry_of_file_with_name): Define new static function. (build_corpus_group_from_kernel_dist_under): Adjust. * tests/print-diff-tree.cc (main): Adjust. * tests/test-diff-dwarf.cc (main): Adjust. * tests/test-ir-walker.cc (main): Adjust. * tests/test-read-dwarf.cc (main): Adjust. * tools/abicompat.cc (main): Adjust. * tools/abidiff.cc (options::di_root_paths{1,2}): Changed di_root_path{1,2} into this, change their types into vectors of allocated char*. (options::prepared_di_root_paths{1,2}): Define new data members. (options::~options): Define new destructor. (parse_command_line): Adjust. (prepare_di_root_paths): Define new static function. (handle_error): Remove arguments input_file_name, debug_info_dir{1,2}. Now just take an instance of options instead. Adjust. (main): Adjust. * tools/abidw.cc (options::dir_root_paths): Renamed dir_root_path into this and make it be a vector of allocated char*. (options::prepared_di_root_paths): Define new data member. (options::~options): Free the allocated char* in options::dir_root_paths. (parse_command_line): Support several --debug-info-dir. (load_corpus_and_write_abixml): Adjust. (prepare_di_root_paths): Define static function. (main): Adjust. * tools/abilint.cc (main): Adjust. * tools/abipkgdiff.cc (compare): Adjust. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2018-11-08 06:26:14 +00:00
std::vector<char**> di_roots;
Make Front Ends first class citizens This patch is a reorganization of the code to better support the need for having several different front-ends. In the libabigail pipeline of operation, a front-end is the part of the pipeline that analyses the input file. For instance, to analyse an ELF file, there is going to be one front-end. To analyse an ABIXML file, there is going to be another front-end. The middle-end is the part of the pipeline that interacts with the internal representation of ABIs. The middle-end knows how to analyse, compare ABI corpora provide an internal representation of the comparison result and analyse it as well. The back-end would be the part of the front-end that knows how to serialize internal representations of ABIs and ABI comparison results. One could thus imagine a front-end that understands the DWARF debug info format embedded in an ELF file. Another front-end would be dedicated to the CTF debug info format, and so on. Front-ends can share capabilities. For instance, DWARF and CTF front-ends are ELF based front end. As such, they share capabilities to understand the ELF format. They don't share much with the ABIXML front-end, however, as it's based on XML, which has almost nothing in common with ELF. To support this organization of concepts, this patch introduces a new hierarchy of types in the form of C++ classes. All front-ends implements the "Front End Interface". As such, they all inherit the abigail::fe_iface class. That class provides properties and behaviours that are shared by all front-ends that libabigail supports today. Namely, that class provides access to some of the options that are relevant to operating the front-end, to the ABI corpus or corpus group being constructed and to the suppression specifications that are considered. It also provides an abstract interface to perform the actual loading of the ABI corpus. That abstract interface has to be implemented by every single concrete front-end that is provided in libabigail. Then, there is the "ELF Reader" front-end. Its class name is abigail::elf::reader. It inherits the abigail::fe_iface class and implements the fe_iface::load_corpus() so that the ELF properties of the ELF file be loaded and exposed in the ABI corpus as returned by the fe_iface::corpus() accessor. This ELF reader front-end also provides lots of capabilities that are specific to accessing ELF content. Then, there is a common base class for ELF-based front-ends to come, named abigail::elf_based_reader, which inherits the abigail::elf::reader class. The purpose of this base class is to provide common properties and behaviours that are necessary to implement things like a DWARF or a CTF front-end, or any other front-end to support an ELF-based debug info format. Then, there is a CTF front-end which class is named abigail::ctf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the CTF-specific properties of the ELF file. To do this, abigail::ctf::reader::load_corpus() re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus. This reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Then, there is a DWARF front-end which class is named abigail::dwarf::reader. It inherits the abigail::elf_based_reader class and implements the fe_iface::load_corpus() interface to load and analyse the DWARF-specific properties of the ELF file. To do this, abigail::dwarf::reader re-uses the abigail::elf::load_corpus() member function to load the generic ELF parts of the ABI corpus, just like what the CTF front-end does. And then, just like the CTF front-end, this reader then constructs the internal representation of the ABI corpus and passes it to the middle-end for further analysis. Lastly, there is an ABIXML front-end which class is named abigail::abixml::reader. It inherits the abigail::fe_iface class directly. Note that unlike the two previous front-ends, this one doesn't inherit the elf_based_reader base class, for reasons that should be obvious to the astute reader by now. So, this front-end implements the abigail::fe_iface::load_corpus() abstract interface to load the properties for the ABI corpus represented in the ABIXML format, construct the internal representation and pass it to the middle-end for further analysis. The code of the tools got adapted to use these front-ends. The support of CTF is still guarded by #ifdef WITH_CTF pre-processor macros, but the one cool side effect is that the amount of guarded code is reduced. Basically, it's only the creation of the CTF front-end that is guarded. After its creation, what is returned is an instance of abigail::elf_based_reader::reader, exactly like what is returned by the creation of a DWARF front-end. Thus, the rest of the code is exactly the same, regardless of the kind of front-end. I believe this results in a more elegant and maintainable code. As a proof-of-concept, this patch also provides the create_best_elf_based_reader function. This function analyses the ELF file and depending on the kind of debug info it provides, returns the right front-end for it. Maybe at some point, all the #ifdef WITH_CTF guard pre-processing macros will be constrained in a single function like this one that will take the decision of instantiating the right front-end. The rest of the code will be as generic as it gets. The patch adjusts the reference abixml files produced by the CTF front-end because it now emits the <elf-needed> XML element which was not emitted before. This is done because the CTF front-end inherits the elf-reader which reads the "elf-needed" property from the binary, without explicit intervention from the CTF front-end. The patch passes 'make distcheck' on all the supported platforms. * include/abg-fwd.h (build_internal_underlying_enum_type_name): Move this here from src/abg-dwarf-reader.cc. * include/abg-elf-reader-common.h: Delete this file. Its content is going to be put in the new include/abg-elf-reader.h. * src/abg-elf-reader-common.cc: Likewise. * include/abg-{elf-based-reader, elf-reader, fe-iface}.h: Add new files. * src/abg-fe-iface.cc: Likewise. * include/Makefile.am: Add the new file abg-fe-iface.h, abg-elf-based-reader.h and abg-elf-reader.h to source distribution and remove include/abg-elf-reader-common.h from source distribution. * src/abg-ir.cc (build_internal_underlying_enum_type_name): Move this here from abg-dwarf-reader.cc so that it can be used by other readers. * include/abg-reader.h (abigail::abixml::reader): Rename the namespace abigail::xml_reader into this one. (read_context, create_native_xml_read_context) (read_context_get_path, read_corpus_from_native_xml) (read_corpus_from_native_xml_file) (read_corpus_group_from_native_xml) (read_corpus_group_from_native_xml_file): Remove. (read_translation_unit_from_file) (read_translation_unit_from_buffer) (read_translation_unit_from_istream) (read_translation_unit) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (load_canonical_type_ids): Take an fe_iface&, not a read_context. (create_reader): Declare new function that returns a fe_iface_sptr. (read_corpus_from_abixml, read_corpus_from_abixml_file) (read_corpus_group_from_abixml) (read_corpus_group_from_abixml_file): Declare new functions. * src/abg-reader.cc (namespace abixml): Rename the xml_reader namespace into this. (abixml::reader_sptr): New typedef. (abixml::reader): Rename read_context into this. Make it inherit the fe_iface interface. (abixml::reader::{m_path, m_env, m_corpus, m_corpus_group, m_exported_decls_builder, m_supprs}): Remove these data members that are now part of the fe_iface parent type. (abixml::reader::{set_environment, get_corpus, set_corpus, set_corpus_group, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls, maybe_check_abixml_canonical_type_stability, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name}): Remove. (read_corpus_from_input): Remove. Actually the code of this went into abixml::reader::read_context(). (abixml::reader::get_libxml_reader): Rename the get_reader member function into this. (abixml::add_reader_suppressions): Rename add_read_context_suppressions into this. (abixml::reader::read_corpus): Implement this virtual member function if the fe_iface parent interface. (maybe_set_naming_typedef, advance_cursor) (handle_version_attribute, walk_xml_node_to_map_type_ids) (read_elf_needed_from_input, read_symbol_db_from_input) (get_or_read_and_add_translation_unit, build_needed) (read_elf_needed_from_input, add_read_context_suppressions) (maybe_set_artificial_location, maybe_set_naming_typedef) (build_namespace_decl, build_elf_symbol) (build_elf_symbol_from_reference, build_elf_symbol_db) (build_function_parameter, build_function_decl) (build_function_decl_if_not_suppressed, function_is_suppressed) (type_is_suppressed, build_var_decl_if_not_suppressed) (variable_is_suppressed, variable_is_suppressed, build_var_decl) (build_type_decl, build_qualified_type_decl) (build_pointer_type_def, build_reference_type_def) (build_function_type, build_subrange_type, build_array_type_def) (build_enum_type_decl_if_not_suppressed, build_enum_type_decl) (build_typedef_decl, build_class_decl_if_not_suppressed) (build_union_decl_if_not_suppressed, build_class_decl) (build_union_decl, build_function_tdecl, build_class_tdecl) (build_type_tparameter, build_type_composition) (build_non_type_tparameter, build_non_type_tparameter) (build_template_tparameter, build_template_parameter, build_type) (handle_type_decl, handle_namespace_decl) (handle_qualified_type_decl, handle_pointer_type_def) (handle_reference_type_def, handle_function_type) (handle_array_type_def, handle_enum_type_decl) (handle_typedef_decl, handle_var_decl, handle_function_decl) (handle_class_decl, handle_union_decl, handle_function_tdecl) (read_translation_unit_from_istream): Take or use an abixml::reader rather than a read_context. (read_translation_unit, read_translation_unit_from_input) (consider_types_not_reachable_from_public_interfaces) (get_types_from_type_id, get_artifact_used_by_relation_map) (read_corpus_group_from_input, read_translation_unit) (handle_element_node, read_location, read_artificial_location) (load_canonical_type_ids) : Take an fe_iface&, not a read_context. (create_abixml_reader): Rename create_native_xml_read_context into this. Make it return a fe_iface_sptr. (read_corpus_from_abixml): Rename read_corpus_from_abixml into this. (read_corpus_from_abixml_file): Rename read_corpus_from_native_xml_file into this. (read_context_get_path): Remove. * include/abg-tools-utils.h (abigail::tools_utils::{file_has_dwarf_debug_info, file_has_ctf_debug_info}): Declare new functions. (create_best_elf_based_reader): Declare new function. * include/abg-corpus.h (corpus::add): Pass the translation unit by reference. (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. * src/abg-corpus-priv.h (corpus::exported_decls_builder::priv::add_{fn,var}_to_exported): Take a const parameter and adjust. * src/abg-corpus.cc (corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns): Take a const parameter. (corpus::add): Take a reference to translation_unit_sptr. * include/abg-suppression.h (abigail::fe_iface): Forward-declare this. (abigail::{suppression_sptr, suppressions_type}): Declare these types here. (abigail::suppr::{suppression_can_match, suppression_matches_function_name, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location, is_elf_symbol_suppressed, is_elf_symbol_suppressed, is_function_suppressed, is_variable_suppressed, is_type_suppressed}): Declare these functions here. * src/abg-suppression-priv.h (function_is_suppressed) (variable_is_suppressed, type_is_suppressed) (is_elf_symbol_suppressed): Remove these template functions. * src/abg-suppression.cc (suppression_matches_function_name) (suppression_matches_function_sym_name): Remove. (variable_is_suppressed, suppression_can_match) (suppression_matches_function_name) (suppression_matches_function_sym_name) (suppression_matches_variable_name) (suppression_matches_variable_sym_name) (suppression_matches_type_name_or_location) (is_elf_symbol_suppressed, is_elf_symbol_suppressed) (is_function_suppressed, is_variable_suppressed) (is_type_suppressed): New functions. * include/abg-ctf-reader.h (abigail::ctf::{read_context, create_read_context, read_corpus, read_and_add_corpus_to_group_from_elf, set_read_context_corpus_group, reset_read_context, dic_type_key}): Remove. (ctf::{create_reader, reset_reader}): Declare new functions. * src/abg-ctf-reader.cc (read_context): Remove. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type) (process_ctf_enum_type, fill_ctf_section) (lookup_symbol_in_ctf_archive, dic_type_key): Forward-declare these static functions. (ctf::reader): New class that is the abstraction of the CTF reader. It extends the abigail::elf_based_reader class. This is a renaming of the abigail::ctf::read_context class. (ctf::reader::{elf_handler, elf_fd, elf_handler_dbg, elf_fd_dbg, symtab, debug_info_root_paths_, debug_info_root_paths_}): Remove these data members as they are now properties of the abigail::elf_reader class, which is a parent class of this abigail::ctf::reader class. (ctf::reader::{exported_decls_builder, maybe_add_fn_to_exported_decls, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group}): Remove these accessors that can now be used from the parent classes abigail::{elf_reader, elf_based_reader}. (ctf::reader::reader): This now delegates to the constructor of elf_based_reader. It doesn't pass any argument to initialize() anymore. (ctf::reader::initialize): Add an overload with no parameter. In the other overload, do not take a pointer to an environment as no new environment can be passed to the instance of reader that is being reset. Adjust the code of the initializer to reflect all the data members that got removed. (ctf::{env, find_ctfa_file, slurp_elf_info, process_ctf_archive, process_ctf_type, lookup_type, read_corpus, ~reader}): New member functions. Most of these were free-form functions that took ctf::read_context as first parameter. In read_corpus, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN origin as that is now done by elf::reader when it reads the binary. (lookup_type): Remove. These are now member functions of the ctf::reader class. (process_ctf_typedef, process_ctf_base_type) (build_ir_node_for_variadic_parameter_type) (process_ctf_function_type, process_ctf_sou_members) (process_ctf_forward_type, process_ctf_struct_type) (process_ctf_union_type, process_ctf_array_type) (process_ctf_qualified_type, process_ctf_pointer_type): Take a ctf::reader rather an ctf::read_context. Adjust the content of the functions. (process_ctf_type, lookup_type, process_ctf_archive): Remove these and turn them into member functions of ctf::reader. (open_elf_handler, close_elf_handler, find_alt_debuginfo): Remove these ELF handling functions as ELF handling is now done by the elf_reader parent class. (fill_ctf_section): Take a const pointer to Elf_Scn. (slurp_elf_info, find_ctfa_file): Remove this and make it be a member of ctf::reader. Also, make it handle only CTF reader specific pieces. slurp_elf_info now delegates the reading of generic ELF properties to elf::reader by calling elf::reader::read_corpus(). (create_read_context, read_corpus, set_read_context_corpus_group) (read_and_add_corpus_to_group_from_elf): Remove these functions. (create_reader, reset_reader): Create new functions (dic_type_key): Make this static. * include/abg-dwarf-reader.h (abigail::dwarf::elf_type): Move this enum into the namespace abigail::elf_reader in the file include/abg-elf-reader.h. (abigail::dwarf::{read_context, read_context_sptr, create_read_context, read_context_get_path, reset_read_context, add_read_context_suppressions, set_read_context_corpus_group, read_corpus_from_elf, read_and_add_corpus_to_group_from_elf, read_and_add_corpus_to_group_from_elf, add_read_context_suppressions, refers_to_alt_debug_info, has_alt_debug_info, get_soname_of_elf_file, get_type_of_elf_file, set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_show_stats, set_drop_undefined_syms, set_do_log, set_environment, get_environment}): Remove. * src/abg-dwarf-reader.cc (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_type) (address_set_sptr): Delete these types. (read_context::options_type): Remove. The data members of this type got moved to struct fe_iface::options_type. (find_alt_debug_info_link, find_alt_debug_info_path) (find_alt_debug_info, lookup_data_tag_from_dynamic_segment) (elf_file_type, refers_to_alt_debug_info, has_alt_debug_info) (get_soname_of_elf_file, get_type_of_elf_file) : Remove these ELF specific functions from here; move them to the elf_reader namespace. (dwarf::reader): Create new class that extends elf_based_reader. dwarf::read_context is renamed into this type, actually. (dwarf::reader::die_source_dependant_container_set::get_container): Adjust. (dwarf::reader::{supprs_, dwarf_version_, offline_callbacks_, debug_info_root_paths_, handle_, dwarf_, alt_fd_, alt_dwarf_, alt_debug_info_path_, elf_module_, elf_handle_, elf_path_, symtab_section_, cur_corpus_group_, cur_corpus_, dt_needed_, dt_soname_, elf_architecture_, exported_decls_builder_, options_, drop_undefined_syms_}): Remove these ELF-related data members to move them into the elf_reader namespace. (maybe_propagate_canonical_type) (build_translation_unit_and_add_to_ir, build_ir_node_from_die) (add_or_update_class_type, add_or_update_union_type) (build_ir_node_for_void_type) (build_ir_node_for_variadic_parameter_type, build_function_decl) (function_is_suppressed, build_or_get_fn_decl_if_not_suppressed) (build_var_decl, build_or_get_var_decl_if_not_suppressed) (variable_is_suppressed) (propagate_canonical_type) (get_parent_die, get_scope_die, die_is_at_class_scope) (die_location, die_qualified_type_name, die_qualified_name) (die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_function_type_is_method_type) (die_pretty_print_type, die_pretty_print_decl, die_pretty_print) (maybe_canonicalize_type, build_subrange_type) (build_subranges_from_array_type_die, compare_dies, die_location) (die_loc_and_name, die_is_effectively_public_decl) (maybe_cache_type_comparison_result) (get_cached_type_comparison_result) (maybe_get_cached_type_comparison_result, die_is_at_class_scope) (die_function_type_is_method_type, die_member_offset) (die_qualified_type_name, die_qualified_decl_name) (die_qualified_name, die_qualified_type_name_empty) (die_return_and_parm_names_from_fn_type_die) (die_function_signature, die_pretty_print_type) (die_pretty_print_decl, die_pretty_print) (at_least_one_decl_only_among_odr_relevant_dies) (compare_as_type_dies, compare_as_decl_and_type_dies) (fn_die_equal_by_linkage_name, try_canonical_die_comparison) (maybe_propagate_canonical_type, propagate_canonical_type) (compare_dies, compare_dies_during_canonicalization) (find_import_unit_point_between_dies, get_parent_die) (get_scope_die, find_lower_bound_in_imported_unit_points) (build_translation_unit_and_add_to_ir) (build_namespace_decl_and_add_to_ir, build_type_decl) (build_enum_underlying_type, build_enum_type) (finish_member_function_reading) (maybe_finish_function_decl_reading) (lookup_class_or_typedef_from_corpus) (is_function_for_die_a_member_of_class) (add_or_update_member_function, add_or_update_class_type) (add_or_update_union_type, build_qualified_type) (schedule_array_tree_for_late_canonicalization) (maybe_strip_qualification, build_pointer_type_def) (build_reference_type, build_function_type, build_subrange_type) (build_subranges_from_array_type_die, build_array_type) (build_typedef_type, build_or_get_var_decl_if_not_suppressed) (build_var_decl, function_is_suppressed) (build_or_get_fn_decl_if_not_suppressed, variable_is_suppressed) (type_is_suppressed, type_is_suppressed) (get_opaque_version_of_type, create_default_fn_sym) (build_function_decl, maybe_canonicalize_type) (build_ir_node_from_die) (build_ir_node_for_variadic_parameter_type): Take a reference to the new dwarf::reader rather than to the previous read_context. Adjust the function body. (return_comparison_result): Adjust. (dwarf::reader::reader): Adjust this from read_context::read_context. (dwarf::reader::initialize): Adjust from dwarf::read_context::initialize. (dwarf::reader::create): New factory static member function. (dwarf::reader::~reader): This doesn't have to clear anything for now. (dwarf::reader::read_corpus): New virtual member function which implements the fe_iface::read_corpus pure virtual interface. This now delegates the reading of the generic ELF properties to elf::reader by calling elf::reader::read_corpus(). Newer front-ends will be able to do the same. (dwarf::reader::reset_corpus): New member function. (dwarf::reader::read_debug_info_into_corpus): Adjust. This is now a member function. Also, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN here as it's now set by the elf::reader when it loads the binary. (dwarf::reader::{env, drop_undefined_syms, drop_undefined_syms, dwarf_elf_handle, dwarf_per_die_source, elf_path, compute_canonical_die_offset, get_die_source, get_die_from_offset, get_die_qualified_name, get_die_pretty_type_representation, get_die_qualified_type_name, get_die_pretty_representation, odr_is_relevant, set_canonical_die_offset, get_canonical_die_offset, erase_canonical_die_offset, die_wip_classes_map, die_wip_function_types_map, compare_before_canonicalisation, resolve_declaration_only_classes, resolve_declaration_only_enums, symbol_already_belongs_to_a_function, fixup_functions_with_no_symbols, canonicalize_types_scheduled, tu_die_imported_unit_points_map, die_parent_map, find_symbol_table_section, get_variable_address, exported_decls_builder, load_all_types, load_in_linux_kernel_mode, show_stats, do_log, build_die_parent_maps): Adjust. (offset_pairs_stack_type::rdr_): Changed the ctxt_ into this. (offset_pairs_stack_type::offset_pairs_stack_type): Adjust. (offset_pairs_stack_type::{erase_redundant_type_pair_entry, cancel_canonical_propagated_type}): Adjust. (dwarf::reader::{get_suppressions, offline_callbacks, create_default_dwfl, dwfl_handle, elf_module, elf_handle, add_debug_info_root_paths, add_debug_info_root_path, find_alt_debug_info, dwarf, alt_dwarf, alt_debug_info_path, current_corpus, reset_current_corpus, current_corpus_group, has_corpus_group, main_corpus_from_current_group, current_corpus_is_main_corpus_from_current_group, should_reuse_type_from_corpus_group, function_symbol_is_exported, variable_symbol_is_exported, symtab, dt_needed, dt_soname, elf_architecture, is_elf_symbol_suppressed, load_dt_soname_and_needed, load_elf_architecture, load_elf_properties, maybe_add_fn_to_exported_decls, maybe_add_var_to_exported_decls}): Remove these member functions as they got moved into the elf_reader namespace or into the fe_iface class. (dwarf::read_context::{suppression_can_match, suppression_matches_function_sym_name, suppression_matches_function_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location}): Move these into the suppr namespace. Make it take an additional parameter that is reference fe_iface. (dwarf::reader::load_debug_info): Remove. This became merged into dwarf::read_debug_info_into_corpus. (dwarf::{set_debug_info_root_path, get_debug_info_root_path, get_show_stats, set_drop_undefined_syms, set_do_log}): Remove. (add_read_context_suppressions) (set_read_context_corpus_group, read_corpus_from_elf): Remove. (read_debug_info_into_corpus): This became a member function of dwarf::reader. (create_reader): Renamed create_read_context into this. Make it return an elf_based_reader_sptr, like the other front-end factory functions. Adjust. (reset_dwarf_reader): Renamed reset_read_context into this. Adjust. (read_corpus_from_elf): Adjust. * src/abg-elf-based-reader.cc: New file. * src/abg-elf-helpers.h (struct dwfl_deleter, dwfl_sptr) (addr_elf_symbol_sptr_map_type, address_set_sptr): Move these types here from abg-dwarf-reader.cc (initialize_dwfl_callbacks, lookup_data_tag_from_dynamic_segment): * src/abg-elf-helpers.cc (lookup_data_tag_from_dynamic_segment) (lookup_data_tag_from_dynamic_segment, initialize_dwfl_callbacks) (create_new_dwfl_handle, get_soname_of_elf_file): New functions that got moved here from the factorizing of abg-dwarf-reader.cc and abg-ctf-reader.cc. * src/abg-tools-utils.cc (file_has_dwarf_debug_info) (file_has_ctf_debug_info): New functions. (load_generate_apply_suppressions): Take an elf_based_reader, not a dwarf::read_context. (maybe_load_vmlinux_dwarf_corpus): Adjust the body to use the new front-end types. * src/Makefile.am: Add the new files src/abg-{fe-iface, elf-based-reader, elf-reader}.cc to source distribution. Remove src/abg-elf-reader-common.cc. * tools/Makefile.am: Factorize linking to libabigail.so by using LDADD. * tools/abicompat.cc (read_corpus, main): Adjust. * tools/abidiff.cc (set_suppressions) (set_native_xml_reader_options, handle_error, main): Adjust. * tools/abidw.cc (set_suppressions, load_corpus_and_write_abixml) (load_kernel_corpus_group_and_write_abixml): Adjust. * tools/abilint.cc (build_type_use_tree, show_how_type_is_used) (set_suppressions, main): Adjust. * tools/abipkgdiff.cc (elf_file::type, compare, compare_to_self) (create_maps_of_package_content) (compare_prepared_userspace_packages) (self_compare_prepared_userspace_package): Adjust. * tools/abisym.cc: Adjust invocation to abigail::dwarf::lookup_symbol_from_elf, from abigail::dwarf_reader::lookup_symbol_from_elf. * tools/kmidiff.cc (main): Adjust. * tests/print-diff-tree.cc (main): Adjust. * tests/test-abidiff.cc (main): Likewise. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-ir-walker.cc (main): Likewise. * tests/test-read-ctf.cc (test_task_ctf::perform): Likewise. * tests/test-read-dwarf.cc: Remove the useless "using" statements. * tests/test-read-write.cc: Likewise. * tests/test-symtab.cc (read_corpus, TEST_CASE) (assert_symbol_count): Adjust. * tests/data/test-read-ctf/test0.abi: Adjust. * tests/data/test-read-ctf/test0.hash.abi: Likewise. * tests/data/test-read-ctf/test1.so.abi: Likewise. * tests/data/test-read-ctf/test1.so.hash.abi: Likewise. * tests/data/test-read-ctf/test2.so.abi: Likewise. * tests/data/test-read-ctf/test2.so.hash.abi: Likewise. * tests/data/test-read-ctf/test3.so.abi: Likewise. * tests/data/test-read-ctf/test3.so.hash.abi: Likewise. * tests/data/test-read-ctf/test4.so.abi: Likewise. * tests/data/test-read-ctf/test4.so.hash.abi: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2022-11-15 16:26:37 +00:00
if (!(c = dwarf::read_corpus_from_elf(file_name, di_roots, env,
/*load_all_type=*/false,
status)))
{
cerr << "failed to read " << file_name << "\n";
return 1;
}
name_printing_visitor v;
// Now traverse each translation unit of the corpus using our
// instance of name_printing_visitor
for (abigail::ir::translation_units::const_iterator tu_iterator =
c->get_translation_units().begin();
tu_iterator != c->get_translation_units().end();
++tu_iterator)
(*tu_iterator)->traverse(v);
}