// Copyright (C) 2017 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_REPRESENTATION_H_ #define IR_REPRESENTATION_H_ #include #include #include #include #include #include #include namespace header_checker { namespace repr { // Classes which act as middle-men between clang AST parsing routines and // message format specific dumpers. template using AbiElementMap = std::map; template using AbiElementUnorderedMap = std::unordered_map; enum TextFormatIR { ProtobufTextFormat = 0, Json = 1, }; enum CompatibilityStatusIR { Compatible = 0, UnreferencedChanges = 1, Extension = 4, Incompatible = 8, ElfIncompatible = 16 }; static inline CompatibilityStatusIR operator|(CompatibilityStatusIR f, CompatibilityStatusIR s) { return static_cast( static_cast::type>(f) | static_cast::type>(s)); } static inline CompatibilityStatusIR operator&(CompatibilityStatusIR f, CompatibilityStatusIR s) { return static_cast( static_cast::type>(f) & static_cast::type>(s)); } enum AccessSpecifierIR { PublicAccess = 1, ProtectedAccess = 2, PrivateAccess = 3 }; enum LinkableMessageKind { RecordTypeKind, EnumTypeKind, PointerTypeKind, QualifiedTypeKind, ArrayTypeKind, LvalueReferenceTypeKind, RvalueReferenceTypeKind, BuiltinTypeKind, FunctionTypeKind, FunctionKind, GlobalVarKind }; template std::map CreateInverseMap(const std::map &m) { std::map inverse_map; for (auto it : m) { inverse_map[it.second] = it.first; } return inverse_map; } class LinkableMessageIR { public: virtual ~LinkableMessageIR() {} const std::string &GetLinkerSetKey() const { return linker_set_key_; } void SetSourceFile(const std::string &source_file) { source_file_ = source_file; } void SetLinkerSetKey(const std::string &linker_set_key) { linker_set_key_ = linker_set_key; } const std::string &GetSourceFile() const { return source_file_; } virtual LinkableMessageKind GetKind() const = 0; protected: // The source file where this message comes from. This will be an empty string // for built-in types. std::string source_file_; std::string linker_set_key_; }; class ReferencesOtherType { public: ReferencesOtherType(const std::string &referenced_type) : referenced_type_(referenced_type) {} ReferencesOtherType(std::string &&referenced_type) : referenced_type_(std::move(referenced_type)) {} ReferencesOtherType() {} void SetReferencedType(const std::string &referenced_type) { referenced_type_ = referenced_type; } const std::string &GetReferencedType() const { return referenced_type_; } protected: std::string referenced_type_; }; // TODO: Break this up into types with sizes and those without types? class TypeIR : public LinkableMessageIR, public ReferencesOtherType { public: virtual ~TypeIR() {} void SetSelfType(const std::string &self_type) { self_type_ = self_type; } const std::string &GetSelfType() const { return self_type_; } void SetName(const std::string &name) { name_ = name; } const std::string &GetName() const { return name_; } void SetSize(uint64_t size) { size_ = size; } uint64_t GetSize() const { return size_; } void SetAlignment(uint32_t alignment) { alignment_ = alignment; } uint32_t GetAlignment() const { return alignment_; } protected: std::string name_; std::string self_type_; uint64_t size_ = 0; uint32_t alignment_ = 0; }; class VTableComponentIR { public: enum Kind { VCallOffset = 0, VBaseOffset = 1, OffsetToTop = 2, RTTI = 3, FunctionPointer = 4, CompleteDtorPointer = 5, DeletingDtorPointer = 6, UnusedFunctionPointer = 7 }; VTableComponentIR(const std::string &name, Kind kind, int64_t value, bool is_pure) : component_name_(name), kind_(kind), value_(value), is_pure_(is_pure) {} VTableComponentIR() {} Kind GetKind() const { return kind_; } int64_t GetValue() const { return value_; } const std::string &GetName() const { return component_name_; } bool GetIsPure() const { return is_pure_; } protected: std::string component_name_; Kind kind_; int64_t value_ = 0; bool is_pure_; }; class VTableLayoutIR { public: void AddVTableComponent(VTableComponentIR &&vtable_component) { vtable_components_.emplace_back(std::move(vtable_component)); } const std::vector &GetVTableComponents() const { return vtable_components_; } uint64_t GetVTableNumEntries() const { return vtable_components_.size(); } protected: std::vector vtable_components_; }; class CXXBaseSpecifierIR : public ReferencesOtherType { public: CXXBaseSpecifierIR(const std::string &type, bool is_virtual, AccessSpecifierIR access) : ReferencesOtherType(type), is_virtual_(is_virtual), access_(access) {} CXXBaseSpecifierIR() {} bool IsVirtual() const { return is_virtual_; } AccessSpecifierIR GetAccess() const { return access_; } protected: bool is_virtual_ = false; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; }; class TemplateElementIR : public ReferencesOtherType { public: TemplateElementIR(std::string &&type) : ReferencesOtherType(std::move(type)) {} TemplateElementIR(const std::string &type) : ReferencesOtherType(type) {} TemplateElementIR() {} }; class TemplateInfoIR { public: void AddTemplateElement(TemplateElementIR &&element) { template_elements_.emplace_back(element); } const std::vector &GetTemplateElements() const { return template_elements_; } std::vector &GetTemplateElements() { return template_elements_; } protected: std::vector template_elements_; }; class TemplatedArtifactIR { public: void SetTemplateInfo(TemplateInfoIR &&template_info) { template_info_ = std::move(template_info); } const std::vector &GetTemplateElements() const { return template_info_.GetTemplateElements(); } std::vector &GetTemplateElements() { return template_info_.GetTemplateElements(); } protected: TemplateInfoIR template_info_; }; class RecordFieldIR : public ReferencesOtherType { public: RecordFieldIR(const std::string &name, const std::string &type, uint64_t offset, AccessSpecifierIR access) : ReferencesOtherType(type), name_(name), offset_(offset), access_(access) {} RecordFieldIR() {} const std::string &GetName() const { return name_; } uint64_t GetOffset() const { return offset_; } AccessSpecifierIR GetAccess() const { return access_; } protected: std::string name_; uint64_t offset_ = 0; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; }; class RecordTypeIR : public TypeIR, public TemplatedArtifactIR { public: enum RecordKind { struct_kind, class_kind, union_kind }; void AddRecordField(RecordFieldIR &&field) { fields_.emplace_back(std::move(field)); } void SetRecordFields(std::vector &&fields) { fields_ = std::move(fields); } void SetVTableLayout(VTableLayoutIR &&vtable_layout) { vtable_layout_ = std::move(vtable_layout); } const VTableLayoutIR &GetVTableLayout() const { return vtable_layout_; } void AddCXXBaseSpecifier(CXXBaseSpecifierIR &&base_specifier) { bases_.emplace_back(std::move(base_specifier)); } void SetCXXBaseSpecifiers(std::vector &&bases) { bases_ = std::move(bases); } const std::vector &GetBases() const { return bases_; } std::vector &GetBases() { return bases_; } void SetAccess(AccessSpecifierIR access) { access_ = access;} AccessSpecifierIR GetAccess() const { return access_; } const std::vector &GetFields() const { return fields_; } std::vector &GetFields() { return fields_; } LinkableMessageKind GetKind() const override { return LinkableMessageKind::RecordTypeKind; } uint64_t GetVTableNumEntries() const { return vtable_layout_.GetVTableNumEntries(); } void SetRecordKind(RecordKind record_kind) { record_kind_ = record_kind; } RecordKind GetRecordKind() const { return record_kind_; } void SetAnonymity(bool is_anonymous) { is_anonymous_ = is_anonymous; } bool IsAnonymous() const { return is_anonymous_; } protected: std::vector fields_; VTableLayoutIR vtable_layout_; std::vector bases_; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; bool is_anonymous_ = false; RecordKind record_kind_; }; class EnumFieldIR { public: EnumFieldIR(const std::string &name, int value) : name_(name), value_(value) {} const std::string &GetName() const { return name_; } int GetValue() const { return value_; } protected: std::string name_; int value_ = 0; }; class EnumTypeIR : public TypeIR { public: // Add Methods to get information from the IR. void AddEnumField(EnumFieldIR &&field) { fields_.emplace_back(std::move(field)); } void SetAccess(AccessSpecifierIR access) { access_ = access;} LinkableMessageKind GetKind() const override { return LinkableMessageKind::EnumTypeKind; } AccessSpecifierIR GetAccess() const { return access_; } void SetUnderlyingType(std::string &&underlying_type) { underlying_type_ = std::move(underlying_type); } void SetUnderlyingType(const std::string &underlying_type) { underlying_type_ = underlying_type; } const std::string &GetUnderlyingType() const { return underlying_type_; } void SetFields(std::vector &&fields) { fields_ = std::move(fields); } const std::vector &GetFields() const { return fields_; } protected: std::vector fields_; std::string underlying_type_; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; }; class ArrayTypeIR : public TypeIR { public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::ArrayTypeKind; } }; class PointerTypeIR : public TypeIR { public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::PointerTypeKind; } }; class BuiltinTypeIR : public TypeIR { public: void SetSignedness(bool is_unsigned) { is_unsigned_ = is_unsigned; } bool IsUnsigned() const { return is_unsigned_; } void SetIntegralType(bool is_integral_type) { is_integral_type_ = is_integral_type; } bool IsIntegralType() const { return is_integral_type_; } public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::BuiltinTypeKind; } protected: bool is_unsigned_ = false; bool is_integral_type_ = false; }; class LvalueReferenceTypeIR : public TypeIR { public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::LvalueReferenceTypeKind; } }; class RvalueReferenceTypeIR : public TypeIR { public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::RvalueReferenceTypeKind; } }; class QualifiedTypeIR : public TypeIR { public: void SetConstness(bool is_const) { is_const_ = is_const; } bool IsConst() const { return is_const_; } void SetRestrictedness(bool is_restricted) { is_restricted_ = is_restricted; } bool IsRestricted() const { return is_restricted_; } void SetVolatility(bool is_volatile) { is_volatile_ = is_volatile; } bool IsVolatile() const { return is_volatile_; } public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::QualifiedTypeKind; } protected: bool is_const_; bool is_restricted_; bool is_volatile_; }; class GlobalVarIR : public LinkableMessageIR , public ReferencesOtherType { public: // Add Methods to get information from the IR. void SetName(std::string &&name) { name_ = std::move(name); } void SetName(const std::string &name) { name_ = name; } const std::string &GetName() const { return name_; } void SetAccess(AccessSpecifierIR access) { access_ = access; } AccessSpecifierIR GetAccess() const { return access_; } LinkableMessageKind GetKind() const override { return LinkableMessageKind::GlobalVarKind; } protected: std::string name_; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; }; class ParamIR : public ReferencesOtherType { public: ParamIR(const std::string &type, bool is_default, bool is_this_ptr) : ReferencesOtherType(type) , is_default_(is_default), is_this_ptr_(is_this_ptr) {} bool GetIsDefault() const { return is_default_; } bool GetIsThisPtr() const { return is_this_ptr_; } protected: bool is_default_ = false; bool is_this_ptr_ = false; }; class CFunctionLikeIR { public: void SetReturnType(const std::string &type) { return_type_ = type; } const std::string &GetReturnType() const { return return_type_; } void AddParameter(ParamIR &¶meter) { parameters_.emplace_back(std::move(parameter)); } const std::vector &GetParameters() const { return parameters_; } std::vector &GetParameters() { return parameters_; } protected: std::string return_type_; // return type reference std::vector parameters_; }; class FunctionTypeIR : public TypeIR, public CFunctionLikeIR { public: LinkableMessageKind GetKind() const override { return LinkableMessageKind::FunctionTypeKind; } }; class FunctionIR : public LinkableMessageIR, public TemplatedArtifactIR, public CFunctionLikeIR { public: void SetAccess(AccessSpecifierIR access) { access_ = access; } AccessSpecifierIR GetAccess() const { return access_; } LinkableMessageKind GetKind() const override { return LinkableMessageKind::FunctionKind; } void SetName(const std::string &name) { name_ = name; } const std::string &GetName() const { return name_; } protected: std::string linkage_name_; std::string name_; AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess; }; class ElfSymbolIR { public: enum ElfSymbolKind { ElfFunctionKind, ElfObjectKind, }; enum ElfSymbolBinding { Weak, Global, }; enum ElfSymbolVisibility { Default, Protected, }; public: ElfSymbolIR(const std::string &name, ElfSymbolBinding binding) : name_(name), binding_(binding) {} virtual ~ElfSymbolIR() {} const std::string GetName() const { return name_; } ElfSymbolBinding GetBinding() const { return binding_; } virtual ElfSymbolKind GetKind() const = 0; protected: std::string name_; ElfSymbolBinding binding_; }; class ElfFunctionIR : public ElfSymbolIR { public: ElfFunctionIR(const std::string &name, ElfSymbolBinding binding) : ElfSymbolIR(name, binding) {} ElfSymbolKind GetKind() const override { return ElfFunctionKind; } }; class ElfObjectIR : public ElfSymbolIR { public: ElfObjectIR(const std::string &name, ElfSymbolBinding binding) : ElfSymbolIR(name, binding) {} ElfSymbolKind GetKind() const override { return ElfObjectKind; } }; class TypeDefinition { public: TypeDefinition(const TypeIR *type_ir, const std::string *compilation_unit_path) : type_ir_(type_ir), compilation_unit_path_(*compilation_unit_path) {} const TypeIR *type_ir_; const std::string &compilation_unit_path_; }; class ModuleIR { public: ModuleIR(const std::set *exported_headers) : exported_headers_(exported_headers) {} const std::string &GetCompilationUnitPath() const { return compilation_unit_path_; } void SetCompilationUnitPath(const std::string &compilation_unit_path) { compilation_unit_path_ = compilation_unit_path; } const AbiElementMap &GetFunctions() const { return functions_; } const AbiElementMap &GetGlobalVariables() const { return global_variables_; } const AbiElementMap &GetRecordTypes() const { return record_types_; } const AbiElementMap &GetFunctionTypes() const { return function_types_; } const AbiElementMap &GetEnumTypes() const { return enum_types_; } const AbiElementMap &GetLvalueReferenceTypes() const { return lvalue_reference_types_; } const AbiElementMap &GetRvalueReferenceTypes() const { return rvalue_reference_types_; } const AbiElementMap &GetQualifiedTypes() const { return qualified_types_; } const AbiElementMap &GetArrayTypes() const { return array_types_; } const AbiElementMap &GetPointerTypes() const { return pointer_types_; } const AbiElementMap &GetBuiltinTypes() const { return builtin_types_; } const AbiElementMap &GetElfFunctions() const { return elf_functions_; } const AbiElementMap &GetElfObjects() const { return elf_objects_; } const AbiElementMap &GetTypeGraph() const { return type_graph_; } const AbiElementUnorderedMap> & GetODRListMap() const { return odr_list_map_; } bool AddLinkableMessage(const LinkableMessageIR &); void AddFunction(FunctionIR &&function); void AddGlobalVariable(GlobalVarIR &&global_var); void AddRecordType(RecordTypeIR &&record_type); void AddFunctionType(FunctionTypeIR &&function_type); void AddEnumType(EnumTypeIR &&enum_type); void AddLvalueReferenceType(LvalueReferenceTypeIR &&lvalue_reference_type); void AddRvalueReferenceType(RvalueReferenceTypeIR &&rvalue_reference_type); void AddQualifiedType(QualifiedTypeIR &&qualified_type); void AddArrayType(ArrayTypeIR &&array_type); void AddPointerType(PointerTypeIR &&pointer_type); void AddBuiltinType(BuiltinTypeIR &&builtin_type); bool AddElfSymbol(const ElfSymbolIR &); void AddElfFunction(ElfFunctionIR &&elf_function); void AddElfObject(ElfObjectIR &&elf_object); // Find the compilation unit path of a RecordTypeIR, FunctionTypeIR, or // EnumTypeIR in odr_list_map_. Return an empty string if the type is not in // the map. std::string GetCompilationUnitPath(const TypeIR *type_ir) const; void AddToODRListMap(const std::string &key, const TypeIR *type_ir, const std::string &compilation_unit_path) { auto compilation_unit_path_it = compilation_unit_paths_.emplace(compilation_unit_path).first; auto map_it = odr_list_map_.find(key); TypeDefinition value(type_ir, &*compilation_unit_path_it); if (map_it == odr_list_map_.end()) { odr_list_map_.emplace(key, std::list({value})); return; } odr_list_map_[key].emplace_back(value); } private: bool IsLinkableMessageInExportedHeaders( const LinkableMessageIR *linkable_message) const; public: // File path to the compilation unit (*.sdump) std::string compilation_unit_path_; AbiElementMap functions_; AbiElementMap global_variables_; AbiElementMap record_types_; AbiElementMap function_types_; AbiElementMap enum_types_; // These maps which contain generic referring types as values are used while // looking up whether in the parent graph, a particular referring type refers // to a certain type id. The mechanism is useful while trying to determine // whether a generic referring type needs to be newly added to the parent // graph or not. AbiElementMap pointer_types_; AbiElementMap lvalue_reference_types_; AbiElementMap rvalue_reference_types_; AbiElementMap array_types_; AbiElementMap builtin_types_; AbiElementMap qualified_types_; AbiElementMap elf_functions_; AbiElementMap elf_objects_; // type-id -> LinkableMessageIR * map AbiElementMap type_graph_; // maps unique_id + source_file -> TypeDefinition AbiElementUnorderedMap> odr_list_map_; private: // The compilation unit paths referenced by odr_list_map_; std::set compilation_unit_paths_; const std::set *exported_headers_; }; } // namespace repr } // namespace header_checker #endif // IR_REPRESENTATION_H_