| // 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 <cassert> |
| #include <list> |
| #include <map> |
| #include <memory> |
| #include <regex> |
| #include <set> |
| #include <string> |
| #include <unordered_map> |
| #include <vector> |
| |
| // Classes which act as middle-men between clang AST parsing routines and |
| // message format specific dumpers. |
| namespace abi_util { |
| |
| template <typename T> |
| using AbiElementMap = std::map<std::string, T>; |
| |
| template <typename T> |
| using AbiElementUnorderedMap = std::unordered_map<std::string, T>; |
| |
| template <typename T> |
| using AbiElementList = std::list<T>; |
| |
| 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<CompatibilityStatusIR>( |
| static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) | |
| static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s)); |
| } |
| |
| static inline CompatibilityStatusIR operator&(CompatibilityStatusIR f, |
| CompatibilityStatusIR s) { |
| return static_cast<CompatibilityStatusIR>( |
| static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) & |
| static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s)); |
| } |
| |
| enum AccessSpecifierIR { |
| PublicAccess = 1, |
| ProtectedAccess = 2, |
| PrivateAccess = 3 |
| }; |
| |
| enum LinkableMessageKind { |
| RecordTypeKind, |
| EnumTypeKind, |
| PointerTypeKind, |
| QualifiedTypeKind, |
| ArrayTypeKind, |
| LvalueReferenceTypeKind, |
| RvalueReferenceTypeKind, |
| BuiltinTypeKind, |
| FunctionTypeKind, |
| FunctionKind, |
| GlobalVarKind |
| }; |
| |
| template <typename K, typename V> |
| std::map<V, K> CreateInverseMap(const std::map<K, V> &m) { |
| std::map<V, K> 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 TagTypeIR { |
| public: |
| const std::string &GetUniqueId() const { |
| return unique_id_; |
| } |
| |
| void SetUniqueId(const std::string &unique_id) { |
| unique_id_ = unique_id; |
| } |
| |
| protected: |
| std::string unique_id_; |
| }; |
| |
| 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<VTableComponentIR> &GetVTableComponents() const { |
| return vtable_components_; |
| } |
| |
| uint64_t GetVTableNumEntries() const { |
| return vtable_components_.size(); |
| } |
| |
| protected: |
| std::vector<VTableComponentIR> 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<TemplateElementIR> &GetTemplateElements() const { |
| return template_elements_; |
| } |
| |
| std::vector<TemplateElementIR> &GetTemplateElements() { |
| return template_elements_; |
| } |
| |
| protected: |
| std::vector<TemplateElementIR> template_elements_; |
| }; |
| |
| class TemplatedArtifactIR { |
| public: |
| void SetTemplateInfo(TemplateInfoIR &&template_info) { |
| template_info_ = std::move(template_info); |
| } |
| |
| const std::vector<TemplateElementIR> &GetTemplateElements() const { |
| return template_info_.GetTemplateElements(); |
| } |
| |
| std::vector<TemplateElementIR> &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 TagTypeIR { |
| public: |
| enum RecordKind { |
| struct_kind, |
| class_kind, |
| union_kind |
| }; |
| |
| void AddRecordField(RecordFieldIR &&field) { |
| fields_.emplace_back(std::move(field)); |
| } |
| |
| void SetRecordFields(std::vector<RecordFieldIR> &&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<CXXBaseSpecifierIR> &&bases) { |
| bases_ = std::move(bases); |
| } |
| |
| const std::vector<CXXBaseSpecifierIR> &GetBases() const { |
| return bases_; |
| } |
| |
| std::vector<CXXBaseSpecifierIR> &GetBases() { |
| return bases_; |
| } |
| |
| void SetAccess(AccessSpecifierIR access) { access_ = access;} |
| |
| AccessSpecifierIR GetAccess() const { |
| return access_; |
| } |
| |
| const std::vector<RecordFieldIR> &GetFields() const { |
| return fields_; |
| } |
| |
| std::vector<RecordFieldIR> &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<RecordFieldIR> fields_; |
| VTableLayoutIR vtable_layout_; |
| std::vector<CXXBaseSpecifierIR> 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 TagTypeIR { |
| 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<EnumFieldIR> &&fields) { |
| fields_ = std::move(fields); |
| } |
| |
| const std::vector<EnumFieldIR> &GetFields() const { |
| return fields_; |
| } |
| |
| protected: |
| std::vector<EnumFieldIR> 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<ParamIR> &GetParameters() const { |
| return parameters_; |
| } |
| |
| std::vector<ParamIR> &GetParameters() { |
| return parameters_; |
| } |
| |
| protected: |
| std::string return_type_; // return type reference |
| std::vector<ParamIR> 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 IRDumper { |
| public: |
| IRDumper(const std::string &dump_path) : dump_path_(dump_path) {} |
| |
| virtual ~IRDumper() {} |
| |
| static std::unique_ptr<IRDumper> CreateIRDumper( |
| TextFormatIR text_format, const std::string &dump_path); |
| |
| virtual bool AddLinkableMessageIR(const LinkableMessageIR *) = 0; |
| |
| virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *) = 0; |
| |
| virtual bool Dump() = 0; |
| |
| protected: |
| const std::string &dump_path_; |
| }; |
| |
| template <typename T> |
| inline std::string GetReferencedTypeMapKey(T &element) { |
| return element.GetReferencedType(); |
| } |
| |
| template <> |
| inline std::string GetReferencedTypeMapKey<ArrayTypeIR>(ArrayTypeIR &element) { |
| return element.GetReferencedType() + ":" + std::to_string(element.GetSize()); |
| } |
| |
| template <> |
| inline std::string GetReferencedTypeMapKey<BuiltinTypeIR>( |
| BuiltinTypeIR &element) { |
| return element.GetLinkerSetKey(); |
| } |
| |
| inline static std::string BoolToString(bool val) { |
| return val ? "true" : "false"; |
| } |
| |
| template <> |
| inline std::string GetReferencedTypeMapKey<QualifiedTypeIR>( |
| QualifiedTypeIR &element) { |
| return element.GetReferencedType() + BoolToString(element.IsRestricted()) + |
| BoolToString(element.IsVolatile()) + BoolToString(element.IsConst()); |
| } |
| |
| inline std::string GetODRListMapKey(const RecordTypeIR *record_type_ir) { |
| if (record_type_ir->IsAnonymous()) { |
| return record_type_ir->GetLinkerSetKey() + record_type_ir->GetUniqueId(); |
| } |
| return record_type_ir->GetUniqueId() + record_type_ir->GetSourceFile(); |
| } |
| |
| inline std::string GetODRListMapKey(const EnumTypeIR *enum_type_ir) { |
| return enum_type_ir->GetUniqueId() + enum_type_ir->GetSourceFile(); |
| } |
| |
| inline std::string GetODRListMapKey(const FunctionTypeIR *function_type_ir) { |
| return function_type_ir->GetLinkerSetKey(); |
| } |
| |
| // The map that is being updated maps special_key -> Type / Function/ GlobVar |
| // This special key is needed to distinguish what is being referenced. |
| template <typename T> |
| typename AbiElementMap<T>::iterator AddToMapAndTypeGraph( |
| T &&element, AbiElementMap<T> *map_to_update, |
| AbiElementMap<const TypeIR *> *type_graph) { |
| auto it = map_to_update->emplace(GetReferencedTypeMapKey(element), |
| std::move(element)); |
| type_graph->emplace(it.first->second.GetSelfType(), &(it.first->second)); |
| return it.first; |
| } |
| |
| class TextFormatToIRReader { |
| public: |
| struct MergeStatus { |
| MergeStatus(bool was_newly_added, const std::string &type_id) |
| : was_newly_added_(was_newly_added), type_id_(type_id) {} |
| |
| MergeStatus() {} |
| |
| // type_id_ always has the global_type_id corresponding to the type this |
| // MergeStatus corresponds to. For |
| // generic reference types (pointers, qual types, l(r)value references etc), |
| // this will be a proactively added type_id, which will be added to the |
| // parent type_graph if the we decide to add the referencing type to the |
| // parent post ODR checking. |
| bool was_newly_added_ = false; |
| |
| std::string type_id_; |
| }; |
| |
| public: |
| TextFormatToIRReader(const std::set<std::string> *exported_headers) |
| : exported_headers_(exported_headers) {} |
| |
| virtual ~TextFormatToIRReader() {} |
| |
| const AbiElementMap<FunctionIR> &GetFunctions() const { |
| return functions_; |
| } |
| |
| const AbiElementMap<GlobalVarIR> &GetGlobalVariables() const { |
| return global_variables_; |
| } |
| |
| const AbiElementMap<RecordTypeIR> &GetRecordTypes() const { |
| return record_types_; |
| } |
| |
| const AbiElementMap<FunctionTypeIR> &GetFunctionTypes() const { |
| return function_types_; |
| } |
| |
| const AbiElementMap<EnumTypeIR> &GetEnumTypes() const { |
| return enum_types_; |
| } |
| |
| const AbiElementMap<LvalueReferenceTypeIR> &GetLvalueReferenceTypes() const { |
| return lvalue_reference_types_; |
| } |
| |
| const AbiElementMap<RvalueReferenceTypeIR> &GetRvalueReferenceTypes() const { |
| return rvalue_reference_types_; |
| } |
| |
| const AbiElementMap<QualifiedTypeIR> &GetQualifiedTypes() const { |
| return qualified_types_; |
| } |
| |
| const AbiElementMap<ArrayTypeIR> &GetArrayTypes() const { |
| return array_types_; |
| } |
| |
| const AbiElementMap<PointerTypeIR> &GetPointerTypes() const { |
| return pointer_types_; |
| } |
| |
| const AbiElementMap<BuiltinTypeIR> &GetBuiltinTypes() const { |
| return builtin_types_; |
| } |
| |
| const AbiElementMap<ElfFunctionIR> &GetElfFunctions() const { |
| return elf_functions_; |
| } |
| |
| const AbiElementMap<ElfObjectIR> &GetElfObjects() const { |
| return elf_objects_; |
| } |
| |
| const AbiElementMap<const TypeIR *> &GetTypeGraph() const { |
| return type_graph_; |
| } |
| |
| const AbiElementUnorderedMap<std::list<const TypeIR *>> & |
| GetODRListMap() const { |
| return odr_list_map_; |
| } |
| |
| virtual bool ReadDump(const std::string &dump_file) = 0; |
| |
| void Merge(TextFormatToIRReader &&addend) { |
| MergeElements(&functions_, std::move(addend.functions_)); |
| MergeElements(&global_variables_, std::move(addend.global_variables_)); |
| MergeElements(&record_types_, std::move(addend.record_types_)); |
| MergeElements(&enum_types_, std::move(addend.enum_types_)); |
| MergeElements(&pointer_types_, std::move(addend.pointer_types_)); |
| MergeElements(&lvalue_reference_types_, |
| std::move(addend.lvalue_reference_types_)); |
| MergeElements(&rvalue_reference_types_, |
| std::move(addend.rvalue_reference_types_)); |
| MergeElements(&array_types_, std::move(addend.array_types_)); |
| MergeElements(&builtin_types_, std::move(addend.builtin_types_)); |
| MergeElements(&qualified_types_, std::move(addend.qualified_types_)); |
| } |
| |
| void AddToODRListMap(const std::string &key, const TypeIR *value); |
| |
| template <typename T> |
| MergeStatus MergeReferencingTypeInternalAndUpdateParent( |
| const TextFormatToIRReader &addend, const T *addend_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map, |
| AbiElementMap<T> *parent_map, const std::string &updated_self_type_id); |
| |
| MergeStatus DoesUDTypeODRViolationExist( |
| const TypeIR *ud_type, const TextFormatToIRReader &addend, |
| const std::string ud_type_unique_id, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map_); |
| |
| MergeStatus MergeReferencingTypeInternal( |
| const TextFormatToIRReader &addend, ReferencesOtherType *references_type, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus MergeReferencingType( |
| const TextFormatToIRReader &addend, const TypeIR *addend_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map, |
| const std::string &updated_self_type_id); |
| |
| MergeStatus MergeGenericReferringType( |
| const TextFormatToIRReader &addend, const TypeIR *addend_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| template <typename T> |
| std::pair<MergeStatus, typename AbiElementMap<T>::iterator> |
| UpdateUDTypeAccounting( |
| const T *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map, |
| AbiElementMap<T> *specific_type_map); |
| |
| MergeStatus MergeTypeInternal( |
| const TypeIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeCFunctionLikeDeps( |
| const TextFormatToIRReader &addend, CFunctionLikeIR *cfunction_like_ir, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus MergeFunctionType( |
| const FunctionTypeIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus MergeEnumType( |
| const EnumTypeIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeEnumDependencies( |
| const TextFormatToIRReader &addend, EnumTypeIR *added_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus MergeRecordAndDependencies( |
| const RecordTypeIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeRecordDependencies( |
| const TextFormatToIRReader &addend, RecordTypeIR *added_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeRecordFields( |
| const TextFormatToIRReader &addend, RecordTypeIR *added_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeRecordCXXBases( |
| const TextFormatToIRReader &addend, RecordTypeIR *added_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeRecordTemplateElements( |
| const TextFormatToIRReader &addend, RecordTypeIR *added_node, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus IsBuiltinTypeNodePresent( |
| const BuiltinTypeIR *builtin_type, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeGlobalVariable( |
| const GlobalVarIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeGlobalVariables( |
| const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeFunctionDeps( |
| FunctionIR *added_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeFunction( |
| const FunctionIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| void MergeGraphs(const TextFormatToIRReader &addend); |
| |
| void UpdateTextFormatToIRReaderTypeGraph( |
| const TypeIR *addend_node, const std::string &added_type_id, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus IsTypeNodePresent( |
| const TypeIR *addend_node, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *local_to_global_type_id_map); |
| |
| MergeStatus MergeType( |
| const TypeIR *addend_type, const TextFormatToIRReader &addend, |
| AbiElementMap<MergeStatus> *merged_types_cache); |
| |
| std::string AllocateNewTypeId(); |
| |
| static std::unique_ptr<TextFormatToIRReader> CreateTextFormatToIRReader( |
| TextFormatIR text_format, |
| const std::set<std::string> *exported_headers = nullptr); |
| |
| protected: |
| template <typename Augend, typename Addend> |
| inline void MergeElements(Augend *augend, Addend &&addend) { |
| augend->insert(std::make_move_iterator(addend.begin()), |
| std::make_move_iterator(addend.end())); |
| } |
| |
| bool IsLinkableMessageInExportedHeaders( |
| const LinkableMessageIR *linkable_message) const; |
| |
| AbiElementList<RecordTypeIR> record_types_list_; |
| AbiElementMap<FunctionIR> functions_; |
| AbiElementMap<GlobalVarIR> global_variables_; |
| AbiElementMap<RecordTypeIR> record_types_; |
| AbiElementMap<FunctionTypeIR> function_types_; |
| AbiElementMap<EnumTypeIR> enum_types_; |
| // These maps which contain generic referring types as values are used while |
| // looking up whether in the parent graph, a particular reffering 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<PointerTypeIR> pointer_types_; |
| AbiElementMap<LvalueReferenceTypeIR> lvalue_reference_types_; |
| AbiElementMap<RvalueReferenceTypeIR> rvalue_reference_types_; |
| AbiElementMap<ArrayTypeIR> array_types_; |
| AbiElementMap<BuiltinTypeIR> builtin_types_; |
| AbiElementMap<QualifiedTypeIR> qualified_types_; |
| AbiElementMap<ElfFunctionIR> elf_functions_; |
| AbiElementMap<ElfObjectIR> elf_objects_; |
| // type-id -> LinkableMessageIR * map |
| AbiElementMap<const TypeIR *> type_graph_; |
| // maps unique_id + source_file -> const TypeIR * |
| AbiElementUnorderedMap<std::list<const TypeIR *>> odr_list_map_; |
| const std::set<std::string> *exported_headers_; |
| uint64_t max_type_id_ = 0; |
| }; |
| |
| class DiffMessageIR { |
| public: |
| enum DiffKind { |
| Extension, // Applicable for enums. |
| Added, |
| Removed, |
| Referenced, |
| Unreferenced |
| }; |
| |
| public: |
| virtual ~DiffMessageIR() {} |
| |
| virtual LinkableMessageKind Kind() const = 0; |
| |
| void SetName(const std::string &name) { |
| name_ = name; |
| } |
| |
| const std::string &GetName() const { |
| return name_; |
| } |
| |
| protected: |
| std::string name_; |
| }; |
| |
| class AccessSpecifierDiffIR { |
| public: |
| AccessSpecifierDiffIR(AccessSpecifierIR old_access, |
| AccessSpecifierIR new_access) |
| : old_access_(old_access), new_access_(new_access) {} |
| |
| protected: |
| AccessSpecifierIR old_access_; |
| AccessSpecifierIR new_access_; |
| }; |
| |
| class TypeDiffIR { |
| public: |
| TypeDiffIR(std::pair<uint64_t, uint64_t> &&sizes, |
| std::pair<uint32_t, uint32_t> &&alignment) |
| : sizes_(std::move(sizes)), alignments_(std::move(alignment)) {} |
| |
| const std::pair<uint64_t, uint64_t> &GetSizes() const { |
| return sizes_; |
| } |
| |
| const std::pair<uint32_t, uint32_t> &GetAlignments() const { |
| return alignments_; |
| } |
| |
| protected: |
| std::pair<uint64_t, uint64_t> sizes_; |
| std::pair<uint32_t, uint32_t> alignments_; |
| }; |
| |
| class VTableLayoutDiffIR { |
| public: |
| VTableLayoutDiffIR(const VTableLayoutIR &old_layout, |
| const VTableLayoutIR &new_layout) |
| : old_layout_(old_layout), new_layout_(new_layout) {} |
| |
| const VTableLayoutIR &GetOldVTable() const { |
| return old_layout_; |
| } |
| |
| const VTableLayoutIR &GetNewVTable() const { |
| return new_layout_; |
| } |
| |
| protected: |
| const VTableLayoutIR &old_layout_; |
| const VTableLayoutIR &new_layout_; |
| }; |
| |
| class RecordFieldDiffIR { |
| public: |
| RecordFieldDiffIR(const RecordFieldIR *old_field, |
| const RecordFieldIR *new_field) |
| : old_field_(old_field), new_field_(new_field) {} |
| |
| const RecordFieldIR *GetOldField() const { |
| return old_field_; |
| } |
| |
| const RecordFieldIR *GetNewField() const { |
| return new_field_; |
| } |
| |
| const RecordFieldIR *old_field_; |
| const RecordFieldIR *new_field_; |
| }; |
| |
| class CXXBaseSpecifierDiffIR { |
| public: |
| CXXBaseSpecifierDiffIR( |
| const std::vector<CXXBaseSpecifierIR> &old_base_specifiers, |
| const std::vector<CXXBaseSpecifierIR> &new_base_specifiers) |
| : old_base_specifiers_(old_base_specifiers), |
| new_base_specifiers_(new_base_specifiers) {} |
| |
| const std::vector<CXXBaseSpecifierIR> &GetOldBases() const { |
| return old_base_specifiers_; |
| } |
| |
| const std::vector<CXXBaseSpecifierIR> &GetNewBases() const { |
| return new_base_specifiers_; |
| } |
| |
| protected: |
| const std::vector<CXXBaseSpecifierIR> &old_base_specifiers_; |
| const std::vector<CXXBaseSpecifierIR> &new_base_specifiers_; |
| }; |
| |
| class RecordTypeDiffIR : public DiffMessageIR { |
| public: |
| LinkableMessageKind Kind() const override { |
| return LinkableMessageKind::RecordTypeKind; |
| } |
| |
| void SetFieldDiffs(std::vector<RecordFieldDiffIR> &&field_diffs) { |
| field_diffs_ = std::move(field_diffs); |
| } |
| |
| const std::vector<RecordFieldDiffIR> &GetFieldDiffs() const { |
| return field_diffs_; |
| } |
| |
| void SetFieldsRemoved(std::vector<const RecordFieldIR *> &&fields_removed) { |
| fields_removed_ = std::move(fields_removed); |
| } |
| |
| void SetFieldsAdded(std::vector<const RecordFieldIR *> &&fields_added) { |
| fields_added_ = std::move(fields_added); |
| } |
| |
| const std::vector<const RecordFieldIR *> &GetFieldsRemoved() const { |
| return fields_removed_; |
| } |
| |
| const std::vector<const RecordFieldIR *> &GetFieldsAdded() const { |
| return fields_added_; |
| } |
| |
| void SetVTableLayoutDiff(std::unique_ptr<VTableLayoutDiffIR> &&vtable_diffs) { |
| vtable_diffs_ = std::move(vtable_diffs); |
| } |
| |
| void SetTypeDiff(std::unique_ptr<TypeDiffIR> &&type_diff) { |
| type_diff_ = std::move(type_diff); |
| } |
| |
| void SetAccessDiff(std::unique_ptr<AccessSpecifierDiffIR> &&access_diff) { |
| access_diff_ = std::move(access_diff); |
| } |
| |
| void SetBaseSpecifierDiffs( |
| std::unique_ptr<CXXBaseSpecifierDiffIR> &&base_diffs) { |
| base_specifier_diffs_ = std::move(base_diffs); |
| } |
| |
| bool DiffExists() const { |
| return (type_diff_ != nullptr) || (vtable_diffs_ != nullptr) || |
| (fields_removed_.size() != 0) || (field_diffs_.size() != 0) || |
| (access_diff_ != nullptr) || (base_specifier_diffs_ != nullptr); |
| } |
| |
| const TypeDiffIR *GetTypeDiff() const { |
| return type_diff_.get(); |
| } |
| |
| const VTableLayoutDiffIR *GetVTableLayoutDiff() const { |
| return vtable_diffs_.get(); |
| } |
| |
| const CXXBaseSpecifierDiffIR *GetBaseSpecifiers() const { |
| return base_specifier_diffs_.get(); |
| } |
| |
| protected: |
| // optional implemented with vector / std::unique_ptr. |
| std::unique_ptr<TypeDiffIR> type_diff_; |
| std::unique_ptr<VTableLayoutDiffIR> vtable_diffs_; |
| std::vector<RecordFieldDiffIR> field_diffs_; |
| std::vector<const RecordFieldIR *> fields_removed_; |
| std::vector<const RecordFieldIR *> fields_added_; |
| std::unique_ptr<AccessSpecifierDiffIR> access_diff_; |
| std::unique_ptr<CXXBaseSpecifierDiffIR> base_specifier_diffs_; |
| // Template Diffs are not needed since they will show up in the linker set |
| // key. |
| }; |
| |
| class EnumFieldDiffIR { |
| public: |
| EnumFieldDiffIR(const EnumFieldIR *old_field, const EnumFieldIR *new_field) |
| : old_field_(old_field), new_field_(new_field) {} |
| |
| const EnumFieldIR *GetOldField() const { |
| return old_field_; |
| } |
| |
| const EnumFieldIR *GetNewField() const { |
| return new_field_; |
| } |
| |
| protected: |
| const EnumFieldIR *old_field_; |
| const EnumFieldIR *new_field_; |
| }; |
| |
| class EnumTypeDiffIR : public DiffMessageIR { |
| public: |
| void SetFieldsRemoved(std::vector<const EnumFieldIR *> &&fields_removed) { |
| fields_removed_ = std::move(fields_removed); |
| } |
| |
| const std::vector<const EnumFieldIR *> &GetFieldsRemoved() const { |
| return fields_removed_; |
| } |
| |
| void SetFieldsAdded(std::vector<const EnumFieldIR *> &&fields_added) { |
| fields_added_ = std::move(fields_added); |
| } |
| |
| const std::vector<const EnumFieldIR *> &GetFieldsAdded() const { |
| return fields_added_; |
| } |
| |
| void SetFieldsDiff(std::vector<EnumFieldDiffIR> &&fields_diff) { |
| fields_diff_ = std::move(fields_diff); |
| } |
| |
| const std::vector<EnumFieldDiffIR> &GetFieldsDiff() const { |
| return fields_diff_; |
| } |
| |
| void SetUnderlyingTypeDiff( |
| std::unique_ptr<std::pair<std::string, std::string>> &&utype_diff) { |
| underlying_type_diff_ = std::move(utype_diff); |
| } |
| |
| const std::pair<std::string, std::string> *GetUnderlyingTypeDiff() const { |
| return underlying_type_diff_.get(); |
| } |
| |
| bool IsExtended() const { |
| if (fields_removed_.size() == 0 && fields_diff_.size() == 0 && |
| fields_added_.size() != 0) { |
| return true; |
| } |
| return false; |
| } |
| |
| bool IsIncompatible() const { |
| if (fields_removed_.size() != 0 || fields_diff_.size() != 0) { |
| return true; |
| } |
| return false; |
| } |
| |
| LinkableMessageKind Kind() const override { |
| return LinkableMessageKind::EnumTypeKind; |
| } |
| |
| protected: |
| // The underlying type can only be integral, so we just need to check for |
| // referenced type. |
| std::unique_ptr<std::pair<std::string, std::string>> underlying_type_diff_; |
| std::vector<const EnumFieldIR *> fields_removed_; |
| std::vector<const EnumFieldIR *> fields_added_; |
| std::vector<EnumFieldDiffIR> fields_diff_; |
| // Modifiable to allow implicit construction. |
| std::string name_; |
| }; |
| |
| class GlobalVarDiffIR : public DiffMessageIR { |
| public: |
| LinkableMessageKind Kind() const override { |
| return LinkableMessageKind::GlobalVarKind; |
| } |
| |
| GlobalVarDiffIR(const GlobalVarIR *old_global_var, |
| const GlobalVarIR *new_global_var) |
| : old_global_var_(old_global_var), new_global_var_(new_global_var) {} |
| |
| const GlobalVarIR *GetOldGlobalVar() const { |
| return old_global_var_; |
| } |
| |
| const GlobalVarIR *GetNewGlobalVar() const { |
| return new_global_var_; |
| } |
| |
| protected: |
| const GlobalVarIR *old_global_var_; |
| const GlobalVarIR *new_global_var_; |
| }; |
| |
| class FunctionDiffIR : public DiffMessageIR { |
| public: |
| FunctionDiffIR(const FunctionIR *old_function, |
| const FunctionIR *new_function) |
| : old_function_(old_function), new_function_(new_function) {} |
| |
| LinkableMessageKind Kind() const override { |
| return LinkableMessageKind::FunctionKind; |
| } |
| |
| const FunctionIR *GetOldFunction() const { |
| return old_function_; |
| } |
| |
| const FunctionIR *GetNewFunction() const { |
| return new_function_; |
| } |
| |
| protected: |
| const FunctionIR *old_function_; |
| const FunctionIR *new_function_; |
| }; |
| |
| class IRDiffDumper { |
| public: |
| typedef DiffMessageIR::DiffKind DiffKind; |
| |
| public: |
| IRDiffDumper(const std::string &dump_path) : dump_path_(dump_path) {} |
| |
| virtual ~IRDiffDumper() {} |
| |
| virtual bool AddDiffMessageIR(const DiffMessageIR *, |
| const std::string &type_stack, |
| DiffKind diff_kind) = 0; |
| |
| virtual bool AddLinkableMessageIR(const LinkableMessageIR *, |
| DiffKind diff_kind) = 0; |
| |
| virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *, |
| DiffKind diff_kind) = 0; |
| |
| virtual void AddLibNameIR(const std::string &name) = 0; |
| |
| virtual void AddArchIR(const std::string &arch) = 0; |
| |
| virtual void AddCompatibilityStatusIR(CompatibilityStatusIR status) = 0; |
| |
| virtual bool Dump() = 0; |
| |
| virtual CompatibilityStatusIR GetCompatibilityStatusIR() = 0; |
| |
| static std::unique_ptr<IRDiffDumper> CreateIRDiffDumper( |
| TextFormatIR, const std::string &dump_path); |
| |
| protected: |
| const std::string &dump_path_; |
| }; |
| |
| } // namespace abi_util |
| |
| #endif // IR_REPRESENTATION_H_ |