Merge "Support VNDK ABI dump in JSON format"

am: d3b65417c2

Change-Id: I486e698da7aa169e6e0229c0301e670ec68e75f3
This commit is contained in:
Hsin-Yi Chen
2018-08-26 20:57:57 -07:00
committed by android-build-merger
6 changed files with 653 additions and 1 deletions

View File

@@ -60,6 +60,7 @@ cc_binary_host {
static_libs: [
"libheader-abi-util",
"libheader-checker-proto",
"libjsoncpp",
"libclangToolingCore",
"libclangTooling",
"libclangFrontendTool",
@@ -97,6 +98,7 @@ cc_defaults {
static_libs: [
"libheader-abi-util",
"libheader-checker-proto",
"libjsoncpp",
"libLLVMObject",
"libLLVMBitReader",
"libLLVMMC",
@@ -162,6 +164,7 @@ cc_library_host_static {
"header-abi-util/src/abi_diff_helpers.cpp",
"header-abi-util/src/collect_exported_headers.cpp",
"header-abi-util/src/ir_representation.cpp",
"header-abi-util/src/ir_representation_json.cpp",
"header-abi-util/src/ir_representation_protobuf.cpp",
"header-abi-util/src/so_file_parser.cpp",
"header-abi-util/src/version_script_parser.cpp",
@@ -169,6 +172,7 @@ cc_library_host_static {
static_libs: [
"libheader-checker-proto",
"libjsoncpp",
],
shared_libs: [

View File

@@ -55,6 +55,7 @@ static llvm::cl::opt<abi_util::TextFormatIR> text_format(
"text-format", llvm::cl::desc("Specify text format of abi dump"),
llvm::cl::values(clEnumValN(abi_util::TextFormatIR::ProtobufTextFormat,
"ProtobufTextFormat", "ProtobufTextFormat"),
clEnumValN(abi_util::TextFormatIR::Json, "Json", "JSON"),
clEnumValEnd),
llvm::cl::init(abi_util::TextFormatIR::ProtobufTextFormat),
llvm::cl::cat(header_checker_category));

View File

@@ -39,6 +39,7 @@ using AbiElementList = std::list<T>;
enum TextFormatIR {
ProtobufTextFormat = 0,
Json = 1,
};
enum CompatibilityStatusIR {

View File

@@ -0,0 +1,275 @@
// Copyright (C) 2018 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 IR_JSON_
#define IR_JSON_
#include <ir_representation.h>
#include <json/value.h>
// Classes which act as middle-men between clang AST parsing routines and
// message format specific dumpers.
namespace abi_util {
enum AccessSpecifier {
public_access = 1,
private_access = 2,
protected_access = 3,
};
enum RecordKind {
struct_kind = 1,
class_kind = 2,
union_kind = 3,
};
enum VTableComponentKind {
VCallOffset = 0,
VBaseOffset = 1,
OffsetToTop = 2,
RTTI = 3,
FunctionPointer = 4,
CompleteDtorPointer = 5,
DeletingDtorPointer = 6,
UnusedFunctionPointer = 7,
};
inline AccessSpecifier AccessIRToJson(AccessSpecifierIR access) {
switch (access) {
case AccessSpecifierIR::PublicAccess:
return AccessSpecifier::public_access;
case AccessSpecifierIR::ProtectedAccess:
return AccessSpecifier::protected_access;
case AccessSpecifierIR::PrivateAccess:
return AccessSpecifier::private_access;
default:
return AccessSpecifier::public_access;
}
// Should not be reached
assert(false);
}
inline AccessSpecifierIR AccessJsonToIR(AccessSpecifier access) {
switch (access) {
case AccessSpecifier::public_access:
return AccessSpecifierIR::PublicAccess;
case AccessSpecifier::protected_access:
return AccessSpecifierIR::ProtectedAccess;
case AccessSpecifier::private_access:
return AccessSpecifierIR::PrivateAccess;
default:
return AccessSpecifierIR::PublicAccess;
}
// Should not be reached
assert(false);
}
inline RecordKind RecordKindIRToJson(RecordTypeIR::RecordKind kind) {
switch (kind) {
case RecordTypeIR::RecordKind::struct_kind:
return RecordKind::struct_kind;
case RecordTypeIR::RecordKind::class_kind:
return RecordKind::class_kind;
case RecordTypeIR::RecordKind::union_kind:
return RecordKind::union_kind;
default:
return RecordKind::struct_kind;
}
// Should not be reached
assert(false);
}
inline RecordTypeIR::RecordKind RecordKindJsonToIR(RecordKind kind) {
switch (kind) {
case RecordKind::struct_kind:
return RecordTypeIR::struct_kind;
case RecordKind::class_kind:
return RecordTypeIR::class_kind;
case RecordKind::union_kind:
return RecordTypeIR::union_kind;
default:
return RecordTypeIR::struct_kind;
}
// Should not be reached
assert(false);
}
inline VTableComponentKind
VTableComponentKindIRToJson(VTableComponentIR::Kind kind) {
switch (kind) {
case VTableComponentIR::Kind::VCallOffset:
return VTableComponentKind::VCallOffset;
case VTableComponentIR::Kind::VBaseOffset:
return VTableComponentKind::VBaseOffset;
case VTableComponentIR::Kind::OffsetToTop:
return VTableComponentKind::OffsetToTop;
case VTableComponentIR::Kind::RTTI:
return VTableComponentKind::RTTI;
case VTableComponentIR::Kind::FunctionPointer:
return VTableComponentKind::FunctionPointer;
case VTableComponentIR::Kind::CompleteDtorPointer:
return VTableComponentKind::CompleteDtorPointer;
case VTableComponentIR::Kind::DeletingDtorPointer:
return VTableComponentKind::DeletingDtorPointer;
case VTableComponentIR::Kind::UnusedFunctionPointer:
return VTableComponentKind::UnusedFunctionPointer;
default:
return VTableComponentKind::UnusedFunctionPointer;
}
// Should not be reached
assert(false);
}
inline VTableComponentIR::Kind
VTableComponentKindJsonToIR(VTableComponentKind kind) {
switch (kind) {
case VTableComponentKind::VCallOffset:
return VTableComponentIR::Kind::VCallOffset;
case VTableComponentKind::VBaseOffset:
return VTableComponentIR::Kind::VBaseOffset;
case VTableComponentKind::OffsetToTop:
return VTableComponentIR::Kind::OffsetToTop;
case VTableComponentKind::RTTI:
return VTableComponentIR::Kind::RTTI;
case VTableComponentKind::FunctionPointer:
return VTableComponentIR::Kind::FunctionPointer;
case VTableComponentKind::CompleteDtorPointer:
return VTableComponentIR::Kind::CompleteDtorPointer;
case VTableComponentKind::DeletingDtorPointer:
return VTableComponentIR::Kind::DeletingDtorPointer;
case VTableComponentKind::UnusedFunctionPointer:
return VTableComponentIR::Kind::UnusedFunctionPointer;
default:
return VTableComponentIR::Kind::UnusedFunctionPointer;
}
// Should not be reached
assert(false);
}
// Classes that wrap constructor of Json::Value.
class JsonArray : public Json::Value {
public:
JsonArray() : Json::Value(Json::ValueType::arrayValue) {}
};
class JsonObject : public Json::Value {
public:
JsonObject() : Json::Value(Json::ValueType::objectValue) {}
};
class IRToJsonConverter {
private:
static void AddTemplateInfo(JsonObject &type_decl,
const abi_util::TemplatedArtifactIR *template_ir);
// BasicNamedAndTypedDecl
static void AddTypeInfo(JsonObject &type_decl, const TypeIR *type_ir);
static void AddRecordFields(JsonObject &record_type,
const RecordTypeIR *record_ir);
static void AddBaseSpecifiers(JsonObject &record_type,
const RecordTypeIR *record_ir);
static void AddVTableLayout(JsonObject &record_type,
const RecordTypeIR *record_ir);
static void AddTagTypeInfo(JsonObject &tag_type,
const TagTypeIR *tag_type_ir);
static void AddEnumFields(JsonObject &enum_type, const EnumTypeIR *enum_ir);
public:
static JsonObject ConvertEnumTypeIR(const EnumTypeIR *enump);
static JsonObject ConvertRecordTypeIR(const RecordTypeIR *recordp);
static JsonObject ConvertFunctionTypeIR(const FunctionTypeIR *function_typep);
static void AddFunctionParametersAndSetReturnType(
JsonObject &function, const CFunctionLikeIR *cfunction_like_ir);
static void AddFunctionParameters(JsonObject &function,
const CFunctionLikeIR *cfunction_like_ir);
static JsonObject ConvertFunctionIR(const FunctionIR *functionp);
static JsonObject ConvertGlobalVarIR(const GlobalVarIR *global_varp);
static JsonObject ConvertPointerTypeIR(const PointerTypeIR *pointerp);
static JsonObject ConvertQualifiedTypeIR(const QualifiedTypeIR *qualtypep);
static JsonObject ConvertBuiltinTypeIR(const BuiltinTypeIR *builtin_typep);
static JsonObject ConvertArrayTypeIR(const ArrayTypeIR *array_typep);
static JsonObject ConvertLvalueReferenceTypeIR(
const LvalueReferenceTypeIR *lvalue_reference_typep);
static JsonObject ConvertRvalueReferenceTypeIR(
const RvalueReferenceTypeIR *rvalue_reference_typep);
static JsonObject ConvertElfFunctionIR(const ElfFunctionIR *elf_function_ir);
static JsonObject ConvertElfObjectIR(const ElfObjectIR *elf_object_ir);
};
class JsonIRDumper : public IRDumper, public IRToJsonConverter {
public:
JsonIRDumper(const std::string &dump_path);
bool AddLinkableMessageIR(const LinkableMessageIR *) override;
bool AddElfSymbolMessageIR(const ElfSymbolIR *) override;
bool Dump() override;
~JsonIRDumper() override {}
private:
JsonObject translation_unit_;
};
} // namespace abi_util
#endif // IR_JSON_

View File

@@ -14,6 +14,7 @@
#include <abi_diff_helpers.h>
#include <ir_representation.h>
#include <ir_representation_json.h>
#include <ir_representation_protobuf.h>
#pragma clang diagnostic push
@@ -40,8 +41,9 @@ std::unique_ptr<IRDumper> IRDumper::CreateIRDumper(
switch (text_format) {
case TextFormatIR::ProtobufTextFormat:
return std::make_unique<ProtobufIRDumper>(dump_path);
case TextFormatIR::Json:
return std::make_unique<JsonIRDumper>(dump_path);
default:
// Nothing else is supported yet.
llvm::errs() << "Text format not supported yet\n";
return nullptr;
}

View File

@@ -0,0 +1,369 @@
// Copyright (C) 2018 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 <ir_representation_json.h>
#include <json/writer.h>
#include <fstream>
#include <string>
namespace abi_util {
void IRToJsonConverter::AddTemplateInfo(
JsonObject &type_decl, const abi_util::TemplatedArtifactIR *template_ir) {
Json::Value &elements = type_decl["template_info"];
elements = JsonArray();
for (auto &&template_element_ir : template_ir->GetTemplateElements()) {
Json::Value &element = elements.append(JsonObject());
element["referenced_type"] = template_element_ir.GetReferencedType();
}
}
void IRToJsonConverter::AddTypeInfo(JsonObject &type_decl,
const TypeIR *type_ir) {
Json::Value &type_info = type_decl["type_info"];
type_info = JsonObject();
type_info["linker_set_key"] = type_ir->GetLinkerSetKey();
type_info["source_file"] = type_ir->GetSourceFile();
type_info["name"] = type_ir->GetName();
type_info["size"] = Json::UInt64(type_ir->GetSize());
type_info["alignment"] = type_ir->GetAlignment();
type_info["referenced_type"] = type_ir->GetReferencedType();
type_info["self_type"] = type_ir->GetSelfType();
}
static JsonObject ConvertRecordFieldIR(const RecordFieldIR *record_field_ir) {
JsonObject record_field;
record_field["field_name"] = record_field_ir->GetName();
record_field["referenced_type"] = record_field_ir->GetReferencedType();
record_field["access"] = AccessIRToJson(record_field_ir->GetAccess());
record_field["field_offset"] = Json::UInt64(record_field_ir->GetOffset());
return record_field;
}
void IRToJsonConverter::AddRecordFields(JsonObject &record_type,
const RecordTypeIR *record_ir) {
Json::Value &fields = record_type["fields"];
fields = JsonArray();
for (auto &&field_ir : record_ir->GetFields()) {
fields.append(ConvertRecordFieldIR(&field_ir));
}
}
static JsonObject
ConvertBaseSpecifierIR(const CXXBaseSpecifierIR &base_specifier_ir) {
JsonObject base_specifier;
base_specifier["referenced_type"] = base_specifier_ir.GetReferencedType();
base_specifier["is_virtual"] = base_specifier_ir.IsVirtual();
base_specifier["access"] = AccessIRToJson(base_specifier_ir.GetAccess());
return base_specifier;
}
void IRToJsonConverter::AddBaseSpecifiers(JsonObject &record_type,
const RecordTypeIR *record_ir) {
Json::Value &base_specifiers = record_type["base_specifiers"];
base_specifiers = JsonArray();
for (auto &&base_ir : record_ir->GetBases()) {
base_specifiers.append(ConvertBaseSpecifierIR(base_ir));
}
}
static JsonObject
ConvertVTableLayoutIR(const VTableLayoutIR &vtable_layout_ir) {
JsonObject vtable_layout;
Json::Value &vtable_components = vtable_layout["vtable_components"];
vtable_components = JsonArray();
for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
Json::Value &vtable_component = vtable_components.append(JsonObject());
vtable_component["kind"] =
VTableComponentKindIRToJson(vtable_component_ir.GetKind());
vtable_component["component_value"] =
Json::Int64(vtable_component_ir.GetValue());
vtable_component["mangled_component_name"] = vtable_component_ir.GetName();
vtable_component["is_pure"] = vtable_component_ir.GetIsPure();
}
return vtable_layout;
}
void IRToJsonConverter::AddVTableLayout(JsonObject &record_type,
const RecordTypeIR *record_ir) {
const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
record_type["vtable_layout"] = ConvertVTableLayoutIR(vtable_layout_ir);
}
void IRToJsonConverter::AddTagTypeInfo(JsonObject &record_type,
const abi_util::TagTypeIR *tag_type_ir) {
Json::Value &tag_type = record_type["tag_info"];
tag_type = JsonObject();
tag_type["unique_id"] = tag_type_ir->GetUniqueId();
}
JsonObject IRToJsonConverter::ConvertRecordTypeIR(const RecordTypeIR *recordp) {
JsonObject record_type;
record_type["access"] = AccessIRToJson(recordp->GetAccess());
record_type["record_kind"] = RecordKindIRToJson(recordp->GetRecordKind());
record_type["is_anonymous"] = recordp->IsAnonymous();
AddTypeInfo(record_type, recordp);
AddRecordFields(record_type, recordp);
AddBaseSpecifiers(record_type, recordp);
AddVTableLayout(record_type, recordp);
AddTagTypeInfo(record_type, recordp);
AddTemplateInfo(record_type, recordp);
return record_type;
}
JsonObject
IRToJsonConverter::ConvertElfObjectIR(const ElfObjectIR *elf_object_ir) {
JsonObject elf_object;
elf_object["name"] = elf_object_ir->GetName();
return elf_object;
}
JsonObject
IRToJsonConverter::ConvertElfFunctionIR(const ElfFunctionIR *elf_function_ir) {
JsonObject elf_function;
elf_function["name"] = elf_function_ir->GetName();
return elf_function;
}
void IRToJsonConverter::AddFunctionParametersAndSetReturnType(
JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) {
function["return_type"] = cfunction_like_ir->GetReturnType();
AddFunctionParameters(function, cfunction_like_ir);
}
void IRToJsonConverter::AddFunctionParameters(
JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) {
Json::Value &parameters = function["parameters"];
parameters = JsonArray();
for (auto &&parameter_ir : cfunction_like_ir->GetParameters()) {
Json::Value &parameter = parameters.append(JsonObject());
parameter["referenced_type"] = parameter_ir.GetReferencedType();
parameter["default_arg"] = parameter_ir.GetIsDefault();
parameter["is_this_ptr"] = parameter_ir.GetIsThisPtr();
}
}
JsonObject
IRToJsonConverter::ConvertFunctionTypeIR(const FunctionTypeIR *function_typep) {
JsonObject function_type;
AddTypeInfo(function_type, function_typep);
AddFunctionParametersAndSetReturnType(function_type, function_typep);
return function_type;
}
JsonObject IRToJsonConverter::ConvertFunctionIR(const FunctionIR *functionp) {
JsonObject function;
function["access"] = AccessIRToJson(functionp->GetAccess());
function["linker_set_key"] = functionp->GetLinkerSetKey();
function["source_file"] = functionp->GetSourceFile();
function["function_name"] = functionp->GetName();
AddFunctionParametersAndSetReturnType(function, functionp);
AddTemplateInfo(function, functionp);
return function;
}
static JsonObject ConvertEnumFieldIR(const EnumFieldIR *enum_field_ir) {
JsonObject enum_field;
enum_field["name"] = enum_field_ir->GetName();
enum_field["enum_field_value"] = Json::Int64(enum_field_ir->GetValue());
return enum_field;
}
void IRToJsonConverter::AddEnumFields(JsonObject &enum_type,
const EnumTypeIR *enum_ir) {
Json::Value &enum_fields = enum_type["enum_fields"];
enum_fields = JsonArray();
for (auto &&field : enum_ir->GetFields()) {
enum_fields.append(ConvertEnumFieldIR(&field));
}
}
JsonObject IRToJsonConverter::ConvertEnumTypeIR(const EnumTypeIR *enump) {
JsonObject enum_type;
enum_type["access"] = AccessIRToJson(enump->GetAccess());
enum_type["underlying_type"] = enump->GetUnderlyingType();
AddTypeInfo(enum_type, enump);
AddEnumFields(enum_type, enump);
AddTagTypeInfo(enum_type, enump);
return enum_type;
}
JsonObject
IRToJsonConverter::ConvertGlobalVarIR(const GlobalVarIR *global_varp) {
JsonObject global_var;
global_var["referenced_type"] = global_varp->GetReferencedType();
global_var["source_file"] = global_varp->GetSourceFile();
global_var["name"] = global_varp->GetName();
global_var["linker_set_key"] = global_varp->GetLinkerSetKey();
global_var["access"] = AccessIRToJson(global_varp->GetAccess());
return global_var;
}
JsonObject
IRToJsonConverter::ConvertPointerTypeIR(const PointerTypeIR *pointerp) {
JsonObject pointer_type;
AddTypeInfo(pointer_type, pointerp);
return pointer_type;
}
JsonObject
IRToJsonConverter::ConvertQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
JsonObject qualified_type;
AddTypeInfo(qualified_type, qualtypep);
qualified_type["is_const"] = qualtypep->IsConst();
qualified_type["is_volatile"] = qualtypep->IsVolatile();
qualified_type["is_restricted"] = qualtypep->IsRestricted();
return qualified_type;
}
JsonObject
IRToJsonConverter::ConvertBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
JsonObject builtin_type;
builtin_type["is_unsigned"] = builtin_typep->IsUnsigned();
builtin_type["is_integral"] = builtin_typep->IsIntegralType();
AddTypeInfo(builtin_type, builtin_typep);
return builtin_type;
}
JsonObject
IRToJsonConverter::ConvertArrayTypeIR(const ArrayTypeIR *array_typep) {
JsonObject array_type;
AddTypeInfo(array_type, array_typep);
return array_type;
}
JsonObject IRToJsonConverter::ConvertLvalueReferenceTypeIR(
const LvalueReferenceTypeIR *lvalue_reference_typep) {
JsonObject lvalue_reference_type;
AddTypeInfo(lvalue_reference_type, lvalue_reference_typep);
return lvalue_reference_type;
}
JsonObject IRToJsonConverter::ConvertRvalueReferenceTypeIR(
const RvalueReferenceTypeIR *rvalue_reference_typep) {
JsonObject rvalue_reference_type;
AddTypeInfo(rvalue_reference_type, rvalue_reference_typep);
return rvalue_reference_type;
}
bool JsonIRDumper::AddLinkableMessageIR(const LinkableMessageIR *lm) {
std::string key;
JsonObject converted;
// No RTTI
switch (lm->GetKind()) {
case RecordTypeKind:
key = "record_types";
converted = ConvertRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
break;
case EnumTypeKind:
key = "enum_types";
converted = ConvertEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
break;
case PointerTypeKind:
key = "pointer_types";
converted = ConvertPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
break;
case QualifiedTypeKind:
key = "qualified_types";
converted =
ConvertQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
break;
case ArrayTypeKind:
key = "array_types";
converted = ConvertArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
break;
case LvalueReferenceTypeKind:
key = "lvalue_reference_types";
converted = ConvertLvalueReferenceTypeIR(
static_cast<const LvalueReferenceTypeIR *>(lm));
break;
case RvalueReferenceTypeKind:
key = "rvalue_reference_types";
converted = ConvertRvalueReferenceTypeIR(
static_cast<const RvalueReferenceTypeIR *>(lm));
break;
case BuiltinTypeKind:
key = "builtin_types";
converted = ConvertBuiltinTypeIR(static_cast<const BuiltinTypeIR *>(lm));
break;
case FunctionTypeKind:
key = "function_types";
converted = ConvertFunctionTypeIR(static_cast<const FunctionTypeIR *>(lm));
break;
case GlobalVarKind:
key = "global_vars";
converted = ConvertGlobalVarIR(static_cast<const GlobalVarIR *>(lm));
break;
case FunctionKind:
key = "functions";
converted = ConvertFunctionIR(static_cast<const FunctionIR *>(lm));
break;
default:
return false;
}
translation_unit_[key].append(converted);
return true;
}
bool JsonIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
std::string key;
JsonObject elf_symbol;
elf_symbol["name"] = em->GetName();
switch (em->GetKind()) {
case ElfSymbolIR::ElfFunctionKind:
key = "elf_functions";
break;
case ElfSymbolIR::ElfObjectKind:
key = "elf_objects";
break;
default:
return false;
}
translation_unit_[key].append(elf_symbol);
return true;
}
bool JsonIRDumper::Dump() {
std::ofstream output(dump_path_);
Json::StyledStreamWriter writer(/* indentation */ " ");
writer.write(output, translation_unit_);
return true;
}
JsonIRDumper::JsonIRDumper(const std::string &dump_path)
: IRDumper(dump_path), translation_unit_() {
const std::string keys[] = {
"record_types",
"enum_types",
"pointer_types",
"lvalue_reference_types",
"rvalue_reference_types",
"builtin_types",
"qualified_types",
"array_types",
"function_types",
"functions",
"global_vars",
"elf_functions",
"elf_objects",
};
for (auto key : keys) {
translation_unit_[key] = JsonArray();
}
}
} // namespace abi_util