diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp index 43fa9612f..3cdec178d 100644 --- a/vndk/tools/header-checker/Android.bp +++ b/vndk/tools/header-checker/Android.bp @@ -98,6 +98,7 @@ cc_library_static { srcs: [ "proto/abi_dump.proto", + "proto/abi_diff.proto", ], proto: { @@ -174,3 +175,35 @@ cc_binary_host { }, }, } + +cc_binary_host { + name: "header-abi-diff", + + defaults: [ + "header-checker-defaults", + "header-abi-linker-lib-defaults", + ], + + srcs: [ + "header-abi-diff/src/*.cpp", + ], + + static_libs: [ + "libheader-checker-proto", + ], + + target: { + linux: { + host_ldlibs: [ + "-ldl", + "-lpthread", + ], + }, + darwin: { + host_ldlibs: [ + "-ldl", + "-lpthread", + ], + }, + }, +} diff --git a/vndk/tools/header-checker/README.md b/vndk/tools/header-checker/README.md index 68edb64d5..9412f60ca 100644 --- a/vndk/tools/header-checker/README.md +++ b/vndk/tools/header-checker/README.md @@ -1,12 +1,33 @@ -# VNDK Header Checker +# VNDK Header Abi Dumper -`header-checker` is a tool to check for ABI compliance. First, we can create a -reference dump for each header file when we are preparing a formal release. -After the release, we can check the ABI compliance by comparing the information -in the reference dump and the latest header. +`header-abi-dumper` is a tool to dump the abi of a source. The Abi dumped + belonging to a source file is filtered by dumping only the Abi contained in a + set of header files exposed through the "export_include_dirs" directory(ies). ## Usage + header-abi-dumper -o -I -I + .. -- -Example 1: +# VNDK Header Abi Linker + +`header-abi-linker` is a tool to link abi dumps produced by header-abi-dumper. + This tool combines all the abi information present in the dump files passed to + it. + +## Usage + header-abi-linker -o ... + +# VNDK Header Abi Diff + +`header-abi-diff` is a tool which compares two header abi dumps produced by + header-abi-dumper. It produces a report outlining all the differences in the + abi's exposed by the two dumps. + +# Return Value + 1: InCompatible + 0: Compatible or Compatible Extension. + + +## Usage + header-abi-diff -old -new -o - $ header-checker -g -r example1.ast tests/example1.h -- clang -x c++ diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp new file mode 100644 index 000000000..ffa118ecd --- /dev/null +++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2016 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 "abi_diff.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +Status HeaderAbiDiff::GenerateCompatibilityReport() { + abi_dump::TranslationUnit old_tu; + abi_dump::TranslationUnit new_tu; + std::ifstream old_input(old_dump_); + std::ifstream new_input(new_dump_); + google::protobuf::io::IstreamInputStream text_iso(&old_input); + google::protobuf::io::IstreamInputStream text_isn(&new_input); + + if (!google::protobuf::TextFormat::Parse(&text_iso, &old_tu) || + !google::protobuf::TextFormat::Parse(&text_isn, &new_tu)) { + llvm::errs() << "Failed to Parse Input\n"; + ::exit(1); + } + return CompareTUs(old_tu, new_tu); +} + +Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu) { + abi_diff::TranslationUnitDiff diff_tu; + Status record_Status = CollectRecords(&diff_tu, old_tu, new_tu); + Status function_Status = CollectFunctions(&diff_tu, old_tu, new_tu); + Status enum_Status = CollectEnums(&diff_tu, old_tu, new_tu); + + Status combined_Status = record_Status | function_Status | enum_Status; + + std::ofstream text_output(cr_); + google::protobuf::io::OstreamOutputStream text_os(&text_output); + + if(!google::protobuf::TextFormat::Print(diff_tu, &text_os)) { + llvm::errs() << "Unable to dump report\n"; + ::exit(1); + } + if (combined_Status & INCOMPATIBLE) { + return INCOMPATIBLE; + } + if (combined_Status & EXTENSION) { + return EXTENSION; + } + return COMPATIBLE; +} + +Status HeaderAbiDiff::CollectRecords(abi_diff::TranslationUnitDiff *diff_tu, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu) { + AddToMap(&old_dump_records_, old_tu.records()); + AddToMap(&new_dump_records_, new_tu.records()); + + if (!PopulateRemovedElements(diff_tu->mutable_records_removed(), + old_dump_records_, new_dump_records_) || + !PopulateRemovedElements(diff_tu->mutable_records_removed(), + new_dump_records_, old_dump_records_) || + !PopulateCommonElements(diff_tu->mutable_records_diff(),old_dump_records_, + new_dump_records_)) { + llvm::errs() << "Populating records in report failed\n"; + ::exit(1); + } + if (diff_tu->records_diff().size() || diff_tu->records_removed().size()) { + return INCOMPATIBLE; + } + if (diff_tu->records_added().size()) { + return EXTENSION; + } + return COMPATIBLE; +} + +Status HeaderAbiDiff::CollectFunctions( + abi_diff::TranslationUnitDiff *diff_tu, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu) { + AddToMap(&old_dump_functions_, old_tu.functions()); + AddToMap(&new_dump_functions_, new_tu.functions()); + + if (!PopulateRemovedElements(diff_tu->mutable_functions_removed(), + old_dump_functions_, new_dump_functions_) || + !PopulateRemovedElements(diff_tu->mutable_functions_added(), + new_dump_functions_, old_dump_functions_)) { + llvm::errs() << "Populating functions in report failed\n"; + ::exit(1); + } + if (diff_tu->functions_removed().size()) { + return INCOMPATIBLE; + } + if (diff_tu->functions_added().size()) { + return EXTENSION; + } + return COMPATIBLE; +} + +Status HeaderAbiDiff::CollectEnums(abi_diff::TranslationUnitDiff *diff_tu, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu) { + AddToMap(&old_dump_enums_, old_tu.enums()); + AddToMap(&new_dump_enums_, new_tu.enums()); + + if (!PopulateRemovedElements(diff_tu->mutable_enums_removed(), + old_dump_enums_, new_dump_enums_) || + !PopulateRemovedElements(diff_tu->mutable_enums_added(), new_dump_enums_, + old_dump_enums_) || + !PopulateCommonElements(diff_tu->mutable_enums_diff(),old_dump_enums_, + new_dump_enums_)) { + llvm::errs() << "Populating enums in report failed\n"; + ::exit(1); + } + if (diff_tu->enums_removed().size() || diff_tu->enums_diff().size()) { + return INCOMPATIBLE; + } + if (diff_tu->enums_added().size()) { + return EXTENSION; + } + return COMPATIBLE; +} + +template +bool HeaderAbiDiff::PopulateRemovedElements( + google::protobuf::RepeatedPtrField *dst, + const std::map &old_elements_map, + const std::map &new_elements_map) const { + + std::vector removed_elements; + for (auto &&map_element : old_elements_map) { + const T *element = map_element.second; + auto new_element = new_elements_map.find(element->linker_set_key()); + if (new_element == new_elements_map.end()) { + removed_elements.emplace_back(element); + } + } + if (!DumpLoneElements(dst, removed_elements)) { + llvm::errs() << "Dumping added / removed element to report failed\n"; + return false; + } + return true; +} + +template +bool HeaderAbiDiff::PopulateCommonElements( + google::protobuf::RepeatedPtrField *dst, + const std::map &old_elements_map, + const std::map &new_elements_map) const { + std::vector> common_elements; + typename std::map::const_iterator old_element = + old_elements_map.begin(); + typename std::map::const_iterator new_element = + new_elements_map.begin(); + while (old_element != old_elements_map.end() && + new_element != new_elements_map.end()) { + if (old_element->first == new_element->first) { + common_elements.emplace_back(std::make_pair( + old_element->second, new_element->second)); + old_element++; + new_element++; + continue; + } + if (old_element->first < new_element->first) { + old_element++; + } else { + new_element++; + } + } + if (!DumpDiffElements(dst, common_elements)) { + llvm::errs() << "Dumping difference in common element to report failed\n"; + return false; + } + return true; +} + +template +bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField *dst, + std::vector &elements) const { + for (auto &&element : elements) { + T *added_element = dst->Add(); + if (!added_element) { + llvm::errs() << "Adding element diff failed\n"; + return false; + } + *added_element = *element; + } + return true; +} + +template +bool HeaderAbiDiff::DumpDiffElements( + google::protobuf::RepeatedPtrField *dst, + std::vector> &pairs) const { + for (auto &&pair : pairs) { + const T *old_element = pair.first; + const T *new_element = pair.second; + // Not having inheritance from protobuf messages makes this + // restrictive code. + abi_diff_wrappers::DiffWrapper diff_wrapper(old_element, + new_element); + std::unique_ptr decl_diff_ptr = diff_wrapper.Get(); + if (!decl_diff_ptr) { + continue; + } + TDiff *added_element_diff = dst->Add(); + if (!added_element_diff) { + llvm::errs() << "Adding element diff failed\n"; + return false; + } + *added_element_diff = *decl_diff_ptr; + } + return true; +} diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h new file mode 100644 index 000000000..7ee0245ae --- /dev/null +++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h @@ -0,0 +1,125 @@ +// Copyright (C) 2016 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 "abi_diff_wrappers.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wnested-anon-types" +#include "proto/abi_dump.pb.h" +#include "proto/abi_diff.pb.h" +#pragma clang diagnostic pop + +#include +#include +#include +#include +#include + + +class HeaderAbiDiff { + public: + enum Status { + COMPATIBLE = 1 << 0, + EXTENSION = 1 << 1, + INCOMPATIBLE = 1 << 2, + }; + + + HeaderAbiDiff(const std::string &old_dump, const std::string &new_dump, + const std::string &compatibility_report) + : old_dump_(old_dump), new_dump_(new_dump), cr_(compatibility_report) { } + + Status GenerateCompatibilityReport(); + + private: + Status CompareTUs(const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu); + // Collect* methods fill in the diff_tu. + Status CollectRecords(abi_diff::TranslationUnitDiff *abi_diff, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu); + + Status CollectFunctions(abi_diff::TranslationUnitDiff *abi_diff, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu); + + Status CollectEnums(abi_diff::TranslationUnitDiff *abi_diff, + const abi_dump::TranslationUnit &old_tu, + const abi_dump::TranslationUnit &new_tu); + + + template + inline void AddToMap(std::map *dst, + const google::protobuf::RepeatedPtrField &src); + + template + bool PopulateRemovedElements( + google::protobuf::RepeatedPtrField *dst, + const std::map &old_elements_map, + const std::map &new_elements_map) const; + + template + bool PopulateCommonElements( + google::protobuf::RepeatedPtrField *dst, + const std::map &old_elements_map, + const std::map &new_elements_map) const; + + template + bool DumpDiffElements( + google::protobuf::RepeatedPtrField *dst, + std::vector> &pairs) const; + + template + bool DumpLoneElements(google::protobuf::RepeatedPtrField *dst, + std::vector &elements) const; + + private: + const std::string &old_dump_; + const std::string &new_dump_; + const std::string &cr_; + + // HashMaps for the old tu abis + std::map old_dump_records_; + std::map old_dump_functions_; + std::map old_dump_enums_; + + // HashMaps for the new tu abis + std::map new_dump_records_; + std::map new_dump_functions_; + std::map new_dump_enums_; +}; + +typedef HeaderAbiDiff::Status Status; + +template +inline void HeaderAbiDiff::AddToMap( + std::map *dst, + const google::protobuf::RepeatedPtrField &src) { + for (auto &&element : src) { + dst->insert(std::make_pair(element.linker_set_key(), &element)); + } +} + +static inline Status operator|(Status f, Status s) { + return static_cast( + static_cast::type>(f) | + static_cast::type>(s)); +} + +static inline Status operator&(Status f, Status s) { + return static_cast( + static_cast::type>(f) & + static_cast::type>(s)); +} diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp new file mode 100644 index 000000000..b2809ba5a --- /dev/null +++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2016 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 "abi_diff_wrappers.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wnested-anon-types" +#include "proto/abi_dump.pb.h" +#include "proto/abi_diff.pb.h" +#pragma clang diagnostic pop + +#include + +using abi_diff::RecordDeclDiff; +using abi_diff::FieldDeclDiff; +using abi_diff::CXXBaseSpecifierDiff; +using abi_diff::EnumDeclDiff; +using abi_diff::EnumFieldDeclDiff; +using abi_dump::RecordDecl; +using abi_dump::EnumDecl; + +namespace abi_diff_wrappers { + +// This function fills in a *Diff Message's repeated field. For eg: +// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff +// fields. +template +template +bool DiffWrapperBase::GetElementDiffs( + google::protobuf::RepeatedPtrField *dst, + const google::protobuf::RepeatedPtrField &old_elements, + const google::protobuf::RepeatedPtrField &new_elements) { + bool differs = false; + assert (dst != nullptr); + int i = 0; + int j = 0; + while (i < old_elements.size() && j < new_elements.size()) { + const Element &old_element = old_elements.Get(i); + const Element &new_element = new_elements.Get(i); + if (old_element.linker_set_key() != new_element.linker_set_key()) { + ElementDiff *diff = dst->Add(); + Element *old_elementp = nullptr; + Element *new_elementp = nullptr; + if (!diff || !(old_elementp = diff->mutable_old()) || + !(new_elementp = diff->mutable_new_())) { + llvm::errs() << "Failed to add diff element\n"; + ::exit(1); + } + *old_elementp = old_element; + *new_elementp = new_element; + diff->set_index(i); + differs = true; + } + i++; + j++; + } + if (old_elements.size() != new_elements.size()) { + GetExtraElementDiffs(dst, i, j, old_elements, new_elements); + differs = true; + } + return differs; +} + +template +template +void DiffWrapperBase::GetExtraElementDiffs( + google::protobuf::RepeatedPtrField *dst, int i, int j, + const google::protobuf::RepeatedPtrField &old_elements, + const google::protobuf::RepeatedPtrField &new_elements) { + assert(dst != nullptr); + while (i < old_elements.size()) { + const Element &old_element = old_elements.Get(i); + ElementDiff *diff = dst->Add(); + Element *old_elementp = nullptr; + if (!diff || !(old_elementp = diff->mutable_old())) { + llvm::errs() << "Failed to add diff element\n"; + ::exit(1); + } + *old_elementp = old_element; + diff->set_index(i); + i++; + } + while (j < new_elements.size()) { + const Element &new_element = new_elements.Get(j); + ElementDiff *diff = dst->Add(); + Element *new_elementp = nullptr; + if (!diff || !(new_elementp = diff->mutable_new_())) { + llvm::errs() << "Failed to add diff element\n"; + ::exit(1); + } + *new_elementp = new_element; + diff->set_index(j); + j++; + } +} + +template <> +std::unique_ptr DiffWrapper::Get() { + std::unique_ptr record_diff(new RecordDeclDiff()); + assert(oldp_->fully_qualified_name() == newp_->fully_qualified_name()); + record_diff->set_name(oldp_->fully_qualified_name()); + google::protobuf::RepeatedPtrField *fdiffs = + record_diff->mutable_field_diffs(); + google::protobuf::RepeatedPtrField *bdiffs = + record_diff->mutable_base_diffs(); + assert(fdiffs != nullptr && bdiffs != nullptr); + // Template Information isn't diffed since the linker_set_key includes the + // mangled name which includes template information. + if (GetElementDiffs(fdiffs, oldp_->fields(), newp_->fields()) || + GetElementDiffs(bdiffs, oldp_->base_specifiers(), + newp_->base_specifiers())) { + return record_diff; + } + return nullptr; +} + +template <> +std::unique_ptr DiffWrapper::Get() { + std::unique_ptr enum_diff(new EnumDeclDiff()); + assert(oldp_->enum_name() == newp_->enum_name()); + google::protobuf::RepeatedPtrField *fdiffs = + enum_diff->mutable_field_diffs(); + assert(fdiffs != nullptr); + if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) || + (oldp_->enum_type() != newp_->enum_type())) { + return enum_diff; + } + return nullptr; +} + +} // abi_diff_wrappers diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h new file mode 100644 index 000000000..c45482c0a --- /dev/null +++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h @@ -0,0 +1,60 @@ +// Copyright (C) 2016 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. + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wnested-anon-types" +#include "proto/abi_dump.pb.h" +#include "proto/abi_diff.pb.h" +#pragma clang diagnostic pop + +namespace abi_diff_wrappers { + +template +class DiffWrapperBase { + public: + virtual std::unique_ptr Get() = 0 ; + protected: + DiffWrapperBase(const T *oldp, const T *newp) + : oldp_(oldp), newp_(newp) { } + template + bool GetElementDiffs( + google::protobuf::RepeatedPtrField *dst, + const google::protobuf::RepeatedPtrField &old_elements, + const google::protobuf::RepeatedPtrField &new_elements); + + private: + template + void GetExtraElementDiffs( + google::protobuf::RepeatedPtrField *dst, int i, int j, + const google::protobuf::RepeatedPtrField &old_elements, + const google::protobuf::RepeatedPtrField &new_elements); + + protected: + const T *oldp_; + const T *newp_; +}; + +template +class DiffWrapper : public DiffWrapperBase { + public: + DiffWrapper(const T *oldp, const T *newp) + : DiffWrapperBase(oldp, newp) { } + + std::unique_ptr Get() override; +}; + +} // abi_diff_wrappers + + diff --git a/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp new file mode 100644 index 000000000..13fc0df81 --- /dev/null +++ b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2016 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 "abi_diff.h" + +#include +#include + +static llvm::cl::OptionCategory header_checker_category( + "header-abi-diff options"); + +static llvm::cl::opt compatibility_report( + "o", llvm::cl::desc(""), llvm::cl::Required, + llvm::cl::cat(header_checker_category)); + +static llvm::cl::opt new_dump( + "new", llvm::cl::desc(""), llvm::cl::Required, + llvm::cl::cat(header_checker_category)); + +static llvm::cl::opt old_dump( + "old", llvm::cl::desc(""), llvm::cl::Required, + llvm::cl::cat(header_checker_category)); + +int main(int argc, const char **argv) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker"); + HeaderAbiDiff judge(old_dump, new_dump, compatibility_report); + switch (judge.GenerateCompatibilityReport()) { + case HeaderAbiDiff::COMPATIBLE: + case HeaderAbiDiff::EXTENSION: + return 0; + default: + llvm::errs() << "******************************************************\n" + << "VNDK Abi Compliance breakage:" + << " Please check compatiblity report at : " + << compatibility_report << "\n" + << "*****************************************************\n"; + return 1; + } +} diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp index 460bf4deb..637542c11 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp @@ -225,9 +225,13 @@ bool RecordDeclWrapper::SetupRecordFields( << " to reference dump\n"; return false; } - record_fieldp->set_field_name(field->getName()); - record_fieldp->set_field_type(QualTypeToString(field->getType())); - record_fieldp->set_access(AccessToString(field->getAccess())); + std::string name = field->getName(); + std::string type = QualTypeToString(field->getType()); + std::string access = AccessToString(field->getAccess()); + record_fieldp->set_field_name(name); + record_fieldp->set_field_type(type); + record_fieldp->set_access(access); + record_fieldp->set_linker_set_key(name + type + access); field++; } return true; @@ -248,11 +252,14 @@ bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const { llvm::errs() << " Couldn't add base specifier to reference dump\n"; return false; } - base_specifierp->set_fully_qualified_name( - QualTypeToString(base_class->getType())); - base_specifierp->set_is_virtual(base_class->isVirtual()); - base_specifierp->set_access( - AccessToString(base_class->getAccessSpecifier())); + std::string name = QualTypeToString(base_class->getType()); + bool is_virtual = base_class->isVirtual(); + char is_virtual_c = is_virtual ? 't' : 'f'; + std::string access = AccessToString(base_class->getAccessSpecifier()); + base_specifierp->set_fully_qualified_name(name); + base_specifierp->set_is_virtual(is_virtual); + base_specifierp->set_access(access); + base_specifierp->set_linker_set_key(name + is_virtual_c + access); base_class++; } return true; @@ -298,9 +305,11 @@ bool RecordDeclWrapper::SetupTemplateInfo( void RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp, const std::string &source_file) const { std::string qualified_name = GetTagDeclQualifiedName(record_decl_); + std::string mangled_name = GetMangledNameDecl(record_decl_); + std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name; record_declp->set_fully_qualified_name(qualified_name); - //TODO: Add Template Information - record_declp->set_linker_set_key(qualified_name); + record_declp->set_mangled_record_name(mangled_name); + record_declp->set_linker_set_key(linker_key); record_declp->set_source_file(source_file); record_declp->set_access(AccessToString(record_decl_->getAccess())); } diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h index ebd1713d1..4beb2162d 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h +++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h @@ -71,7 +71,7 @@ class RecordDeclWrapper : public ABIWrapper { void SetupRecordInfo(abi_dump::RecordDecl *record_declp, const std::string &source_file) const; - bool SetupRecordFields(abi_dump::RecordDecl *recordp, + bool SetupRecordFields(abi_dump::RecordDecl *record_declp, const std::string &source_file) const; bool SetupCXXBases(abi_dump::RecordDecl *cxxp) const; diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp index 46b82ec31..d5fe042a9 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -128,11 +129,8 @@ HeaderASTConsumer::HeaderASTConsumer( void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) { GOOGLE_PROTOBUF_VERIFY_VERSION; - std::ofstream text_output(out_dump_name_ + ".txt"); - std::fstream binary_output( - out_dump_name_, - std::ios::out | std::ios::trunc | std::ios::binary); - + std::ofstream text_output(out_dump_name_); + google::protobuf::io::OstreamOutputStream text_os(&text_output); clang::TranslationUnitDecl* translation_unit = ctx.getTranslationUnitDecl(); std::unique_ptr mangle_contextp( ctx.createMangleContext()); @@ -141,12 +139,10 @@ void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) { HeaderASTVisitor v(&tu, mangle_contextp.get(), &ctx, cip_, file_name_, exported_headers_); if (!v.TraverseDecl(translation_unit) || - !google::protobuf::TextFormat::PrintToString(tu, &str_out) || - !tu.SerializeToOstream(&binary_output)) { + !google::protobuf::TextFormat::Print(tu, &text_os)) { llvm::errs() << "Serialization to ostream failed\n"; ::exit(1); } - text_output << str_out; } void HeaderASTConsumer::HandleVTable(clang::CXXRecordDecl *crd) { diff --git a/vndk/tools/header-checker/header-abi-linker/src/header_linker.cpp b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp similarity index 91% rename from vndk/tools/header-checker/header-abi-linker/src/header_linker.cpp rename to vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp index 6595634f0..ca1f772a9 100644 --- a/vndk/tools/header-checker/header-abi-linker/src/header_linker.cpp +++ b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp @@ -23,6 +23,7 @@ #include +#include #include #include @@ -78,15 +79,13 @@ class HeaderAbiLinker { bool HeaderAbiLinker::LinkAndDump() { abi_dump::TranslationUnit linked_tu; - std::string str_out; - std::ofstream text_output(out_dump_name_ + ".txt"); - std::fstream binary_output( - out_dump_name_, - std::ios::out | std::ios::trunc | std::ios::binary); + std::ofstream text_output(out_dump_name_); + google::protobuf::io::OstreamOutputStream text_os(&text_output); for (auto &&i : dump_files_) { abi_dump::TranslationUnit dump_tu; - std::fstream input(i, std::ios::binary | std::ios::in); - if (!dump_tu.ParseFromIstream(&input) || + std::ifstream input(i); + google::protobuf::io::IstreamInputStream text_is(&input); + if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) || !LinkRecords(dump_tu, &linked_tu) || !LinkFunctions(dump_tu, &linked_tu) || !LinkEnums(dump_tu, &linked_tu)) { @@ -95,13 +94,10 @@ bool HeaderAbiLinker::LinkAndDump() { } } - if (!google::protobuf::TextFormat::PrintToString(linked_tu, &str_out) || - !linked_tu.SerializeToOstream(&binary_output)) { + if (!google::protobuf::TextFormat::Print(linked_tu, &text_os)) { llvm::errs() << "Serialization to ostream failed\n"; return false; } - text_output << str_out; - return true; } diff --git a/vndk/tools/header-checker/proto/abi_diff.proto b/vndk/tools/header-checker/proto/abi_diff.proto new file mode 100644 index 000000000..e963de59c --- /dev/null +++ b/vndk/tools/header-checker/proto/abi_diff.proto @@ -0,0 +1,55 @@ +syntax = "proto2"; + +import "development/vndk/tools/header-checker/proto/abi_dump.proto"; + +package abi_diff; + +message FieldDeclDiff { + optional abi_dump.FieldDecl old = 1; + optional abi_dump.FieldDecl new = 2; + required uint32 index = 3; +} + +message EnumFieldDeclDiff { + optional abi_dump.EnumFieldDecl old = 1; + optional abi_dump.EnumFieldDecl new = 2; + required uint32 index = 3; +} + +message CXXBaseSpecifierDiff { + optional abi_dump.CXXBaseSpecifier old = 1; + optional abi_dump.CXXBaseSpecifier new = 2; + required uint32 index = 3; +} + +message AccessDiff { + required string old = 1; + required string new = 2; +} + +message RecordDeclDiff { + repeated FieldDeclDiff field_diffs = 1; + repeated CXXBaseSpecifierDiff base_diffs = 2; + required AccessDiff access_diff = 3; + required string name = 4; +} + +message EnumDeclDiff { + repeated EnumFieldDeclDiff field_diffs = 1; + optional AccessDiff access_diff = 2; + required string name = 3; +} + +message TranslationUnitDiff { + // Differing Elements. + repeated RecordDeclDiff records_diff = 1; + repeated EnumDeclDiff enums_diff = 3; + // Removed Elements. + repeated abi_dump.RecordDecl records_removed = 4; + repeated abi_dump.FunctionDecl functions_removed = 5; + repeated abi_dump.EnumDecl enums_removed = 6; + // Added Elements. + repeated abi_dump.RecordDecl records_added = 7; + repeated abi_dump.FunctionDecl functions_added = 8; + repeated abi_dump.EnumDecl enums_added = 9; +} diff --git a/vndk/tools/header-checker/proto/abi_dump.proto b/vndk/tools/header-checker/proto/abi_dump.proto index 4ecf3dce8..a7ab9cc6a 100644 --- a/vndk/tools/header-checker/proto/abi_dump.proto +++ b/vndk/tools/header-checker/proto/abi_dump.proto @@ -25,11 +25,13 @@ message FieldDecl { optional string field_type = 2 [default = "VOID"]; optional string access = 3 [default = "public"]; optional bool default_arg = 4 [default = false]; + optional string linker_set_key = 5 [default = "NONE"]; } message EnumFieldDecl { optional string enum_field_name = 1 [default = "NONE"]; optional int64 enum_field_value = 2 [default = 0]; // assumption: fits int64 + optional string linker_set_key = 3 [default = "NONE"]; } message TemplateInfo { @@ -40,19 +42,19 @@ message CXXBaseSpecifier { optional string fully_qualified_name = 1 [default = "NONE"]; optional string access = 2 [default = "public"]; optional bool is_virtual = 3 [default = false]; + optional string linker_set_key = 4 [default = "NONE"]; } message RecordDecl { - repeated FieldDecl fields = 2; - repeated string inner_classes = 3; - repeated CXXBaseSpecifier base_specifiers = 4; - optional string fully_qualified_name = 5 [default = "NONE"]; - optional int64 id = 6 [default = 0]; - optional string source_file = 9 [default = "NONE"]; - optional string template_kind = 11 [default = "NONE"]; - optional TemplateInfo template_info = 12; - optional string access = 13 [default = "public"]; - optional string linker_set_key = 14 [default = "NONE"]; + repeated FieldDecl fields = 1; + repeated CXXBaseSpecifier base_specifiers = 2; + optional string fully_qualified_name = 3 [default = "NONE"]; + optional string source_file = 4 [default = "NONE"]; + optional uint32 template_kind = 5 [default = 0]; + optional TemplateInfo template_info = 6; + optional string access = 7 [default = "public"]; + optional string linker_set_key = 8 [default = "NONE"]; + optional string mangled_record_name = 9 [default = "NONE"]; } message EnumDecl {