Added More Abi information.

Make Messages mirror clang Types better.
Added type size and alignments for independent and complete types.
Added vtable layout for CXXRecordDecls.
Added abi information for variables with global storage.
Added new return status to signify abi extension.
Added checks for access specifier downgrades.
Removed repeated code from header-abi-diff.

Test: header-abi-dumper -o example1.dump tests/input/example1.cpp -I
tests -- -x c++ -std=c++11 -I . -I
~/android/aosp/external/clang/lib/Headers

Change-Id: I21b5a8ef6dff92ecae47a0b1c46342862c5e0ebd
This commit is contained in:
Jayant Chowdhary
2017-02-21 15:05:08 -08:00
parent edaab1ab96
commit ee0a448f4a
15 changed files with 769 additions and 316 deletions

View File

@@ -26,6 +26,7 @@ cc_defaults {
"-Werror", "-Werror",
"-std=c++11", "-std=c++11",
"-DGOOGLE_PROTOBUF_NO_RTTI", "-DGOOGLE_PROTOBUF_NO_RTTI",
"-UNDEBUG"
], ],
target: { target: {

View File

@@ -45,95 +45,76 @@ Status HeaderAbiDiff::GenerateCompatibilityReport() {
Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu, Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu,
const abi_dump::TranslationUnit &new_tu) { const abi_dump::TranslationUnit &new_tu) {
abi_diff::TranslationUnitDiff diff_tu; std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
Status record_Status = CollectRecords(&diff_tu, old_tu, new_tu); new abi_diff::TranslationUnitDiff);
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; Status record_status = Collect<abi_dump::RecordDecl>(
diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records());
Status function_status = Collect<abi_dump::FunctionDecl>(
diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
diff_tu->mutable_functions_diff(), old_tu.functions(),
new_tu.functions());
Status enum_status = Collect<abi_dump::EnumDecl>(
diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums());
Status global_var_status = Collect<abi_dump::GlobalVarDecl>(
diff_tu->mutable_global_vars_added(),
diff_tu->mutable_global_vars_removed(),
diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
new_tu.global_vars());
Status combined_status =
record_status | function_status | enum_status | global_var_status;
std::ofstream text_output(cr_); std::ofstream text_output(cr_);
google::protobuf::io::OstreamOutputStream text_os(&text_output); google::protobuf::io::OstreamOutputStream text_os(&text_output);
if(!google::protobuf::TextFormat::Print(diff_tu, &text_os)) { if(!google::protobuf::TextFormat::Print(*diff_tu, &text_os)) {
llvm::errs() << "Unable to dump report\n"; llvm::errs() << "Unable to dump report\n";
::exit(1); ::exit(1);
} }
if (combined_Status & INCOMPATIBLE) { if (combined_status & INCOMPATIBLE) {
return INCOMPATIBLE; return INCOMPATIBLE;
} }
if (combined_Status & EXTENSION) { if (combined_status & EXTENSION) {
return EXTENSION; return EXTENSION;
} }
return COMPATIBLE; return COMPATIBLE;
} }
Status HeaderAbiDiff::CollectRecords(abi_diff::TranslationUnitDiff *diff_tu, template <typename T, typename TDiff>
const abi_dump::TranslationUnit &old_tu, Status HeaderAbiDiff::Collect(
const abi_dump::TranslationUnit &new_tu) { google::protobuf::RepeatedPtrField<T> *elements_added,
AddToMap(&old_dump_records_, old_tu.records()); google::protobuf::RepeatedPtrField<T> *elements_removed,
AddToMap(&new_dump_records_, new_tu.records()); google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
const google::protobuf::RepeatedPtrField<T> &old_srcs,
const google::protobuf::RepeatedPtrField<T> &new_srcs) {
assert(elements_added != nullptr);
assert(elements_removed != nullptr);
assert(elements_diff != nullptr);
if (!PopulateRemovedElements(diff_tu->mutable_records_removed(), std::map<std::string, const T*> old_elements_map;
old_dump_records_, new_dump_records_) || std::map<std::string, const T*> new_elements_map;
!PopulateRemovedElements(diff_tu->mutable_records_removed(), AddToMap(&old_elements_map, old_srcs);
new_dump_records_, old_dump_records_) || AddToMap(&new_elements_map, new_srcs);
!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( if (!PopulateRemovedElements(elements_removed, old_elements_map,
abi_diff::TranslationUnitDiff *diff_tu, new_elements_map) ||
const abi_dump::TranslationUnit &old_tu, !PopulateRemovedElements(elements_added, new_elements_map,
const abi_dump::TranslationUnit &new_tu) { old_elements_map) ||
AddToMap(&old_dump_functions_, old_tu.functions()); !PopulateCommonElements(elements_diff, old_elements_map,
AddToMap(&new_dump_functions_, new_tu.functions()); new_elements_map)) {
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"; llvm::errs() << "Populating functions in report failed\n";
::exit(1); ::exit(1);
} }
if (diff_tu->functions_removed().size()) { if (elements_diff->size() || elements_removed->size()) {
return INCOMPATIBLE; return INCOMPATIBLE;
} }
if (diff_tu->functions_added().size()) { if (elements_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 EXTENSION;
} }
return COMPATIBLE; return COMPATIBLE;
@@ -143,12 +124,13 @@ template <typename T>
bool HeaderAbiDiff::PopulateRemovedElements( bool HeaderAbiDiff::PopulateRemovedElements(
google::protobuf::RepeatedPtrField<T> *dst, google::protobuf::RepeatedPtrField<T> *dst,
const std::map<std::string, const T*> &old_elements_map, const std::map<std::string, const T*> &old_elements_map,
const std::map<std::string, const T*> &new_elements_map) const { const std::map<std::string, const T*> &new_elements_map) {
std::vector<const T *> removed_elements; std::vector<const T *> removed_elements;
for (auto &&map_element : old_elements_map) { for (auto &&map_element : old_elements_map) {
const T *element = map_element.second; const T *element = map_element.second;
auto new_element = new_elements_map.find(element->linker_set_key()); auto new_element =
new_elements_map.find(element->basic_abi().linker_set_key());
if (new_element == new_elements_map.end()) { if (new_element == new_elements_map.end()) {
removed_elements.emplace_back(element); removed_elements.emplace_back(element);
} }
@@ -164,7 +146,7 @@ template <typename T, typename TDiff>
bool HeaderAbiDiff::PopulateCommonElements( bool HeaderAbiDiff::PopulateCommonElements(
google::protobuf::RepeatedPtrField<TDiff> *dst, google::protobuf::RepeatedPtrField<TDiff> *dst,
const std::map<std::string, const T *> &old_elements_map, const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const { const std::map<std::string, const T *> &new_elements_map) {
std::vector<std::pair<const T *, const T *>> common_elements; std::vector<std::pair<const T *, const T *>> common_elements;
typename std::map<std::string, const T *>::const_iterator old_element = typename std::map<std::string, const T *>::const_iterator old_element =
old_elements_map.begin(); old_elements_map.begin();
@@ -194,7 +176,7 @@ bool HeaderAbiDiff::PopulateCommonElements(
template <typename T> template <typename T>
bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst, bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements) const { std::vector<const T *> &elements) {
for (auto &&element : elements) { for (auto &&element : elements) {
T *added_element = dst->Add(); T *added_element = dst->Add();
if (!added_element) { if (!added_element) {
@@ -209,7 +191,7 @@ bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
template <typename T, typename TDiff> template <typename T, typename TDiff>
bool HeaderAbiDiff::DumpDiffElements( bool HeaderAbiDiff::DumpDiffElements(
google::protobuf::RepeatedPtrField<TDiff> *dst, google::protobuf::RepeatedPtrField<TDiff> *dst,
std::vector<std::pair<const T *,const T *>> &pairs) const { std::vector<std::pair<const T *,const T *>> &pairs) {
for (auto &&pair : pairs) { for (auto &&pair : pairs) {
const T *old_element = pair.first; const T *old_element = pair.first;
const T *new_element = pair.second; const T *new_element = pair.second;

View File

@@ -47,58 +47,43 @@ class HeaderAbiDiff {
Status CompareTUs(const abi_dump::TranslationUnit &old_tu, Status CompareTUs(const abi_dump::TranslationUnit &old_tu,
const abi_dump::TranslationUnit &new_tu); const abi_dump::TranslationUnit &new_tu);
// Collect* methods fill in the diff_tu. // Collect* methods fill in the diff_tu.
Status CollectRecords(abi_diff::TranslationUnitDiff *abi_diff, template <typename T, typename TDiff>
const abi_dump::TranslationUnit &old_tu, static Status Collect(
const abi_dump::TranslationUnit &new_tu); google::protobuf::RepeatedPtrField<T> *elements_added,
google::protobuf::RepeatedPtrField<T> *elements_removed,
Status CollectFunctions(abi_diff::TranslationUnitDiff *abi_diff, google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
const abi_dump::TranslationUnit &old_tu, const google::protobuf::RepeatedPtrField<T> &old_srcs,
const abi_dump::TranslationUnit &new_tu); const google::protobuf::RepeatedPtrField<T> &new_srcs);
Status CollectEnums(abi_diff::TranslationUnitDiff *abi_diff,
const abi_dump::TranslationUnit &old_tu,
const abi_dump::TranslationUnit &new_tu);
template <typename T> template <typename T>
inline void AddToMap(std::map<std::string, const T *> *dst, static inline void AddToMap(std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &src); const google::protobuf::RepeatedPtrField<T> &src);
template <typename T> template <typename T>
bool PopulateRemovedElements( static bool PopulateRemovedElements(
google::protobuf::RepeatedPtrField<T> *dst, google::protobuf::RepeatedPtrField<T> *dst,
const std::map<std::string, const T *> &old_elements_map, const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const; const std::map<std::string, const T *> &new_elements_map);
template <typename T, typename TDiff> template <typename T, typename TDiff>
bool PopulateCommonElements( static bool PopulateCommonElements(
google::protobuf::RepeatedPtrField<TDiff> *dst, google::protobuf::RepeatedPtrField<TDiff> *dst,
const std::map<std::string, const T *> &old_elements_map, const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map) const; const std::map<std::string, const T *> &new_elements_map);
template <typename T, typename TDiff> template <typename T, typename TDiff>
bool DumpDiffElements( static bool DumpDiffElements(
google::protobuf::RepeatedPtrField<TDiff> *dst, google::protobuf::RepeatedPtrField<TDiff> *dst,
std::vector<std::pair<const T *, const T *>> &pairs) const; std::vector<std::pair<const T *, const T *>> &pairs);
template <typename T> template <typename T>
bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst, static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements) const; std::vector<const T *> &elements);
private: private:
const std::string &old_dump_; const std::string &old_dump_;
const std::string &new_dump_; const std::string &new_dump_;
const std::string &cr_; 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; typedef HeaderAbiDiff::Status Status;
@@ -108,7 +93,7 @@ inline void HeaderAbiDiff::AddToMap(
std::map<std::string, const T *> *dst, std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &src) { const google::protobuf::RepeatedPtrField<T> &src) {
for (auto &&element : src) { for (auto &&element : src) {
dst->insert(std::make_pair(element.linker_set_key(), &element)); dst->insert(std::make_pair(element.basic_abi().linker_set_key(), &element));
} }
} }

View File

@@ -24,15 +24,93 @@
#include <llvm/Support/raw_ostream.h> #include <llvm/Support/raw_ostream.h>
using abi_diff::RecordDeclDiff; using abi_diff::RecordDeclDiff;
using abi_diff::FieldDeclDiff; using abi_diff::RecordFieldDeclDiff;
using abi_diff::CXXBaseSpecifierDiff; using abi_diff::CXXBaseSpecifierDiff;
using abi_diff::CXXVTableDiff;
using abi_diff::EnumDeclDiff;
using abi_diff::ReturnTypeDiff;
using abi_diff::FunctionDeclDiff;
using abi_diff::EnumDeclDiff; using abi_diff::EnumDeclDiff;
using abi_diff::EnumFieldDeclDiff; using abi_diff::EnumFieldDeclDiff;
using abi_diff::GlobalVarDeclDiff;
using abi_dump::RecordDecl; using abi_dump::RecordDecl;
using abi_dump::RecordFieldDecl;
using abi_dump::EnumDecl; using abi_dump::EnumDecl;
using abi_dump::EnumFieldDecl;
using abi_dump::FunctionDecl;
using abi_dump::ParamDecl;
using abi_dump::VTableComponent;
using abi_dump::CXXBaseSpecifier;
using abi_dump::GlobalVarDecl;
namespace abi_diff_wrappers { namespace abi_diff_wrappers {
static bool IsAccessDownGraded(abi_dump::AccessSpecifier old_access,
abi_dump::AccessSpecifier new_access) {
bool access_downgraded = false;
switch (old_access) {
case abi_dump::AccessSpecifier::protected_access:
if (new_access == abi_dump::AccessSpecifier::private_access) {
access_downgraded = true;
}
break;
case abi_dump::AccessSpecifier::public_access:
if (new_access != abi_dump::AccessSpecifier::public_access) {
access_downgraded = true;
}
break;
default:
break;
}
return access_downgraded;
}
static bool DiffBasicTypeAbi(const abi_dump::BasicTypeAbi &old_abi,
const abi_dump::BasicTypeAbi &new_abi) {
bool name_comparison = (old_abi.name() != new_abi.name());
bool size_comparison = (old_abi.size() != new_abi.size());
bool alignment_comparison = (old_abi.alignment() != new_abi.alignment());
return name_comparison || size_comparison || alignment_comparison;
}
template <typename T>
static bool Diff(const T &old_element, const T &new_element) {
// Can be specialized for future changes in the format.
return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
new_element.basic_abi().type_abi()) ||
IsAccessDownGraded(old_element.basic_abi().access(),
new_element.basic_abi().access());
}
template <>
bool Diff<EnumFieldDecl>(const EnumFieldDecl &old_element,
const EnumFieldDecl &new_element) {
// Can be specialized for future changes in the format.
return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
new_element.basic_abi().type_abi()) ||
(old_element.enum_field_value() != new_element.enum_field_value());
}
template <>
bool Diff<CXXBaseSpecifier>(const CXXBaseSpecifier &old_element,
const CXXBaseSpecifier &new_element) {
// Can be specialized for future changes in the format.
return (DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
new_element.basic_abi().type_abi()) ||
old_element.basic_abi().access() != new_element.basic_abi().access() ||
old_element.is_virtual() != new_element.is_virtual());
}
template <>
bool Diff<VTableComponent>(const VTableComponent &old_element,
const VTableComponent &new_element) {
bool kind_comparison = old_element.kind() != new_element.kind();
bool mangled_name_comparison = old_element.mangled_component_name() !=
new_element.mangled_component_name();
bool value_comparison = old_element.value() != new_element.value();
return kind_comparison || mangled_name_comparison || value_comparison;
}
// This function fills in a *Diff Message's repeated field. For eg: // This function fills in a *Diff Message's repeated field. For eg:
// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff // RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff
// fields. // fields.
@@ -49,7 +127,8 @@ bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
while (i < old_elements.size() && j < new_elements.size()) { while (i < old_elements.size() && j < new_elements.size()) {
const Element &old_element = old_elements.Get(i); const Element &old_element = old_elements.Get(i);
const Element &new_element = new_elements.Get(i); const Element &new_element = new_elements.Get(i);
if (old_element.linker_set_key() != new_element.linker_set_key()) {
if (Diff(old_element, new_element)) {
ElementDiff *diff = dst->Add(); ElementDiff *diff = dst->Add();
Element *old_elementp = nullptr; Element *old_elementp = nullptr;
Element *new_elementp = nullptr; Element *new_elementp = nullptr;
@@ -109,18 +188,22 @@ void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
template <> template <>
std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() { std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff()); std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
assert(oldp_->fully_qualified_name() == newp_->fully_qualified_name()); assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
record_diff->set_name(oldp_->fully_qualified_name()); record_diff->set_name(oldp_->basic_abi().name());
google::protobuf::RepeatedPtrField<FieldDeclDiff> *fdiffs = google::protobuf::RepeatedPtrField<RecordFieldDeclDiff> *fdiffs =
record_diff->mutable_field_diffs(); record_diff->mutable_field_diffs();
google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *bdiffs = google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *bdiffs =
record_diff->mutable_base_diffs(); record_diff->mutable_base_diffs();
google::protobuf::RepeatedPtrField<CXXVTableDiff> *vtdiffs =
record_diff->mutable_vtable_diffs();
assert(fdiffs != nullptr && bdiffs != nullptr); assert(fdiffs != nullptr && bdiffs != nullptr);
// Template Information isn't diffed since the linker_set_key includes the // Template Information isn't diffed since the linker_set_key includes the
// mangled name which includes template information. // mangled name which includes template information.
if (GetElementDiffs(fdiffs, oldp_->fields(), newp_->fields()) || if (GetElementDiffs(fdiffs, oldp_->fields(), newp_->fields()) ||
GetElementDiffs(bdiffs, oldp_->base_specifiers(), GetElementDiffs(bdiffs, oldp_->base_specifiers(),
newp_->base_specifiers())) { newp_->base_specifiers()) ||
GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
newp_->vtable_layout().vtable_components())) {
return record_diff; return record_diff;
} }
return nullptr; return nullptr;
@@ -129,15 +212,51 @@ std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
template <> template <>
std::unique_ptr<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() { std::unique_ptr<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff()); std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
assert(oldp_->enum_name() == newp_->enum_name()); assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs = google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
enum_diff->mutable_field_diffs(); enum_diff->mutable_field_diffs();
assert(fdiffs != nullptr); assert(fdiffs != nullptr);
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) || if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields())) {
(oldp_->enum_type() != newp_->enum_type())) {
return enum_diff; return enum_diff;
} }
return nullptr; return nullptr;
} }
template <>
std::unique_ptr<FunctionDeclDiff>
DiffWrapper<FunctionDecl, FunctionDeclDiff>::Get() {
std::unique_ptr<FunctionDeclDiff> func_diff(new FunctionDeclDiff());
if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
newp_->basic_abi().type_abi()) ||
IsAccessDownGraded(oldp_->basic_abi().access(),
newp_->basic_abi().access())) {
assert(func_diff->mutable_return_type_diffs() != nullptr &&
func_diff->mutable_return_type_diffs()->mutable_old() != nullptr &&
func_diff->mutable_return_type_diffs()->mutable_new_() != nullptr);
*(func_diff->mutable_return_type_diffs()->mutable_old()) =
oldp_->basic_abi();
*(func_diff->mutable_return_type_diffs()->mutable_new_()) =
newp_->basic_abi();
return func_diff;
}
return nullptr;
}
template <>
std::unique_ptr<GlobalVarDeclDiff>
DiffWrapper<GlobalVarDecl, GlobalVarDeclDiff>::Get() {
std::unique_ptr<GlobalVarDeclDiff> global_var_diff(new GlobalVarDeclDiff());
if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
newp_->basic_abi().type_abi()) ||
IsAccessDownGraded(oldp_->basic_abi().access(),
newp_->basic_abi().access())) {
assert(global_var_diff->mutable_old() != nullptr);
assert(global_var_diff->mutable_new_() != nullptr);
*(global_var_diff->mutable_old()) = oldp_->basic_abi();
*(global_var_diff->mutable_new_()) = newp_->basic_abi();
return global_var_diff;
}
return nullptr;
}
} // abi_diff_wrappers } // abi_diff_wrappers

View File

@@ -35,17 +35,24 @@ static llvm::cl::opt<std::string> old_dump(
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker"); llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
uint8_t extension_or_incompatible = 0;
HeaderAbiDiff judge(old_dump, new_dump, compatibility_report); HeaderAbiDiff judge(old_dump, new_dump, compatibility_report);
switch (judge.GenerateCompatibilityReport()) { switch (judge.GenerateCompatibilityReport()) {
case HeaderAbiDiff::COMPATIBLE: case HeaderAbiDiff::COMPATIBLE:
break;
case HeaderAbiDiff::EXTENSION: case HeaderAbiDiff::EXTENSION:
return 0; extension_or_incompatible = 1;
break;
default: default:
extension_or_incompatible = 2;
break;
}
if (extension_or_incompatible) {
llvm::errs() << "******************************************************\n" llvm::errs() << "******************************************************\n"
<< "VNDK Abi Compliance breakage:" << "VNDK Abi Compliance breakage:"
<< " Please check compatiblity report at : " << " Please check compatiblity report at : "
<< compatibility_report << "\n" << compatibility_report << "\n"
<< "*****************************************************\n"; << "*****************************************************\n";
return 1;
} }
return extension_or_incompatible;
} }

View File

@@ -22,7 +22,7 @@ using namespace abi_wrapper;
ABIWrapper::ABIWrapper( ABIWrapper::ABIWrapper(
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *cip) const clang::CompilerInstance *cip)
: cip_(cip), : cip_(cip),
mangle_contextp_(mangle_contextp), mangle_contextp_(mangle_contextp),
@@ -40,26 +40,66 @@ std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
return abs_path.str(); return abs_path.str();
} }
std::string ABIWrapper::AccessToString(const clang::AccessSpecifier sp) const { abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
std::string str = "public"; const clang::AccessSpecifier sp) const {
switch (sp) { switch (sp) {
case clang::AS_private: { case clang::AS_private: {
str = "private"; return abi_dump::AccessSpecifier::private_access;
break; break;
} }
case clang::AS_protected: { case clang::AS_protected: {
str = "protected"; return abi_dump::AccessSpecifier::protected_access;
break; break;
} }
default: { default: {
return abi_dump::AccessSpecifier::public_access;
break; break;
} }
} }
return str; }
bool ABIWrapper::SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
const clang::QualType type) const {
if (!type_abi) {
return false;
}
type_abi->set_name(QualTypeToString(type));
// Cannot determine the size and alignment for template parameter dependent
// types as well as incomplete types.
const clang::Type *base_type = type.getTypePtr();
if (base_type && !(base_type->isDependentType()) &&
!(base_type->isIncompleteType())) {
std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
ast_contextp_->getTypeInfoInChars(type);
int64_t size = size_and_alignment.first.getQuantity();
int64_t alignment = size_and_alignment.second.getQuantity();
type_abi->set_size(size);
type_abi->set_alignment(alignment);
}
return true;
}
bool ABIWrapper::SetupBasicNamedAndTypedDecl(
abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
const clang::QualType type, const std::string &name,
const clang::AccessSpecifier &access, std::string key) const {
if (!basic_named_and_typed_decl) {
return false;
}
abi_dump::AccessSpecifier access_dump = AccessClangToDump(access);
basic_named_and_typed_decl->set_name(name);
basic_named_and_typed_decl->set_access(access_dump);
if (key != "") {
basic_named_and_typed_decl->set_linker_set_key(key);
}
return SetupBasicTypeAbi(basic_named_and_typed_decl->mutable_type_abi(),
type);
} }
std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const { std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const {
std::string mangled_or_demangled_name = decl->getName(); clang::IdentifierInfo *identifier = decl->getIdentifier();
std::string mangled_or_demangled_name =
identifier ? identifier->getName() : "";
if (mangle_contextp_->shouldMangleDeclName(decl)) { if (mangle_contextp_->shouldMangleDeclName(decl)) {
llvm::raw_string_ostream ostream(mangled_or_demangled_name); llvm::raw_string_ostream ostream(mangled_or_demangled_name);
mangle_contextp_->mangleName(decl, ostream); mangle_contextp_->mangleName(decl, ostream);
@@ -71,17 +111,26 @@ std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const {
bool ABIWrapper::SetupTemplateParamNames( bool ABIWrapper::SetupTemplateParamNames(
abi_dump::TemplateInfo *tinfo, abi_dump::TemplateInfo *tinfo,
clang::TemplateParameterList *pl) const { clang::TemplateParameterList *pl) const {
if (tinfo->template_parameters_size() > 0) { if (tinfo->elements_size() > 0) {
return true; return true;
} }
clang::TemplateParameterList::iterator template_it = pl->begin(); clang::TemplateParameterList::iterator template_it = pl->begin();
while (template_it != pl->end()) { while (template_it != pl->end()) {
abi_dump::FieldDecl *template_parameterp = tinfo->add_template_parameters(); abi_dump::TemplateElement *template_parameterp =
tinfo->add_elements();
if (!template_parameterp) { if (!template_parameterp) {
return false; return false;
} }
template_parameterp->set_field_name((*template_it)->getName()); abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
template_parameterp->mutable_basic_abi();
if (!basic_abi) {
return false;
}
std::string name = (*template_it)->getName();
basic_abi->set_name(name);
// TODO : Default arg ?
basic_abi->set_linker_set_key(name);
template_it++; template_it++;
} }
return true; return true;
@@ -92,7 +141,6 @@ std::string ABIWrapper::GetTagDeclQualifiedName(
if (decl->getTypedefNameForAnonDecl()) { if (decl->getTypedefNameForAnonDecl()) {
return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString(); return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
} }
return decl->getQualifiedNameAsString(); return decl->getQualifiedNameAsString();
} }
@@ -102,16 +150,22 @@ bool ABIWrapper::SetupTemplateArguments(
for (int i = 0; i < tl->size(); i++) { for (int i = 0; i < tl->size(); i++) {
const clang::TemplateArgument &arg = (*tl)[i]; const clang::TemplateArgument &arg = (*tl)[i];
//TODO: More comprehensive checking needed. //TODO: More comprehensive checking needed.
std::string type = " "; if (arg.getKind() != clang::TemplateArgument::Type) {
if(arg.getKind() == clang::TemplateArgument::Type) { continue;
type = QualTypeToString(arg.getAsType());
} }
abi_dump::FieldDecl *template_parameterp = clang::QualType type = arg.getAsType();
tinfo->add_template_parameters(); abi_dump::TemplateElement *template_parameterp =
tinfo->add_elements();
if (!template_parameterp) { if (!template_parameterp) {
return false; return false;
} }
template_parameterp->set_field_type((type)); abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
template_parameterp->mutable_basic_abi();
if (!basic_abi || !SetupBasicTypeAbi(basic_abi->mutable_type_abi(), type)) {
return false;
}
// TODO : default arg
basic_abi->set_linker_set_key(QualTypeToString(type));
} }
return true; return true;
} }
@@ -124,42 +178,51 @@ std::string ABIWrapper::QualTypeToString(
FunctionDeclWrapper::FunctionDeclWrapper( FunctionDeclWrapper::FunctionDeclWrapper(
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::FunctionDecl *decl) const clang::FunctionDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p), : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
function_decl_(decl) { } function_decl_(decl) { }
bool FunctionDeclWrapper::SetupFunctionParameters(
abi_dump::FunctionDecl *functionp) const {
clang::FunctionDecl::param_const_iterator param_it =
function_decl_->param_begin();
while (param_it != function_decl_->param_end()) {
abi_dump::ParamDecl *function_fieldp = functionp->add_parameters();
if (!function_fieldp) {
llvm::errs() << "Couldn't add parameter to method. Aborting\n";
return false;
}
// The linker set key is blank since that shows up in the mangled name.
bool has_default_arg = (*param_it)->hasDefaultArg();
if (!SetupBasicNamedAndTypedDecl(
function_fieldp->mutable_basic_abi(),
(*param_it)->getType(), (*param_it)->getName(),
(*param_it)->getAccess(), has_default_arg ? "true" : "false")) {
return false;
}
function_fieldp->set_default_arg(has_default_arg);
param_it++;
}
return true;
}
bool FunctionDeclWrapper::SetupFunction(abi_dump::FunctionDecl *functionp, bool FunctionDeclWrapper::SetupFunction(abi_dump::FunctionDecl *functionp,
const std::string &source_file) const { const std::string &source_file) const {
// Go through all the parameters in the method and add them to the fields. // Go through all the parameters in the method and add them to the fields.
// Also get the fully qualfied name and mangled name and store them. // Also get the fully qualfied name and mangled name and store them.
std::string mangled_name = GetMangledNameDecl(function_decl_); std::string mangled_name = GetMangledNameDecl(function_decl_);
functionp->set_function_name(function_decl_->getQualifiedNameAsString());
functionp->set_mangled_function_name(mangled_name); functionp->set_mangled_function_name(mangled_name);
functionp->set_linker_set_key(mangled_name);
functionp->set_source_file(source_file); functionp->set_source_file(source_file);
functionp->set_return_type(QualTypeToString(function_decl_->getReturnType()));
clang::FunctionDecl::param_const_iterator param_it = // Combine the function name and return type to form a NamedAndTypedDecl
function_decl_->param_begin(); return SetupBasicNamedAndTypedDecl(
while (param_it != function_decl_->param_end()) { functionp->mutable_basic_abi(),
abi_dump::FieldDecl *function_fieldp = functionp->add_parameters(); function_decl_->getReturnType(),
if (!function_fieldp) { function_decl_->getQualifiedNameAsString(),
llvm::errs() << "Couldn't add parameter to method. Aborting\n"; function_decl_->getAccess(), mangled_name) &&
return false; SetupTemplateInfo(functionp) && SetupFunctionParameters(functionp);
}
function_fieldp->set_field_name((*param_it)->getName());
function_fieldp->set_default_arg((*param_it)->hasDefaultArg());
function_fieldp->set_field_type(QualTypeToString((*param_it)->getType()));
param_it++;
}
functionp->set_access(AccessToString(function_decl_->getAccess()));
functionp->set_template_kind(function_decl_->getTemplatedKind());
if(!SetupTemplateInfo(functionp)) {
return false;
}
return true;
} }
bool FunctionDeclWrapper::SetupTemplateInfo( bool FunctionDeclWrapper::SetupTemplateInfo(
@@ -209,42 +272,35 @@ FunctionDeclWrapper::GetFunctionDecl() const {
RecordDeclWrapper::RecordDeclWrapper( RecordDeclWrapper::RecordDeclWrapper(
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::RecordDecl *decl) const clang::RecordDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p), : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
record_decl_(decl) { } record_decl_(decl) { }
bool RecordDeclWrapper::SetupRecordFields( bool RecordDeclWrapper::SetupRecordFields(abi_dump::RecordDecl *recordp) const {
abi_dump::RecordDecl *recordp,
const std::string &source_file) const {
clang::RecordDecl::field_iterator field = record_decl_->field_begin(); clang::RecordDecl::field_iterator field = record_decl_->field_begin();
while (field != record_decl_->field_end()) { while (field != record_decl_->field_end()) {
abi_dump::FieldDecl *record_fieldp = recordp->add_fields(); abi_dump::RecordFieldDecl *record_fieldp = recordp->add_fields();
if (!record_fieldp) { if (!record_fieldp) {
llvm::errs() << " Couldn't add record field: " << field->getName() llvm::errs() << " Couldn't add record field: " << field->getName()
<< " to reference dump\n"; << " to reference dump\n";
return false; return false;
} }
std::string name = field->getName(); if (!SetupBasicNamedAndTypedDecl(record_fieldp->mutable_basic_abi(),
std::string type = QualTypeToString(field->getType()); field->getType(), field->getName(),
std::string access = AccessToString(field->getAccess()); field->getAccess(), "")) {
record_fieldp->set_field_name(name); return false;
record_fieldp->set_field_type(type); }
record_fieldp->set_access(access);
record_fieldp->set_linker_set_key(name + type + access);
field++; field++;
} }
return true; return true;
} }
bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const { bool RecordDeclWrapper::SetupCXXBases(
const clang::CXXRecordDecl *cxx_record_decl = abi_dump::RecordDecl *cxxp,
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_); const clang::CXXRecordDecl *cxx_record_decl) const {
if (!cxx_record_decl) { assert(cxx_record_decl != nullptr);
return true;
}
clang::CXXRecordDecl::base_class_const_iterator base_class = clang::CXXRecordDecl::base_class_const_iterator base_class =
cxx_record_decl->bases_begin(); cxx_record_decl->bases_begin();
while (base_class != cxx_record_decl->bases_end()) { while (base_class != cxx_record_decl->bases_end()) {
@@ -255,25 +311,121 @@ bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const {
} }
std::string name = QualTypeToString(base_class->getType()); std::string name = QualTypeToString(base_class->getType());
bool is_virtual = base_class->isVirtual(); bool is_virtual = base_class->isVirtual();
char is_virtual_c = is_virtual ? 't' : 'f'; if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
std::string access = AccessToString(base_class->getAccessSpecifier()); base_class->getType(),
base_specifierp->set_fully_qualified_name(name); "", base_class->getAccessSpecifier(),
"")) {
return false;
}
base_specifierp->set_is_virtual(is_virtual); 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++; base_class++;
} }
return true; return true;
} }
bool RecordDeclWrapper::SetupTemplateInfo( bool RecordDeclWrapper::SetupRecordVTable(
abi_dump::RecordDecl *record_declp) const { abi_dump::RecordDecl *record_declp,
const clang::CXXRecordDecl *cxx_record_decl = const clang::CXXRecordDecl *cxx_record_decl) const {
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_); assert(cxx_record_decl != nullptr);
if (!cxx_record_decl) { clang::VTableContextBase *base_vtable_contextp =
ast_contextp_->getVTableContext();
const clang::Type *typep = cxx_record_decl->getTypeForDecl();
if (!base_vtable_contextp || !typep) {
return false;
}
// Skip Microsoft ABI.
clang::ItaniumVTableContext *itanium_vtable_contextp =
llvm::dyn_cast<clang::ItaniumVTableContext>(base_vtable_contextp);
if (!itanium_vtable_contextp || !cxx_record_decl->isPolymorphic() ||
typep->isDependentType() || typep->isIncompleteType()) {
return true;
}
const clang::VTableLayout &vtable_layout =
itanium_vtable_contextp->getVTableLayout(cxx_record_decl);
abi_dump::VTableLayout *vtablep = record_declp->mutable_vtable_layout();
if (!vtablep) {
return false;
}
for (const auto &vtable_component : vtable_layout.vtable_components()) {
abi_dump::VTableComponent *added_vtable_component =
vtablep->add_vtable_components();
if (!added_vtable_component ||
!SetupRecordVTableComponent(added_vtable_component, vtable_component)) {
return false;
}
}
return true; return true;
} }
bool RecordDeclWrapper::SetupRecordVTableComponent(
abi_dump::VTableComponent *added_vtable_component,
const clang::VTableComponent &vtable_component) const {
assert(added_vtable_component != nullptr);
abi_dump::VTableComponent_Kind kind = abi_dump::VTableComponent_Kind_RTTI;
std::string mangled_component_name = "";
uint64_t value = 0;
clang::VTableComponent::Kind clang_component_kind =
vtable_component.getKind();
switch (clang_component_kind) {
case clang::VTableComponent::CK_VCallOffset:
kind = abi_dump::VTableComponent_Kind_VCallOffset;
value = vtable_component.getVCallOffset().getQuantity();
break;
case clang::VTableComponent::CK_VBaseOffset:
kind = abi_dump::VTableComponent_Kind_VBaseOffset;
value = vtable_component.getVBaseOffset().getQuantity();
break;
case clang::VTableComponent::CK_OffsetToTop:
kind = abi_dump::VTableComponent_Kind_OffsetToTop;
value = vtable_component.getOffsetToTop().getQuantity();
break;
case clang::VTableComponent::CK_RTTI:
{
kind = abi_dump::VTableComponent_Kind_RTTI;
const clang::CXXRecordDecl *rtti_decl =
vtable_component.getRTTIDecl();
assert(rtti_decl != nullptr);
mangled_component_name = GetMangledNameDecl(rtti_decl);
}
break;
case clang::VTableComponent::CK_FunctionPointer:
case clang::VTableComponent::CK_CompleteDtorPointer:
case clang::VTableComponent::CK_DeletingDtorPointer:
case clang::VTableComponent::CK_UnusedFunctionPointer:
{
const clang::CXXMethodDecl *method_decl =
vtable_component.getFunctionDecl();
assert(method_decl != nullptr);
mangled_component_name = GetMangledNameDecl(method_decl);
switch (clang_component_kind) {
case clang::VTableComponent::CK_FunctionPointer:
kind = abi_dump::VTableComponent_Kind_FunctionPointer;
break;
case clang::VTableComponent::CK_CompleteDtorPointer:
kind = abi_dump::VTableComponent_Kind_CompleteDtorPointer;
break;
case clang::VTableComponent::CK_DeletingDtorPointer:
kind = abi_dump::VTableComponent_Kind_DeletingDtorPointer;
case clang::VTableComponent::CK_UnusedFunctionPointer:
kind = abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
default:
break;
}
}
break;
default:
return false;
}
added_vtable_component->set_kind(kind);
added_vtable_component->set_value(value);
added_vtable_component->set_mangled_component_name(mangled_component_name);
return true;
}
bool RecordDeclWrapper::SetupTemplateInfo(
abi_dump::RecordDecl *record_declp,
const clang::CXXRecordDecl *cxx_record_decl) const {
assert(cxx_record_decl != nullptr);
if (cxx_record_decl->isTemplateDecl()) { if (cxx_record_decl->isTemplateDecl()) {
clang::ClassTemplateDecl *template_decl = clang::ClassTemplateDecl *template_decl =
cxx_record_decl->getDescribedClassTemplate(); cxx_record_decl->getDescribedClassTemplate();
@@ -303,28 +455,45 @@ bool RecordDeclWrapper::SetupTemplateInfo(
return true; return true;
} }
void RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp, bool RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
const std::string &source_file) const { const std::string &source_file) const {
std::string qualified_name = GetTagDeclQualifiedName(record_decl_); std::string qualified_name = GetTagDeclQualifiedName(record_decl_);
std::string mangled_name = GetMangledNameDecl(record_decl_); std::string mangled_name = GetMangledNameDecl(record_decl_);
const clang::Type *basic_type = nullptr;
if (!(basic_type = record_decl_->getTypeForDecl())) {
return false;
}
clang::QualType type = basic_type->getCanonicalTypeInternal();
std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name; std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name;
record_declp->set_fully_qualified_name(qualified_name); if (!SetupBasicNamedAndTypedDecl(record_declp->mutable_basic_abi(),
type, qualified_name,
record_decl_->getAccess(), linker_key)) {
return false;
}
record_declp->set_mangled_record_name(mangled_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_source_file(source_file);
record_declp->set_access(AccessToString(record_decl_->getAccess())); return true;
}
bool RecordDeclWrapper::SetupCXXRecordInfo(
abi_dump::RecordDecl *record_declp) const {
const clang::CXXRecordDecl *cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
if (!cxx_record_decl) {
return true;
}
return SetupTemplateInfo(record_declp, cxx_record_decl) &&
SetupCXXBases(record_declp, cxx_record_decl) &&
SetupRecordVTable(record_declp, cxx_record_decl);
} }
std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const { std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
std::unique_ptr<abi_dump::RecordDecl> abi_decl(new abi_dump::RecordDecl()); std::unique_ptr<abi_dump::RecordDecl> abi_decl(new abi_dump::RecordDecl());
std::string source_file = GetDeclSourceFile(record_decl_, cip_); std::string source_file = GetDeclSourceFile(record_decl_, cip_);
SetupRecordInfo(abi_decl.get(), source_file); abi_dump::RecordDecl *record_declp = abi_decl.get();
if (!SetupRecordFields(abi_decl.get(), source_file)) { if (!SetupRecordInfo(record_declp, source_file) ||
llvm::errs() << "Setting up Record Fields failed\n"; !SetupRecordFields(record_declp) ||
return nullptr; !SetupCXXRecordInfo(abi_decl.get())) {
}
if (!SetupCXXBases(abi_decl.get()) || !SetupTemplateInfo(abi_decl.get())) {
llvm::errs() << "Setting up CXX Bases / Template Info failed\n"; llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
return nullptr; return nullptr;
} }
@@ -333,34 +502,46 @@ std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
EnumDeclWrapper::EnumDeclWrapper( EnumDeclWrapper::EnumDeclWrapper(
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::EnumDecl *decl) const clang::EnumDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p), : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
enum_decl_(decl) { } enum_decl_(decl) { }
bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump, bool EnumDeclWrapper::SetupEnumFields(abi_dump::EnumDecl *enump) const {
const std::string &source_file) const {
// Enum's name.
std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
std::string enum_type = QualTypeToString(enum_decl_->getIntegerType());
enump->set_enum_name(enum_name);
// Enum's base integer type.
enump->set_enum_type(enum_type);
enump->set_linker_set_key(enum_name + enum_type);
clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin(); clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
while (enum_it != enum_decl_->enumerator_end()) { while (enum_it != enum_decl_->enumerator_end()) {
abi_dump::EnumFieldDecl *enum_fieldp = enump->add_enum_fields(); abi_dump::EnumFieldDecl *enum_fieldp = enump->add_enum_fields();
if (!enum_fieldp) { std::string name = enum_it->getQualifiedNameAsString();
uint64_t field_value = enum_it->getInitVal().getExtValue();
if (!enum_fieldp ||
!SetupBasicNamedAndTypedDecl(enum_fieldp->mutable_basic_abi(),
enum_it->getType(), name,
enum_it->getAccess(),
std::to_string(field_value))) {
return false; return false;
} }
enum_fieldp->set_enum_field_name(enum_it->getQualifiedNameAsString()); enum_fieldp->set_enum_field_value(field_value);
enum_fieldp->set_enum_field_value(enum_it->getInitVal().getExtValue());
enum_it++; enum_it++;
} }
return true; return true;
} }
bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
const std::string &source_file) const {
std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
std::string enum_mangled_name = GetMangledNameDecl(enum_decl_);
clang::QualType enum_type = enum_decl_->getIntegerType();
if (!SetupBasicNamedAndTypedDecl(enump->mutable_basic_abi(), enum_type,
enum_name, enum_decl_->getAccess(),
enum_mangled_name) ||
!SetupEnumFields(enump)) {
return false;
}
enump->set_source_file(source_file);
return true;
}
std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const { std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
std::unique_ptr<abi_dump::EnumDecl> abi_decl(new abi_dump::EnumDecl()); std::unique_ptr<abi_dump::EnumDecl> abi_decl(new abi_dump::EnumDecl());
std::string source_file = GetDeclSourceFile(enum_decl_, cip_); std::string source_file = GetDeclSourceFile(enum_decl_, cip_);
@@ -371,3 +552,35 @@ std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
} }
return abi_decl; return abi_decl;
} }
GlobalVarDeclWrapper::GlobalVarDeclWrapper(
clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::VarDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
global_var_decl_(decl) { }
bool GlobalVarDeclWrapper::SetupGlobalVar(
abi_dump::GlobalVarDecl *global_varp,
const std::string &source_file) const {
if (!SetupBasicNamedAndTypedDecl(
global_varp->mutable_basic_abi(),global_var_decl_->getType(),
global_var_decl_->getQualifiedNameAsString(),
global_var_decl_->getAccess(), GetMangledNameDecl(global_var_decl_))) {
return false;
}
global_varp->set_source_file(source_file);
return true;
}
std::unique_ptr<abi_dump::GlobalVarDecl>
GlobalVarDeclWrapper::GetGlobalVarDecl() const {
std::unique_ptr<abi_dump::GlobalVarDecl>
abi_decl(new abi_dump::GlobalVarDecl);
std::string source_file = GetDeclSourceFile(global_var_decl_, cip_);
if (!SetupGlobalVar(abi_decl.get(), source_file)) {
return nullptr;
}
return abi_decl;
}

View File

@@ -24,20 +24,22 @@
#include <clang/AST/AST.h> #include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h> #include <clang/AST/ASTConsumer.h>
#include <clang/AST/Mangle.h> #include <clang/AST/Mangle.h>
#include <clang/AST/VTableBuilder.h>
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
namespace abi_wrapper { namespace abi_wrapper {
class ABIWrapper { class ABIWrapper {
public: public:
ABIWrapper(clang::MangleContext *mangle_contextp, ABIWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *cip); const clang::CompilerInstance *cip);
static std::string GetDeclSourceFile(const clang::Decl *decl, static std::string GetDeclSourceFile(const clang::Decl *decl,
const clang::CompilerInstance *cip); const clang::CompilerInstance *cip);
protected: protected:
std::string AccessToString(const clang::AccessSpecifier sp) const; abi_dump::AccessSpecifier AccessClangToDump(
const clang::AccessSpecifier sp) const;
std::string GetMangledNameDecl(const clang::NamedDecl *decl) const; std::string GetMangledNameDecl(const clang::NamedDecl *decl) const;
@@ -51,18 +53,24 @@ class ABIWrapper {
std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const; std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const;
bool SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
const clang::QualType type) const;
bool SetupBasicNamedAndTypedDecl(
abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
const clang::QualType type, const std::string &name,
const clang::AccessSpecifier &access, std::string key) const;
protected: protected:
const clang::CompilerInstance *cip_; const clang::CompilerInstance *cip_;
private:
clang::MangleContext *mangle_contextp_; clang::MangleContext *mangle_contextp_;
const clang::ASTContext *ast_contextp_; clang::ASTContext *ast_contextp_;
}; };
class RecordDeclWrapper : public ABIWrapper { class RecordDeclWrapper : public ABIWrapper {
public: public:
RecordDeclWrapper(clang::MangleContext *mangle_contextp, RecordDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::RecordDecl *decl); const clang::RecordDecl *decl);
@@ -72,21 +80,30 @@ class RecordDeclWrapper : public ABIWrapper {
const clang::RecordDecl *record_decl_; const clang::RecordDecl *record_decl_;
private: private:
void SetupRecordInfo(abi_dump::RecordDecl *record_declp, bool SetupRecordInfo(abi_dump::RecordDecl *record_declp,
const std::string &source_file) const; const std::string &source_file) const;
bool SetupRecordFields(abi_dump::RecordDecl *record_declp, bool SetupRecordFields(abi_dump::RecordDecl *record_declp) const;
const std::string &source_file) const;
bool SetupCXXBases(abi_dump::RecordDecl *cxxp) const; bool SetupCXXBases(abi_dump::RecordDecl *cxxp,
const clang::CXXRecordDecl *cxx_record_decl) const;
bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp) const; bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp,
const clang::CXXRecordDecl *cxx_record_decl) const;
bool SetupRecordVTable(abi_dump::RecordDecl *record_declp,
const clang::CXXRecordDecl *cxx_record_decl) const;
bool SetupRecordVTableComponent(
abi_dump::VTableComponent *added_vtable_component,
const clang::VTableComponent &vtable_component) const;
bool SetupCXXRecordInfo(abi_dump::RecordDecl *record_declp) const;
}; };
class FunctionDeclWrapper : public ABIWrapper { class FunctionDeclWrapper : public ABIWrapper {
public: public:
FunctionDeclWrapper(clang::MangleContext *mangle_contextp, FunctionDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::FunctionDecl *decl); const clang::FunctionDecl *decl);
@@ -100,12 +117,14 @@ class FunctionDeclWrapper : public ABIWrapper {
const std::string &source_file) const; const std::string &source_file) const;
bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const; bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const;
bool SetupFunctionParameters(abi_dump::FunctionDecl *functionp) const;
}; };
class EnumDeclWrapper : public ABIWrapper { class EnumDeclWrapper : public ABIWrapper {
public: public:
EnumDeclWrapper(clang::MangleContext *mangle_contextp, EnumDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const clang::EnumDecl *decl); const clang::EnumDecl *decl);
@@ -117,6 +136,23 @@ class EnumDeclWrapper : public ABIWrapper {
private: private:
bool SetupEnum(abi_dump::EnumDecl *enump, bool SetupEnum(abi_dump::EnumDecl *enump,
const std::string &source_file) const; const std::string &source_file) const;
bool SetupEnumFields(abi_dump::EnumDecl *enump) const;
};
class GlobalVarDeclWrapper : public ABIWrapper {
public:
GlobalVarDeclWrapper(clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::VarDecl *decl);
std::unique_ptr<abi_dump::GlobalVarDecl> GetGlobalVarDecl() const;
private:
const clang::VarDecl *global_var_decl_;
private:
bool SetupGlobalVar(abi_dump::GlobalVarDecl *global_varp,
const std::string &source_file) const;
}; };
} //end namespace abi_wrapper } //end namespace abi_wrapper

View File

@@ -29,11 +29,12 @@ using abi_wrapper::ABIWrapper;
using abi_wrapper::FunctionDeclWrapper; using abi_wrapper::FunctionDeclWrapper;
using abi_wrapper::RecordDeclWrapper; using abi_wrapper::RecordDeclWrapper;
using abi_wrapper::EnumDeclWrapper; using abi_wrapper::EnumDeclWrapper;
using abi_wrapper::GlobalVarDeclWrapper;
HeaderASTVisitor::HeaderASTVisitor( HeaderASTVisitor::HeaderASTVisitor(
abi_dump::TranslationUnit *tu_ptr, abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const std::string &current_file_name, const std::string &current_file_name,
const std::set<std::string> &exported_headers, const std::set<std::string> &exported_headers,
@@ -47,7 +48,7 @@ HeaderASTVisitor::HeaderASTVisitor(
tu_decl_(tu_decl) { } tu_decl_(tu_decl) { }
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) { bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
// Forward declaration // Skip forward declaration.
if (!decl->isThisDeclarationADefinition()) { if (!decl->isThisDeclarationADefinition()) {
return true; return true;
} }
@@ -59,11 +60,11 @@ bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
llvm::errs() << "Getting Record Decl failed\n"; llvm::errs() << "Getting Record Decl failed\n";
return false; return false;
} }
abi_dump::RecordDecl *record_declp = tu_ptr_->add_records(); abi_dump::RecordDecl *added_record_declp = tu_ptr_->add_records();
if (!record_declp) { if (!added_record_declp) {
return false; return false;
} }
*record_declp = *wrapped_record_decl; *added_record_declp = *wrapped_record_decl;
return true; return true;
} }
@@ -79,35 +80,57 @@ bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
llvm::errs() << "Getting Enum Decl failed\n"; llvm::errs() << "Getting Enum Decl failed\n";
return false; return false;
} }
abi_dump::EnumDecl *enum_declp = tu_ptr_->add_enums(); abi_dump::EnumDecl *added_enum_declp = tu_ptr_->add_enums();
if (!enum_declp) { if (!added_enum_declp) {
return false; return false;
} }
*enum_declp = *wrapped_enum_decl; *added_enum_declp = *wrapped_enum_decl;
return true; return true;
} }
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) { bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
FunctionDeclWrapper function_decl_wrapper( FunctionDeclWrapper function_decl_wrapper(mangle_contextp_, ast_contextp_,
mangle_contextp_, ast_contextp_, cip_, decl); cip_, decl);
std::unique_ptr<abi_dump::FunctionDecl> wrapped_function_decl = std::unique_ptr<abi_dump::FunctionDecl> wrapped_function_decl =
function_decl_wrapper.GetFunctionDecl(); function_decl_wrapper.GetFunctionDecl();
if (!wrapped_function_decl) { if (!wrapped_function_decl) {
llvm::errs() << "Getting Function Decl failed\n"; llvm::errs() << "Getting Function Decl failed\n";
return false; return false;
} }
abi_dump::FunctionDecl *function_declp = tu_ptr_->add_functions(); abi_dump::FunctionDecl *added_function_declp = tu_ptr_->add_functions();
if (!function_declp) { if (!added_function_declp) {
return false; return false;
} }
*function_declp = *wrapped_function_decl; *added_function_declp = *wrapped_function_decl;
return true;
}
bool HeaderASTVisitor::VisitVarDecl(const clang::VarDecl *decl) {
if(!decl->hasGlobalStorage()) {
// Non global / static variable declarations don't need to be dumped.
return true;
}
GlobalVarDeclWrapper global_var_decl_wrapper(mangle_contextp_, ast_contextp_,
cip_, decl);
std::unique_ptr<abi_dump::GlobalVarDecl> wrapped_global_var_decl =
global_var_decl_wrapper.GetGlobalVarDecl();
if (!wrapped_global_var_decl) {
llvm::errs() << "Getting Global Var Decl failed\n";
return false;
}
abi_dump::GlobalVarDecl *added_global_var_declp = tu_ptr_->add_global_vars();
if (!added_global_var_declp) {
return false;
}
*added_global_var_declp = *wrapped_global_var_decl;
return true; return true;
} }
// We don't need to recurse into Declarations which are not exported. // We don't need to recurse into Declarations which are not exported.
bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) { bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
if (!decl) if (!decl) {
return true; return true;
}
std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_); std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
if ((decl != tu_decl_) && if ((decl != tu_decl_) &&
(exported_headers_.find(source_file) == exported_headers_.end())) { (exported_headers_.find(source_file) == exported_headers_.end())) {
@@ -150,5 +173,5 @@ void HeaderASTConsumer::HandleVTable(clang::CXXRecordDecl *crd) {
void HeaderASTPPCallbacks::MacroDefined(const clang::Token &macro_name_tok, void HeaderASTPPCallbacks::MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) { const clang::MacroDirective *) {
assert(macro_name_tok.isAnyIdentifier()); assert(macro_name_tok.getLength() != 0);
} }

View File

@@ -35,7 +35,7 @@ class HeaderASTVisitor
public: public:
HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr, HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp, clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp, clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p, const clang::CompilerInstance *compiler_instance_p,
const std::string &current_file_name, const std::string &current_file_name,
const std::set<std::string> &exported_headers, const std::set<std::string> &exported_headers,
@@ -47,6 +47,8 @@ class HeaderASTVisitor
bool VisitEnumDecl(const clang::EnumDecl *decl); bool VisitEnumDecl(const clang::EnumDecl *decl);
bool VisitVarDecl(const clang::VarDecl *decl);
bool TraverseDecl(clang::Decl *decl); bool TraverseDecl(clang::Decl *decl);
// Enable recursive traversal of template instantiations. // Enable recursive traversal of template instantiations.
@@ -57,7 +59,7 @@ class HeaderASTVisitor
private: private:
abi_dump::TranslationUnit *tu_ptr_; abi_dump::TranslationUnit *tu_ptr_;
clang::MangleContext *mangle_contextp_; clang::MangleContext *mangle_contextp_;
const clang::ASTContext *ast_contextp_; clang::ASTContext *ast_contextp_;
const clang::CompilerInstance *cip_; const clang::CompilerInstance *cip_;
const std::string current_file_name_; const std::string current_file_name_;
const std::set<std::string> &exported_headers_; const std::set<std::string> &exported_headers_;

View File

@@ -63,6 +63,9 @@ class HeaderAbiLinker {
bool LinkEnums(const abi_dump::TranslationUnit &dump_tu, bool LinkEnums(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu); abi_dump::TranslationUnit *linked_tu);
bool LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu);
template <typename T> template <typename T>
static inline bool LinkDecl( static inline bool LinkDecl(
google::protobuf::RepeatedPtrField<T> *dst, google::protobuf::RepeatedPtrField<T> *dst,
@@ -75,6 +78,7 @@ class HeaderAbiLinker {
std::set<std::string> record_decl_set_; std::set<std::string> record_decl_set_;
std::set<std::string> function_decl_set_; std::set<std::string> function_decl_set_;
std::set<std::string> enum_decl_set_; std::set<std::string> enum_decl_set_;
std::set<std::string> globvar_decl_set_;
}; };
bool HeaderAbiLinker::LinkAndDump() { bool HeaderAbiLinker::LinkAndDump() {
@@ -88,7 +92,8 @@ bool HeaderAbiLinker::LinkAndDump() {
if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) || if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) ||
!LinkRecords(dump_tu, &linked_tu) || !LinkRecords(dump_tu, &linked_tu) ||
!LinkFunctions(dump_tu, &linked_tu) || !LinkFunctions(dump_tu, &linked_tu) ||
!LinkEnums(dump_tu, &linked_tu)) { !LinkEnums(dump_tu, &linked_tu) ||
!LinkGlobalVars(dump_tu, &linked_tu)) {
llvm::errs() << "Failed to link elements\n"; llvm::errs() << "Failed to link elements\n";
return false; return false;
} }
@@ -110,7 +115,7 @@ inline bool HeaderAbiLinker::LinkDecl(
assert(link_set != nullptr); assert(link_set != nullptr);
for (auto &&element : src) { for (auto &&element : src) {
// The element already exists in the linked dump. Skip. // The element already exists in the linked dump. Skip.
if (!link_set->insert(element.linker_set_key()).second) { if (!link_set->insert(element.basic_abi().linker_set_key()).second) {
continue; continue;
} }
T *added_element = dst->Add(); T *added_element = dst->Add();
@@ -144,6 +149,13 @@ bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
dump_tu.enums()); dump_tu.enums());
} }
bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu) {
assert(linked_tu != nullptr);
return LinkDecl(linked_tu->mutable_global_vars(), &globvar_decl_set_,
dump_tu.global_vars());
}
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker"); llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");

View File

@@ -4,9 +4,9 @@ import "development/vndk/tools/header-checker/proto/abi_dump.proto";
package abi_diff; package abi_diff;
message FieldDeclDiff { message RecordFieldDeclDiff {
optional abi_dump.FieldDecl old = 1; optional abi_dump.RecordFieldDecl old = 1;
optional abi_dump.FieldDecl new = 2; optional abi_dump.RecordFieldDecl new = 2;
required uint32 index = 3; required uint32 index = 3;
} }
@@ -22,16 +22,23 @@ message CXXBaseSpecifierDiff {
required uint32 index = 3; required uint32 index = 3;
} }
message CXXVTableDiff {
optional abi_dump.VTableComponent old = 1;
optional abi_dump.VTableComponent new = 2;
required uint32 index = 3;
}
message AccessDiff { message AccessDiff {
required string old = 1; required abi_dump.AccessSpecifier old = 1;
required string new = 2; required abi_dump.AccessSpecifier new = 2;
} }
message RecordDeclDiff { message RecordDeclDiff {
repeated FieldDeclDiff field_diffs = 1; repeated RecordFieldDeclDiff field_diffs = 1;
repeated CXXBaseSpecifierDiff base_diffs = 2; repeated CXXBaseSpecifierDiff base_diffs = 2;
required AccessDiff access_diff = 3; repeated CXXVTableDiff vtable_diffs = 3;
required string name = 4; required AccessDiff access_diff = 4;
required string name = 5;
} }
message EnumDeclDiff { message EnumDeclDiff {
@@ -40,16 +47,34 @@ message EnumDeclDiff {
required string name = 3; required string name = 3;
} }
message ReturnTypeDiff {
required abi_dump.BasicNamedAndTypedDecl old = 1;
required abi_dump.BasicNamedAndTypedDecl new = 2;
}
message FunctionDeclDiff {
required ReturnTypeDiff return_type_diffs = 1;
}
message GlobalVarDeclDiff {
required abi_dump.BasicNamedAndTypedDecl old = 1;
required abi_dump.BasicNamedAndTypedDecl new = 2;
}
message TranslationUnitDiff { message TranslationUnitDiff {
// Differing Elements. // Differing Elements.
repeated RecordDeclDiff records_diff = 1; repeated RecordDeclDiff records_diff = 1;
repeated EnumDeclDiff enums_diff = 3; repeated EnumDeclDiff enums_diff = 2;
repeated FunctionDeclDiff functions_diff = 3;
repeated GlobalVarDeclDiff global_vars_diff = 4;
// Removed Elements. // Removed Elements.
repeated abi_dump.RecordDecl records_removed = 4; repeated abi_dump.RecordDecl records_removed = 5;
repeated abi_dump.FunctionDecl functions_removed = 5; repeated abi_dump.FunctionDecl functions_removed = 6;
repeated abi_dump.EnumDecl enums_removed = 6; repeated abi_dump.EnumDecl enums_removed = 7;
repeated abi_dump.GlobalVarDecl global_vars_removed = 8;
// Added Elements. // Added Elements.
repeated abi_dump.RecordDecl records_added = 7; repeated abi_dump.RecordDecl records_added = 9;
repeated abi_dump.FunctionDecl functions_added = 8; repeated abi_dump.FunctionDecl functions_added = 10;
repeated abi_dump.EnumDecl enums_added = 9; repeated abi_dump.EnumDecl enums_added = 11;
repeated abi_dump.GlobalVarDecl global_vars_added = 12;
} }

View File

@@ -2,72 +2,114 @@ syntax = "proto2";
package abi_dump; package abi_dump;
message FunctionDecl { message BasicTypeAbi {
// Fully Qualified Name. // The type's name. for eg : a record field's type.
optional string function_name = 1 [default = "NONE"]; required string name = 1;
// Optional since templated types will not have this information.
// Mangled name. optional uint64 size = 2 [default = 0];
optional string mangled_function_name = 2 [default = "NONE"]; optional uint32 alignment = 3 [default = 0];
optional string source_file = 3;
optional string parent_name = 4 [default = "NONE"];
repeated string template_arguments = 5 ;
repeated FieldDecl parameters = 6;
optional string return_type = 7 [default = "VOID"];
optional string access = 8 [default = "public"];
optional uint32 template_kind = 9 [default = 0];
optional TemplateInfo template_info = 10;
optional string linker_set_key = 11 [default = "NONE"];
} }
message FieldDecl { enum AccessSpecifier {
optional string field_name = 1 [default = "NONE"]; public_access = 1;
optional string field_type = 2 [default = "VOID"]; private_access = 2;
optional string access = 3 [default = "public"]; protected_access = 3;
optional bool default_arg = 4 [default = false]; }
optional string linker_set_key = 5 [default = "NONE"];
message BasicNamedAndTypedDecl {
required BasicTypeAbi type_abi = 1;
// The TypedDecl's name.
required string name = 2;
required AccessSpecifier access = 3;
optional string linker_set_key = 4;
}
message FunctionDecl {
required BasicNamedAndTypedDecl basic_abi = 1;
// Mangled name.
required string mangled_function_name = 2;
required string source_file = 3;
repeated ParamDecl parameters = 4;
optional TemplateInfo template_info = 5;
}
message ParamDecl {
required BasicNamedAndTypedDecl basic_abi = 1;
required bool default_arg = 2;
}
message RecordFieldDecl {
// For future additions.
required BasicNamedAndTypedDecl basic_abi = 1;
} }
message EnumFieldDecl { message EnumFieldDecl {
optional string enum_field_name = 1 [default = "NONE"]; required BasicNamedAndTypedDecl basic_abi = 1;
optional int64 enum_field_value = 2 [default = 0]; // assumption: fits int64 required int64 enum_field_value = 2; // assumption: fits int64
optional string linker_set_key = 3 [default = "NONE"];
} }
message TemplateInfo { message TemplateInfo {
repeated FieldDecl template_parameters = 1; repeated TemplateElement elements = 1;
}
message TemplateElement {
required BasicTemplateElementAbi basic_abi = 1;
message BasicTemplateElementAbi {
optional BasicTypeAbi type_abi = 1;
optional string name = 2;
required string linker_set_key = 3;
}
} }
message CXXBaseSpecifier { message CXXBaseSpecifier {
optional string fully_qualified_name = 1 [default = "NONE"]; required BasicNamedAndTypedDecl basic_abi = 1;
optional string access = 2 [default = "public"]; required bool is_virtual = 2;
optional bool is_virtual = 3 [default = false]; }
optional string linker_set_key = 4 [default = "NONE"];
message VTableComponent {
enum Kind {
VCallOffset = 0;
VBaseOffset = 1;
OffsetToTop = 2;
RTTI = 3;
FunctionPointer = 4;
CompleteDtorPointer = 5;
DeletingDtorPointer = 6;
UnusedFunctionPointer = 7;
}
required Kind kind = 1;
optional string mangled_component_name = 2 [default = ""];
optional uint64 value = 3 [default = 0];
}
message VTableLayout {
repeated VTableComponent vtable_components = 1;
} }
message RecordDecl { message RecordDecl {
repeated FieldDecl fields = 1; required BasicNamedAndTypedDecl basic_abi = 1;
repeated CXXBaseSpecifier base_specifiers = 2; repeated RecordFieldDecl fields = 2;
optional string fully_qualified_name = 3 [default = "NONE"]; repeated CXXBaseSpecifier base_specifiers = 3;
optional string source_file = 4 [default = "NONE"]; required string source_file = 4;
optional uint32 template_kind = 5 [default = 0]; optional TemplateInfo template_info = 5;
optional TemplateInfo template_info = 6; required string mangled_record_name = 6;
optional string access = 7 [default = "public"]; optional VTableLayout vtable_layout = 7;
optional string linker_set_key = 8 [default = "NONE"];
optional string mangled_record_name = 9 [default = "NONE"];
} }
message EnumDecl { message EnumDecl {
optional string enum_name = 1 [default = "NONE"]; required BasicNamedAndTypedDecl basic_abi = 1;
optional string access = 2 [default = "public"]; repeated EnumFieldDecl enum_fields = 2;
optional string enum_type = 3 [default = "int"]; required string source_file = 3;
repeated EnumFieldDecl enum_fields = 4; }
optional string source_file = 5 [default = "NONE"];
optional string linker_set_key = 6 [default = "NONE"]; message GlobalVarDecl {
required BasicNamedAndTypedDecl basic_abi = 1;
required string source_file = 2;
} }
message TranslationUnit { message TranslationUnit {
repeated RecordDecl records = 1; repeated RecordDecl records = 1;
repeated FunctionDecl functions = 2; repeated FunctionDecl functions = 2;
repeated EnumDecl enums = 3; repeated EnumDecl enums = 3;
repeated GlobalVarDecl global_vars = 4;
} }

View File

@@ -1,4 +1,4 @@
#include "example2.h" #include "example1.h"
class NotIncluded { class NotIncluded {
int not_included; int not_included;

View File

@@ -22,7 +22,7 @@ typedef const float_type cfloat_type;
struct CPPHello : private HelloAgain, public ByeAgain<float_type> { struct CPPHello : private HelloAgain, public ByeAgain<float_type> {
const int cpp_foo; const int cpp_foo;
cfloat_type cpp_bar; cfloat_type cpp_bar;
virtual int again() { return 0; }
CPPHello() : cpp_foo(20), cpp_bar(1.234) { } CPPHello() : cpp_foo(20), cpp_bar(1.234) { }
}; };

View File

@@ -1,12 +1,16 @@
#ifndef EXAMPLE2_H_ #ifndef EXAMPLE2_H_
#define EXAMPLE2_H_ #define EXAMPLE2_H_
#include <memory> #include <memory>
#include <vector>
#include <string>
#include "example3.h" #include "example3.h"
namespace test2 { namespace test2 {
struct HelloAgain { struct HelloAgain {
std::unique_ptr<HelloAgain> foo_again; std::vector<HelloAgain *> foo_again;
int bar_again; int bar_again;
static int hello_forever;
virtual int again();
}; };
struct NowWeCrash; struct NowWeCrash;
} // namespace test2 } // namespace test2
@@ -16,6 +20,7 @@ enum Foo_s {
foosbat foosbat
}; };
namespace test3 { namespace test3 {
template <typename T> template <typename T>
struct ByeAgain { struct ByeAgain {
@@ -27,6 +32,7 @@ struct ByeAgain {
template<> template<>
struct ByeAgain<float> { struct ByeAgain<float> {
float foo_again; float foo_again;
static int foo_forever;
float bar_Again; float bar_Again;
float method_foo(int); float method_foo(int);
}; };
@@ -34,12 +40,11 @@ struct ByeAgain<float> {
ByeAgain<double> double_bye; ByeAgain<double> double_bye;
template <typename T1, typename T2> template <typename T1, typename T2>
bool Begin(T1 arg1, T2 arg2); bool Begin( T1 arg1, T2 arg2, int c);
template <>
bool Begin<int, float>(int a, float b);
bool End ( float arg = 2.0) { bool End ( float arg = 2.0) {
bool ret = Begin(arg, 2); bool ret = Begin(arg, 2, 2);
return ret; return true;
} }
@@ -57,6 +62,7 @@ class Outer {
}; };
}; };
std::vector<int *> Dummy(int t);
} // namespace test3 } // namespace test3