C++程序  |  613行  |  22.68 KB

// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "abi_wrappers.h"

#include <header_abi_util.h>

#include <limits.h>
#include <stdlib.h>
#include <clang/Tooling/Core/QualTypeNames.h>

#include <string>

using namespace abi_wrapper;

ABIWrapper::ABIWrapper(
    clang::MangleContext *mangle_contextp,
    clang::ASTContext *ast_contextp,
    const clang::CompilerInstance *cip)
  : cip_(cip),
    mangle_contextp_(mangle_contextp),
    ast_contextp_(ast_contextp) { }

std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
                                          const clang::CompilerInstance *cip) {
  clang::SourceManager &sm = cip->getSourceManager();
  clang::SourceLocation location = decl->getLocation();
  // We need to use the expansion location to identify whether we should recurse
  // into the AST Node or not. For eg: macros specifying LinkageSpecDecl can
  // have their spelling location defined somewhere outside a source / header
  // file belonging to a library. This should not allow the AST node to be
  // skipped. Its expansion location will still be the source-file / header
  // belonging to the library.
  clang::SourceLocation expansion_location = sm.getExpansionLoc(location);
  llvm::StringRef file_name = sm.getFilename(expansion_location);
  std::string file_name_adjusted = "";
  char file_abs_path[PATH_MAX];
  if (realpath(file_name.str().c_str(), file_abs_path) == nullptr) {
    return "";
  }
  return file_abs_path;
}

abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
    const clang::AccessSpecifier sp) const {
  switch (sp) {
    case clang::AS_private: {
      return abi_dump::AccessSpecifier::private_access;
      break;
    }
    case clang::AS_protected: {
      return abi_dump::AccessSpecifier::protected_access;
      break;
    }
    default: {
      return abi_dump::AccessSpecifier::public_access;
      break;
    }
  }
}

bool ABIWrapper::SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
                                   const clang::QualType type) const {
  if (!type_abi) {
    return false;
  }
  const clang::QualType canonical_type = type.getCanonicalType();
  type_abi->set_name(QualTypeToString(canonical_type));
  // Cannot determine the size and alignment for template parameter dependent
  // types as well as incomplete types.
  const clang::Type *base_type = canonical_type.getTypePtr();
  clang::Type::TypeClass type_class = base_type->getTypeClass();
  // Temporary Hack for auto type sizes. Not determinable.
  if (base_type && !(base_type->isDependentType()) &&
      !(base_type->isIncompleteType()) && (type_class != clang::Type::Auto)) {
    std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
    ast_contextp_->getTypeInfoInChars(canonical_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 {
  assert(&(mangle_contextp_->getASTContext()) == ast_contextp_);
  if (!mangle_contextp_->shouldMangleDeclName(decl)) {
    clang::IdentifierInfo *identifier = decl->getIdentifier();
    return identifier ? identifier->getName() : "";
  }
  std::string mangled_name;
  llvm::raw_string_ostream ostream(mangled_name);
  mangle_contextp_->mangleName(decl, ostream);
  ostream.flush();
  return mangled_name;
}

bool ABIWrapper::SetupTemplateParamNames(
    abi_dump::TemplateInfo *tinfo,
    clang::TemplateParameterList *pl) const {
  if (tinfo->elements_size() > 0) {
    return true;
  }

  clang::TemplateParameterList::iterator template_it = pl->begin();
  while (template_it != pl->end()) {
    abi_dump::TemplateElement *template_parameterp =
        tinfo->add_elements();
    if (!template_parameterp) {
      return false;
    }
    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;
}

std::string ABIWrapper::GetTagDeclQualifiedName(
    const clang::TagDecl *decl) const {
  if (decl->getTypedefNameForAnonDecl()) {
    return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
  }
  return decl->getQualifiedNameAsString();
}

bool ABIWrapper::SetupTemplateArguments(
    abi_dump::TemplateInfo *tinfo,
    const clang::TemplateArgumentList *tl) const {
  for (int i = 0; i < tl->size(); i++) {
    const clang::TemplateArgument &arg = (*tl)[i];
    //TODO: More comprehensive checking needed.
    if (arg.getKind() != clang::TemplateArgument::Type) {
      continue;
    }
    clang::QualType type = arg.getAsType();
    abi_dump::TemplateElement *template_parameterp =
        tinfo->add_elements();
    if (!template_parameterp) {
      return false;
    }
    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;
}

std::string ABIWrapper::QualTypeToString(
    const clang::QualType &sweet_qt) const {
  const clang::QualType salty_qt = sweet_qt.getCanonicalType();
  // clang::TypeName::getFullyQualifiedName removes the part of the type related
  // to it being a template parameter. Don't use it for dependent types.
  if (salty_qt.getTypePtr()->isDependentType()) {
    return salty_qt.getAsString();
  }
  return clang::TypeName::getFullyQualifiedName(salty_qt, *ast_contextp_);
}

FunctionDeclWrapper::FunctionDeclWrapper(
    clang::MangleContext *mangle_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_mangled_function_name(mangled_name);
  functionp->set_source_file(source_file);
  // 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(
    abi_dump::FunctionDecl *functionp) const {
  switch (function_decl_->getTemplatedKind()) {
    case clang::FunctionDecl::TK_FunctionTemplate: {
      clang::FunctionTemplateDecl *template_decl =
          function_decl_->getDescribedFunctionTemplate();
      if (template_decl) {
        clang::TemplateParameterList *template_parameter_list =
            template_decl->getTemplateParameters();
        if (template_parameter_list &&
            !SetupTemplateParamNames(functionp->mutable_template_info(),
                                     template_parameter_list)) {
          return false;
        }
      }
      break;
    }
    case clang::FunctionDecl::TK_FunctionTemplateSpecialization: {
      const clang::TemplateArgumentList *arg_list =
          function_decl_->getTemplateSpecializationArgs();
      if (arg_list &&
          !SetupTemplateArguments(functionp->mutable_template_info(),
                                  arg_list)) {
        return false;
      }
      break;
    }
    default: {
      break;
    }
  }
  return true;
}

std::unique_ptr<abi_dump::FunctionDecl>
FunctionDeclWrapper::GetFunctionDecl() const {
  std::unique_ptr<abi_dump::FunctionDecl> abi_decl(
      new abi_dump::FunctionDecl());
  std::string source_file = GetDeclSourceFile(function_decl_, cip_);
  if (!SetupFunction(abi_decl.get(), source_file)) {
    return nullptr;
  }
  return abi_decl;
}

RecordDeclWrapper::RecordDeclWrapper(
    clang::MangleContext *mangle_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 {
  clang::RecordDecl::field_iterator field = record_decl_->field_begin();
  while (field != record_decl_->field_end()) {
    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;
    }
    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 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()) {
    abi_dump::CXXBaseSpecifier *base_specifierp = cxxp->add_base_specifiers();
    if (!base_specifierp) {
      llvm::errs() << " Couldn't add base specifier to reference dump\n";
      return false;
    }
    std::string name = QualTypeToString(base_class->getType());
    bool is_virtual = base_class->isVirtual();
    if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
                                     base_class->getType(),
                                     "", base_class->getAccessSpecifier(),
                                     "")) {
      return false;
    }
    base_specifierp->set_is_virtual(is_virtual);
    base_class++;
  }
  return true;
}

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();
    if (template_decl) {
      clang::TemplateParameterList *template_parameter_list =
          template_decl->getTemplateParameters();
      if (template_parameter_list &&
          !SetupTemplateParamNames(record_declp->mutable_template_info(),
                                   template_parameter_list)) {
        return false;
      }
    }
  } else {
    const clang::ClassTemplateSpecializationDecl *specialization_decl =
        clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
            cxx_record_decl);
    if(specialization_decl) {
      const clang::TemplateArgumentList *arg_list =
          &specialization_decl->getTemplateArgs();
      if (arg_list &&
          !SetupTemplateArguments(record_declp->mutable_template_info(),
                                  arg_list)) {
        return false;
      }
    }
  }
  return true;
}

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;
  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_source_file(source_file);
  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_);
  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;
  }
  return abi_decl;
}

EnumDeclWrapper::EnumDeclWrapper(
    clang::MangleContext *mangle_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::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();
    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_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_);

  if (!SetupEnum(abi_decl.get(), source_file)) {
    llvm::errs() << "Setting up Enum fields failed\n";
    return nullptr;
  }
  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 {
  // Temporary fix : clang segfaults on trying to mangle global variable which
  // is a dependent sized array type.
  std::string qualified_name = global_var_decl_->getQualifiedNameAsString();
  std::string mangled_or_qualified_name =
      global_var_decl_->getType()->isDependentSizedArrayType() ?
      qualified_name : GetMangledNameDecl(global_var_decl_);
  if (!SetupBasicNamedAndTypedDecl(
      global_varp->mutable_basic_abi(),global_var_decl_->getType(),
      qualified_name, global_var_decl_->getAccess(),
      mangled_or_qualified_name)) {
    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;
}