Merge "Added header-abi-diff." am: 4f4b426e06 am: 8800a6b8d9 am: 649fbd4ce4

am: eb9d98f889

Change-Id: I1a8054aeb53414f729711de05fea85d113131235
This commit is contained in:
Jayant Chowdhary
2017-02-16 20:23:09 +00:00
committed by android-build-merger
13 changed files with 770 additions and 47 deletions

View File

@@ -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",
],
},
},
}

View File

@@ -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 <dump-file> <source_file> -I <export-include-dir-1> -I
<export-include-dir-2>.. -- <cflags>
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 <linked-abi-dump> <abi-dump1> <abi-dump2> <abi-dump3> ...
# 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 <old-abi-dump> -new <new-abi-dump> -o <report>
$ header-checker -g -r example1.ast tests/example1.h -- clang -x c++

View File

@@ -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 <llvm/Support/raw_ostream.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <memory>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
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 <typename T>
bool HeaderAbiDiff::PopulateRemovedElements(
google::protobuf::RepeatedPtrField<T> *dst,
const std::map<std::string, const T*> &old_elements_map,
const std::map<std::string, const T*> &new_elements_map) const {
std::vector<const T *> 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 <typename T, typename TDiff>
bool HeaderAbiDiff::PopulateCommonElements(
google::protobuf::RepeatedPtrField<TDiff> *dst,
const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const {
std::vector<std::pair<const T *, const T *>> common_elements;
typename std::map<std::string, const T *>::const_iterator old_element =
old_elements_map.begin();
typename std::map<std::string, const T *>::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 <typename T>
bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &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 <typename T, typename TDiff>
bool HeaderAbiDiff::DumpDiffElements(
google::protobuf::RepeatedPtrField<TDiff> *dst,
std::vector<std::pair<const T *,const T *>> &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<T, TDiff> diff_wrapper(old_element,
new_element);
std::unique_ptr<TDiff> 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;
}

View File

@@ -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 <memory>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
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 <typename T>
inline void AddToMap(std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &src);
template <typename T>
bool PopulateRemovedElements(
google::protobuf::RepeatedPtrField<T> *dst,
const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const;
template <typename T, typename TDiff>
bool PopulateCommonElements(
google::protobuf::RepeatedPtrField<TDiff> *dst,
const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const;
template <typename T, typename TDiff>
bool DumpDiffElements(
google::protobuf::RepeatedPtrField<TDiff> *dst,
std::vector<std::pair<const T *, const T *>> &pairs) const;
template <typename T>
bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &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<std::string, const abi_dump::RecordDecl *> old_dump_records_;
std::map<std::string, const abi_dump::FunctionDecl *> old_dump_functions_;
std::map<std::string, const abi_dump::EnumDecl *> old_dump_enums_;
// HashMaps for the new tu abis
std::map<std::string, const abi_dump::RecordDecl *> new_dump_records_;
std::map<std::string, const abi_dump::FunctionDecl *> new_dump_functions_;
std::map<std::string, const abi_dump::EnumDecl *> new_dump_enums_;
};
typedef HeaderAbiDiff::Status Status;
template <typename T>
inline void HeaderAbiDiff::AddToMap(
std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &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<Status>(
static_cast<std::underlying_type<Status>::type>(f) |
static_cast<std::underlying_type<Status>::type>(s));
}
static inline Status operator&(Status f, Status s) {
return static_cast<Status>(
static_cast<std::underlying_type<Status>::type>(f) &
static_cast<std::underlying_type<Status>::type>(s));
}

View File

@@ -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 <llvm/Support/raw_ostream.h>
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 <typename T, typename TDiff>
template <typename Element, typename ElementDiff>
bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
google::protobuf::RepeatedPtrField<ElementDiff> *dst,
const google::protobuf::RepeatedPtrField<Element> &old_elements,
const google::protobuf::RepeatedPtrField<Element> &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 <typename T, typename TDiff>
template <typename Element, typename ElementDiff>
void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
const google::protobuf::RepeatedPtrField<Element> &old_elements,
const google::protobuf::RepeatedPtrField<Element> &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<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
assert(oldp_->fully_qualified_name() == newp_->fully_qualified_name());
record_diff->set_name(oldp_->fully_qualified_name());
google::protobuf::RepeatedPtrField<FieldDeclDiff> *fdiffs =
record_diff->mutable_field_diffs();
google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *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<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
assert(oldp_->enum_name() == newp_->enum_name());
google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *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

View File

@@ -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 <typename T, typename TDiff>
class DiffWrapperBase {
public:
virtual std::unique_ptr<TDiff> Get() = 0 ;
protected:
DiffWrapperBase(const T *oldp, const T *newp)
: oldp_(oldp), newp_(newp) { }
template <typename Element, typename ElementDiff>
bool GetElementDiffs(
google::protobuf::RepeatedPtrField<ElementDiff> *dst,
const google::protobuf::RepeatedPtrField<Element> &old_elements,
const google::protobuf::RepeatedPtrField<Element> &new_elements);
private:
template <typename Element, typename ElementDiff>
void GetExtraElementDiffs(
google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
const google::protobuf::RepeatedPtrField<Element> &old_elements,
const google::protobuf::RepeatedPtrField<Element> &new_elements);
protected:
const T *oldp_;
const T *newp_;
};
template <typename T, typename TDiff>
class DiffWrapper : public DiffWrapperBase<T, TDiff> {
public:
DiffWrapper(const T *oldp, const T *newp)
: DiffWrapperBase<T, TDiff>(oldp, newp) { }
std::unique_ptr<TDiff> Get() override;
};
} // abi_diff_wrappers

View File

@@ -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 <llvm/Support/CommandLine.h>
#include <llvm/Support/raw_ostream.h>
static llvm::cl::OptionCategory header_checker_category(
"header-abi-diff options");
static llvm::cl::opt<std::string> compatibility_report(
"o", llvm::cl::desc("<compatibility report>"), llvm::cl::Required,
llvm::cl::cat(header_checker_category));
static llvm::cl::opt<std::string> new_dump(
"new", llvm::cl::desc("<new dump>"), llvm::cl::Required,
llvm::cl::cat(header_checker_category));
static llvm::cl::opt<std::string> old_dump(
"old", llvm::cl::desc("<old dump>"), 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;
}
}

View File

@@ -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()));
}

View File

@@ -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;

View File

@@ -19,6 +19,7 @@
#include <clang/Tooling/Core/QualTypeNames.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <fstream>
#include <iostream>
@@ -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<clang::MangleContext> 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) {

View File

@@ -23,6 +23,7 @@
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <memory>
#include <fstream>
@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 {