Merge "Added More Abi information." am: 1345214bfc

am: 1b856be6a0

Change-Id: I8611cadd6ee393b85d25c14dc346e9dbbff3e3d0
This commit is contained in:
Jayant Chowdhary
2017-03-17 17:03:07 +00:00
committed by android-build-merger
15 changed files with 769 additions and 316 deletions

View File

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

View File

@@ -45,95 +45,76 @@ Status HeaderAbiDiff::GenerateCompatibilityReport() {
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);
std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
new abi_diff::TranslationUnitDiff);
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_);
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";
::exit(1);
}
if (combined_Status & INCOMPATIBLE) {
if (combined_status & INCOMPATIBLE) {
return INCOMPATIBLE;
}
if (combined_Status & EXTENSION) {
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());
template <typename T, typename TDiff>
Status HeaderAbiDiff::Collect(
google::protobuf::RepeatedPtrField<T> *elements_added,
google::protobuf::RepeatedPtrField<T> *elements_removed,
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(),
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;
}
std::map<std::string, const T*> old_elements_map;
std::map<std::string, const T*> new_elements_map;
AddToMap(&old_elements_map, old_srcs);
AddToMap(&new_elements_map, new_srcs);
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_)) {
if (!PopulateRemovedElements(elements_removed, old_elements_map,
new_elements_map) ||
!PopulateRemovedElements(elements_added, new_elements_map,
old_elements_map) ||
!PopulateCommonElements(elements_diff, old_elements_map,
new_elements_map)) {
llvm::errs() << "Populating functions in report failed\n";
::exit(1);
}
if (diff_tu->functions_removed().size()) {
if (elements_diff->size() || elements_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()) {
if (elements_added->size()) {
return EXTENSION;
}
return COMPATIBLE;
@@ -143,12 +124,13 @@ 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 {
const std::map<std::string, const T*> &new_elements_map) {
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());
auto new_element =
new_elements_map.find(element->basic_abi().linker_set_key());
if (new_element == new_elements_map.end()) {
removed_elements.emplace_back(element);
}
@@ -164,7 +146,7 @@ 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 {
const std::map<std::string, const T *> &new_elements_map) {
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();
@@ -194,7 +176,7 @@ bool HeaderAbiDiff::PopulateCommonElements(
template <typename T>
bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements) const {
std::vector<const T *> &elements) {
for (auto &&element : elements) {
T *added_element = dst->Add();
if (!added_element) {
@@ -209,7 +191,7 @@ bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
template <typename T, typename TDiff>
bool HeaderAbiDiff::DumpDiffElements(
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) {
const T *old_element = pair.first;
const T *new_element = pair.second;

View File

@@ -47,58 +47,43 @@ class HeaderAbiDiff {
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, typename TDiff>
static Status Collect(
google::protobuf::RepeatedPtrField<T> *elements_added,
google::protobuf::RepeatedPtrField<T> *elements_removed,
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
const google::protobuf::RepeatedPtrField<T> &old_srcs,
const google::protobuf::RepeatedPtrField<T> &new_srcs);
template <typename T>
inline void AddToMap(std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &src);
static inline void AddToMap(std::map<std::string, const T *> *dst,
const google::protobuf::RepeatedPtrField<T> &src);
template <typename T>
bool PopulateRemovedElements(
static 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;
const std::map<std::string, const T *> &new_elements_map);
template <typename T, typename TDiff>
bool PopulateCommonElements(
static 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;
const std::map<std::string, const T *> &new_elements_map);
template <typename T, typename TDiff>
bool DumpDiffElements(
static bool DumpDiffElements(
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>
bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements) const;
static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements);
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;
@@ -108,7 +93,7 @@ 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));
dst->insert(std::make_pair(element.basic_abi().linker_set_key(), &element));
}
}

View File

@@ -24,15 +24,93 @@
#include <llvm/Support/raw_ostream.h>
using abi_diff::RecordDeclDiff;
using abi_diff::FieldDeclDiff;
using abi_diff::RecordFieldDeclDiff;
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::EnumFieldDeclDiff;
using abi_diff::GlobalVarDeclDiff;
using abi_dump::RecordDecl;
using abi_dump::RecordFieldDecl;
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 {
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:
// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff
// fields.
@@ -43,13 +121,14 @@ bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
const google::protobuf::RepeatedPtrField<Element> &old_elements,
const google::protobuf::RepeatedPtrField<Element> &new_elements) {
bool differs = false;
assert (dst != nullptr);
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()) {
if (Diff(old_element, new_element)) {
ElementDiff *diff = dst->Add();
Element *old_elementp = nullptr;
Element *new_elementp = nullptr;
@@ -109,18 +188,22 @@ void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
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 =
assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
record_diff->set_name(oldp_->basic_abi().name());
google::protobuf::RepeatedPtrField<RecordFieldDeclDiff> *fdiffs =
record_diff->mutable_field_diffs();
google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *bdiffs =
record_diff->mutable_base_diffs();
google::protobuf::RepeatedPtrField<CXXVTableDiff> *vtdiffs =
record_diff->mutable_vtable_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())) {
newp_->base_specifiers()) ||
GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
newp_->vtable_layout().vtable_components())) {
return record_diff;
}
return nullptr;
@@ -129,15 +212,51 @@ std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
template <>
std::unique_ptr<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
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 =
enum_diff->mutable_field_diffs();
assert(fdiffs != nullptr);
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
(oldp_->enum_type() != newp_->enum_type())) {
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields())) {
return enum_diff;
}
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

View File

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

View File

@@ -22,7 +22,7 @@ using namespace abi_wrapper;
ABIWrapper::ABIWrapper(
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *cip)
: cip_(cip),
mangle_contextp_(mangle_contextp),
@@ -40,26 +40,66 @@ std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
return abs_path.str();
}
std::string ABIWrapper::AccessToString(const clang::AccessSpecifier sp) const {
std::string str = "public";
abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
const clang::AccessSpecifier sp) const {
switch (sp) {
case clang::AS_private: {
str = "private";
return abi_dump::AccessSpecifier::private_access;
break;
}
case clang::AS_protected: {
str = "protected";
return abi_dump::AccessSpecifier::protected_access;
break;
}
default: {
return abi_dump::AccessSpecifier::public_access;
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 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)) {
llvm::raw_string_ostream ostream(mangled_or_demangled_name);
mangle_contextp_->mangleName(decl, ostream);
@@ -71,17 +111,26 @@ std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const {
bool ABIWrapper::SetupTemplateParamNames(
abi_dump::TemplateInfo *tinfo,
clang::TemplateParameterList *pl) const {
if (tinfo->template_parameters_size() > 0) {
if (tinfo->elements_size() > 0) {
return true;
}
clang::TemplateParameterList::iterator template_it = pl->begin();
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) {
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++;
}
return true;
@@ -92,7 +141,6 @@ std::string ABIWrapper::GetTagDeclQualifiedName(
if (decl->getTypedefNameForAnonDecl()) {
return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
}
return decl->getQualifiedNameAsString();
}
@@ -102,16 +150,22 @@ bool ABIWrapper::SetupTemplateArguments(
for (int i = 0; i < tl->size(); i++) {
const clang::TemplateArgument &arg = (*tl)[i];
//TODO: More comprehensive checking needed.
std::string type = " ";
if(arg.getKind() == clang::TemplateArgument::Type) {
type = QualTypeToString(arg.getAsType());
if (arg.getKind() != clang::TemplateArgument::Type) {
continue;
}
abi_dump::FieldDecl *template_parameterp =
tinfo->add_template_parameters();
clang::QualType type = arg.getAsType();
abi_dump::TemplateElement *template_parameterp =
tinfo->add_elements();
if (!template_parameterp) {
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;
}
@@ -124,42 +178,51 @@ std::string ABIWrapper::QualTypeToString(
FunctionDeclWrapper::FunctionDeclWrapper(
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::FunctionDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
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,
const std::string &source_file) const {
// 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.
std::string mangled_name = GetMangledNameDecl(function_decl_);
functionp->set_function_name(function_decl_->getQualifiedNameAsString());
functionp->set_mangled_function_name(mangled_name);
functionp->set_linker_set_key(mangled_name);
functionp->set_source_file(source_file);
functionp->set_return_type(QualTypeToString(function_decl_->getReturnType()));
clang::FunctionDecl::param_const_iterator param_it =
function_decl_->param_begin();
while (param_it != function_decl_->param_end()) {
abi_dump::FieldDecl *function_fieldp = functionp->add_parameters();
if (!function_fieldp) {
llvm::errs() << "Couldn't add parameter to method. Aborting\n";
return false;
}
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;
// Combine the function name and return type to form a NamedAndTypedDecl
return SetupBasicNamedAndTypedDecl(
functionp->mutable_basic_abi(),
function_decl_->getReturnType(),
function_decl_->getQualifiedNameAsString(),
function_decl_->getAccess(), mangled_name) &&
SetupTemplateInfo(functionp) && SetupFunctionParameters(functionp);
}
bool FunctionDeclWrapper::SetupTemplateInfo(
@@ -209,42 +272,35 @@ FunctionDeclWrapper::GetFunctionDecl() const {
RecordDeclWrapper::RecordDeclWrapper(
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::RecordDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
record_decl_(decl) { }
bool RecordDeclWrapper::SetupRecordFields(
abi_dump::RecordDecl *recordp,
const std::string &source_file) const {
bool RecordDeclWrapper::SetupRecordFields(abi_dump::RecordDecl *recordp) const {
clang::RecordDecl::field_iterator field = record_decl_->field_begin();
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) {
llvm::errs() << " Couldn't add record field: " << field->getName()
<< " to reference dump\n";
return false;
}
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);
if (!SetupBasicNamedAndTypedDecl(record_fieldp->mutable_basic_abi(),
field->getType(), field->getName(),
field->getAccess(), "")) {
return false;
}
field++;
}
return true;
}
bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const {
const clang::CXXRecordDecl *cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
if (!cxx_record_decl) {
return true;
}
bool RecordDeclWrapper::SetupCXXBases(
abi_dump::RecordDecl *cxxp,
const clang::CXXRecordDecl *cxx_record_decl) const {
assert(cxx_record_decl != nullptr);
clang::CXXRecordDecl::base_class_const_iterator base_class =
cxx_record_decl->bases_begin();
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());
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);
if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
base_class->getType(),
"", base_class->getAccessSpecifier(),
"")) {
return false;
}
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;
}
bool RecordDeclWrapper::SetupTemplateInfo(
abi_dump::RecordDecl *record_declp) const {
const clang::CXXRecordDecl *cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
if (!cxx_record_decl) {
bool RecordDeclWrapper::SetupRecordVTable(
abi_dump::RecordDecl *record_declp,
const clang::CXXRecordDecl *cxx_record_decl) const {
assert(cxx_record_decl != nullptr);
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;
}
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()) {
clang::ClassTemplateDecl *template_decl =
cxx_record_decl->getDescribedClassTemplate();
@@ -303,28 +455,45 @@ bool RecordDeclWrapper::SetupTemplateInfo(
return true;
}
void RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
bool 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_);
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;
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_linker_set_key(linker_key);
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> abi_decl(new abi_dump::RecordDecl());
std::string source_file = GetDeclSourceFile(record_decl_, cip_);
SetupRecordInfo(abi_decl.get(), source_file);
if (!SetupRecordFields(abi_decl.get(), source_file)) {
llvm::errs() << "Setting up Record Fields failed\n";
return nullptr;
}
if (!SetupCXXBases(abi_decl.get()) || !SetupTemplateInfo(abi_decl.get())) {
abi_dump::RecordDecl *record_declp = abi_decl.get();
if (!SetupRecordInfo(record_declp, source_file) ||
!SetupRecordFields(record_declp) ||
!SetupCXXRecordInfo(abi_decl.get())) {
llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
return nullptr;
}
@@ -333,34 +502,46 @@ std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
EnumDeclWrapper::EnumDeclWrapper(
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::EnumDecl *decl)
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
enum_decl_(decl) { }
bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
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);
bool EnumDeclWrapper::SetupEnumFields(abi_dump::EnumDecl *enump) const {
clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
while (enum_it != enum_decl_->enumerator_end()) {
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;
}
enum_fieldp->set_enum_field_name(enum_it->getQualifiedNameAsString());
enum_fieldp->set_enum_field_value(enum_it->getInitVal().getExtValue());
enum_fieldp->set_enum_field_value(field_value);
enum_it++;
}
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> abi_decl(new abi_dump::EnumDecl());
std::string source_file = GetDeclSourceFile(enum_decl_, cip_);
@@ -371,3 +552,35 @@ std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
}
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/ASTConsumer.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/VTableBuilder.h>
#include <clang/Frontend/CompilerInstance.h>
namespace abi_wrapper {
class ABIWrapper {
public:
ABIWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *cip);
static std::string GetDeclSourceFile(const clang::Decl *decl,
const clang::CompilerInstance *cip);
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;
@@ -51,18 +53,24 @@ class ABIWrapper {
std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const;
protected:
const clang::CompilerInstance *cip_;
bool SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
const clang::QualType type) const;
private:
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:
const clang::CompilerInstance *cip_;
clang::MangleContext *mangle_contextp_;
const clang::ASTContext *ast_contextp_;
clang::ASTContext *ast_contextp_;
};
class RecordDeclWrapper : public ABIWrapper {
public:
RecordDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::RecordDecl *decl);
@@ -72,21 +80,30 @@ class RecordDeclWrapper : public ABIWrapper {
const clang::RecordDecl *record_decl_;
private:
void SetupRecordInfo(abi_dump::RecordDecl *record_declp,
bool SetupRecordInfo(abi_dump::RecordDecl *record_declp,
const std::string &source_file) const;
bool SetupRecordFields(abi_dump::RecordDecl *record_declp,
const std::string &source_file) const;
bool SetupRecordFields(abi_dump::RecordDecl *record_declp) 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 {
public:
FunctionDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::FunctionDecl *decl);
@@ -100,12 +117,14 @@ class FunctionDeclWrapper : public ABIWrapper {
const std::string &source_file) const;
bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const;
bool SetupFunctionParameters(abi_dump::FunctionDecl *functionp) const;
};
class EnumDeclWrapper : public ABIWrapper {
public:
EnumDeclWrapper(clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const clang::EnumDecl *decl);
@@ -117,6 +136,23 @@ class EnumDeclWrapper : public ABIWrapper {
private:
bool SetupEnum(abi_dump::EnumDecl *enump,
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

View File

@@ -29,11 +29,12 @@ using abi_wrapper::ABIWrapper;
using abi_wrapper::FunctionDeclWrapper;
using abi_wrapper::RecordDeclWrapper;
using abi_wrapper::EnumDeclWrapper;
using abi_wrapper::GlobalVarDeclWrapper;
HeaderASTVisitor::HeaderASTVisitor(
abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const std::string &current_file_name,
const std::set<std::string> &exported_headers,
@@ -47,7 +48,7 @@ HeaderASTVisitor::HeaderASTVisitor(
tu_decl_(tu_decl) { }
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
// Forward declaration
// Skip forward declaration.
if (!decl->isThisDeclarationADefinition()) {
return true;
}
@@ -59,11 +60,11 @@ bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
llvm::errs() << "Getting Record Decl failed\n";
return false;
}
abi_dump::RecordDecl *record_declp = tu_ptr_->add_records();
if (!record_declp) {
abi_dump::RecordDecl *added_record_declp = tu_ptr_->add_records();
if (!added_record_declp) {
return false;
}
*record_declp = *wrapped_record_decl;
*added_record_declp = *wrapped_record_decl;
return true;
}
@@ -79,35 +80,57 @@ bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
llvm::errs() << "Getting Enum Decl failed\n";
return false;
}
abi_dump::EnumDecl *enum_declp = tu_ptr_->add_enums();
if (!enum_declp) {
abi_dump::EnumDecl *added_enum_declp = tu_ptr_->add_enums();
if (!added_enum_declp) {
return false;
}
*enum_declp = *wrapped_enum_decl;
*added_enum_declp = *wrapped_enum_decl;
return true;
}
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
FunctionDeclWrapper function_decl_wrapper(
mangle_contextp_, ast_contextp_, cip_, decl);
FunctionDeclWrapper function_decl_wrapper(mangle_contextp_, ast_contextp_,
cip_, decl);
std::unique_ptr<abi_dump::FunctionDecl> wrapped_function_decl =
function_decl_wrapper.GetFunctionDecl();
if (!wrapped_function_decl) {
llvm::errs() << "Getting Function Decl failed\n";
return false;
}
abi_dump::FunctionDecl *function_declp = tu_ptr_->add_functions();
if (!function_declp) {
abi_dump::FunctionDecl *added_function_declp = tu_ptr_->add_functions();
if (!added_function_declp) {
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;
}
// We don't need to recurse into Declarations which are not exported.
bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
if (!decl)
if (!decl) {
return true;
}
std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
if ((decl != tu_decl_) &&
(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,
const clang::MacroDirective *) {
assert(macro_name_tok.isAnyIdentifier());
assert(macro_name_tok.getLength() != 0);
}

View File

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

View File

@@ -63,6 +63,9 @@ class HeaderAbiLinker {
bool LinkEnums(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu);
bool LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu);
template <typename T>
static inline bool LinkDecl(
google::protobuf::RepeatedPtrField<T> *dst,
@@ -75,6 +78,7 @@ class HeaderAbiLinker {
std::set<std::string> record_decl_set_;
std::set<std::string> function_decl_set_;
std::set<std::string> enum_decl_set_;
std::set<std::string> globvar_decl_set_;
};
bool HeaderAbiLinker::LinkAndDump() {
@@ -88,7 +92,8 @@ bool HeaderAbiLinker::LinkAndDump() {
if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) ||
!LinkRecords(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";
return false;
}
@@ -110,7 +115,7 @@ inline bool HeaderAbiLinker::LinkDecl(
assert(link_set != nullptr);
for (auto &&element : src) {
// 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;
}
T *added_element = dst->Add();
@@ -144,6 +149,13 @@ bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
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) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
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;
message FieldDeclDiff {
optional abi_dump.FieldDecl old = 1;
optional abi_dump.FieldDecl new = 2;
message RecordFieldDeclDiff {
optional abi_dump.RecordFieldDecl old = 1;
optional abi_dump.RecordFieldDecl new = 2;
required uint32 index = 3;
}
@@ -22,16 +22,23 @@ message CXXBaseSpecifierDiff {
required uint32 index = 3;
}
message CXXVTableDiff {
optional abi_dump.VTableComponent old = 1;
optional abi_dump.VTableComponent new = 2;
required uint32 index = 3;
}
message AccessDiff {
required string old = 1;
required string new = 2;
required abi_dump.AccessSpecifier old = 1;
required abi_dump.AccessSpecifier new = 2;
}
message RecordDeclDiff {
repeated FieldDeclDiff field_diffs = 1;
repeated RecordFieldDeclDiff field_diffs = 1;
repeated CXXBaseSpecifierDiff base_diffs = 2;
required AccessDiff access_diff = 3;
required string name = 4;
repeated CXXVTableDiff vtable_diffs = 3;
required AccessDiff access_diff = 4;
required string name = 5;
}
message EnumDeclDiff {
@@ -40,16 +47,34 @@ message EnumDeclDiff {
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 {
// Differing Elements.
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.
repeated abi_dump.RecordDecl records_removed = 4;
repeated abi_dump.FunctionDecl functions_removed = 5;
repeated abi_dump.EnumDecl enums_removed = 6;
repeated abi_dump.RecordDecl records_removed = 5;
repeated abi_dump.FunctionDecl functions_removed = 6;
repeated abi_dump.EnumDecl enums_removed = 7;
repeated abi_dump.GlobalVarDecl global_vars_removed = 8;
// Added Elements.
repeated abi_dump.RecordDecl records_added = 7;
repeated abi_dump.FunctionDecl functions_added = 8;
repeated abi_dump.EnumDecl enums_added = 9;
repeated abi_dump.RecordDecl records_added = 9;
repeated abi_dump.FunctionDecl functions_added = 10;
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;
message FunctionDecl {
// Fully Qualified Name.
optional string function_name = 1 [default = "NONE"];
// Mangled name.
optional string mangled_function_name = 2 [default = "NONE"];
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 BasicTypeAbi {
// The type's name. for eg : a record field's type.
required string name = 1;
// Optional since templated types will not have this information.
optional uint64 size = 2 [default = 0];
optional uint32 alignment = 3 [default = 0];
}
message FieldDecl {
optional string field_name = 1 [default = "NONE"];
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"];
enum AccessSpecifier {
public_access = 1;
private_access = 2;
protected_access = 3;
}
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 {
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"];
required BasicNamedAndTypedDecl basic_abi = 1;
required int64 enum_field_value = 2; // assumption: fits int64
}
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 {
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"];
required BasicNamedAndTypedDecl basic_abi = 1;
required bool is_virtual = 2;
}
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 {
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"];
required BasicNamedAndTypedDecl basic_abi = 1;
repeated RecordFieldDecl fields = 2;
repeated CXXBaseSpecifier base_specifiers = 3;
required string source_file = 4;
optional TemplateInfo template_info = 5;
required string mangled_record_name = 6;
optional VTableLayout vtable_layout = 7;
}
message EnumDecl {
optional string enum_name = 1 [default = "NONE"];
optional string access = 2 [default = "public"];
optional string enum_type = 3 [default = "int"];
repeated EnumFieldDecl enum_fields = 4;
optional string source_file = 5 [default = "NONE"];
optional string linker_set_key = 6 [default = "NONE"];
required BasicNamedAndTypedDecl basic_abi = 1;
repeated EnumFieldDecl enum_fields = 2;
required string source_file = 3;
}
message GlobalVarDecl {
required BasicNamedAndTypedDecl basic_abi = 1;
required string source_file = 2;
}
message TranslationUnit {
repeated RecordDecl records = 1;
repeated FunctionDecl functions = 2;
repeated EnumDecl enums = 3;
repeated GlobalVarDecl global_vars = 4;
}

View File

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

View File

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

View File

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