diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp index 9d7e07e30..4c5196a40 100644 --- a/vndk/tools/header-checker/Android.bp +++ b/vndk/tools/header-checker/Android.bp @@ -110,6 +110,7 @@ cc_binary_host { srcs: [ "src/linker/header_abi_linker.cpp", + "src/linker/module_merger.cpp", ], } diff --git a/vndk/tools/header-checker/src/diff/abi_diff.cpp b/vndk/tools/header-checker/src/diff/abi_diff.cpp index 1784a8c88..0dd4439c8 100644 --- a/vndk/tools/header-checker/src/diff/abi_diff.cpp +++ b/vndk/tools/header-checker/src/diff/abi_diff.cpp @@ -14,6 +14,7 @@ #include "diff/abi_diff.h" +#include "repr/ir_reader.h" #include "utils/header_abi_util.h" #include @@ -112,7 +113,7 @@ HeaderAbiDiff::ExtractUserDefinedTypes(const repr::ModuleIR &tu) { if (odr_list.size() != 1) { continue; } - const repr::TypeIR *type = *(odr_list.begin()); + const repr::TypeIR *type = odr_list.begin()->type_ir_; const repr::RecordTypeIR *record_type = nullptr; switch (type->GetKind()) { case repr::RecordTypeKind: diff --git a/vndk/tools/header-checker/src/linker/header_abi_linker.cpp b/vndk/tools/header-checker/src/linker/header_abi_linker.cpp index 1ab50ba24..2a486d17e 100644 --- a/vndk/tools/header-checker/src/linker/header_abi_linker.cpp +++ b/vndk/tools/header-checker/src/linker/header_abi_linker.cpp @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "repr/ir_representation.h" +#include "linker/module_merger.h" #include "repr/ir_dumper.h" #include "repr/ir_reader.h" +#include "repr/ir_representation.h" #include "repr/symbol/so_file_parser.h" #include "repr/symbol/version_script_parser.h" #include "utils/command_line_utils.h" @@ -42,8 +43,6 @@ using header_checker::utils::CollectAllExportedHeaders; using header_checker::utils::HideIrrelevantCommandLineOptions; -static constexpr std::size_t kSourcesPerBatchThread = 7; - static llvm::cl::OptionCategory header_linker_category( "header-abi-linker options"); @@ -104,6 +103,12 @@ static llvm::cl::opt output_format( llvm::cl::init(TextFormatIR::Json), llvm::cl::cat(header_linker_category)); +static llvm::cl::opt sources_per_thread( + "sources-per-thread", + llvm::cl::desc("Specify number of input dump files each thread parses, for " + "debugging merging types"), + llvm::cl::init(7), llvm::cl::Hidden); + class HeaderAbiLinker { public: HeaderAbiLinker( @@ -130,7 +135,7 @@ class HeaderAbiLinker { const repr::AbiElementMap &src, const std::function &symbol_filter); - std::unique_ptr ReadInputDumpFiles(); + std::unique_ptr ReadInputDumpFiles(); bool ReadExportedSymbols(); @@ -138,11 +143,13 @@ class HeaderAbiLinker { bool ReadExportedSymbolsFromSharedObjectFile(); - bool LinkTypes(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkTypes(const repr::ModuleIR &module, repr::ModuleIR *linked_module); - bool LinkFunctions(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkFunctions(const repr::ModuleIR &module, + repr::ModuleIR *linked_module); - bool LinkGlobalVars(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkGlobalVars(const repr::ModuleIR &module, + repr::ModuleIR *linked_module); bool LinkExportedSymbols(repr::ModuleIR *linked_module); @@ -177,22 +184,22 @@ class HeaderAbiLinker { std::unique_ptr version_script_symbols_; }; -static void DeDuplicateAbiElementsThread( - const std::vector &dump_files, - const std::set *exported_headers, - repr::IRReader *greader, std::mutex *greader_lock, - std::atomic *cnt) { - std::unique_ptr local_reader = - repr::IRReader::CreateIRReader(input_format, exported_headers); +static void +DeDuplicateAbiElementsThread(const std::vector &dump_files, + const std::set *exported_headers, + repr::ModuleMerger *global_merger, + std::mutex *global_merger_lock, + std::atomic *cnt) { + repr::ModuleMerger local_merger(exported_headers); auto begin_it = dump_files.begin(); std::size_t num_sources = dump_files.size(); while (1) { - std::size_t i = cnt->fetch_add(kSourcesPerBatchThread); + std::size_t i = cnt->fetch_add(sources_per_thread); if (i >= num_sources) { break; } - std::size_t end = std::min(i + kSourcesPerBatchThread, num_sources); + std::size_t end = std::min(i + sources_per_thread, num_sources); for (auto it = begin_it + i; it != begin_it + end; it++) { std::unique_ptr reader = repr::IRReader::CreateIRReader(input_format, exported_headers); @@ -201,37 +208,37 @@ static void DeDuplicateAbiElementsThread( llvm::errs() << "ReadDump failed\n"; ::exit(1); } - local_reader->MergeGraphs(*reader); + local_merger.MergeGraphs(reader->GetModule()); } } - std::lock_guard lock(*greader_lock); - greader->MergeGraphs(*local_reader); + std::lock_guard lock(*global_merger_lock); + global_merger->MergeGraphs(local_merger.GetModule()); } -std::unique_ptr -HeaderAbiLinker::ReadInputDumpFiles() { - std::unique_ptr greader = - repr::IRReader::CreateIRReader(input_format, &exported_headers_); +std::unique_ptr HeaderAbiLinker::ReadInputDumpFiles() { + std::unique_ptr merger( + new repr::ModuleMerger(&exported_headers_)); std::size_t max_threads = std::thread::hardware_concurrency(); - std::size_t num_threads = kSourcesPerBatchThread < dump_files_.size() ? - std::min(dump_files_.size() / kSourcesPerBatchThread, max_threads) : 0; + std::size_t num_threads = + sources_per_thread < dump_files_.size() + ? std::min(dump_files_.size() / sources_per_thread, max_threads) + : 1; std::vector threads; std::atomic cnt(0); - std::mutex greader_lock; + std::mutex merger_lock; for (std::size_t i = 1; i < num_threads; i++) { threads.emplace_back(DeDuplicateAbiElementsThread, dump_files_, - &exported_headers_, greader.get(), &greader_lock, - &cnt); + &exported_headers_, merger.get(), &merger_lock, &cnt); } - DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, greader.get(), - &greader_lock, &cnt); + DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, merger.get(), + &merger_lock, &cnt); for (auto &thread : threads) { thread.join(); } - return greader; + return merger; } bool HeaderAbiLinker::LinkAndDump() { @@ -245,9 +252,9 @@ bool HeaderAbiLinker::LinkAndDump() { exported_headers_ = CollectAllExportedHeaders(exported_header_dirs_); // Read all input ABI dumps. - auto greader = ReadInputDumpFiles(); + auto merger = ReadInputDumpFiles(); - repr::ModuleIR &module = greader->GetModule(); + const repr::ModuleIR &module = merger->GetModule(); // Link input ABI dumps. std::unique_ptr linked_module( @@ -302,7 +309,7 @@ bool HeaderAbiLinker::LinkDecl( return true; } -bool HeaderAbiLinker::LinkTypes(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkTypes(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto no_filter = [](const std::string &symbol) { return true; }; return LinkDecl(linked_module, module.GetRecordTypes(), no_filter) && @@ -326,7 +333,7 @@ bool HeaderAbiLinker::IsSymbolExported(const std::string &name) const { return true; } -bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkFunctions(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto symbol_filter = [this](const std::string &linker_set_key) { return IsSymbolExported(linker_set_key); @@ -334,7 +341,7 @@ bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module, return LinkDecl(linked_module, module.GetFunctions(), symbol_filter); } -bool HeaderAbiLinker::LinkGlobalVars(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkGlobalVars(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto symbol_filter = [this](const std::string &linker_set_key) { return IsSymbolExported(linker_set_key); diff --git a/vndk/tools/header-checker/src/linker/module_merger.cpp b/vndk/tools/header-checker/src/linker/module_merger.cpp new file mode 100644 index 000000000..5132d2fe6 --- /dev/null +++ b/vndk/tools/header-checker/src/linker/module_merger.cpp @@ -0,0 +1,594 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "linker/module_merger.h" +#include "repr/abi_diff_helpers.h" +#include "repr/ir_representation_internal.h" + +#include + +#include + + +namespace header_checker { +namespace repr { + + +MergeStatus ModuleMerger::MergeBuiltinType( + const BuiltinTypeIR *builtin_type, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + std::string linker_set_key = builtin_type->GetLinkerSetKey(); + auto builtin_it = module_->builtin_types_.find(linker_set_key); + if (builtin_it != module_->builtin_types_.end()) { + return MergeStatus(false, builtin_it->second.GetSelfType()); + } + + // Add this builtin type to the parent graph's builtin_types_ map. + const std::string &type_id = builtin_type->GetSelfType(); + auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type); + module_->type_graph_.emplace(type_id, &p.first->second); + + MergeStatus merge_status(true, type_id); + local_to_global_type_id_map->emplace(type_id, merge_status); + return merge_status; +} + + +MergeStatus ModuleMerger::LookupUserDefinedType( + const TypeIR *ud_type, const ModuleIR &addend, + const std::string &ud_type_unique_id_and_source, + AbiElementMap *local_to_global_type_id_map_) { + auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source); + if (it == module_->odr_list_map_.end()) { + // Calling this an ODR violation even though it means no UD with the same + // name + source combination was seen in the parent graph. The type-id + // passed does not matter since was_newly_added_ is true, the type will get + // allocated a new type id. + return MergeStatus(true, ""); + } + + // Initialize type comparator (which will compare the referenced types + // recursively). + std::set type_cache; + DiffPolicyOptions diff_policy_options(false); + AbiDiffHelper diff_helper(module_->type_graph_, addend.type_graph_, + diff_policy_options, &type_cache, nullptr); + + // Compare each user-defined type with the latest input user-defined type. + // If there is a match, re-use the existing user-defined type. + for (auto &definition : it->second) { + const TypeIR *contender_ud = definition.type_ir_; + DiffStatus result = diff_helper.CompareAndDumpTypeDiff( + contender_ud->GetSelfType(), ud_type->GetSelfType()); + if (result == DiffStatus::no_diff) { + local_to_global_type_id_map_->emplace( + ud_type->GetSelfType(), + MergeStatus(false, contender_ud->GetSelfType())); + return MergeStatus(false, contender_ud->GetSelfType()); + } + } + +#ifdef DEBUG + llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n"; +#endif + return MergeStatus(true, it->second.begin()->type_ir_->GetSelfType()); +} + + +MergeStatus ModuleMerger::LookupType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + std::string unique_type_id; + switch (addend_node->GetKind()) { + case RecordTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + case EnumTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + case FunctionTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + default: + // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind, + // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind) + // should be proactively added by returning MergeStatus with + // was_newly_added_ = true. + return MergeStatus(true, "type-hidden"); + } + + return LookupUserDefinedType( + addend_node, addend, unique_type_id, local_to_global_type_id_map); +} + + +// This method merges the type referenced by 'references_type' into the parent +// graph. It also corrects the referenced_type field in the references_type +// object passed and returns the merge status of the *referenced type*. +MergeStatus ModuleMerger::MergeReferencingTypeInternal( + const ModuleIR &addend, ReferencesOtherType *references_type, + AbiElementMap *local_to_global_type_id_map) { + // First look in the local_to_global_type_id_map for the referenced type's + // id. + const std::string &referenced_type_id = references_type->GetReferencedType(); + auto local_to_global_it = local_to_global_type_id_map->find( + referenced_type_id); + if (local_to_global_it != local_to_global_type_id_map->end()) { + // The type was already added to the parent graph. So change the + // referenced type to the global type id. + references_type->SetReferencedType(local_to_global_it->second.type_id_); + return local_to_global_it->second; + } + + // If that did not go through, look at the addend's type_map_ and get the + // TypeIR* and call MergeType on it. + auto local_type_it = addend.type_graph_.find(referenced_type_id); + if (local_type_it != addend.type_graph_.end()) { + // We don't care about merge_status.was_newly_added since we wouldn't have + // gotten this far if we weren't adding this. + MergeStatus merge_status = + MergeType(local_type_it->second, addend, local_to_global_type_id_map); + const std::string &global_type_id = merge_status.type_id_; + references_type->SetReferencedType(global_type_id); + return merge_status; + } + + // If the referenced type was hidden, create the name reference type in the + // parent module and keep the referenced type_id as-is. + return MergeStatus(true, referenced_type_id); +} + + +void ModuleMerger::MergeRecordFields( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &field : added_node->GetFields()) { + MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordCXXBases( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &base : added_node->GetBases()) { + MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordTemplateElements( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &template_element : added_node->GetTemplateElements()) { + MergeReferencingTypeInternal( + addend, &template_element, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordDependencies( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + // First call MergeType on all its fields. + MergeRecordFields(addend, added_node, local_to_global_type_id_map); + + // Call MergeType on CXXBases of the record. + MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map); + + MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map); +} + + +template +std::pair::iterator> +ModuleMerger::UpdateUDTypeAccounting( + const T *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *specific_type_map) { + const std::string addend_compilation_unit_path = + addend.GetCompilationUnitPath(addend_node); + assert(addend_compilation_unit_path != ""); + std::string added_type_id = addend_node->GetSelfType(); + auto type_id_it = module_->type_graph_.find(added_type_id); + if (type_id_it != module_->type_graph_.end()) { + added_type_id = added_type_id + "#ODR:" + addend_compilation_unit_path; + } + + // Add the ud-type with type-id to the type_graph_, since if there are generic + // reference types which refer to the record being added, they'll need to find + // it's id in the map. + // Add ud-type to the parent graph. + T added_type_ir = *addend_node; + added_type_ir.SetSelfType(added_type_id); + added_type_ir.SetReferencedType(added_type_id); + auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map, + &module_->type_graph_); + // Add to facilitate ODR checking. + const std::string &key = GetODRListMapKey(&(it->second)); + MergeStatus type_merge_status = MergeStatus(true, added_type_id); + module_->AddToODRListMap(key, &(it->second), addend_compilation_unit_path); + local_to_global_type_id_map->emplace(addend_node->GetSelfType(), + type_merge_status); + return {type_merge_status, it}; +} + + +// This method is necessarily going to have a was_newly_merged_ = true in its +// MergeStatus return. So it necessarily merges a new RecordType. +MergeStatus ModuleMerger::MergeRecordAndDependencies( + const RecordTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, + &module_->record_types_); + MergeRecordDependencies(addend, &p.second->second, + local_to_global_type_id_map); + return p.first; +} + + +void ModuleMerger::MergeEnumDependencies( + const ModuleIR &addend, EnumTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + const std::string underlying_type_id = added_node->GetUnderlyingType(); + // Get the underlying type, it nessarily has to be present in the addend's + // type graph since builtin types can't be hidden. Call MergeType on it and + // change the underlying type to that. + auto it = addend.type_graph_.find(underlying_type_id); + if (it == addend.type_graph_.end()) { + llvm::errs() << "Enum underlying types should not be hidden\n"; + ::exit(1); + } + MergeStatus merge_status = MergeType( + it->second, addend, local_to_global_type_id_map); + added_node->SetUnderlyingType(merge_status.type_id_); +} + + +// This method is necessarily going to have a was_newly_merged_ = true in its +// MergeStatus return. So it necessarily merges a new EnumType. +MergeStatus ModuleMerger::MergeEnumType( + const EnumTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, &module_->enum_types_); + MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map); + return p.first; +} + + +MergeStatus ModuleMerger::MergeFunctionType( + const FunctionTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, + &module_->function_types_); + MergeCFunctionLikeDeps(addend, &p.second->second, + local_to_global_type_id_map); + return p.first; +} + + +template +MergeStatus ModuleMerger::MergeReferencingTypeInternalAndUpdateParent( + const ModuleIR &addend, const T *addend_node, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *parent_map, const std::string &updated_self_type_id) { + MergeStatus merge_status; + uint64_t old_max_type_id = max_type_id_; + + // Create copy of addend_node + T added_node = *addend_node; + added_node.SetSelfType(updated_self_type_id); + + // The merge status returned is the merge status of the referenced type. + merge_status = MergeReferencingTypeInternal(addend, &added_node, + local_to_global_type_id_map); + if (merge_status.was_newly_added_) { + // Emplace to map (type-referenced -> Referencing type) + AddToMapAndTypeGraph(std::move(added_node), parent_map, + &module_->type_graph_); + return MergeStatus(true, updated_self_type_id); + } + + // The type that the added_node references was not newly added to the parent + // graph. However, we still might need to add the added_node to the parent + // graph, since for the particular 'Kind' of the added_node, it may not be + // present in the parent graph. This will be determined by looking at the + // appropriate 'type-referenced' -> TypeElement map in the parent for the + // type-id returned by the MergeStatus. If the map doesn't have an entry for + // the type-id returned by the MergeStatus, the added_type is not present in + // the parent graph and needs to be 'newly' added. We also need to modify the + // global type id in the local_to_global_type_id map. The added_node should + // already have it's self_type and referenced_type fields fixed up. + // We maintain a rollback id to have contiguous type ids. + max_type_id_ = old_max_type_id; + + // Try finding the referenced_type is referred to by any referencing type + // of the same kind in the parent graph. It is safe to call this on the + // added_node, since the referenced_type in the added_node would have been + // modified by the MergeReferencingTypeInternal call. + auto it = parent_map->find(GetReferencedTypeMapKey(added_node)); + if (it == parent_map->end()) { + // There was no counterpart found for the added_node's type Kind referencing + // the referenced type, so we added it to the parent and also updated the + // local_to_global_type_id_map's global_id value. + AddToMapAndTypeGraph(std::move(added_node), parent_map, + &module_->type_graph_); + + merge_status = MergeStatus(true, updated_self_type_id); + return merge_status; + } + + // Update local_to_global_type_id map's MergeStatus.was_newly_added value for + // this key with false since this was node was not newly added. + // We never remove anything from the local_to_global_type_id_map, what's + // the point ? Since you store the decision of whether the type was newly + // added or not. It's global type id is the type-id of the element found + // in the parent map which refers to the added_node's modified + // referenced_type. + merge_status = MergeStatus(false, it->second.GetSelfType()); + (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status; + + return merge_status; +} + + +static bool IsReferencingType(LinkableMessageKind kind) { + switch (kind) { + case PointerTypeKind: + case QualifiedTypeKind: + case ArrayTypeKind: + case LvalueReferenceTypeKind: + case RvalueReferenceTypeKind: + return true; + case RecordTypeKind: + case EnumTypeKind: + case BuiltinTypeKind: + case FunctionTypeKind: + case FunctionKind: + case GlobalVarKind: + return false; + } +} + + +// Trace the referenced type until reaching a RecordTypeIR, EnumTypeIR, +// FunctionTypeIR, or BuiltinTypeIR. Return nullptr if the referenced type is +// undefined or built-in. +static const TypeIR *DereferenceType(const ModuleIR &module, + const TypeIR *type_ir) { + auto &type_graph = module.GetTypeGraph(); + while (IsReferencingType(type_ir->GetKind())) { + auto it = type_graph.find(type_ir->GetReferencedType()); + // The referenced type is undefined in the module. + if (it == type_graph.end()) { + return nullptr; + } + type_ir = it->second; + } + return type_ir; +} + + +// This method creates a new node for the addend node in the graph if MergeType +// on the reference returned a MergeStatus with was_newly_added_ = true. +MergeStatus ModuleMerger::MergeReferencingType( + const ModuleIR &addend, const TypeIR *addend_node, + AbiElementMap *local_to_global_type_id_map) { + // First add the type 'pro-actively'. We need to do this since we'll need to + // fill in 'referenced-type' fields in all this type's descendants and + // descendants which are compound types (records), can refer to this type. + std::string added_type_id = addend_node->GetSelfType(); + auto type_id_it = module_->type_graph_.find(added_type_id); + if (type_id_it != module_->type_graph_.end()) { + const TypeIR *final_referenced_type = DereferenceType(addend, addend_node); + if (final_referenced_type != nullptr) { + std::string compilation_unit_path = + addend.GetCompilationUnitPath(final_referenced_type); + // The path is empty for built-in types. + if (compilation_unit_path != "") { + added_type_id = added_type_id + "#ODR:" + compilation_unit_path; + } + } + } + + // Add the added record type to the local_to_global_type_id_map. + local_to_global_type_id_map->emplace(addend_node->GetSelfType(), + MergeStatus(true, added_type_id)); + + // Merge the type. + switch (addend_node->GetKind()) { + case PointerTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->pointer_types_, + added_type_id); + case QualifiedTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->qualified_types_, + added_type_id); + case ArrayTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->array_types_, + added_type_id); + case LvalueReferenceTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->lvalue_reference_types_, + added_type_id); + case RvalueReferenceTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->rvalue_reference_types_, + added_type_id); + default: + // Only referencing types + assert(0); + } +} + + +MergeStatus ModuleMerger::MergeTypeInternal( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + switch (addend_node->GetKind()) { + case BuiltinTypeKind: + return MergeBuiltinType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case RecordTypeKind: + return MergeRecordAndDependencies( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case EnumTypeKind: + return MergeEnumType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case FunctionTypeKind: + return MergeFunctionType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + default: + return MergeReferencingType(addend, addend_node, + local_to_global_type_id_map); + } + assert(0); +} + + +MergeStatus ModuleMerger::MergeType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + // Check if the addend type is already in the parent graph. Since we're + // going to traverse all the dependencies add whichever ones are not in the + // parent graph. This does not add the node itself though. + auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType()); + if (type_it != local_to_global_type_id_map->end()) { + return type_it->second; + } + + MergeStatus merge_status = LookupType( + addend_node, addend, local_to_global_type_id_map); + if (!merge_status.was_newly_added_) { + return merge_status; + } + merge_status = MergeTypeInternal( + addend_node, addend, local_to_global_type_id_map); + return merge_status; +} + + +void ModuleMerger::MergeCFunctionLikeDeps( + const ModuleIR &addend, CFunctionLikeIR *cfunction_like_ir, + AbiElementMap *local_to_global_type_id_map) { + // Merge the return type. + auto ret_type_it = + addend.type_graph_.find(cfunction_like_ir->GetReturnType()); + if (ret_type_it != addend.type_graph_.end()) { + // Merge the type if we can find another type in the parent module. + MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend, + local_to_global_type_id_map); + cfunction_like_ir->SetReturnType(ret_merge_status.type_id_); + } + + // Merge the argument types. + for (auto ¶m : cfunction_like_ir->GetParameters()) { + MergeReferencingTypeInternal(addend, ¶m, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeFunctionDeps( + FunctionIR *added_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map); + + // Merge the template arguments. + for (auto &template_element : added_node->GetTemplateElements()) { + MergeReferencingTypeInternal(addend, &template_element, + local_to_global_type_id_map); + } +} + + +template +static bool IsLinkableMessagePresent(const LinkableMessageIR *lm, + const AbiElementMap &message_map) { + return (message_map.find(lm->GetLinkerSetKey()) != message_map.end()); +} + + +void ModuleMerger::MergeFunction( + const FunctionIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + const std::string &function_linkage_name = addend_node->GetLinkerSetKey(); + if (IsLinkableMessagePresent(addend_node, module_->functions_)) { + // The functions and all of its dependencies have already been added. + // No two globally visible functions can have the same symbol name. + return; + } + FunctionIR function_ir = *addend_node; + MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map); + // Add it to the parent's function map. + module_->functions_.emplace(function_linkage_name, std::move(function_ir)); +} + + +void ModuleMerger::MergeGlobalVariable( + const GlobalVarIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + const std::string &global_variable_linkage_name = + addend_node->GetLinkerSetKey(); + if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) { + // The global variable and all of its dependencies have already been added. + return; + } + GlobalVarIR global_variable_ir = *addend_node; + MergeReferencingTypeInternal(addend, &global_variable_ir, + local_to_global_type_id_map); + module_->global_variables_.emplace( + global_variable_linkage_name, std::move(global_variable_ir)); +} + + +void ModuleMerger::MergeGraphs(const ModuleIR &addend) { + // Iterate through nodes of addend reader and merge them. + // Keep a merged types cache since if a type is merged, so will all of its + // dependencies which weren't already merged. + AbiElementMap merged_types_cache; + + for (auto &&type_ir : addend.type_graph_) { + MergeType(type_ir.second, addend, &merged_types_cache); + } + + for (auto &&function_ir : addend.functions_) { + MergeFunction(&function_ir.second, addend, &merged_types_cache); + } + + for (auto &&global_var_ir : addend.global_variables_) { + MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache); + } +} + + +} // namespace repr +} // namespace header_checker + diff --git a/vndk/tools/header-checker/src/linker/module_merger.h b/vndk/tools/header-checker/src/linker/module_merger.h new file mode 100644 index 000000000..56acbfa69 --- /dev/null +++ b/vndk/tools/header-checker/src/linker/module_merger.h @@ -0,0 +1,155 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "repr/ir_representation.h" + + +namespace header_checker { +namespace repr { + + +class MergeStatus { +public: + MergeStatus(bool was_newly_added, const std::string &type_id) + : was_newly_added_(was_newly_added), type_id_(type_id) {} + + MergeStatus() {} + + // type_id_ always has the global_type_id corresponding to the type this + // MergeStatus corresponds to. For + // generic reference types (pointers, qual types, l(r)value references etc), + // this will be a proactively added type_id, which will be added to the + // parent type_graph if the we decide to add the referencing type to the + // parent post ODR checking. + bool was_newly_added_ = false; + + std::string type_id_; +}; + + +class ModuleMerger { +public: + ModuleMerger(const std::set *exported_headers) + : module_(new ModuleIR(exported_headers)) {} + + const ModuleIR &GetModule() { + return *module_; + } + + void MergeGraphs(const ModuleIR &addend); + +private: + void MergeCFunctionLikeDeps( + const ModuleIR &addend, CFunctionLikeIR *cfunction_like_ir, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeFunctionType( + const FunctionTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeEnumType( + const EnumTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeEnumDependencies( + const ModuleIR &addend, EnumTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeRecordAndDependencies( + const RecordTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordDependencies( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordFields( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordCXXBases( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordTemplateElements( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeGlobalVariable( + const GlobalVarIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeGlobalVariables( + const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeFunctionDeps( + FunctionIR *added_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeFunction( + const FunctionIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + template + MergeStatus MergeReferencingTypeInternalAndUpdateParent( + const ModuleIR &addend, const T *addend_node, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *parent_map, const std::string &updated_self_type_id); + + MergeStatus MergeReferencingTypeInternal( + const ModuleIR &addend, ReferencesOtherType *references_type, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeReferencingType( + const ModuleIR &addend, const TypeIR *addend_node, + AbiElementMap *local_to_global_type_id_map); + + template + std::pair::iterator> + UpdateUDTypeAccounting( + const T *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *specific_type_map); + + MergeStatus MergeBuiltinType( + const BuiltinTypeIR *builtin_type, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus LookupUserDefinedType( + const TypeIR *ud_type, const ModuleIR &addend, + const std::string &ud_type_unique_id, + AbiElementMap *local_to_global_type_id_map_); + + MergeStatus LookupType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeTypeInternal( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeType( + const TypeIR *addend_type, const ModuleIR &addend, + AbiElementMap *merged_types_cache); + +private: + std::unique_ptr module_; + + uint64_t max_type_id_ = 0; +}; + + +} // namespace repr +} // namespace header_checker diff --git a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h index fff7ab430..7b67d2be3 100644 --- a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h +++ b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h @@ -17,7 +17,6 @@ #include "repr/ir_diff_dumper.h" #include "repr/ir_diff_representation.h" -#include "repr/ir_reader.h" #include "repr/ir_representation.h" #include @@ -30,8 +29,6 @@ namespace repr { // Classes which act as middle-men between clang AST parsing routines and // message format specific dumpers. -using MergeStatus = IRReader::MergeStatus; - enum DiffStatus { // There was no diff found while comparing types. no_diff = 0, @@ -83,12 +80,10 @@ class AbiDiffHelper { const AbiElementMap &new_types, const DiffPolicyOptions &diff_policy_options, std::set *type_cache, - IRDiffDumper *ir_diff_dumper = nullptr, - AbiElementMap *local_to_global_type_id_map = nullptr) + IRDiffDumper *ir_diff_dumper = nullptr) : old_types_(old_types), new_types_(new_types), diff_policy_options_(diff_policy_options), type_cache_(type_cache), - ir_diff_dumper_(ir_diff_dumper), - local_to_global_type_id_map_(local_to_global_type_id_map) {} + ir_diff_dumper_(ir_diff_dumper) {} DiffStatus CompareAndDumpTypeDiff( const std::string &old_type_str, const std::string &new_type_str, @@ -214,7 +209,6 @@ class AbiDiffHelper { const DiffPolicyOptions &diff_policy_options_; std::set *type_cache_; IRDiffDumper *ir_diff_dumper_; - AbiElementMap *local_to_global_type_id_map_; }; void ReplaceTypeIdsWithTypeNames( diff --git a/vndk/tools/header-checker/src/repr/ir_reader.cpp b/vndk/tools/header-checker/src/repr/ir_reader.cpp index a47bab4f3..04de74264 100644 --- a/vndk/tools/header-checker/src/repr/ir_reader.cpp +++ b/vndk/tools/header-checker/src/repr/ir_reader.cpp @@ -14,9 +14,7 @@ #include "repr/ir_reader.h" -#include "repr/abi_diff_helpers.h" #include "repr/ir_representation.h" -#include "repr/ir_representation_internal.h" #include "repr/json/api.h" #include "repr/protobuf/api.h" @@ -32,9 +30,6 @@ namespace header_checker { namespace repr { -using MergeStatus = IRReader::MergeStatus; - - std::unique_ptr IRReader::CreateIRReader( TextFormatIR text_format, const std::set *exported_headers) { @@ -56,527 +51,5 @@ bool IRReader::ReadDump(const std::string &dump_file) { } -MergeStatus IRReader::MergeBuiltinType( - const BuiltinTypeIR *builtin_type, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - std::string linker_set_key = builtin_type->GetLinkerSetKey(); - auto builtin_it = module_->builtin_types_.find(linker_set_key); - if (builtin_it != module_->builtin_types_.end()) { - return MergeStatus(false, builtin_it->second.GetSelfType()); - } - - // Add this builtin type to the parent graph's builtin_types_ map. - const std::string &type_id = builtin_type->GetSelfType(); - auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type); - module_->type_graph_.emplace(type_id, &p.first->second); - - MergeStatus merge_status(true, type_id); - local_to_global_type_id_map->emplace(type_id, merge_status); - return merge_status; -} - - -MergeStatus IRReader::LookupUserDefinedType( - const TypeIR *ud_type, const IRReader &addend, - const std::string &ud_type_unique_id_and_source, - AbiElementMap *local_to_global_type_id_map_) { - auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source); - if (it == module_->odr_list_map_.end()) { - // Calling this an ODR violation even though it means no UD with the same - // name + source combination was seen in the parent graph. The type-id - // passed does not matter since was_newly_added_ is true, the type will get - // allocated a new type id. - return MergeStatus(true, ""); - } - - // Initialize type comparator (which will compare the referenced types - // recursively). - std::set type_cache; - DiffPolicyOptions diff_policy_options(false) ; - AbiDiffHelper diff_helper(module_->type_graph_, addend.module_->type_graph_, - diff_policy_options, &type_cache, - nullptr, local_to_global_type_id_map_); - - // Compare each user-defined type with the latest input user-defined type. - // If there is a match, re-use the existing user-defined type. - for (auto &contender_ud : it->second) { - DiffStatus result = diff_helper.CompareAndDumpTypeDiff( - contender_ud->GetSelfType(), ud_type->GetSelfType()); - if (result == DiffStatus::no_diff) { - local_to_global_type_id_map_->emplace( - ud_type->GetSelfType(), - MergeStatus(false, contender_ud->GetSelfType())); - return MergeStatus(false, contender_ud->GetSelfType()); - } - } - -#ifdef DEBUG - llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n"; -#endif - return MergeStatus(true, (*(it->second.begin()))->GetSelfType()); -} - - -MergeStatus IRReader::LookupType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - std::string unique_type_id; - switch (addend_node->GetKind()) { - case RecordTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - case EnumTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - case FunctionTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - default: - // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind, - // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind) - // should be proactively added by returning MergeStatus with - // was_newly_added_ = true. - return MergeStatus(true, "type-hidden"); - } - - return LookupUserDefinedType( - addend_node, addend, unique_type_id, local_to_global_type_id_map); -} - - -// This method merges the type referenced by 'references_type' into the parent -// graph. It also corrects the referenced_type field in the references_type -// object passed and returns the merge status of the *referenced type*. -MergeStatus IRReader::MergeReferencingTypeInternal( - const IRReader &addend, ReferencesOtherType *references_type, - AbiElementMap *local_to_global_type_id_map) { - // First look in the local_to_global_type_id_map for the referenced type's - // id. - const std::string &referenced_type_id = references_type->GetReferencedType(); - auto local_to_global_it = local_to_global_type_id_map->find( - referenced_type_id); - if (local_to_global_it != local_to_global_type_id_map->end()) { - // The type was already added to the parent graph. So change the - // referenced type to the global type id. - references_type->SetReferencedType(local_to_global_it->second.type_id_); - return local_to_global_it->second; - } - - // If that did not go through, look at the addend's type_map_ and get the - // TypeIR* and call MergeType on it. - auto local_type_it = addend.module_->type_graph_.find(referenced_type_id); - if (local_type_it != addend.module_->type_graph_.end()) { - // We don't care about merge_status.was_newly_added since we wouldn't have - // gotten this far if we weren't adding this. - MergeStatus merge_status = - MergeType(local_type_it->second, addend, local_to_global_type_id_map); - const std::string &global_type_id = merge_status.type_id_; - references_type->SetReferencedType(global_type_id); - return merge_status; - } - - // If the referenced type was hidden, create the name reference type in the - // parent module and keep the referenced type_id as-is. - return MergeStatus(true, referenced_type_id); -} - - -void IRReader::MergeRecordFields( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &field : added_node->GetFields()) { - MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordCXXBases( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &base : added_node->GetBases()) { - MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordTemplateElements( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &template_element : added_node->GetTemplateElements()) { - MergeReferencingTypeInternal( - addend, &template_element, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordDependencies( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - // First call MergeType on all its fields. - MergeRecordFields(addend, added_node, local_to_global_type_id_map); - - // Call MergeType on CXXBases of the record. - MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map); - - MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map); -} - - -template -std::pair::iterator> -IRReader::UpdateUDTypeAccounting( - const T *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *specific_type_map) { - std::string added_type_id = addend_node->GetSelfType(); - auto type_id_it = module_->type_graph_.find(added_type_id); - if (type_id_it != module_->type_graph_.end()) { - added_type_id = AllocateNewTypeId(added_type_id, *addend.module_); - } - - // Add the ud-type with type-id to the type_graph_, since if there are generic - // reference types which refer to the record being added, they'll need to find - // it's id in the map. - // Add ud-type to the parent graph. - T added_type_ir = *addend_node; - added_type_ir.SetSelfType(added_type_id); - added_type_ir.SetReferencedType(added_type_id); - auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map, - &module_->type_graph_); - // Add to faciliate ODR checking. - const std::string &key = GetODRListMapKey(&(it->second)); - MergeStatus type_merge_status = MergeStatus(true, added_type_id); - module_->AddToODRListMap(key, &(it->second)); - local_to_global_type_id_map->emplace(addend_node->GetSelfType(), - type_merge_status); - return {type_merge_status, it}; -} - - -// This method is necessarily going to have a was_newly_merged_ = true in its -// MergeStatus return. So it necessarily merges a new RecordType. -MergeStatus IRReader::MergeRecordAndDependencies( - const RecordTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, - &module_->record_types_); - MergeRecordDependencies(addend, &p.second->second, - local_to_global_type_id_map); - return p.first; -} - - -void IRReader::MergeEnumDependencies( - const IRReader &addend, EnumTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - const std::string underlying_type_id = added_node->GetUnderlyingType(); - // Get the underlying type, it nessarily has to be present in the addend's - // type graph since builtin types can't be hidden. Call MergeType on it and - // change the underlying type to that. - auto it = addend.module_->type_graph_.find(underlying_type_id); - if (it == addend.module_->type_graph_.end()) { - llvm::errs() << "Enum underlying types should not be hidden\n"; - ::exit(1); - } - MergeStatus merge_status = MergeType( - it->second, addend, local_to_global_type_id_map); - added_node->SetUnderlyingType(merge_status.type_id_); -} - - -// This method is necessarily going to have a was_newly_merged_ = true in its -// MergeStatus return. So it necessarily merges a new EnumType. -MergeStatus IRReader::MergeEnumType( - const EnumTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, &module_->enum_types_); - MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map); - return p.first; -} - - -MergeStatus IRReader::MergeFunctionType( - const FunctionTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, - &module_->function_types_); - MergeCFunctionLikeDeps(addend, &p.second->second, - local_to_global_type_id_map); - return p.first; -} - - -template -MergeStatus IRReader::MergeReferencingTypeInternalAndUpdateParent( - const IRReader &addend, const T *addend_node, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *parent_map, const std::string &updated_self_type_id) { - MergeStatus merge_status; - uint64_t old_max_type_id = max_type_id_; - - // Create copy of addend_node - T added_node = *addend_node; - added_node.SetSelfType(updated_self_type_id); - - // The merge status returned is the merge status of the referenced type. - merge_status = MergeReferencingTypeInternal(addend, &added_node, - local_to_global_type_id_map); - if (merge_status.was_newly_added_) { - // Emplace to map (type-referenced -> Referencing type) - AddToMapAndTypeGraph(std::move(added_node), parent_map, - &module_->type_graph_); - return MergeStatus(true, updated_self_type_id); - } - - // The type that the added_node references was not newly added to the parent - // graph. However, we still might need to add the added_node to the parent - // graph, since for the particular 'Kind' of the added_node, it may not be - // present in the parent graph. This will be determined by looking at the - // appropriate 'type-referenced' -> TypeElement map in the parent for the - // type-id returned by the MergeStatus. If the map doesn't have an entry for - // the type-id returned by the MergeStatus, the added_type is not present in - // the parent graph and needs to be 'newly' added. We also need to modify the - // global type id in the local_to_global_type_id map. The added_node should - // already have it's self_type and referenced_type fields fixed up. - // We maintain a rollback id to have contiguous type ids. - max_type_id_ = old_max_type_id; - - // Try finding the referenced_type is referred to by any referencing type - // of the same kind in the parent graph. It is safe to call this on the - // added_node, since the referenced_type in the added_node would have been - // modified by the MergeReferencingTypeInternal call. - auto it = parent_map->find(GetReferencedTypeMapKey(added_node)); - if (it == parent_map->end()) { - // There was no counterpart found for the added_node's type Kind referencing - // the referenced type, so we added it to the parent and also updated the - // local_to_global_type_id_map's global_id value. - AddToMapAndTypeGraph(std::move(added_node), parent_map, - &module_->type_graph_); - - merge_status = MergeStatus(true, updated_self_type_id); - return merge_status; - } - - // Update local_to_global_type_id map's MergeStatus.was_newly_added value for - // this key with false since this was node was not newly added. - // We never remove anything from the local_to_global_type_id_map, what's - // the point ? Since you store the decision of whether the type was newly - // added or not. It's global type id is the type-id of the element found - // in the parent map which refers to the added_node's modified - // referenced_type. - merge_status = MergeStatus(false, it->second.GetSelfType()); - (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status; - - return merge_status; -} - - -// This method creates a new node for the addend node in the graph if MergeType -// on the reference returned a MergeStatus with was_newly_added_ = true. -MergeStatus IRReader::MergeReferencingType( - const IRReader &addend, const TypeIR *addend_node, - AbiElementMap *local_to_global_type_id_map) { - // First add the type 'pro-actively'. We need to do this since we'll need to - // fill in 'referenced-type' fields in all this type's descendants and - // descendants which are compound types (records), can refer to this type. - std::string added_type_id = addend_node->GetSelfType(); - auto type_id_it = module_->type_graph_.find(added_type_id); - if (type_id_it != module_->type_graph_.end()) { - added_type_id = AllocateNewTypeId(added_type_id, *addend.module_); - } - - // Add the added record type to the local_to_global_type_id_map. - local_to_global_type_id_map->emplace(addend_node->GetSelfType(), - MergeStatus(true, added_type_id)); - - // Merge the type. - switch (addend_node->GetKind()) { - case PointerTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->pointer_types_, - added_type_id); - case QualifiedTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->qualified_types_, - added_type_id); - case ArrayTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->array_types_, - added_type_id); - case LvalueReferenceTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->lvalue_reference_types_, - added_type_id); - case RvalueReferenceTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->rvalue_reference_types_, - added_type_id); - default: - // Only referencing types - assert(0); - } -} - - -MergeStatus IRReader::MergeTypeInternal( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - switch (addend_node->GetKind()) { - case BuiltinTypeKind: - return MergeBuiltinType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case RecordTypeKind: - return MergeRecordAndDependencies( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case EnumTypeKind: - return MergeEnumType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case FunctionTypeKind: - return MergeFunctionType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - default: - return MergeReferencingType(addend, addend_node, - local_to_global_type_id_map); - } - assert(0); -} - - -MergeStatus IRReader::MergeType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - // Check if the addend type is already in the parent graph. Since we're - // going to traverse all the dependencies add whichever ones are not in the - // parent graph. This does not add the node itself though. - auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType()); - if (type_it != local_to_global_type_id_map->end()) { - return type_it->second; - } - - MergeStatus merge_status = LookupType( - addend_node, addend, local_to_global_type_id_map); - if (!merge_status.was_newly_added_) { - return merge_status; - } - merge_status = MergeTypeInternal( - addend_node, addend, local_to_global_type_id_map); - return merge_status; -} - - -void IRReader::MergeCFunctionLikeDeps( - const IRReader &addend, CFunctionLikeIR *cfunction_like_ir, - AbiElementMap *local_to_global_type_id_map) { - // Merge the return type. - auto ret_type_it = - addend.module_->type_graph_.find(cfunction_like_ir->GetReturnType()); - if (ret_type_it != addend.module_->type_graph_.end()) { - // Merge the type if we can find another type in the parent module. - MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend, - local_to_global_type_id_map); - cfunction_like_ir->SetReturnType(ret_merge_status.type_id_); - } - - // Merge the argument types. - for (auto ¶m : cfunction_like_ir->GetParameters()) { - MergeReferencingTypeInternal(addend, ¶m, local_to_global_type_id_map); - } -} - - -void IRReader::MergeFunctionDeps( - FunctionIR *added_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map); - - // Merge the template arguments. - for (auto &template_element : added_node->GetTemplateElements()) { - MergeReferencingTypeInternal(addend, &template_element, - local_to_global_type_id_map); - } -} - - -template -static bool IsLinkableMessagePresent(const LinkableMessageIR *lm, - const AbiElementMap &message_map) { - return (message_map.find(lm->GetLinkerSetKey()) != message_map.end()); -} - - -void IRReader::MergeFunction( - const FunctionIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - const std::string &function_linkage_name = addend_node->GetLinkerSetKey(); - if (IsLinkableMessagePresent(addend_node, module_->functions_)) { - // The functions and all of its dependencies have already been added. - // No two globally visible functions can have the same symbol name. - return; - } - FunctionIR function_ir = *addend_node; - MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map); - // Add it to the parent's function map. - module_->functions_.emplace(function_linkage_name, std::move(function_ir)); -} - - -std::string IRReader::AllocateNewTypeId(const std::string &addend_type_id, - const ModuleIR &addend_module) { - return addend_type_id + "#ODR:" + addend_module.GetCompilationUnitPath(); -} - - -void IRReader::MergeGlobalVariable( - const GlobalVarIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - const std::string &global_variable_linkage_name = - addend_node->GetLinkerSetKey(); - if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) { - // The global variable and all of its dependencies have already been added. - return; - } - GlobalVarIR global_variable_ir = *addend_node; - MergeReferencingTypeInternal(addend, &global_variable_ir, - local_to_global_type_id_map); - module_->global_variables_.emplace( - global_variable_linkage_name, std::move(global_variable_ir)); -} - - -void IRReader::MergeGraphs(const IRReader &addend) { - // Iterate through nodes of addend reader and merge them. - // Keep a merged types cache since if a type is merged, so will all of its - // dependencies which weren't already merged. - AbiElementMap merged_types_cache; - - for (auto &&type_ir : addend.module_->type_graph_) { - MergeType(type_ir.second, addend, &merged_types_cache); - } - - for (auto &&function_ir : addend.module_->functions_) { - MergeFunction(&function_ir.second, addend, &merged_types_cache); - } - - for (auto &&global_var_ir : addend.module_->global_variables_) { - MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache); - } -} - - } // namespace repr } // header_checker diff --git a/vndk/tools/header-checker/src/repr/ir_reader.h b/vndk/tools/header-checker/src/repr/ir_reader.h index a35418354..ecd64bbf3 100644 --- a/vndk/tools/header-checker/src/repr/ir_reader.h +++ b/vndk/tools/header-checker/src/repr/ir_reader.h @@ -17,12 +17,9 @@ #include "repr/ir_representation.h" -#include -#include #include #include #include -#include namespace header_checker { @@ -30,24 +27,6 @@ namespace repr { class IRReader { - public: - struct MergeStatus { - MergeStatus(bool was_newly_added, const std::string &type_id) - : was_newly_added_(was_newly_added), type_id_(type_id) {} - - MergeStatus() {} - - // type_id_ always has the global_type_id corresponding to the type this - // MergeStatus corresponds to. For - // generic reference types (pointers, qual types, l(r)value references etc), - // this will be a proactively added type_id, which will be added to the - // parent type_graph if the we decide to add the referencing type to the - // parent post ODR checking. - bool was_newly_added_ = false; - - std::string type_id_; - }; - public: static std::unique_ptr CreateIRReader( TextFormatIR text_format, @@ -68,112 +47,11 @@ class IRReader { return std::move(module_); } - void MergeGraphs(const IRReader &addend); - private: virtual bool ReadDumpImpl(const std::string &dump_file) = 0; - void MergeCFunctionLikeDeps( - const IRReader &addend, CFunctionLikeIR *cfunction_like_ir, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeFunctionType( - const FunctionTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeEnumType( - const EnumTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeEnumDependencies( - const IRReader &addend, EnumTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeRecordAndDependencies( - const RecordTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordDependencies( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordFields( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordCXXBases( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordTemplateElements( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeGlobalVariable( - const GlobalVarIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeGlobalVariables( - const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeFunctionDeps( - FunctionIR *added_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeFunction( - const FunctionIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - template - MergeStatus MergeReferencingTypeInternalAndUpdateParent( - const IRReader &addend, const T *addend_node, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *parent_map, const std::string &updated_self_type_id); - - MergeStatus MergeReferencingTypeInternal( - const IRReader &addend, ReferencesOtherType *references_type, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeReferencingType( - const IRReader &addend, const TypeIR *addend_node, - AbiElementMap *local_to_global_type_id_map); - - template - std::pair::iterator> - UpdateUDTypeAccounting( - const T *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *specific_type_map); - - MergeStatus MergeBuiltinType( - const BuiltinTypeIR *builtin_type, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus LookupUserDefinedType( - const TypeIR *ud_type, const IRReader &addend, - const std::string &ud_type_unique_id, - AbiElementMap *local_to_global_type_id_map_); - - MergeStatus LookupType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeTypeInternal( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeType( - const TypeIR *addend_type, const IRReader &addend, - AbiElementMap *merged_types_cache); - - std::string AllocateNewTypeId(const std::string &addend_type_id, - const ModuleIR &addend_module); - protected: std::unique_ptr module_; - - uint64_t max_type_id_ = 0; }; diff --git a/vndk/tools/header-checker/src/repr/ir_representation.cpp b/vndk/tools/header-checker/src/repr/ir_representation.cpp index 50d1bf974..6f512fdaa 100644 --- a/vndk/tools/header-checker/src/repr/ir_representation.cpp +++ b/vndk/tools/header-checker/src/repr/ir_representation.cpp @@ -109,7 +109,7 @@ void ModuleIR::AddRecordType(RecordTypeIR &&record_type) { auto it = AddToMapAndTypeGraph( std::move(record_type), &record_types_, &type_graph_); const std::string &key = GetODRListMapKey(&(it->second)); - AddToODRListMap(key, &(it->second)); + AddToODRListMap(key, &(it->second), compilation_unit_path_); } @@ -120,7 +120,7 @@ void ModuleIR::AddFunctionType(FunctionTypeIR &&function_type) { auto it = AddToMapAndTypeGraph( std::move(function_type), &function_types_, &type_graph_); const std::string &key = GetODRListMapKey(&(it->second)); - AddToODRListMap(key, &(it->second)); + AddToODRListMap(key, &(it->second), compilation_unit_path_); } @@ -131,7 +131,7 @@ void ModuleIR::AddEnumType(EnumTypeIR &&enum_type) { auto it = AddToMapAndTypeGraph( std::move(enum_type), &enum_types_, &type_graph_); const std::string &key = GetODRListMapKey(&(it->second)); - AddToODRListMap(key, (&it->second)); + AddToODRListMap(key, (&it->second), compilation_unit_path_); } @@ -197,6 +197,34 @@ void ModuleIR::AddElfObject(ElfObjectIR &&elf_object) { } +std::string ModuleIR::GetCompilationUnitPath(const TypeIR *type_ir) const { + std::string key; + switch (type_ir->GetKind()) { + case RecordTypeKind: + key = GetODRListMapKey(static_cast(type_ir)); + break; + case EnumTypeKind: + key = GetODRListMapKey(static_cast(type_ir)); + break; + case FunctionTypeKind: + key = GetODRListMapKey(static_cast(type_ir)); + break; + default: + return ""; + } + auto it = odr_list_map_.find(key); + if (it == odr_list_map_.end()) { + return ""; + } + for (const auto &definition : it->second) { + if (definition.type_ir_ == type_ir) { + return definition.compilation_unit_path_; + } + } + return ""; +} + + bool ModuleIR::IsLinkableMessageInExportedHeaders( const LinkableMessageIR *linkable_message) const { if (exported_headers_ == nullptr || exported_headers_->empty()) { diff --git a/vndk/tools/header-checker/src/repr/ir_representation.h b/vndk/tools/header-checker/src/repr/ir_representation.h index 12ba97a24..f74d3b7a7 100644 --- a/vndk/tools/header-checker/src/repr/ir_representation.h +++ b/vndk/tools/header-checker/src/repr/ir_representation.h @@ -37,9 +37,6 @@ using AbiElementMap = std::map; template using AbiElementUnorderedMap = std::unordered_map; -template -using AbiElementList = std::list; - enum TextFormatIR { ProtobufTextFormat = 0, Json = 1, @@ -759,6 +756,16 @@ class ElfObjectIR : public ElfSymbolIR { } }; +class TypeDefinition { + public: + TypeDefinition(const TypeIR *type_ir, + const std::string *compilation_unit_path) + : type_ir_(type_ir), compilation_unit_path_(*compilation_unit_path) {} + + const TypeIR *type_ir_; + const std::string &compilation_unit_path_; +}; + class ModuleIR { public: ModuleIR(const std::set *exported_headers) @@ -828,7 +835,7 @@ class ModuleIR { return type_graph_; } - const AbiElementUnorderedMap> & + const AbiElementUnorderedMap> & GetODRListMap() const { return odr_list_map_; } @@ -864,10 +871,19 @@ class ModuleIR { void AddElfObject(ElfObjectIR &&elf_object); - void AddToODRListMap(const std::string &key, const TypeIR *value) { + // Find the compilation unit path of a RecordTypeIR, FunctionTypeIR, or + // EnumTypeIR in odr_list_map_. Return an empty string if the type is not in + // the map. + std::string GetCompilationUnitPath(const TypeIR *type_ir) const; + + void AddToODRListMap(const std::string &key, const TypeIR *type_ir, + const std::string &compilation_unit_path) { + auto compilation_unit_path_it = + compilation_unit_paths_.emplace(compilation_unit_path).first; auto map_it = odr_list_map_.find(key); + TypeDefinition value(type_ir, &*compilation_unit_path_it); if (map_it == odr_list_map_.end()) { - odr_list_map_.emplace(key, std::list({value})); + odr_list_map_.emplace(key, std::list({value})); return; } odr_list_map_[key].emplace_back(value); @@ -883,7 +899,6 @@ class ModuleIR { // File path to the compilation unit (*.sdump) std::string compilation_unit_path_; - AbiElementList record_types_list_; AbiElementMap functions_; AbiElementMap global_variables_; AbiElementMap record_types_; @@ -904,8 +919,13 @@ class ModuleIR { AbiElementMap elf_objects_; // type-id -> LinkableMessageIR * map AbiElementMap type_graph_; - // maps unique_id + source_file -> const TypeIR * - AbiElementUnorderedMap> odr_list_map_; + // maps unique_id + source_file -> TypeDefinition + AbiElementUnorderedMap> odr_list_map_; + + + private: + // The compilation unit paths referenced by odr_list_map_; + std::set compilation_unit_paths_; const std::set *exported_headers_; }; diff --git a/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h new file mode 100644 index 000000000..54686ba13 --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h @@ -0,0 +1,9 @@ +extern char var; + +struct Struct { + Struct *member1; +}; + +struct Opaque; + +void func(const struct Struct *, const struct Opaque *); diff --git a/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h new file mode 100644 index 000000000..075f78cab --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h @@ -0,0 +1,9 @@ +extern int var; + +struct Struct { + Struct *member2; +}; + +struct Opaque; + +void func(const struct Opaque *, const struct Struct *); diff --git a/vndk/tools/header-checker/tests/integration/merge_multi_definitions/map.txt b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/map.txt new file mode 100644 index 000000000..654d2c4bf --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/merge_multi_definitions/map.txt @@ -0,0 +1,5 @@ +libmerge_multi_definitions { + global: + func; + var; +}; diff --git a/vndk/tools/header-checker/tests/module.py b/vndk/tools/header-checker/tests/module.py index 338058d13..d0ba0c2f4 100755 --- a/vndk/tools/header-checker/tests/module.py +++ b/vndk/tools/header-checker/tests/module.py @@ -9,7 +9,6 @@ import_path = os.path.abspath(os.path.join(import_path, 'utils')) sys.path.insert(1, import_path) from utils import run_header_abi_dumper -from utils import run_header_abi_dumper_on_file from utils import run_header_abi_linker from utils import SOURCE_ABI_DUMP_EXT @@ -125,13 +124,15 @@ class LsdumpModule(Module): output_path = os.path.join(tmp, os.path.basename(src) + '.sdump') dumps_to_link.append(output_path) - run_header_abi_dumper_on_file( - src, output_path, self.export_include_dirs, - self.cflags + self.arch_cflags, - self.dumper_flags) + content = run_header_abi_dumper( + src, self.cflags + self.arch_cflags, + self.export_include_dirs, self.dumper_flags) + with open(output_path, 'w') as dump_file: + dump_file.write(content) return run_header_abi_linker(output_lsdump, dumps_to_link, self.version_script, self.api, - self.arch, self.linker_flags) + self.arch, self.linker_flags, + input_dir=tmp) def mutate_for_arch(self, target_arch): return LsdumpModule(self.name, self.srcs, self.version_script, @@ -642,6 +643,17 @@ TEST_MODULES = [ export_include_dirs=['integration/cpp/anonymous_enum/include'], linker_flags=['-output-format', 'Json'], ), + LsdumpModule( + name='libmerge_multi_definitions', + arch='arm64', + srcs=[ + 'integration/merge_multi_definitions/include/def1.h', + 'integration/merge_multi_definitions/include/def2.h', + ], + version_script='integration/merge_multi_definitions/map.txt', + export_include_dirs=['integration/merge_multi_definitions/include'], + linker_flags=['-output-format', 'Json', '-sources-per-thread', '1'], + ), ] TEST_MODULES = {m.name: m for m in TEST_MODULES} diff --git a/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump b/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump new file mode 100644 index 000000000..74a60065a --- /dev/null +++ b/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump @@ -0,0 +1,169 @@ +{ + "array_types" : [], + "builtin_types" : + [ + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIc", + "name" : "char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIc", + "size" : 1 + }, + { + "alignment" : 4, + "is_integral" : true, + "linker_set_key" : "_ZTIi", + "name" : "int", + "referenced_type" : "_ZTIi", + "self_type" : "_ZTIi", + "size" : 4 + }, + { + "linker_set_key" : "_ZTIv", + "name" : "void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIv" + } + ], + "elf_functions" : + [ + { + "name" : "func" + }, + { + "name" : "var" + } + ], + "elf_objects" : [], + "enum_types" : [], + "function_types" : [], + "functions" : [], + "global_vars" : + [ + { + "linker_set_key" : "var", + "name" : "var", + "referenced_type" : "_ZTIc", + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + } + ], + "lvalue_reference_types" : [], + "pointer_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIP6Struct", + "name" : "Struct *", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIP6Struct", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIP6Struct", + "name" : "Struct *", + "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump", + "self_type" : "_ZTIP6Struct#ODR:/def2.h.sdump", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK6Opaque", + "name" : "const Opaque *", + "referenced_type" : "_ZTIK6Opaque", + "self_type" : "_ZTIPK6Opaque", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK6Struct", + "name" : "const Struct *", + "referenced_type" : "_ZTIK6Struct", + "self_type" : "_ZTIPK6Struct", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPK6Struct", + "name" : "const Struct *", + "referenced_type" : "_ZTIK6Struct#ODR:/def2.h.sdump", + "self_type" : "_ZTIPK6Struct#ODR:/def2.h.sdump", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h" + } + ], + "qualified_types" : + [ + { + "is_const" : true, + "linker_set_key" : "_ZTIK6Opaque", + "name" : "const Opaque", + "referenced_type" : "_ZTI6Opaque", + "self_type" : "_ZTIK6Opaque", + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIK6Struct", + "name" : "const Struct", + "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump", + "self_type" : "_ZTIK6Struct#ODR:/def2.h.sdump", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIK6Struct", + "name" : "const Struct", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIK6Struct", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + } + ], + "record_types" : + [ + { + "alignment" : 8, + "fields" : + [ + { + "field_name" : "member1", + "referenced_type" : "_ZTIP6Struct" + } + ], + "linker_set_key" : "_ZTI6Struct", + "name" : "Struct", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTI6Struct", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h" + }, + { + "alignment" : 8, + "fields" : + [ + { + "field_name" : "member2", + "referenced_type" : "_ZTIP6Struct#ODR:/def2.h.sdump" + } + ], + "linker_set_key" : "_ZTI6Struct", + "name" : "Struct", + "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump", + "self_type" : "_ZTI6Struct#ODR:/def2.h.sdump", + "size" : 8, + "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h" + } + ], + "rvalue_reference_types" : [] +} diff --git a/vndk/tools/header-checker/tests/test.py b/vndk/tools/header-checker/tests/test.py index 0bbd4cdac..ada57bc8a 100755 --- a/vndk/tools/header-checker/tests/test.py +++ b/vndk/tools/header-checker/tests/test.py @@ -376,6 +376,10 @@ class HeaderCheckerTest(unittest.TestCase): self.prepare_and_absolute_diff_all_archs( "libifunc", "libifunc") + def test_merge_multi_definitions(self): + self.prepare_and_absolute_diff_all_archs( + "libmerge_multi_definitions", "libmerge_multi_definitions") + if __name__ == '__main__': unittest.main() diff --git a/vndk/tools/header-checker/utils/utils.py b/vndk/tools/header-checker/utils/utils.py index fd945ec95..369a6cad4 100644 --- a/vndk/tools/header-checker/utils/utils.py +++ b/vndk/tools/header-checker/utils/utils.py @@ -109,14 +109,14 @@ def run_header_abi_dumper(input_path, cflags=tuple(), output.""" with tempfile.TemporaryDirectory() as tmp: output_path = os.path.join(tmp, os.path.basename(input_path)) + '.dump' - run_header_abi_dumper_on_file(input_path, output_path, - export_include_dirs, cflags, flags) + _run_header_abi_dumper_on_file(input_path, output_path, + export_include_dirs, cflags, flags) return read_output_content(output_path, AOSP_DIR) -def run_header_abi_dumper_on_file(input_path, output_path, - export_include_dirs=tuple(), cflags=tuple(), - flags=tuple()): +def _run_header_abi_dumper_on_file(input_path, output_path, + export_include_dirs=tuple(), cflags=tuple(), + flags=tuple()): """Run header-abi-dumper to dump ABI from `input_path` and the output is written to `output_path`.""" input_ext = os.path.splitext(input_path)[1] @@ -144,7 +144,7 @@ def run_header_abi_dumper_on_file(input_path, output_path, def run_header_abi_linker(output_path, inputs, version_script, api, arch, - flags=tuple()): + flags=tuple(), input_dir=AOSP_DIR): """Link inputs, taking version_script into account""" cmd = ['header-abi-linker', '-o', output_path, '-v', version_script, '-api', api, '-arch', arch] @@ -155,7 +155,7 @@ def run_header_abi_linker(output_path, inputs, version_script, api, arch, cmd += ['-output-format', DEFAULT_FORMAT] cmd += inputs subprocess.check_call(cmd) - return read_output_content(output_path, AOSP_DIR) + return read_output_content(output_path, input_dir) def make_targets(product, variant, targets):