Merge "Added libprotobuf to extract and dump ABI."

am: 7272d52f76

Change-Id: I696beff34a2052eaca4c78e08ac362b0c277a5a6
This commit is contained in:
Jayant Chowdhary
2017-01-17 17:26:55 +00:00
committed by android-build-merger
6 changed files with 271 additions and 46 deletions

View File

@@ -25,7 +25,14 @@ cc_defaults {
"-Wall",
"-Werror",
"-std=c++11",
"-DGOOGLE_PROTOBUF_NO_RTTI",
],
target: {
windows: {
enabled: false
}
}
}
cc_defaults {
@@ -34,6 +41,7 @@ cc_defaults {
shared_libs: [
"libclang",
"libLLVM",
"libprotobuf-cpp-full",
],
}
@@ -42,6 +50,7 @@ cc_defaults {
static_libs: [
"libclangTooling",
"libclangToolingCore",
"libclangFrontendTool",
"libclangFrontend",
"libclangDriver",
@@ -74,6 +83,30 @@ cc_defaults {
"libLLVMMCDisassembler",
"libLLVMSupport",
],
shared_libs: [
"libprotobuf-cpp-full",
],
}
cc_library_static {
name: "libheader-checker-proto",
host_supported: true,
export_include_dirs: ["."],
srcs: [
"proto/abi_dump.proto",
],
proto: {
export_proto_headers: true,
},
cflags: [
"-Wcast-qual",
"-Wno-long-long",
"-Wno-unused-parameter",
],
}
cc_binary_host {
@@ -84,20 +117,15 @@ cc_binary_host {
"header-checker-lib-debug-defaults",
],
srcs: ["header-abi-dumper/src/*.cpp"],
srcs: [
"header-abi-dumper/src/*.cpp",
],
static_libs: [
"libheader-checker-proto",
],
target: {
windows: {
host_ldlibs: [
"-limagehlp",
"-lole32",
"-lversion",
],
cflags: [
// Skip missing-field-initializer warnings for mingw.
"-Wno-error=missing-field-initializers",
],
},
linux: {
host_ldlibs: [
"-ldl",
@@ -111,10 +139,4 @@ cc_binary_host {
],
},
},
product_variables: {
unbundled_build: {
enabled: false,
},
},
}

View File

@@ -1,37 +1,154 @@
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ast_processing.h"
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
llvm::errs() << "struct: " << decl->getName() << "\n";
return true;
}
#include <clang/Lex/Token.h>
#include <clang/Tooling/Core/QualTypeNames.h>
bool HeaderASTVisitor::VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) {
llvm::errs() << "class: " << decl->getName() << "\n";
#include <google/protobuf/text_format.h>
#include <fstream>
#include <iostream>
#include <string>
HeaderASTVisitor::HeaderASTVisitor(
abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p)
: tu_ptr_(tu_ptr),
mangle_contextp_(mangle_contextp),
ast_contextp_(ast_contextp),
cip_(compiler_instance_p) { }
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
abi_dump::RecordDecl *record_decl = tu_ptr_->add_classes();
SetupClassFields(record_decl, decl);
return true;
}
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
llvm::errs() << "func: " << decl->getName() << "\n";
abi_dump::FunctionDecl *function_decl = tu_ptr_->add_functions();
// FIXME: Use return value.
SetupFunction(function_decl, decl);
return true;
}
HeaderASTConsumer::HeaderASTConsumer(
const std::string &file_name,
clang::CompilerInstance *compiler_instancep,
const std::string &out_dump_name)
: file_name_(file_name),
cip_(compiler_instancep),
out_dump_name_(out_dump_name) { }
void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
llvm::errs() << "HandleTranslationUnit ------------------------------\n";
clang::TranslationUnitDecl* translation_unit = ctx.getTranslationUnitDecl();
HeaderASTVisitor v;
std::unique_ptr<clang::MangleContext> mangle_contextp(
ctx.createMangleContext());
abi_dump::TranslationUnit tu;
HeaderASTVisitor v(&tu, mangle_contextp.get(), &ctx, cip_);
v.TraverseDecl(translation_unit);
std::ofstream text_output(out_dump_name_ + ".txt");
std::fstream binary_output(
(out_dump_name_).c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
std::string str_out;
google::protobuf::TextFormat::PrintToString(tu, &str_out);
text_output << str_out;
if (!tu.SerializeToOstream(&binary_output)) {
llvm::errs() << "Serialization to ostream failed\n";
}
}
void HeaderASTConsumer::HandleVTable(clang::CXXRecordDecl *crd) {
llvm::errs() << "HandleVTable: " << crd->getName() << "\n";
}
llvm::StringRef HeaderASTPPCallbacks::ToString(const clang::Token &tok) {
return tok.getIdentifierInfo()->getName();
std::string HeaderASTVisitor::GetDeclSourceFile(const clang::NamedDecl *decl) {
clang::SourceManager &SM = cip_->getSourceManager();
clang::SourceLocation location = decl->getLocation();
llvm::StringRef file_name= SM.getFilename(location);
return file_name.str();
}
std::string HeaderASTVisitor::GetMangledNameDecl(const clang::NamedDecl *decl) {
std::string mangled_or_demangled_name = decl->getName();
if (mangle_contextp_->shouldMangleDeclName(decl)) {
llvm::raw_string_ostream ostream(mangled_or_demangled_name);
mangle_contextp_->mangleName(decl, ostream);
ostream.flush();
}
return mangled_or_demangled_name;
}
bool HeaderASTVisitor::SetupFunction(abi_dump::FunctionDecl *functionp,
const clang::FunctionDecl *decl) {
// 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.
functionp->set_function_name(decl->getQualifiedNameAsString());
functionp->set_mangled_function_name(GetMangledNameDecl(decl));
functionp->set_source_file(GetDeclSourceFile(decl));
clang::QualType return_type =
decl->getReturnType().getDesugaredType(*ast_contextp_);
functionp->set_return_type(
clang::TypeName::getFullyQualifiedName(return_type, *ast_contextp_));
clang::FunctionDecl::param_const_iterator param_it = decl->param_begin();
while (param_it != decl->param_end()) {
abi_dump::FieldDecl *function_fieldp = functionp->add_parameters();
if (!function_fieldp) {
llvm::errs() << "Couldn't add parameter to method. Aborting";
return false;
}
function_fieldp->set_field_name((*param_it)->getName());
clang::QualType field_type =
(*param_it)->getType().getDesugaredType(*ast_contextp_);
function_fieldp->set_field_type(
clang::TypeName::getFullyQualifiedName(field_type, *ast_contextp_));
param_it++;
}
return true;
}
bool HeaderASTVisitor::SetupClassFields(abi_dump::RecordDecl *classp,
const clang::RecordDecl *decl) {
classp->set_fully_qualified_name(decl->getQualifiedNameAsString());
classp->set_source_file(GetDeclSourceFile(decl));
classp->set_entity_type("class");
clang::RecordDecl::field_iterator field = decl->field_begin();
while (field != decl->field_end()) {
abi_dump::FieldDecl *class_fieldp = classp->add_fields();
if (!class_fieldp) {
llvm::errs() << " Couldn't add class field: " << field->getName()
<< " to reference dump\n";
return false;
}
class_fieldp->set_field_name(field->getName());
//FIXME: This needs to change. Resolve typedef, class name, built-in etc.
clang::QualType field_type =
field->getType().getDesugaredType(*ast_contextp_);
class_fieldp->set_field_type(
clang::TypeName::getFullyQualifiedName(field_type, *ast_contextp_));
field++;
}
return true;
}
void HeaderASTPPCallbacks::MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) {
const clang::MacroDirective *) {
assert(macro_name_tok.isAnyIdentifier());
llvm::errs() << "defines: " << ToString(macro_name_tok) << "\n";
}

View File

@@ -1,28 +1,83 @@
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef AST_PROCESSING_H_
#define AST_PROCESSING_H_
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#include "proto/abi_dump.pb.h"
#pragma clang diagnostic pop
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/Lex/Preprocessor.h>
class HeaderASTVisitor
: public clang::RecursiveASTVisitor<HeaderASTVisitor> {
public:
HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp,
const clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p);
bool VisitRecordDecl(const clang::RecordDecl *decl);
bool VisitCXXRecordDecl(const clang::CXXRecordDecl *decl);
bool VisitFunctionDecl(const clang::FunctionDecl *decl);
private:
bool SetupFunction(abi_dump::FunctionDecl *methodp,
const clang::FunctionDecl *decl);
bool SetupClassFields(abi_dump::RecordDecl *classp,
const clang::RecordDecl *decl);
std::string GetDeclSourceFile(const clang::NamedDecl *decl);
std::string GetMangledNameDecl(const clang::NamedDecl *decl);
private:
abi_dump::TranslationUnit *tu_ptr_;
clang::MangleContext *mangle_contextp_;
const clang::ASTContext *ast_contextp_;
const clang::CompilerInstance *cip_;
};
class HeaderASTConsumer : public clang::ASTConsumer {
public:
HeaderASTConsumer(const std::string &file_name,
clang::CompilerInstance *compiler_instancep,
const std::string &out_dump_name);
void HandleTranslationUnit(clang::ASTContext &ctx) override;
void HandleVTable(clang::CXXRecordDecl *crd) override;
private:
std::string file_name_;
clang::CompilerInstance *cip_;
std::string out_dump_name_;
};
class HeaderASTPPCallbacks : public clang::PPCallbacks {
private:
llvm::StringRef ToString(const clang::Token &tok);
public:
void MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) override;
};
#endif // AST_PROCESSING_H_

View File

@@ -13,16 +13,13 @@
// limitations under the License.
#include "frontend_action.h"
#include "ast_processing.h"
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/MultiplexConsumer.h>
#include <clang/Lex/Token.h>
#include <clang/Serialization/ASTWriter.h>
#include <clang/Lex/Preprocessor.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/Support/raw_ostream.h>
#include <memory>
#include <string>
@@ -39,9 +36,5 @@ HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
pp.addPPCallbacks(llvm::make_unique<HeaderASTPPCallbacks>());
// Create AST consumers.
std::vector<std::unique_ptr<clang::ASTConsumer>> consumers;
consumers.push_back(llvm::make_unique<HeaderASTConsumer>());
// Still have a MultiplexConsumer in case other consumers need to be
// added later.
return llvm::make_unique<clang::MultiplexConsumer>(std::move(consumers));
return llvm::make_unique<HeaderASTConsumer>(header_file, &ci, dump_name_);
}

View File

@@ -24,6 +24,7 @@
#include <memory>
#include <string>
#include <vector>
#include <stdlib.h>

View File

@@ -0,0 +1,37 @@
syntax = "proto2";
package abi_dump;
message FunctionDecl {
// Fully Qualified Name.
required string function_name = 1 [default = "NONE"];
// Mangled name.
required string mangled_function_name = 2 [default = "NONE"];
required string source_file = 3;
required string parent_name = 4 [default = "NONE"];
repeated string template_arguments = 5 ;
repeated FieldDecl parameters = 6;
required string return_type = 7 [default = "VOID"];
}
message FieldDecl {
required string field_name = 1 [default = "NONE"];
required string field_type = 2 [default = "VOID"];
}
message RecordDecl {
repeated FieldDecl fields = 2;
repeated string inner_classes = 3;
repeated string base_classes = 4;
required string fully_qualified_name = 5 [default = "NONE"];
required int64 id = 6 [default = 0];
required string entity_type = 7 [default = "NONE"];
required string source_file = 9;
}
message TranslationUnit {
repeated RecordDecl classes = 1;
repeated FunctionDecl functions = 2;
}