mirror of
git://sourceware.org/git/libabigail.git
synced 2025-01-22 09:12:55 +00:00
2bb45265d3
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>
180 lines
4.1 KiB
C++
180 lines
4.1 KiB
C++
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
// -*- Mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2013-2022 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;
|
|
|
|
///@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
|
|
{
|
|
unsigned level_;
|
|
|
|
name_printing_visitor()
|
|
: level_()
|
|
{
|
|
// Using this visitor, the IR walker will visit each type only
|
|
// once.
|
|
allow_visiting_already_visited_type_node(false);
|
|
}
|
|
|
|
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
|
|
visit_begin(abigail::var_decl* v)
|
|
{
|
|
string prefix = build_level_prefix();
|
|
cout << prefix << v->get_pretty_representation() << "\n";
|
|
++level_;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
visit_end(abigail::var_decl*)
|
|
{
|
|
--level_;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return 0;
|
|
|
|
string file_name = argv[1];
|
|
|
|
abigail::ir::environment env;
|
|
abigail::corpus_sptr c;
|
|
abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
|
|
std::vector<char**> di_roots;
|
|
if (!(c = abigail::dwarf_reader::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);
|
|
}
|