| // Copyright (C) 2019 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 "repr/json/ir_dumper.h" |
| |
| #include "repr/ir_dumper.h" |
| #include "repr/ir_reader.h" |
| #include "repr/ir_representation_internal.h" |
| #include "repr/json/api.h" |
| #include "repr/json/converter.h" |
| |
| #include <json/reader.h> |
| #include <json/writer.h> |
| |
| #include <llvm/Support/raw_ostream.h> |
| |
| #include <cstdlib> |
| #include <fstream> |
| #include <sstream> |
| #include <string> |
| |
| |
| namespace header_checker { |
| namespace repr { |
| |
| |
| static void AddAccess(JsonObject &type_decl, AccessSpecifierIR value) { |
| if (value != default_access_ir) { |
| type_decl.Set("access", |
| FindInMap(access_ir_to_json, value, |
| "Failed to convert AccessSpecifierIR to JSON")); |
| } |
| } |
| |
| static void AddRecordKind(JsonObject &record_type, |
| RecordTypeIR::RecordKind value) { |
| if (value != default_record_kind_ir) { |
| record_type.Set("record_kind", |
| FindInMap(record_kind_ir_to_json, value, |
| "Failed to convert RecordKind to JSON")); |
| } |
| } |
| |
| static void AddVtableComponentKind(JsonObject &vtable_component, |
| VTableComponentIR::Kind value) { |
| if (value != default_vtable_component_kind_ir) { |
| vtable_component.Set( |
| "kind", FindInMap(vtable_component_kind_ir_to_json, value, |
| "Failed to convert VTableComponentIR::Kind to JSON")); |
| } |
| } |
| |
| static void AddElfSymbolBinding(JsonObject &elf_symbol, |
| ElfSymbolIR::ElfSymbolBinding value) { |
| if (value != default_elf_symbol_binding_ir) { |
| elf_symbol.Set("binding", |
| FindInMap(elf_symbol_binding_ir_to_json, value, |
| "Failed to convert ElfSymbolBinding to JSON")); |
| } |
| } |
| |
| void IRToJsonConverter::AddTemplateInfo( |
| JsonObject &type_decl, const TemplatedArtifactIR *template_ir) { |
| JsonArray args; |
| for (auto &&template_element_ir : template_ir->GetTemplateElements()) { |
| args.append(template_element_ir.GetReferencedType()); |
| } |
| type_decl.Set("template_args", args); |
| } |
| |
| void IRToJsonConverter::AddTypeInfo(JsonObject &type_decl, |
| const TypeIR *type_ir) { |
| type_decl.Set("linker_set_key", type_ir->GetLinkerSetKey()); |
| type_decl.Set("source_file", type_ir->GetSourceFile()); |
| type_decl.Set("name", type_ir->GetName()); |
| type_decl.Set("size", (uint64_t)type_ir->GetSize()); |
| type_decl.Set("alignment", (uint64_t)type_ir->GetAlignment()); |
| type_decl.Set("referenced_type", type_ir->GetReferencedType()); |
| type_decl.Set("self_type", type_ir->GetSelfType()); |
| } |
| |
| static JsonObject ConvertRecordFieldIR(const RecordFieldIR *record_field_ir) { |
| JsonObject record_field; |
| record_field.Set("field_name", record_field_ir->GetName()); |
| record_field.Set("referenced_type", record_field_ir->GetReferencedType()); |
| AddAccess(record_field, record_field_ir->GetAccess()); |
| record_field.Set("field_offset", (uint64_t)record_field_ir->GetOffset()); |
| return record_field; |
| } |
| |
| void IRToJsonConverter::AddRecordFields(JsonObject &record_type, |
| const RecordTypeIR *record_ir) { |
| JsonArray fields; |
| for (auto &&field_ir : record_ir->GetFields()) { |
| fields.append(ConvertRecordFieldIR(&field_ir)); |
| } |
| record_type.Set("fields", fields); |
| } |
| |
| static JsonObject |
| ConvertBaseSpecifierIR(const CXXBaseSpecifierIR &base_specifier_ir) { |
| JsonObject base_specifier; |
| base_specifier.Set("referenced_type", base_specifier_ir.GetReferencedType()); |
| base_specifier.Set("is_virtual", base_specifier_ir.IsVirtual()); |
| AddAccess(base_specifier, base_specifier_ir.GetAccess()); |
| return base_specifier; |
| } |
| |
| void IRToJsonConverter::AddBaseSpecifiers(JsonObject &record_type, |
| const RecordTypeIR *record_ir) { |
| JsonArray base_specifiers; |
| for (auto &&base_ir : record_ir->GetBases()) { |
| base_specifiers.append(ConvertBaseSpecifierIR(base_ir)); |
| } |
| record_type.Set("base_specifiers", base_specifiers); |
| } |
| |
| static JsonObject |
| ConvertVTableComponentIR(const VTableComponentIR &vtable_component_ir) { |
| JsonObject vtable_component; |
| AddVtableComponentKind(vtable_component, vtable_component_ir.GetKind()); |
| vtable_component.Set("component_value", |
| (int64_t)vtable_component_ir.GetValue()); |
| vtable_component.Set("mangled_component_name", vtable_component_ir.GetName()); |
| vtable_component.Set("is_pure", vtable_component_ir.GetIsPure()); |
| return vtable_component; |
| } |
| |
| void IRToJsonConverter::AddVTableLayout(JsonObject &record_type, |
| const RecordTypeIR *record_ir) { |
| JsonArray vtable_components; |
| for (auto &&vtable_component_ir : |
| record_ir->GetVTableLayout().GetVTableComponents()) { |
| vtable_components.append(ConvertVTableComponentIR(vtable_component_ir)); |
| } |
| record_type.Set("vtable_components", vtable_components); |
| } |
| |
| JsonObject IRToJsonConverter::ConvertRecordTypeIR(const RecordTypeIR *recordp) { |
| JsonObject record_type; |
| |
| AddAccess(record_type, recordp->GetAccess()); |
| AddRecordKind(record_type, recordp->GetRecordKind()); |
| record_type.Set("is_anonymous", recordp->IsAnonymous()); |
| AddTypeInfo(record_type, recordp); |
| AddRecordFields(record_type, recordp); |
| AddBaseSpecifiers(record_type, recordp); |
| AddVTableLayout(record_type, recordp); |
| AddTemplateInfo(record_type, recordp); |
| return record_type; |
| } |
| |
| void IRToJsonConverter::AddFunctionParametersAndSetReturnType( |
| JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) { |
| function.Set("return_type", cfunction_like_ir->GetReturnType()); |
| AddFunctionParameters(function, cfunction_like_ir); |
| } |
| |
| void IRToJsonConverter::AddFunctionParameters( |
| JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) { |
| JsonArray parameters; |
| for (auto &¶meter_ir : cfunction_like_ir->GetParameters()) { |
| JsonObject parameter; |
| parameter.Set("referenced_type", parameter_ir.GetReferencedType()); |
| parameter.Set("default_arg", parameter_ir.GetIsDefault()); |
| parameter.Set("is_this_ptr", parameter_ir.GetIsThisPtr()); |
| parameters.append(parameter); |
| } |
| function.Set("parameters", parameters); |
| } |
| |
| 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; |
| AddAccess(function, functionp->GetAccess()); |
| function.Set("linker_set_key", functionp->GetLinkerSetKey()); |
| function.Set("source_file", functionp->GetSourceFile()); |
| function.Set("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.Set("name", enum_field_ir->GetName()); |
| // Never omit enum values. |
| Json::Value &enum_field_value = enum_field["enum_field_value"]; |
| if (enum_field_ir->IsSigned()) { |
| enum_field_value = Json::Int64(enum_field_ir->GetSignedValue()); |
| } else { |
| enum_field_value = Json::UInt64(enum_field_ir->GetUnsignedValue()); |
| } |
| return enum_field; |
| } |
| |
| void IRToJsonConverter::AddEnumFields(JsonObject &enum_type, |
| const EnumTypeIR *enum_ir) { |
| JsonArray enum_fields; |
| for (auto &&field : enum_ir->GetFields()) { |
| enum_fields.append(ConvertEnumFieldIR(&field)); |
| } |
| enum_type.Set("enum_fields", enum_fields); |
| } |
| |
| JsonObject IRToJsonConverter::ConvertEnumTypeIR(const EnumTypeIR *enump) { |
| JsonObject enum_type; |
| AddAccess(enum_type, enump->GetAccess()); |
| enum_type.Set("underlying_type", enump->GetUnderlyingType()); |
| AddTypeInfo(enum_type, enump); |
| AddEnumFields(enum_type, enump); |
| return enum_type; |
| } |
| |
| JsonObject |
| IRToJsonConverter::ConvertGlobalVarIR(const GlobalVarIR *global_varp) { |
| JsonObject global_var; |
| global_var.Set("referenced_type", global_varp->GetReferencedType()); |
| global_var.Set("source_file", global_varp->GetSourceFile()); |
| global_var.Set("name", global_varp->GetName()); |
| global_var.Set("linker_set_key", global_varp->GetLinkerSetKey()); |
| AddAccess(global_var, 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.Set("is_const", qualtypep->IsConst()); |
| qualified_type.Set("is_volatile", qualtypep->IsVolatile()); |
| qualified_type.Set("is_restricted", qualtypep->IsRestricted()); |
| return qualified_type; |
| } |
| |
| JsonObject |
| IRToJsonConverter::ConvertBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) { |
| JsonObject builtin_type; |
| builtin_type.Set("is_unsigned", builtin_typep->IsUnsigned()); |
| builtin_type.Set("is_integral", builtin_typep->IsIntegralType()); |
| AddTypeInfo(builtin_type, builtin_typep); |
| return builtin_type; |
| } |
| |
| JsonObject |
| IRToJsonConverter::ConvertArrayTypeIR(const ArrayTypeIR *array_typep) { |
| JsonObject array_type; |
| array_type.Set("is_of_unknown_bound", array_typep->IsOfUnknownBound()); |
| 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 *elf_symbol_ir) { |
| std::string key; |
| switch (elf_symbol_ir->GetKind()) { |
| case ElfSymbolIR::ElfFunctionKind: |
| key = "elf_functions"; |
| break; |
| case ElfSymbolIR::ElfObjectKind: |
| key = "elf_objects"; |
| break; |
| default: |
| return false; |
| } |
| JsonObject elf_symbol; |
| elf_symbol.Set("name", elf_symbol_ir->GetName()); |
| AddElfSymbolBinding(elf_symbol, elf_symbol_ir->GetBinding()); |
| translation_unit_[key].append(elf_symbol); |
| return true; |
| } |
| |
| static std::string DumpJson(const JsonObject &obj) { |
| Json::StreamWriterBuilder factory; |
| factory["indentation"] = " "; |
| return Json::writeString(factory, obj); |
| } |
| |
| static void WriteTailTrimmedLinesToFile(const std::string &path, |
| const std::string &output_string) { |
| std::ofstream output_file(path); |
| size_t line_start = 0; |
| while (line_start < output_string.size()) { |
| size_t trailing_space_start = line_start; |
| size_t index; |
| for (index = line_start; |
| index < output_string.size() && output_string[index] != '\n'; |
| index++) { |
| if (output_string[index] != ' ') { |
| trailing_space_start = index + 1; |
| } |
| } |
| // Only write this line if this line contains non-whitespace characters. |
| if (trailing_space_start != line_start) { |
| output_file.write(output_string.data() + line_start, |
| trailing_space_start - line_start); |
| output_file.write("\n", 1); |
| } |
| line_start = index + 1; |
| } |
| } |
| |
| bool JsonIRDumper::Dump(const ModuleIR &module) { |
| DumpModule(module); |
| std::string output_string = DumpJson(translation_unit_); |
| WriteTailTrimmedLinesToFile(dump_path_, output_string); |
| 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(); |
| } |
| } |
| |
| std::unique_ptr<IRDumper> CreateJsonIRDumper(const std::string &dump_path) { |
| return std::make_unique<JsonIRDumper>(dump_path); |
| } |
| |
| |
| } // namespace repr |
| } // header_checker |