diff --git a/include/phasar/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h index 4067f05c1..4abfbd983 100644 --- a/include/phasar/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -131,7 +131,8 @@ template class CFGBase { void print(ByConstRef Fun, llvm::raw_ostream &OS) const { self().printImpl(Fun, OS); } - [[nodiscard]] nlohmann::json getAsJson(ByConstRef Fun) const { + [[nodiscard, deprecated("Please use printAsJson() instead")]] nlohmann::json + getAsJson(ByConstRef Fun) const { return self().getAsJsonImpl(Fun); } diff --git a/include/phasar/ControlFlow/CallGraph.h b/include/phasar/ControlFlow/CallGraph.h index 590b16964..7751aa963 100644 --- a/include/phasar/ControlFlow/CallGraph.h +++ b/include/phasar/ControlFlow/CallGraph.h @@ -11,18 +11,18 @@ #define PHASAR_CONTROLFLOW_CALLGRAPH_H #include "phasar/ControlFlow/CallGraphBase.h" +#include "phasar/ControlFlow/CallGraphData.h" #include "phasar/Utils/ByRef.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Function.h" #include "nlohmann/json.hpp" #include +#include #include #include @@ -58,7 +58,7 @@ class CallGraph : public CallGraphBase> { /// Deserializes a previously computed call-graph template [[nodiscard]] static CallGraph - deserialize(const nlohmann::json &PrecomputedCG, + deserialize(const CallGraphData &PrecomputedCG, FunctionGetter GetFunctionFromName, InstructionGetter GetInstructionFromId); @@ -86,12 +86,33 @@ class CallGraph : public CallGraphBase> { [[nodiscard]] bool empty() const noexcept { return CallersOf.empty(); } + template + void printAsJson(llvm::raw_ostream &OS, FunctionIdGetter GetFunctionId, + InstIdGetter GetInstructionId) const { + CallGraphData CGData; + CGData.FToFunctionVertexTy.reserve(CallersOf.size()); + + for (const auto &[Fun, Callers] : CallersOf) { + auto &JCallers = + CGData.FToFunctionVertexTy[std::invoke(GetFunctionId, Fun)]; + + CGData.FToFunctionVertexTy.reserve(Callers->size()); + for (const auto &CS : *Callers) { + JCallers.push_back(std::invoke(GetInstructionId, CS)); + } + } + + CGData.printAsJson(OS); + } + /// Creates a JSON representation of this call-graph suitable for presistent /// storage. /// Use the ctor taking a json object for deserialization template - [[nodiscard]] nlohmann::json getAsJson(FunctionIdGetter GetFunctionId, - InstIdGetter GetInstructionId) const { + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson(FunctionIdGetter GetFunctionId, + InstIdGetter GetInstructionId) const { nlohmann::json J; for (const auto &[Fun, Callers] : CallersOf) { @@ -254,18 +275,13 @@ template class CallGraphBuilder { template template [[nodiscard]] CallGraph -CallGraph::deserialize(const nlohmann::json &PrecomputedCG, +CallGraph::deserialize(const CallGraphData &PrecomputedCG, FunctionGetter GetFunctionFromName, InstructionGetter GetInstructionFromId) { - if (!PrecomputedCG.is_object()) { - PHASAR_LOG_LEVEL_CAT(ERROR, "CallGraph", "Invalid Json. Expected object"); - return {}; - } - CallGraphBuilder CGBuilder; - CGBuilder.reserve(PrecomputedCG.size()); + CGBuilder.reserve(PrecomputedCG.FToFunctionVertexTy.size()); - for (const auto &[FunName, CallerIDs] : PrecomputedCG.items()) { + for (const auto &[FunName, CallerIDs] : PrecomputedCG.FToFunctionVertexTy) { const auto &Fun = std::invoke(GetFunctionFromName, FunName); if (!Fun) { PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph", @@ -277,11 +293,10 @@ CallGraph::deserialize(const nlohmann::json &PrecomputedCG, CEdges->reserve(CallerIDs.size()); for (const auto &JId : CallerIDs) { - auto Id = JId.get(); - const auto &CS = std::invoke(GetInstructionFromId, Id); + const auto &CS = std::invoke(GetInstructionFromId, JId); if (!CS) { PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph", - "Invalid CAll-Instruction Id: " << Id); + "Invalid CAll-Instruction Id: " << JId); } CGBuilder.addCallEdge(CS, Fun); diff --git a/include/phasar/ControlFlow/CallGraphData.h b/include/phasar/ControlFlow/CallGraphData.h new file mode 100644 index 000000000..4321d7cea --- /dev/null +++ b/include/phasar/ControlFlow/CallGraphData.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace psr { +struct CallGraphData { + std::unordered_map> FToFunctionVertexTy{}; + + CallGraphData() noexcept = default; + void printAsJson(llvm::raw_ostream &OS); + + static CallGraphData deserializeJson(const llvm::Twine &Path); + static CallGraphData loadJsonString(llvm::StringRef JsonAsString); +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index 4291faf20..2f03bba60 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -106,8 +106,16 @@ template class ICFGBase { void print(llvm::raw_ostream &OS = llvm::outs()) const { self().printImpl(OS); } + + /// Prints the underlying call-graph as Json to the given output-stream + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const { + self().printAsJsonImpl(OS); + } + /// Returns the underlying call-graph as JSON - [[nodiscard]] nlohmann::json getAsJson() const { + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const { return self().getAsJsonImpl(); } diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h index 101718a42..c9bbb5b99 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h @@ -44,6 +44,8 @@ class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, using CFGBase::print; using ICFGBase::print; + using ICFGBase::printAsJson; + using CFGBase::getAsJson; using ICFGBase::getAsJson; @@ -64,7 +66,8 @@ class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, [[nodiscard]] llvm::SmallVector getReturnSitesOfCallAtImpl(n_t Inst) const; void printImpl(llvm::raw_ostream &OS) const; - [[nodiscard]] nlohmann::json getAsJsonImpl() const; + void printAsJsonImpl(llvm::raw_ostream &OS) const; + [[nodiscard, deprecated]] nlohmann::json getAsJsonImpl() const; [[nodiscard]] const CallGraph &getCallGraphImpl() const noexcept; llvm::LLVMContext BackwardRetsCtx; diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 92e964e14..ffac5e51f 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -35,8 +35,6 @@ #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" -#include "nlohmann/json.hpp" - #include namespace psr { @@ -99,7 +97,7 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { LLVMTypeHierarchy *TH = nullptr); explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG, + const CallGraphData &SerializedCG, LLVMTypeHierarchy *TH = nullptr); // Deleter of LLVMTypeHierarchy may be unknown here... @@ -141,6 +139,8 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { using CFGBase::print; using ICFGBase::print; + using ICFGBase::printAsJson; + using CFGBase::getAsJson; using ICFGBase::getAsJson; @@ -155,7 +155,8 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { [[nodiscard]] llvm::SmallVector getReturnSitesOfCallAtImpl(n_t Inst) const; void printImpl(llvm::raw_ostream &OS) const; - [[nodiscard]] nlohmann::json getAsJsonImpl() const; + void printAsJsonImpl(llvm::raw_ostream &OS) const; + [[nodiscard, deprecated]] nlohmann::json getAsJsonImpl() const; [[nodiscard]] const CallGraph &getCallGraphImpl() const noexcept { return CG; } diff --git a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h index a33b6e10d..4f0e943b7 100644 --- a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h +++ b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h @@ -176,7 +176,9 @@ struct GeneralStatistics { "instead")]] const std::set & getRetResInstructions() const; - [[nodiscard]] nlohmann::json getAsJson() const; + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const; void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; }; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h index c266980b1..83c22dbef 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h @@ -58,8 +58,9 @@ struct AliasInfoTraits * * @brief Represents the points-to graph of a function. */ -class LLVMAliasGraph : public AnalysisPropertiesMixin, - AliasInfoBaseUtils { +class [[deprecated("Use LLVMAliasSet Instead")]] LLVMAliasGraph + : public AnalysisPropertiesMixin, + AliasInfoBaseUtils { using traits_t = AliasInfoTraits; public: @@ -126,9 +127,9 @@ class LLVMAliasGraph : public AnalysisPropertiesMixin, * considered. False, if May and Must Aliases should be * considered. */ - explicit LLVMAliasGraph( - LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, - AliasAnalysisType PATy = AliasAnalysisType::CFLAnders); + explicit LLVMAliasGraph(LLVMProjectIRDB & IRDB, bool UseLazyEvaluation = true, + AliasAnalysisType PATy = + AliasAnalysisType::CFLAnders); /** * @brief Returns true if graph contains 0 nodes. @@ -162,15 +163,15 @@ class LLVMAliasGraph : public AnalysisPropertiesMixin, * @param F Function pointer * @return Vector with pointers. */ - std::vector - getPointersEscapingThroughReturnsForFunction(const llvm::Function *Fd) const; + std::vector getPointersEscapingThroughReturnsForFunction( + const llvm::Function *Fd) const; /** * @brief Checks if a given value is represented by a vertex in the points-to * graph. * @return True, the points-to graph contains the given value. */ - bool containsValue(llvm::Value *V); + bool containsValue(llvm::Value * V); /** * The value-vertex-map maps each Value of the points-to graph to @@ -192,8 +193,8 @@ class LLVMAliasGraph : public AnalysisPropertiesMixin, const graph_t &PAG; }; - static inline PointerVertexOrEdgePrinter - makePointerVertexOrEdgePrinter(const graph_t &PAG) { + static inline PointerVertexOrEdgePrinter makePointerVertexOrEdgePrinter( + const graph_t &PAG) { return {PAG}; } @@ -220,9 +221,9 @@ class LLVMAliasGraph : public AnalysisPropertiesMixin, AliasSetPtrTy getAliasSet(const llvm::Value *V, const llvm::Instruction *I = nullptr); - AllocationSiteSetPtrTy - getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false, - const llvm::Instruction *I = nullptr); + AllocationSiteSetPtrTy getReachableAllocationSites( + const llvm::Value *V, bool IntraProcOnly = false, + const llvm::Instruction *I = nullptr); [[nodiscard]] bool isInReachableAllocationSites( const llvm::Value *V, const llvm::Value *PotentialValue, @@ -251,7 +252,7 @@ class LLVMAliasGraph : public AnalysisPropertiesMixin, void computeAliasGraph(const llvm::Value *V); - void computeAliasGraph(llvm::Function *F); + void computeAliasGraph(llvm::Function * F); struct AllocationSiteDFSVisitor; struct ReachabilityDFSVisitor; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h index 0775e98d2..55c150df7 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_POINTER_LLVMALIASSET_H #define PHASAR_PHASARLLVM_POINTER_LLVMALIASSET_H +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h" #include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" #include "phasar/Pointer/AliasInfoBase.h" #include "phasar/Pointer/AliasInfoTraits.h" @@ -95,7 +96,11 @@ class LLVMAliasSet : public AnalysisPropertiesMixin, void print(llvm::raw_ostream &OS = llvm::outs()) const; - [[nodiscard]] nlohmann::json getAsJson() const; + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const; + + [[nodiscard]] LLVMAliasSetData getLLVMAliasSetData() const; void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h new file mode 100644 index 000000000..bf924e39c --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMALIASSETDATA_H +#define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMALIASSETDATA_H + +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +struct LLVMAliasSetData { + std::vector> AliasSets; + std::vector AnalyzedFunctions; + + LLVMAliasSetData() noexcept = default; + void printAsJson(llvm::raw_ostream &OS); + + static LLVMAliasSetData deserializeJson(const llvm::Twine &Path); + static LLVMAliasSetData loadJsonString(llvm::StringRef JsonAsString); +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMALIASSETDATA_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h index 0048e2ecf..b1bc594ed 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_DIBASEDTYPEHIERARCHY_H #define PHASAR_PHASARLLVM_TYPEHIERARCHY_DIBASEDTYPEHIERARCHY_H +#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" #include "phasar/TypeHierarchy/TypeHierarchy.h" @@ -32,6 +33,8 @@ class DIBasedTypeHierarchy using f_t = const llvm::Function *; explicit DIBasedTypeHierarchy(const LLVMProjectIRDB &IRDB); + explicit DIBasedTypeHierarchy(const LLVMProjectIRDB *IRDB, + const DIBasedTypeHierarchyData &SerializedData); ~DIBasedTypeHierarchy() override = default; [[nodiscard]] bool hasType(ClassType Type) const override { @@ -67,9 +70,7 @@ class DIBasedTypeHierarchy [[nodiscard]] const auto &getAllVTables() const noexcept { return VTables; } - [[nodiscard]] std::string getTypeName(ClassType Type) const override { - return Type->getName().str(); - } + [[nodiscard]] std::string getTypeName(ClassType Type) const override; [[nodiscard]] bool hasVFTable(ClassType Type) const override; @@ -93,9 +94,18 @@ class DIBasedTypeHierarchy */ void printAsDot(llvm::raw_ostream &OS = llvm::outs()) const; - [[nodiscard]] nlohmann::json getAsJson() const override; + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const override; + + /** + * @brief Prints the class hierarchy to an ostream in json format. + * @param an outputstream + */ + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const override; private: + [[nodiscard]] DIBasedTypeHierarchyData getTypeHierarchyData() const; [[nodiscard]] llvm::iterator_range subTypesOf(size_t TypeIdx) const noexcept; diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h new file mode 100644 index 000000000..52cd85569 --- /dev/null +++ b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_DIBASEDTYPEHIERARCHYDATA_H +#define PHASAR_PHASARLLVM_TYPEHIERARCHY_DIBASEDTYPEHIERARCHYDATA_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace psr { +struct DIBasedTypeHierarchyData { + // DITypes and llvm::Function * are serialized by serializing their names and + // using the DebugInfoFinder to deserialize them + + std::vector VertexTypes; + std::vector> TransitiveDerivedIndex; + std::vector Hierarchy; + std::vector> VTables; + + DIBasedTypeHierarchyData() noexcept = default; + void printAsJson(llvm::raw_ostream &OS); + + static DIBasedTypeHierarchyData deserializeJson(const llvm::Twine &Path); + static DIBasedTypeHierarchyData loadJsonString(llvm::StringRef JsonAsString); +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TYPEHIERARCHY_DIBASEDTYPEHIERARCHYDATA_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h index c5b744e12..f54153121 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h @@ -17,10 +17,12 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHY_H_ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHY_H_ +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" #include "phasar/TypeHierarchy/TypeHierarchy.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" @@ -125,7 +127,7 @@ class LLVMTypeHierarchy static bool isStruct(llvm::StringRef TypeName); std::vector - getSubTypes(const llvm::Module &M, const llvm::StructType &Type); + getSubTypes(const llvm::Module &M, const llvm::StructType &Type) const; std::vector getVirtualFunctions(const llvm::Module &M, const llvm::StructType &Type); @@ -140,6 +142,8 @@ class LLVMTypeHierarchy * @param IRDB ProjectIRCompiledDB object. */ LLVMTypeHierarchy(LLVMProjectIRDB &IRDB); + LLVMTypeHierarchy(LLVMProjectIRDB &IRDB, + const LLVMTypeHierarchyData &SerializedData); /** * @brief Creates a LLVMStructTypeHierarchy based on the @@ -193,6 +197,10 @@ class LLVMTypeHierarchy [[nodiscard]] bool hasVFTable(const llvm::StructType *Type) const override; + [[nodiscard]] const auto &getAllVTables() const noexcept { + return TypeVFTMap; + } + [[nodiscard]] const LLVMVFTable * getVFTable(const llvm::StructType *Type) const override; @@ -204,7 +212,9 @@ class LLVMTypeHierarchy void print(llvm::raw_ostream &OS = llvm::outs()) const override; - [[nodiscard]] nlohmann::json getAsJson() const override; + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const override; // void mergeWith(LLVMTypeHierarchy &Other); @@ -223,7 +233,7 @@ class LLVMTypeHierarchy * @brief Prints the class hierarchy to an ostream in json format. * @param an outputstream */ - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const override; // void printGraphAsDot(llvm::raw_ostream &out); diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.h new file mode 100644 index 000000000..b9757d0b3 --- /dev/null +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHYDATA_H_ +#define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHYDATA_H_ + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +struct LLVMTypeHierarchyData { + std::string PhasarConfigJsonTypeHierarchyID; + // key = vertex, value = edges + llvm::StringMap> TypeGraph; + + LLVMTypeHierarchyData() noexcept = default; + void printAsJson(llvm::raw_ostream &OS); + + static LLVMTypeHierarchyData deserializeJson(const llvm::Twine &Path); + static LLVMTypeHierarchyData loadJsonString(llvm::StringRef JsonAsString); +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHYDATA_H_ diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h index fd55a006a..20bfb5196 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLE_H_ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLE_H_ +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h" #include "phasar/TypeHierarchy/VFTable.h" #include "nlohmann/json.hpp" @@ -36,6 +37,9 @@ class LLVMVFTable : public VFTable { std::vector VFT; public: + // NOLINTNEXTLINE + static constexpr char NullFunName[] = "__null__"; + LLVMVFTable() = default; LLVMVFTable(std::vector Fs) : VFT(std::move(Fs)) {} ~LLVMVFTable() override = default; @@ -66,7 +70,13 @@ class LLVMVFTable : public VFTable { void print(llvm::raw_ostream &OS) const override; - [[nodiscard]] nlohmann::json getAsJson() const override; + [[nodiscard]] [[deprecated( + "Please use printAsJson() instead")]] nlohmann::json + getAsJson() const override; + + [[nodiscard]] LLVMVFTableData getVFTableData() const; + + void printAsJson(llvm::raw_ostream &OS) const override; [[nodiscard]] std::vector::iterator begin() { return VFT.begin(); diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h new file mode 100644 index 000000000..e3997d9f5 --- /dev/null +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLEDATA_H_ +#define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLEDATA_H_ + +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +struct LLVMVFTableData { + std::vector VFT; + + LLVMVFTableData() noexcept = default; + void printAsJson(llvm::raw_ostream &OS) const; + + static LLVMVFTableData deserializeJson(const llvm::Twine &Path); + static LLVMVFTableData loadJsonString(llvm::StringRef JsonAsString); +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLEDATA_H_ diff --git a/include/phasar/Pointer/AliasInfo.h b/include/phasar/Pointer/AliasInfo.h index ba9fa480f..3ab63412e 100644 --- a/include/phasar/Pointer/AliasInfo.h +++ b/include/phasar/Pointer/AliasInfo.h @@ -21,8 +21,6 @@ #include "llvm/Support/TypeName.h" #include "llvm/Support/raw_ostream.h" -#include "nlohmann/json.hpp" - #include #include @@ -140,7 +138,8 @@ class AliasInfoRef : public AnalysisPropertiesMixin> { VT->Print(AA, OS); } - [[nodiscard]] nlohmann::json getAsJson() const { + [[nodiscard, deprecated("Use printAsJson() instead")]] nlohmann::json + getAsJson() const { assert(VT != nullptr); return VT->GetAsJson(AA); } @@ -240,8 +239,14 @@ class AliasInfoRef : public AnalysisPropertiesMixin> { [](const void *AA, llvm::raw_ostream &OS) { static_cast(AA)->print(OS); }, - [](const void *AA) { - return static_cast(AA)->getAsJson(); + [](const void *AA) noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + if constexpr (has_getAsJson::value) { + return static_cast(AA)->getAsJson(); + } + return nlohmann::json(); +#pragma GCC diagnostic pop }, [](const void *AA, llvm::raw_ostream &OS) { static_cast(AA)->printAsJson(OS); diff --git a/include/phasar/Pointer/AliasInfoBase.h b/include/phasar/Pointer/AliasInfoBase.h index 039a212ed..8e57f200c 100644 --- a/include/phasar/Pointer/AliasInfoBase.h +++ b/include/phasar/Pointer/AliasInfoBase.h @@ -49,7 +49,7 @@ auto testAliasInfo( CAI.isInterProcedural(), CAI.getAliasAnalysisType(), AI.alias(*VT, *VT, *NT), AI.getAliasSet(*VT, *NT), AI.getReachableAllocationSites(*VT, true, *NT), - AI.isInReachableAllocationSites(*VT, *VT, true, *NT), CAI.getAsJson(), + AI.isInReachableAllocationSites(*VT, *VT, true, *NT), CAI.getAnalysisProperties(), CAI.isContextSensitive(), CAI.isFieldSensitive(), CAI.isFlowSensitive())); template @@ -69,7 +69,7 @@ struct IsAliasInfo< std::tuple::AliasSetPtrTy, typename AliasInfoTraits::AllocationSiteSetPtrTy, bool, - nlohmann::json, AnalysisProperties, bool, bool, bool>, + AnalysisProperties, bool, bool, bool>, decltype(testAliasInfo(std::declval(), std::declval()))>>> : std::true_type { }; diff --git a/include/phasar/TypeHierarchy/TypeHierarchy.h b/include/phasar/TypeHierarchy/TypeHierarchy.h index e3f44e879..f2bf769d3 100644 --- a/include/phasar/TypeHierarchy/TypeHierarchy.h +++ b/include/phasar/TypeHierarchy/TypeHierarchy.h @@ -51,7 +51,11 @@ template class TypeHierarchy { virtual void print(llvm::raw_ostream &OS = llvm::outs()) const = 0; - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; + [[nodiscard, + deprecated("Please use printAsJson() instead")]] virtual nlohmann::json + getAsJson() const = 0; + + virtual void printAsJson(llvm::raw_ostream &OS) const = 0; }; template diff --git a/include/phasar/TypeHierarchy/VFTable.h b/include/phasar/TypeHierarchy/VFTable.h index 56334171b..83c544dbc 100644 --- a/include/phasar/TypeHierarchy/VFTable.h +++ b/include/phasar/TypeHierarchy/VFTable.h @@ -38,7 +38,11 @@ template class VFTable { virtual void print(llvm::raw_ostream &OS) const = 0; - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; + [[nodiscard, + deprecated("Please use printAsJson() instead")]] virtual nlohmann::json + getAsJson() const = 0; + + virtual void printAsJson(llvm::raw_ostream &OS) const = 0; }; template diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 2c6d771c7..8be00acd3 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -13,6 +13,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" +#include "nlohmann/json.hpp" + #include #include #include @@ -246,6 +248,12 @@ template using type_identity_t = typename type_identity::type; template static constexpr size_t variant_idx = detail::variant_idx::value; +template +struct has_getAsJson : std::false_type {}; // NOLINT +template +struct has_getAsJson().getAsJson())> + : std::true_type {}; // NOLINT + struct TrueFn { template [[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept { diff --git a/lib/ControlFlow/CMakeLists.txt b/lib/ControlFlow/CMakeLists.txt index 39084cd11..d6f91baa6 100644 --- a/lib/ControlFlow/CMakeLists.txt +++ b/lib/ControlFlow/CMakeLists.txt @@ -2,6 +2,8 @@ file(GLOB_RECURSE CONTROLFLOW_SRC *.h *.cpp) add_phasar_library(phasar_controlflow ${CONTROLFLOW_SRC} + LINKS + phasar_utils LLVM_LINK_COMPONENTS Support LINK_PRIVATE nlohmann_json::nlohmann_json ) diff --git a/lib/ControlFlow/CallGraphData.cpp b/lib/ControlFlow/CallGraphData.cpp new file mode 100644 index 000000000..8b0f13a85 --- /dev/null +++ b/lib/ControlFlow/CallGraphData.cpp @@ -0,0 +1,57 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#include "phasar/ControlFlow/CallGraphData.h" + +#include "phasar/Utils/IO.h" +#include "phasar/Utils/NlohmannLogging.h" + +namespace psr { +static CallGraphData getDataFromJson(const nlohmann::json &Json) { + CallGraphData ToReturn; + + // map F to vector of n_t's + for (const auto &[FVal, FunctionVertexTyVals] : + Json.get()) { + auto &FValMappedVector = ToReturn.FToFunctionVertexTy[FVal]; + FValMappedVector.reserve(FunctionVertexTyVals.size()); + + for (const auto &Curr : FunctionVertexTyVals) { + FValMappedVector.push_back(Curr.get()); + } + } + + return ToReturn; +} + +void CallGraphData::printAsJson(llvm::raw_ostream &OS) { + nlohmann::json JSON; + + for (const auto &[Fun, Callers] : FToFunctionVertexTy) { + auto &JCallers = JSON[Fun]; + + for (const auto &CS : Callers) { + JCallers.push_back(CS); + } + } + + OS << JSON << '\n'; +} + +CallGraphData CallGraphData::deserializeJson(const llvm::Twine &Path) { + return getDataFromJson(readJsonFile(Path)); +} + +CallGraphData CallGraphData::loadJsonString(llvm::StringRef JsonAsString) { + auto ToStringify = + nlohmann::json::parse(JsonAsString.begin(), JsonAsString.end()); + return getDataFromJson(ToStringify); +} + +} // namespace psr diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index fd77d2ec5..98f44f609 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -72,7 +72,7 @@ emitRequestedHelperAnalysisResults(AnalysisController::ControllerData &Data) { } if (EmitterOptions & AnalysisControllerEmitterOptions::EmitCGAsJson) { WithResultFileOrStdout("/psr-cg.json", - [&HA](auto &OS) { OS << HA.getICFG().getAsJson(); }); + [&HA](auto &OS) { HA.getICFG().printAsJson(OS); }); } if (EmitterOptions & diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp index 0ca199d25..f029a39d9 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp @@ -64,6 +64,10 @@ void LLVMBasedBackwardICFG::printImpl(llvm::raw_ostream &OS) const { ForwardICFG->print(OS); } +void LLVMBasedBackwardICFG::printAsJsonImpl(llvm::raw_ostream &OS) const { + ForwardICFG->printAsJson(OS); +} + nlohmann::json LLVMBasedBackwardICFG::getAsJsonImpl() const { return ForwardICFG->getAsJson(); } diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index eadc987db..1c4b37376 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -11,6 +11,7 @@ #include "phasar/ControlFlow/CallGraph.h" #include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/ControlFlow/CallGraphData.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" @@ -383,7 +384,7 @@ LLVMBasedICFG::LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB, } LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG, + const CallGraphData &SerializedCG, LLVMTypeHierarchy *TH) : CG(CallGraph::deserialize( SerializedCG, @@ -467,7 +468,13 @@ void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const { [](n_t CS) { return llvmIRToStableString(CS); }); } -[[nodiscard]] nlohmann::json LLVMBasedICFG::getAsJsonImpl() const { +void LLVMBasedICFG::printAsJsonImpl(llvm::raw_ostream &OS) const { + CG.printAsJson( + OS, [](f_t F) { return F->getName().str(); }, + [this](n_t Inst) { return IRDB->getInstructionId(Inst); }); +} + +nlohmann::json LLVMBasedICFG::getAsJsonImpl() const { return CG.getAsJson( [](f_t F) { return F->getName().str(); }, [this](n_t Inst) { return IRDB->getInstructionId(Inst); }); diff --git a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp index e853bf724..ed64e4784 100644 --- a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp +++ b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" @@ -289,31 +290,55 @@ GeneralStatistics::getRetResInstructions() const { } void GeneralStatistics::printAsJson(llvm::raw_ostream &OS) const { - OS << getAsJson() << '\n'; + nlohmann::json Json; + + Json["ModuleName"] = ModuleName; + Json["Instructions"] = Instructions; + Json["Functions"] = Functions; + Json["ExternalFunctions"] = ExternalFunctions; + Json["FunctionDefinitions"] = FunctionDefinitions; + Json["AddressTakenFunctions"] = AddressTakenFunctions; + Json["Globals"] = Globals; + Json["GlobalConsts"] = GlobalConsts; + Json["GlobalVariables"] = Globals - GlobalConsts; + Json["ExternalGlobals"] = ExternalGlobals; + Json["GlobalsDefinitions"] = GlobalsDefinitions; + Json["AllocaInstructions"] = AllocaInstructions.size(); + Json["CallSites"] = CallSites; + Json["IndirectCallSites"] = IndCalls; + Json["NumInlineAssembly"] = NumInlineAsm; + Json["MemoryIntrinsics"] = MemIntrinsics; + Json["DebugIntrinsics"] = DebugIntrinsics; + Json["Switches"] = Switches; + Json["GetElementPtrs"] = GetElementPtrs; + Json["PhiNodes"] = PhiNodes; + Json["LandingPads"] = LandingPads; + Json["BasicBlocks"] = BasicBlocks; + Json["TotalNumPredecessorBBs"] = TotalNumPredecessorBBs; + Json["Branches"] = Branches; + Json["AvgPredPerBasicBlock"] = + double(TotalNumPredecessorBBs) / double(BasicBlocks); + Json["MaxPredPerBasicBlock"] = MaxNumPredecessorBBs; + Json["AvgSuccPerBasicBlock"] = + double(TotalNumSuccessorBBs) / double(BasicBlocks); + Json["MaxSuccPerBasicBlock"] = MaxNumSuccessorBBs; + Json["AvgOperandsPerInst"] = double(TotalNumOperands) / double(Instructions); + Json["MaxNumOperandsPerInst"] = MaxNumOperands; + Json["AvgUsesPerInst"] = double(TotalNumUses) / double(Instructions); + Json["MaxUsesPerInst"] = MaxNumUses; + Json["NumInstWithMultipleUses"] = NumInstWithMultipleUses; + Json["NonVoidInsts"] = NonVoidInsts; + Json["NumInstsUsedOutsideBB"] = NumInstsUsedOutsideBB; + + OS << Json << '\n'; } nlohmann::json GeneralStatistics::getAsJson() const { - nlohmann::json J; - J["ModuleName"] = ModuleName; - J["Instructions"] = Instructions; - J["Functions"] = Functions; - J["ExternalFunctions"] = ExternalFunctions; - J["FunctionDefinitions"] = FunctionDefinitions; - J["AddressTakenFunctions"] = AddressTakenFunctions; - J["AllocaInstructions"] = AllocaInstructions.size(); - J["CallSites"] = CallSites; - J["IndirectCallSites"] = IndCalls; - J["MemoryIntrinsics"] = MemIntrinsics; - J["DebugIntrinsics"] = DebugIntrinsics; - J["InlineAssembly"] = NumInlineAsm; - J["GlobalVariables"] = Globals; - J["Branches"] = Branches; - J["GetElementPtrs"] = GetElementPtrs; - J["BasicBlocks"] = BasicBlocks; - J["PhiNodes"] = PhiNodes; - J["LandingPads"] = LandingPads; - J["GlobalConsts"] = GlobalConsts; - return J; + std::string GeneralStatisticsAsString; + llvm::raw_string_ostream Stream(GeneralStatisticsAsString); + printAsJson(Stream); + + return nlohmann::json::parse(GeneralStatisticsAsString); } } // namespace psr @@ -377,6 +402,7 @@ llvm::raw_ostream &psr::operator<<(llvm::raw_ostream &OS, << AlignNum("Phi Nodes", Statistics.PhiNodes) << AlignNum("LandingPads", Statistics.LandingPads) << AlignNum("Basic Blocks", Statistics.BasicBlocks) + << AlignNum("Branches", Statistics.Branches) << AlignNum("Avg #pred per BasicBlock", Statistics.TotalNumPredecessorBBs, Statistics.BasicBlocks) << AlignNum("Max #pred per BasicBlock", diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp index 83e796b6b..40b95feaa 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp @@ -723,8 +723,35 @@ nlohmann::json LLVMAliasSet::getAsJson() const { return J; } +LLVMAliasSetData LLVMAliasSet::getLLVMAliasSetData() const { + LLVMAliasSetData Data; + + /// Serialize the AliasSets + for (const AliasSetTy *PTS : Owner.getAllAliasSets()) { + + std::vector PtsJson{}; + for (const auto *Alias : *PTS) { + auto Id = getMetaDataID(Alias); + if (Id != "-1") { + PtsJson.push_back(std::move(Id)); + } + } + if (!PtsJson.empty()) { + Data.AliasSets.push_back(std::move(PtsJson)); + } + } + + /// Serialize the AnalyzedFunctions + for (const auto *F : AnalyzedFunctions) { + Data.AnalyzedFunctions.push_back(F->getName().str()); + } + + return Data; +} + void LLVMAliasSet::printAsJson(llvm::raw_ostream &OS) const { - OS << getAsJson(); + LLVMAliasSetData Data = getLLVMAliasSetData(); + Data.printAsJson(OS); } void LLVMAliasSet::print(llvm::raw_ostream &OS) const { diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSetData.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSetData.cpp new file mode 100644 index 000000000..4f807c581 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSetData.cpp @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h" + +#include "phasar/Utils/IO.h" +#include "phasar/Utils/NlohmannLogging.h" + +namespace psr { + +static LLVMAliasSetData getDataFromJson(const nlohmann::json &Json) { + LLVMAliasSetData Data; + + for (const auto &Value : Json["AliasSets"]) { + Data.AliasSets.push_back(Value.get>()); + } + + for (const auto &Value : Json["AnalyzedFunctions"]) { + Data.AnalyzedFunctions.push_back(Value.get()); + } + + return Data; +} + +void LLVMAliasSetData::printAsJson(llvm::raw_ostream &OS) { + nlohmann::json JSON; + + for (const auto &Curr : AliasSets) { + JSON["AliasSets"].push_back(Curr); + } + + for (const auto &Curr : AnalyzedFunctions) { + JSON["AnalyzedFunctions"].push_back(Curr); + } + + OS << JSON << '\n'; +} + +LLVMAliasSetData LLVMAliasSetData::deserializeJson(const llvm::Twine &Path) { + return getDataFromJson(readJsonFile(Path)); +} + +LLVMAliasSetData +LLVMAliasSetData::loadJsonString(llvm::StringRef JsonAsString) { + nlohmann::json Data = + nlohmann::json::parse(JsonAsString.begin(), JsonAsString.end()); + return getDataFromJson(Data); +} + +} // namespace psr diff --git a/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp index e84c09f17..14b9a14cc 100644 --- a/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp @@ -10,6 +10,7 @@ #include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Utilities.h" @@ -17,8 +18,10 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -29,6 +32,10 @@ #include "llvm/Support/raw_ostream.h" #include +#include +#include +#include +#include namespace psr { using ClassType = DIBasedTypeHierarchy::ClassType; @@ -103,8 +110,13 @@ buildTypeGraph(llvm::ArrayRef VertexTypes, if (const auto *Inheritenace = llvm::dyn_cast(Fld); Inheritenace && Inheritenace->getTag() == llvm::dwarf::DW_TAG_inheritance) { - auto BaseIdx = TypeToVertex.lookup(Inheritenace->getBaseType()); - assert(BaseIdx != 0 || VertexTypes[0] == Inheritenace->getBaseType()); + const auto *Base = Inheritenace->getBaseType(); + while (Base->getTag() == llvm::dwarf::DW_TAG_typedef) { + Base = llvm::cast(Base)->getBaseType(); + } + + auto BaseIdx = TypeToVertex.lookup(Base); + assert(BaseIdx != 0 || VertexTypes[0] == Base); TG.DerivedTypesOf[BaseIdx].push_back(DerivedIdx); TG.Roots.reset(DerivedIdx); @@ -153,6 +165,11 @@ static void buildTypeHierarchy( } } +static llvm::StringRef getCompositeTypeName(const llvm::DICompositeType *Ty) { + auto Ident = Ty->getIdentifier(); + return Ident.empty() ? Ty->getName() : Ident; +} + DIBasedTypeHierarchy::DIBasedTypeHierarchy(const LLVMProjectIRDB &IRDB) { // -- Find all types { @@ -167,11 +184,24 @@ DIBasedTypeHierarchy::DIBasedTypeHierarchy(const LLVMProjectIRDB &IRDB) { // -- Filter all struct- or class types + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) + static constexpr llvm::dwarf::Tag DwarfTags[] = { + llvm::dwarf::DW_TAG_class_type, + llvm::dwarf::DW_TAG_structure_type, + llvm::dwarf::DW_TAG_union_type, + }; + for (const auto *Ty : DIF.types()) { if (const auto *Composite = llvm::dyn_cast(Ty)) { - TypeToVertex.try_emplace(Composite, VertexTypes.size()); - VertexTypes.push_back(Composite); - NameToType.try_emplace(Composite->getName(), Composite); + if (!llvm::is_contained(DwarfTags, Composite->getTag())) { + continue; + } + if (TypeToVertex.try_emplace(Composite, VertexTypes.size()).second) { + VertexTypes.push_back(Composite); + NameToType.try_emplace(getCompositeTypeName(Composite), Composite); + + assert(!getCompositeTypeName(Composite).empty()); + } } } @@ -189,6 +219,82 @@ DIBasedTypeHierarchy::DIBasedTypeHierarchy(const LLVMProjectIRDB &IRDB) { buildTypeHierarchy(TG, VertexTypes, TransitiveDerivedIndex, Hierarchy); } +static const llvm::DICompositeType * +stringToDICompositeType(const llvm::DebugInfoFinder &DIF, + const llvm::StringRef DITypeName) { + for (const auto *Type : DIF.types()) { + if (const auto *DICT = llvm::dyn_cast(Type)) { + auto Ident = DICT->getIdentifier(); + if (Ident == DITypeName) { + return DICT; + } + if (Ident.empty() && DICT->getName() == DITypeName) { + return DICT; + } + } + } + + llvm::report_fatal_error("DIType doesn't exist"); +} + +static const llvm::DIType *stringToDIType(const llvm::DebugInfoFinder &DIF, + const llvm::StringRef DITypeName) { + for (const auto *Type : DIF.types()) { + if (Type) { + if (Type->getName() == DITypeName) { + if (const auto *DIT = llvm::dyn_cast(Type)) { + return DIT; + } + } + } + } + + llvm::report_fatal_error("DIType doesn't exist"); +} + +// NOLINTNEXTLINE +static constexpr char NullFunName[] = "__null__"; + +DIBasedTypeHierarchy::DIBasedTypeHierarchy( + const LLVMProjectIRDB *IRDB, const DIBasedTypeHierarchyData &SerializedData) + : TransitiveDerivedIndex(SerializedData.TransitiveDerivedIndex) { + + llvm::DebugInfoFinder DIF; + const auto *Module = IRDB->getModule(); + DIF.processModule(*Module); + + VertexTypes.reserve(SerializedData.VertexTypes.size()); + TypeToVertex.reserve(SerializedData.VertexTypes.size()); + size_t Idx = 0; + for (const auto &Curr : SerializedData.VertexTypes) { + const auto *Ty = stringToDICompositeType(DIF, Curr); + VertexTypes.push_back(Ty); + TypeToVertex.try_emplace(Ty, Idx); + NameToType.try_emplace(Curr, Ty); + + ++Idx; + } + + Hierarchy.reserve(SerializedData.Hierarchy.size()); + for (const auto &Curr : SerializedData.Hierarchy) { + Hierarchy.push_back(stringToDIType(DIF, Curr)); + } + + for (const auto &Curr : SerializedData.VTables) { + std::vector CurrVTable; + + CurrVTable.reserve(Curr.size()); + for (const auto &FuncName : Curr) { + if (FuncName == NullFunName) { + CurrVTable.push_back(nullptr); + } + CurrVTable.push_back(IRDB->getFunction(FuncName)); + } + + VTables.emplace_back(std::move(CurrVTable)); + } +} + auto DIBasedTypeHierarchy::subTypesOf(size_t TypeIdx) const noexcept -> llvm::iterator_range { const auto *Data = Hierarchy.data(); @@ -218,6 +324,13 @@ auto DIBasedTypeHierarchy::subTypesOf(ClassType Ty) const noexcept llvm::report_fatal_error("Not implemented"); } +std::string DIBasedTypeHierarchy::getTypeName(ClassType Type) const { + if (const auto *CT = llvm::dyn_cast(Type)) { + return getCompositeTypeName(CT).str(); + } + return Type->getName().str(); +} + [[nodiscard]] bool DIBasedTypeHierarchy::hasVFTable(ClassType Type) const { const auto *StructTy = llvm::dyn_cast(Type); return StructTy && StructTy->getVTableHolder(); @@ -252,11 +365,51 @@ void DIBasedTypeHierarchy::print(llvm::raw_ostream &OS) const { } } -[[nodiscard]] nlohmann::json DIBasedTypeHierarchy::getAsJson() const { +[[nodiscard]] [[deprecated("Please use printAsJson() instead")]] nlohmann::json +DIBasedTypeHierarchy::getAsJson() const { /// TODO: implement llvm::report_fatal_error("Not implemented"); } +DIBasedTypeHierarchyData DIBasedTypeHierarchy::getTypeHierarchyData() const { + DIBasedTypeHierarchyData Data; + + Data.VertexTypes.reserve(VertexTypes.size()); + + for (const auto &Curr : VertexTypes) { + Data.VertexTypes.push_back(getTypeName(Curr)); + } + + Data.TransitiveDerivedIndex = TransitiveDerivedIndex; + + Data.Hierarchy.reserve(Hierarchy.size()); + for (const auto &Curr : Hierarchy) { + Data.Hierarchy.push_back(Curr->getName().str()); + } + + for (const auto &Curr : VTables) { + std::vector CurrVTableAsString; + CurrVTableAsString.reserve(Curr.getAllFunctions().size()); + + for (const auto &Func : Curr.getAllFunctions()) { + if (Func) { + CurrVTableAsString.push_back(Func->getName().str()); + continue; + } + CurrVTableAsString.emplace_back(NullFunName); + } + + Data.VTables.push_back(std::move(CurrVTableAsString)); + } + + return Data; +} + +void DIBasedTypeHierarchy::printAsJson(llvm::raw_ostream &OS) const { + DIBasedTypeHierarchyData Data = getTypeHierarchyData(); + Data.printAsJson(OS); +} + void DIBasedTypeHierarchy::printAsDot(llvm::raw_ostream &OS) const { OS << "digraph TypeHierarchy{\n"; scope_exit CloseBrace = [&OS] { OS << "}\n"; }; diff --git a/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.cpp b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.cpp new file mode 100644 index 000000000..b1fc17cb2 --- /dev/null +++ b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.cpp @@ -0,0 +1,76 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyData.h" + +#include "phasar/Utils/IO.h" +#include "phasar/Utils/NlohmannLogging.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include + +namespace psr { + +static DIBasedTypeHierarchyData getDataFromJson(const nlohmann::json &Json) { + DIBasedTypeHierarchyData Data; + + Data.VertexTypes = Json["VertexTypes"].get>(); + + Data.TransitiveDerivedIndex = + Json["TransitiveDerivedIndex"] + .get>>(); + + Data.Hierarchy = Json["Hierarchy"].get>(); + + for (const auto &CurrVTable : Json["VTables"]) { + auto &DataPos = Data.VTables.emplace_back(); + + for (const auto &CurrVFunc : CurrVTable) { + DataPos.push_back(CurrVFunc.get()); + } + } + + return Data; +} + +void DIBasedTypeHierarchyData::printAsJson(llvm::raw_ostream &OS) { + nlohmann::json Json; + + Json["VertexTypes"] = VertexTypes; + Json["TransitiveDerivedIndex"] = TransitiveDerivedIndex; + Json["Hierarchy"] = Hierarchy; + + auto &JVTables = Json["VTables"]; + for (const auto &CurrVTable : VTables) { + auto &DataPos = JVTables.emplace_back(); + + for (const auto &CurrVFunc : CurrVTable) { + DataPos.push_back(CurrVFunc); + } + } + + OS << Json << '\n'; +} + +DIBasedTypeHierarchyData +DIBasedTypeHierarchyData::deserializeJson(const llvm::Twine &Path) { + return getDataFromJson(readJsonFile(Path)); +} + +DIBasedTypeHierarchyData +DIBasedTypeHierarchyData::loadJsonString(llvm::StringRef JsonAsString) { + nlohmann::json Data = + nlohmann::json::parse(JsonAsString.begin(), JsonAsString.end()); + return getDataFromJson(Data); +} + +} // namespace psr diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp index bc2e32534..74a1dd971 100644 --- a/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp @@ -24,8 +24,10 @@ #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InstIterator.h" @@ -73,6 +75,63 @@ LLVMTypeHierarchy::LLVMTypeHierarchy(LLVMProjectIRDB &IRDB) { buildLLVMTypeHierarchy(*IRDB.getModule()); } +LLVMTypeHierarchy::LLVMTypeHierarchy( + LLVMProjectIRDB &IRDB, const LLVMTypeHierarchyData &SerializedData) { + + llvm::StringMap NameToStructType; + const auto &IRDBModule = IRDB.getModule(); + + VisitedModules.insert(IRDBModule); + auto StructTypes = IRDBModule->getIdentifiedStructTypes(); + + // find all struct types by name + for (const auto &SerElement : SerializedData.TypeGraph) { + bool MatchFound = false; + + for (const auto &StructTypeElement : StructTypes) { + if (SerElement.getKey() == StructTypeElement->getName()) { + NameToStructType.try_emplace(SerElement.getKey(), StructTypeElement); + MatchFound = true; + break; + } + } + + if (!MatchFound) { + PHASAR_LOG_LEVEL(WARNING, + "No matching StructType found for Type with name: " + << SerElement.getKey()); + } + } + + // add all vertices + for (const auto &Curr : NameToStructType) { + const auto &StructType = Curr.getValue(); + auto Vertex = boost::add_vertex(TypeGraph); + TypeVertexMap[StructType] = Vertex; + TypeGraph[Vertex] = VertexProperties(StructType); + TypeVFTMap[StructType] = getVirtualFunctions(*IRDBModule, *StructType); + } + + // add all edges + for (const auto &SerElement : SerializedData.TypeGraph) { + const auto *SrcType = NameToStructType[SerElement.getKey()]; + if (!SrcType) { + continue; + } + auto Vtx = TypeVertexMap.at(SrcType); + for (const auto &CurrEdge : SerElement.getValue()) { + const auto *DestType = NameToStructType[CurrEdge]; + if (!SrcType) { + continue; + } + auto DestVtx = TypeVertexMap.at(DestType); + + TypeGraph[Vtx].ReachableTypes.insert(DestType); + boost::add_edge(Vtx, DestVtx, TypeGraph); + } + } +} + LLVMTypeHierarchy::LLVMTypeHierarchy(const llvm::Module &M) { PHASAR_LOG_LEVEL_CAT(INFO, "LLVMTypeHierarchy", "Construct type hierarchy"); buildLLVMTypeHierarchy(M); @@ -152,11 +211,13 @@ void LLVMTypeHierarchy::buildLLVMTypeHierarchy(const llvm::Module &M) { std::vector LLVMTypeHierarchy::getSubTypes(const llvm::Module & /*M*/, - const llvm::StructType &Type) { + const llvm::StructType &Type) const { // find corresponding type info variable std::vector SubTypes; std::string ClearName = removeStructOrClassPrefix(Type); - if (const auto *TI = ClearNameTIMap[ClearName]) { + + if (auto It = ClearNameTIMap.find(ClearName); It != ClearNameTIMap.end()) { + const auto *TI = It->second; if (!TI->hasInitializer()) { PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMTypeHierarchy", ClearName << " does not have initializer"); @@ -172,8 +233,9 @@ LLVMTypeHierarchy::getSubTypes(const llvm::Module & /*M*/, if (Name.find(TypeInfoPrefix) != llvm::StringRef::npos) { auto ClearName = removeTypeInfoPrefix(llvm::demangle(Name.str())); - if (const auto *Type = ClearNameTypeMap[ClearName]) { - SubTypes.push_back(Type); + if (auto TypeIt = ClearNameTypeMap.find(ClearName); + TypeIt != ClearNameTypeMap.end()) { + SubTypes.push_back(TypeIt->second); } } } @@ -239,10 +301,12 @@ void LLVMTypeHierarchy::constructHierarchy(const llvm::Module &M) { TypeVFTMap[StructType] = getVirtualFunctions(M, *StructType); } } + // construct the edges between a type and its subtypes for (auto *StructType : StructTypes) { // use type information to check if it is really a subtype auto SubTypes = getSubTypes(M, *StructType); + for (const auto *SubType : SubTypes) { boost::add_edge(TypeVertexMap[SubType], TypeVertexMap[StructType], TypeGraph); @@ -402,7 +466,20 @@ void LLVMTypeHierarchy::printAsDot(llvm::raw_ostream &OS) const { } void LLVMTypeHierarchy::printAsJson(llvm::raw_ostream &OS) const { - OS << getAsJson(); + LLVMTypeHierarchyData Data; + Data.PhasarConfigJsonTypeHierarchyID = + PhasarConfig::JsonTypeHierarchyID().str(); + + // iterate all graph vertices + for (auto Vtx : boost::make_iterator_range(boost::vertices(TypeGraph))) { + // iterate all out edges of vertex vi_v + auto &SerTypes = Data.TypeGraph[TypeGraph[Vtx].getTypeName()]; + for (const auto &CurrReachable : TypeGraph[Vtx].ReachableTypes) { + SerTypes.push_back(CurrReachable->getName().str()); + } + } + + Data.printAsJson(OS); } // void LLVMTypeHierarchy::printGraphAsDot(ostream &out) { diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.cpp new file mode 100644 index 000000000..5247e8f17 --- /dev/null +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.cpp @@ -0,0 +1,66 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyData.h" + +#include "phasar/Utils/IO.h" +#include "phasar/Utils/NlohmannLogging.h" + +namespace psr { + +static LLVMTypeHierarchyData getDataFromJson(const nlohmann::json &Json) { + LLVMTypeHierarchyData Data; + Data.PhasarConfigJsonTypeHierarchyID = + Json["PhasarConfigJsonTypeHierarchyID"]; + + for (const auto &[Key, ValueArray] : + Json[Data.PhasarConfigJsonTypeHierarchyID] + .get()) { + Data.TypeGraph.try_emplace(Key, std::vector{}); + + for (const auto &CurrInnerType : ValueArray) { + for (const auto &CurrString : CurrInnerType) { + Data.TypeGraph[Key].push_back(CurrString.get()); + } + } + } + + return Data; +} + +void LLVMTypeHierarchyData::printAsJson(llvm::raw_ostream &OS) { + nlohmann::json Json; + + Json["PhasarConfigJsonTypeHierarchyID"] = PhasarConfigJsonTypeHierarchyID; + + for (const auto &Curr : TypeGraph) { + auto &DataPos = + Json[PhasarConfigJsonTypeHierarchyID][Curr.getKey()].emplace_back(); + + for (const auto &CurrTypeName : Curr.getValue()) { + DataPos.push_back(CurrTypeName); + } + } + + OS << Json << '\n'; +} + +LLVMTypeHierarchyData +LLVMTypeHierarchyData::deserializeJson(const llvm::Twine &Path) { + return getDataFromJson(readJsonFile(Path)); +} + +LLVMTypeHierarchyData +LLVMTypeHierarchyData::loadJsonString(llvm::StringRef JsonAsString) { + nlohmann::json Data = + nlohmann::json::parse(JsonAsString.begin(), JsonAsString.end()); + return getDataFromJson(Data); +} + +} // namespace psr diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp index 76c2f7c82..2b6b443ef 100644 --- a/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp @@ -9,9 +9,13 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h" +#include "phasar/Utils/NlohmannLogging.h" + #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/Operator.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -49,6 +53,26 @@ nlohmann::json LLVMVFTable::getAsJson() const { return J; } +[[nodiscard]] LLVMVFTableData LLVMVFTable::getVFTableData() const { + LLVMVFTableData Data; + + for (const auto &Curr : VFT) { + if (Curr) { + Data.VFT.push_back(Curr->getName().str()); + continue; + } + + Data.VFT.emplace_back(NullFunName); + } + + return Data; +} + +void LLVMVFTable::printAsJson(llvm::raw_ostream &OS) const { + LLVMVFTableData Data = getVFTableData(); + Data.printAsJson(OS); +} + std::vector LLVMVFTable::getVFVectorFromIRVTable(const llvm::ConstantStruct &VT) { std::vector VFS; diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMVFTableData.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTableData.cpp new file mode 100644 index 000000000..69d2a8da6 --- /dev/null +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTableData.cpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTableData.h" + +#include "phasar/Utils/IO.h" +#include "phasar/Utils/NlohmannLogging.h" + +namespace psr { + +static LLVMVFTableData getDataFromJson(const nlohmann::json &Json) { + LLVMVFTableData Data; + + for (const auto &Curr : Json["VFT"]) { + Data.VFT.push_back(Curr); + } + + return Data; +} + +void LLVMVFTableData::printAsJson(llvm::raw_ostream &OS) const { + nlohmann::json JSON; + + for (const auto &Curr : VFT) { + JSON["VFT"].push_back(Curr); + } + + OS << JSON << '\n'; +} + +LLVMVFTableData LLVMVFTableData::deserializeJson(const llvm::Twine &Path) { + return getDataFromJson(readJsonFile(Path)); +} + +LLVMVFTableData LLVMVFTableData::loadJsonString(llvm::StringRef JsonAsString) { + nlohmann::json Data = + nlohmann::json::parse(JsonAsString.begin(), JsonAsString.end()); + return getDataFromJson(Data); +} + +} // namespace psr diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp index 35619ce5a..194872b8d 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp @@ -1,8 +1,15 @@ #include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/ControlFlow/CallGraphData.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/IO.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" #include "TestConfig.h" #include "gtest/gtest.h" @@ -15,13 +22,19 @@ class LLVMBasedICFGGSerializationTest : public ::testing::Test { using namespace std::string_literals; psr::LLVMProjectIRDB IRDB(PathToLLFiles + IRFile); - psr::LLVMBasedICFG ICF(&IRDB, psr::CallGraphAnalysisType::OTF, {"main"s}); - auto Ser = ICF.getAsJson(); - psr::LLVMBasedICFG Deser(&IRDB, Ser); + std::string Ser; + // stream ICF data into a json file using the printAsJson() function + llvm::raw_string_ostream StringStream(Ser); + + ICF.printAsJson(StringStream); + + // deserialize data into CallGraphData object + psr::LLVMBasedICFG DeserializedICF(&IRDB, + psr::CallGraphData::loadJsonString(Ser)); - compareResults(ICF, Deser); + compareResults(ICF, DeserializedICF); } void compareResults(const psr::LLVMBasedICFG &Orig, diff --git a/unittests/PhasarLLVM/Pointer/LLVMAliasSetSerializationTest.cpp b/unittests/PhasarLLVM/Pointer/LLVMAliasSetSerializationTest.cpp index 1da745937..431c82218 100644 --- a/unittests/PhasarLLVM/Pointer/LLVMAliasSetSerializationTest.cpp +++ b/unittests/PhasarLLVM/Pointer/LLVMAliasSetSerializationTest.cpp @@ -39,7 +39,6 @@ static SetTy makeSet(const nlohmann::json &J) { } static void checkSer(const nlohmann::json &Ser, const GroundTruthTy &Gt) { - ASSERT_TRUE(Ser.count("AliasSets")); ASSERT_TRUE(Ser.count("AnalyzedFunctions")); @@ -77,18 +76,19 @@ static void analyze(llvm::StringRef File, const GroundTruthTy &Gt, ValueAnnotationPass::resetValueID(); LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + File); - // llvm::outs() << *IRDB.getWPAModule() << '\n'; - LLVMAliasSet PTS(&IRDB, false); LLVMTypeHierarchy TH(IRDB); LLVMBasedICFG ICF(&IRDB, CallGraphAnalysisType::OTF, {EntryPoint.str()}, &TH, &PTS); - auto Ser = PTS.getAsJson(); - checkSer(Ser, Gt); + std::string SerString; + llvm::raw_string_ostream StringStream(SerString); + PTS.printAsJson(StringStream); + nlohmann::json PrintAsJsonSer = nlohmann::json::parse(SerString); + checkSer(PrintAsJsonSer, Gt); - LLVMAliasSet Deser(&IRDB, Ser); - checkDeser(*IRDB.getModule(), PTS, Deser); + LLVMAliasSet PrintAsJsonDeser(&IRDB, PrintAsJsonSer); + checkDeser(*IRDB.getModule(), PTS, PrintAsJsonDeser); } TEST(LLVMAliasSetSerializationTest, Ser_Intra01) { diff --git a/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt b/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt index 512574c25..d4407ecef 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt +++ b/unittests/PhasarLLVM/TypeHierarchy/CMakeLists.txt @@ -1,5 +1,7 @@ set(PointerSources + DIBasedTypeHierarchySerializationTest.cpp DIBasedTypeHierarchyTest.cpp + LLVMTypeHierarchySerializationTest.cpp LLVMTypeHierarchyTest.cpp TypeGraphTest.cpp ) diff --git a/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchySerializationTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchySerializationTest.cpp new file mode 100644 index 000000000..57299bc9e --- /dev/null +++ b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchySerializationTest.cpp @@ -0,0 +1,125 @@ + +#include "phasar/Config/Configuration.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/StringRef.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +/* ============== TEST FIXTURE ============== */ +class TypeHierarchySerialization + : public ::testing::TestWithParam { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("type_hierarchies/"); + const std::vector EntryPoints = {"main"}; + +}; // Test Fixture + +void compareResults(const psr::DIBasedTypeHierarchy &Orig, + const psr::DIBasedTypeHierarchy &Deser) { + + EXPECT_EQ(Orig.getAllTypes().size(), Deser.getAllTypes().size()); + EXPECT_EQ(Orig.getAllVTables().size(), Deser.getAllVTables().size()); + + for (const auto *OrigCurrentType : Orig.getAllTypes()) { + // check types + const auto *DeserTy = Deser.getType(Orig.getTypeName(OrigCurrentType)); + EXPECT_EQ(OrigCurrentType, DeserTy); + + // check edges + const auto OrigSubTypes = Orig.subTypesOf(OrigCurrentType); + const auto DeserSubTypes = Deser.subTypesOf(OrigCurrentType); + + for (const auto &CurrOrigSubType : OrigSubTypes) { + bool DeserHasSubType = false; + + for (const auto &CurrDeserSubType : DeserSubTypes) { + if (CurrDeserSubType->getName() == CurrOrigSubType->getName()) { + DeserHasSubType = true; + break; + } + } + + EXPECT_TRUE(DeserHasSubType); + } + + // check virtual functions and vtables + if (OrigCurrentType != DeserTy) { + llvm::errs() << "Mismatched types:\n> OrigTy: " << *OrigCurrentType + << '\n'; + llvm::errs() << "> DeserTy: " << *DeserTy << '\n'; + } + + for (const auto &CurrVFunc : + Orig.getVFTable(OrigCurrentType)->getAllFunctions()) { + bool FoundFunction = false; + for (const auto &DeserFunc : + Deser.getVFTable(OrigCurrentType)->getAllFunctions()) { + if (DeserFunc) { + if (CurrVFunc) { + if (DeserFunc->getName() == CurrVFunc->getName()) { + FoundFunction = true; + break; + } + } + } else { + // This case is for a function that has no caller + if (!CurrVFunc) { + FoundFunction = true; + break; + } + } + } + EXPECT_TRUE(FoundFunction); + } + } +} + +TEST_P(TypeHierarchySerialization, OrigAndDeserEqual) { + using namespace std::string_literals; + + psr::LLVMProjectIRDB IRDB(PathToLlFiles + GetParam()); + psr::DIBasedTypeHierarchy DIBTH(IRDB); + + std::string Ser; + llvm::raw_string_ostream StringStream(Ser); + + DIBTH.printAsJson(StringStream); + + psr::DIBasedTypeHierarchy DeserializedDIBTH( + &IRDB, psr::DIBasedTypeHierarchyData::loadJsonString(Ser)); + + compareResults(DIBTH, DeserializedDIBTH); +} + +static constexpr std::string_view TypeHierarchyTestFiles[] = { + "type_hierarchy_1_cpp_dbg.ll", "type_hierarchy_2_cpp_dbg.ll", + "type_hierarchy_3_cpp_dbg.ll", "type_hierarchy_4_cpp_dbg.ll", + "type_hierarchy_5_cpp_dbg.ll", "type_hierarchy_6_cpp_dbg.ll", + "type_hierarchy_7_cpp_dbg.ll", "type_hierarchy_7_b_cpp_dbg.ll", + "type_hierarchy_8_cpp_dbg.ll", "type_hierarchy_9_cpp_dbg.ll", + "type_hierarchy_10_cpp_dbg.ll", "type_hierarchy_11_cpp_dbg.ll", + "type_hierarchy_12_cpp_dbg.ll", "type_hierarchy_12_b_cpp_dbg.ll", + "type_hierarchy_12_c_cpp_dbg.ll", "type_hierarchy_13_cpp_dbg.ll", + "type_hierarchy_14_cpp_dbg.ll", "type_hierarchy_15_cpp_dbg.ll", + "type_hierarchy_16_cpp_dbg.ll", "type_hierarchy_17_cpp_dbg.ll", + "type_hierarchy_18_cpp_dbg.ll", "type_hierarchy_19_cpp_dbg.ll", + "type_hierarchy_20_cpp_dbg.ll", "type_hierarchy_21_cpp_dbg.ll", +}; + +INSTANTIATE_TEST_SUITE_P(TypeHierarchySerializationTest, + TypeHierarchySerialization, + ::testing::ValuesIn(TypeHierarchyTestFiles)); + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + auto Res = RUN_ALL_TESTS(); + return Res; +} diff --git a/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp index 5b97f15e8..01f677363 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp +++ b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp @@ -24,9 +24,9 @@ TEST(DBTHTest, BasicTHReconstruction_1) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -44,9 +44,9 @@ TEST(DBTHTest, BasicTHReconstruction_2) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -64,9 +64,9 @@ TEST(DBTHTest, BasicTHReconstruction_3) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -84,9 +84,9 @@ TEST(DBTHTest, BasicTHReconstruction_4) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -104,11 +104,11 @@ TEST(DBTHTest, BasicTHReconstruction_5) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 3U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &OtherBaseType = DBTH.getType("OtherBase"); + const auto &OtherBaseType = DBTH.getType("_ZTS9OtherBase"); ASSERT_NE(nullptr, OtherBaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -129,9 +129,9 @@ TEST(DBTHTest, BasicTHReconstruction_6) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -149,19 +149,19 @@ TEST(DBTHTest, BasicTHReconstruction_7) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 7U); - const auto &AType = DBTH.getType("A"); + const auto &AType = DBTH.getType("_ZTS1A"); ASSERT_NE(nullptr, AType); - const auto &BType = DBTH.getType("B"); + const auto &BType = DBTH.getType("_ZTS1B"); ASSERT_NE(nullptr, BType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); - const auto &DType = DBTH.getType("D"); + const auto &DType = DBTH.getType("_ZTS1D"); ASSERT_NE(nullptr, DType); - const auto &XType = DBTH.getType("X"); + const auto &XType = DBTH.getType("_ZTS1X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); EXPECT_TRUE(DBTH.hasType(AType)); @@ -202,15 +202,15 @@ TEST(DBTHTest, BasicTHReconstruction_7_b) { EXPECT_EQ(DBTH.getAllTypes().size(), 6U); const auto &AType = DBTH.getType("A"); ASSERT_NE(nullptr, AType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); const auto &XType = DBTH.getType("X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); - const auto &OmegaType = DBTH.getType("Omega"); + const auto &OmegaType = DBTH.getType("_ZTS5Omega"); ASSERT_NE(nullptr, OmegaType); EXPECT_TRUE(DBTH.hasType(AType)); @@ -247,13 +247,13 @@ TEST(DBTHTest, BasicTHReconstruction_8) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 4U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &NonvirtualClassType = DBTH.getType("NonvirtualClass"); + const auto &NonvirtualClassType = DBTH.getType("_ZTS15NonvirtualClass"); EXPECT_NE(nullptr, NonvirtualClassType); - const auto &NonvirtualStructType = DBTH.getType("NonvirtualStruct"); + const auto &NonvirtualStructType = DBTH.getType("_ZTS16NonvirtualStruct"); EXPECT_NE(nullptr, NonvirtualStructType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -273,9 +273,9 @@ TEST(DBTHTest, BasicTHReconstruction_9) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -293,9 +293,9 @@ TEST(DBTHTest, BasicTHReconstruction_10) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -313,9 +313,9 @@ TEST(DBTHTest, BasicTHReconstruction_11) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -333,9 +333,9 @@ TEST(DBTHTest, BasicTHReconstruction_12) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 2U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -357,7 +357,7 @@ TEST(DBTHTest, BasicTHReconstruction_12_b) { ASSERT_NE(nullptr, BaseType); const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -380,7 +380,7 @@ TEST(DBTHTest, BasicTHReconstruction_12_c) { EXPECT_EQ(DBTH.getAllTypes().size(), 2U); const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); EXPECT_TRUE(DBTH.hasType(ChildType)); @@ -439,16 +439,16 @@ TEST(DBTHTest, BasicTHReconstruction_16) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 5U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // Since ChildsChild is never used, it is optimized out // const auto &ChildsChildType = DBTH.getType("ChildsChild"); // ASSERT_EQ(nullptr, ChildsChildType); - const auto &BaseTwoType = DBTH.getType("BaseTwo"); + const auto &BaseTwoType = DBTH.getType("_ZTS7BaseTwo"); ASSERT_NE(nullptr, BaseTwoType); - const auto &ChildTwoType = DBTH.getType("ChildTwo"); + const auto &ChildTwoType = DBTH.getType("_ZTS8ChildTwo"); ASSERT_NE(nullptr, ChildTwoType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -475,16 +475,16 @@ TEST(DBTHTest, BasicTHReconstruction_17) { // check for all types // EXPECT_EQ(DBTH.getAllTypes().size(), 5U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // const auto &Child2Type = DBTH.getType("Child2"); // Since Child2Type is never used, it is optimized out // ASSERT_EQ(nullptr, Child2Type); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &KidType = DBTH.getType("Kid"); + const auto &KidType = DBTH.getType("_ZTS3Kid"); ASSERT_NE(nullptr, KidType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -511,14 +511,14 @@ TEST(DBTHTest, BasicTHReconstruction_18) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 4U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // const auto &Child_2Type = DBTH.getType("Child_2"); // Since Child2Type is never used, it is optimized out // ASSERT_EQ(nullptr, Child2Type); - const auto &Child3Type = DBTH.getType("Child_3"); + const auto &Child3Type = DBTH.getType("_ZTS7Child_3"); ASSERT_NE(nullptr, Child3Type); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -544,17 +544,17 @@ TEST(DBTHTest, BasicTHReconstruction_19) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 6U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &FooType = DBTH.getType("Foo"); + const auto &FooType = DBTH.getType("_ZTS3Foo"); ASSERT_NE(nullptr, FooType); - const auto &BarType = DBTH.getType("Bar"); + const auto &BarType = DBTH.getType("_ZTS3Bar"); ASSERT_NE(nullptr, BarType); - const auto &LoremType = DBTH.getType("Lorem"); + const auto &LoremType = DBTH.getType("_ZTS5Lorem"); ASSERT_NE(nullptr, LoremType); - const auto &ImpsumType = DBTH.getType("Impsum"); + const auto &ImpsumType = DBTH.getType("_ZTS6Impsum"); ASSERT_NE(nullptr, ImpsumType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -580,11 +580,11 @@ TEST(DBTHTest, BasicTHReconstruction_20) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 3U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -605,15 +605,15 @@ TEST(DBTHTest, BasicTHReconstruction_21) { // check for all types EXPECT_EQ(DBTH.getAllTypes().size(), 5U); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &Base3Type = DBTH.getType("Base3"); + const auto &Base3Type = DBTH.getType("_ZTS5Base3"); ASSERT_NE(nullptr, Base3Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child2"); + const auto &Child2Type = DBTH.getType("_ZTS6Child2"); ASSERT_NE(nullptr, Child2Type); EXPECT_TRUE(DBTH.hasType(BaseType)); @@ -645,9 +645,9 @@ TEST(DBTHTest, VTableConstruction_1) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); ASSERT_TRUE(DBTH.hasVFTable(BaseType)); @@ -670,9 +670,9 @@ TEST(DBTHTest, VTableConstruction_2) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); ASSERT_TRUE(DBTH.hasVFTable(BaseType)); @@ -695,9 +695,9 @@ TEST(DBTHTest, VTableConstruction_3) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); ASSERT_TRUE(DBTH.hasVFTable(BaseType)); @@ -722,9 +722,9 @@ TEST(DBTHTest, VTableConstruction_4) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); ASSERT_TRUE(DBTH.hasVFTable(BaseType)); @@ -752,11 +752,11 @@ TEST(DBTHTest, VTableConstruction_5) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &OtherBaseType = DBTH.getType("OtherBase"); + const auto &OtherBaseType = DBTH.getType("_ZTS9OtherBase"); ASSERT_NE(nullptr, OtherBaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); ASSERT_TRUE(DBTH.hasVFTable(BaseType)); @@ -792,9 +792,9 @@ TEST(DBTHTest, VTableConstruction_6) { "type_hierarchies/type_hierarchy_6_cpp_dbg.ll"); DIBasedTypeHierarchy DBTH(IRDB); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -819,19 +819,19 @@ TEST(DBTHTest, VTableConstruction_7) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &AType = DBTH.getType("A"); + const auto &AType = DBTH.getType("_ZTS1A"); ASSERT_NE(nullptr, AType); - const auto &BType = DBTH.getType("B"); + const auto &BType = DBTH.getType("_ZTS1B"); ASSERT_NE(nullptr, BType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); - const auto &DType = DBTH.getType("D"); + const auto &DType = DBTH.getType("_ZTS1D"); ASSERT_NE(nullptr, DType); - const auto &XType = DBTH.getType("X"); + const auto &XType = DBTH.getType("_ZTS1X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); const auto &VTableForAType = DBTH.getVFTable(AType); @@ -867,15 +867,15 @@ TEST(DBTHTest, VTableConstruction_7_b) { // check for all types const auto &AType = DBTH.getType("A"); ASSERT_NE(nullptr, AType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); const auto &XType = DBTH.getType("X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); - const auto &OmegaType = DBTH.getType("Omega"); + const auto &OmegaType = DBTH.getType("_ZTS5Omega"); ASSERT_NE(nullptr, OmegaType); const auto &VTableForAType = DBTH.getVFTable(AType); @@ -907,13 +907,13 @@ TEST(DBTHTest, VTableConstruction_8) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &NonvirtualClassType = DBTH.getType("NonvirtualClass"); + const auto &NonvirtualClassType = DBTH.getType("_ZTS15NonvirtualClass"); EXPECT_NE(nullptr, NonvirtualClassType); - const auto &NonvirtualStructType = DBTH.getType("NonvirtualStruct"); + const auto &NonvirtualStructType = DBTH.getType("_ZTS16NonvirtualStruct"); EXPECT_NE(nullptr, NonvirtualStructType); const auto &VTableForBaseType = DBTH.getVFTable(BaseType); @@ -945,9 +945,9 @@ TEST(DBTHTest, VTableConstruction_9) { "type_hierarchies/type_hierarchy_9_cpp_dbg.ll"); DIBasedTypeHierarchy DBTH(IRDB); - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -972,9 +972,9 @@ TEST(DBTHTest, VTableConstruction_10) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -998,9 +998,9 @@ TEST(DBTHTest, VTableConstruction_11) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1020,9 +1020,9 @@ TEST(DBTHTest, VTableConstruction_12) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1046,7 +1046,7 @@ TEST(DBTHTest, VTableConstruction_12_b) { ASSERT_NE(nullptr, BaseType); const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1072,7 +1072,7 @@ TEST(DBTHTest, VTableConstruction_12_c) { // check for all types const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); const auto &VTableForChild = DBTH.getVFTable(ChildType); @@ -1133,15 +1133,15 @@ TEST(DBTHTest, VTableConstruction_16) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildOfChildType = DBTH.getType("ChildOfChild"); + const auto &ChildOfChildType = DBTH.getType("_ZTS12ChildOfChild"); ASSERT_NE(nullptr, ChildOfChildType); - const auto &BaseTwoType = DBTH.getType("BaseTwo"); + const auto &BaseTwoType = DBTH.getType("_ZTS7BaseTwo"); ASSERT_NE(nullptr, BaseTwoType); - const auto &ChildTwoType = DBTH.getType("ChildTwo"); + const auto &ChildTwoType = DBTH.getType("_ZTS8ChildTwo"); ASSERT_NE(nullptr, ChildTwoType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1177,16 +1177,16 @@ TEST(DBTHTest, VTableConstruction_17) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // Since Child2 is never used, it is sometimes optimized out by the compiler // const auto &Child2Type = DBTH.getType("Child2"); // ASSERT_NE(nullptr, Child2Type); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &KidType = DBTH.getType("Kid"); + const auto &KidType = DBTH.getType("_ZTS3Kid"); ASSERT_NE(nullptr, KidType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1229,13 +1229,13 @@ TEST(DBTHTest, VTableConstruction_18) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child_2"); + const auto &Child2Type = DBTH.getType("_ZTS7Child_2"); ASSERT_NE(nullptr, Child2Type); - const auto &Child3Type = DBTH.getType("Child_3"); + const auto &Child3Type = DBTH.getType("_ZTS7Child_3"); ASSERT_NE(nullptr, Child3Type); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1272,17 +1272,17 @@ TEST(DBTHTest, VTableConstruction_19) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &FooType = DBTH.getType("Foo"); + const auto &FooType = DBTH.getType("_ZTS3Foo"); ASSERT_NE(nullptr, FooType); - const auto &BarType = DBTH.getType("Bar"); + const auto &BarType = DBTH.getType("_ZTS3Bar"); ASSERT_NE(nullptr, BarType); - const auto &LoremType = DBTH.getType("Lorem"); + const auto &LoremType = DBTH.getType("_ZTS5Lorem"); ASSERT_NE(nullptr, LoremType); - const auto &ImpsumType = DBTH.getType("Impsum"); + const auto &ImpsumType = DBTH.getType("_ZTS6Impsum"); ASSERT_NE(nullptr, ImpsumType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1325,11 +1325,11 @@ TEST(DBTHTest, VTableConstruction_20) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1358,15 +1358,15 @@ TEST(DBTHTest, VTableConstruction_21) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &Base3Type = DBTH.getType("Base3"); + const auto &Base3Type = DBTH.getType("_ZTS5Base3"); ASSERT_NE(nullptr, Base3Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child2"); + const auto &Child2Type = DBTH.getType("_ZTS6Child2"); ASSERT_NE(nullptr, Child2Type); const auto &VTableForBase = DBTH.getVFTable(BaseType); @@ -1422,9 +1422,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_1) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1444,9 +1444,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_2) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1466,9 +1466,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_3) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1486,9 +1486,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_4) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1508,11 +1508,11 @@ TEST(DBTHTest, TransitivelyReachableTypes_5) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &OtherBaseType = DBTH.getType("OtherBase"); + const auto &OtherBaseType = DBTH.getType("_ZTS9OtherBase"); ASSERT_NE(nullptr, OtherBaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1537,9 +1537,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_6) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1559,19 +1559,19 @@ TEST(DBTHTest, TransitivelyReachableTypes_7) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &AType = DBTH.getType("A"); + const auto &AType = DBTH.getType("_ZTS1A"); ASSERT_NE(nullptr, AType); - const auto &BType = DBTH.getType("B"); + const auto &BType = DBTH.getType("_ZTS1B"); ASSERT_NE(nullptr, BType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); - const auto &DType = DBTH.getType("D"); + const auto &DType = DBTH.getType("_ZTS1D"); ASSERT_NE(nullptr, DType); - const auto &XType = DBTH.getType("X"); + const auto &XType = DBTH.getType("_ZTS1X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); auto ReachableTypesA = DBTH.getSubTypes(AType); @@ -1655,15 +1655,15 @@ TEST(DBTHTest, TransitivelyReachableTypes_7_b) { // check for all types const auto &AType = DBTH.getType("A"); ASSERT_NE(nullptr, AType); - const auto &CType = DBTH.getType("C"); + const auto &CType = DBTH.getType("_ZTS1C"); ASSERT_NE(nullptr, CType); const auto &XType = DBTH.getType("X"); ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); + const auto &YType = DBTH.getType("_ZTS1Y"); ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); + const auto &ZType = DBTH.getType("_ZTS1Z"); ASSERT_NE(nullptr, ZType); - const auto &OmegaType = DBTH.getType("Omega"); + const auto &OmegaType = DBTH.getType("_ZTS5Omega"); ASSERT_NE(nullptr, OmegaType); auto ReachableTypesA = DBTH.getSubTypes(AType); @@ -1729,13 +1729,13 @@ TEST(DBTHTest, TransitivelyReachableTypes_8) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &NonvirtualClassType = DBTH.getType("NonvirtualClass"); + const auto &NonvirtualClassType = DBTH.getType("_ZTS15NonvirtualClass"); ASSERT_NE(nullptr, NonvirtualClassType); - const auto &NonvirtualStructType = DBTH.getType("NonvirtualStruct"); + const auto &NonvirtualStructType = DBTH.getType("_ZTS16NonvirtualStruct"); ASSERT_NE(nullptr, NonvirtualStructType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1775,9 +1775,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_9) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1797,9 +1797,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_10) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1819,9 +1819,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_11) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1841,9 +1841,9 @@ TEST(DBTHTest, TransitivelyReachableTypes_12) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1867,7 +1867,7 @@ TEST(DBTHTest, TransitivelyReachableTypes_12_b) { ASSERT_NE(nullptr, BaseType); const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -1896,7 +1896,7 @@ TEST(DBTHTest, TransitivelyReachableTypes_12_c) { // check for all types const auto &ChildType = DBTH.getType("Child"); ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); + const auto &ChildsChildType = DBTH.getType("_ZTS11ChildsChild"); ASSERT_NE(nullptr, ChildsChildType); auto ReachableTypesChild = DBTH.getSubTypes(ChildType); @@ -1959,16 +1959,16 @@ TEST(DBTHTest, TransitivelyReachableTypes_16) { "type_hierarchies/type_hierarchy_16_cpp_dbg.ll"); DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // const auto &ChildsChildType = DBTH.getType("ChildsChild"); // Since ChildsChild is never used, it is optimized out // ASSERT_EQ(nullptr, ChildsChildType); - const auto &BaseTwoType = DBTH.getType("BaseTwo"); + const auto &BaseTwoType = DBTH.getType("_ZTS7BaseTwo"); ASSERT_NE(nullptr, BaseTwoType); - const auto &ChildTwoType = DBTH.getType("ChildTwo"); + const auto &ChildTwoType = DBTH.getType("_ZTS8ChildTwo"); ASSERT_NE(nullptr, ChildTwoType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -2004,16 +2004,16 @@ TEST(DBTHTest, TransitivelyReachableTypes_17) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); // const auto &Child2Type = DBTH.getType("Child2"); // Since Child2 is never used, it is optimized out // ASSERT_EQ(nullptr, Child2Type); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &KidType = DBTH.getType("Kid"); + const auto &KidType = DBTH.getType("_ZTS3Kid"); ASSERT_NE(nullptr, KidType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -2049,13 +2049,13 @@ TEST(DBTHTest, TransitivelyReachableTypes_18) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child_2"); + const auto &Child2Type = DBTH.getType("_ZTS7Child_2"); ASSERT_NE(nullptr, Child2Type); - const auto &Child3Type = DBTH.getType("Child_3"); + const auto &Child3Type = DBTH.getType("_ZTS7Child_3"); ASSERT_NE(nullptr, Child3Type); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -2087,17 +2087,17 @@ TEST(DBTHTest, TransitivelyReachableTypes_19) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &FooType = DBTH.getType("Foo"); + const auto &FooType = DBTH.getType("_ZTS3Foo"); ASSERT_NE(nullptr, FooType); - const auto &BarType = DBTH.getType("Bar"); + const auto &BarType = DBTH.getType("_ZTS3Bar"); ASSERT_NE(nullptr, BarType); - const auto &LoremType = DBTH.getType("Lorem"); + const auto &LoremType = DBTH.getType("_ZTS5Lorem"); ASSERT_NE(nullptr, LoremType); - const auto &ImpsumType = DBTH.getType("Impsum"); + const auto &ImpsumType = DBTH.getType("_ZTS6Impsum"); ASSERT_NE(nullptr, ImpsumType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -2136,11 +2136,11 @@ TEST(DBTHTest, TransitivelyReachableTypes_20) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); @@ -2166,15 +2166,15 @@ TEST(DBTHTest, TransitivelyReachableTypes_21) { DIBasedTypeHierarchy DBTH(IRDB); // check for all types - const auto &BaseType = DBTH.getType("Base"); + const auto &BaseType = DBTH.getType("_ZTS4Base"); ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); + const auto &Base2Type = DBTH.getType("_ZTS5Base2"); ASSERT_NE(nullptr, Base2Type); - const auto &Base3Type = DBTH.getType("Base3"); + const auto &Base3Type = DBTH.getType("_ZTS5Base3"); ASSERT_NE(nullptr, Base3Type); - const auto &ChildType = DBTH.getType("Child"); + const auto &ChildType = DBTH.getType("_ZTS5Child"); ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child2"); + const auto &Child2Type = DBTH.getType("_ZTS6Child2"); ASSERT_NE(nullptr, Child2Type); auto ReachableTypesBase = DBTH.getSubTypes(BaseType); diff --git a/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchySerializationTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchySerializationTest.cpp new file mode 100644 index 000000000..57d3bb4cf --- /dev/null +++ b/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchySerializationTest.cpp @@ -0,0 +1,92 @@ + +#include "phasar/Config/Configuration.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/NlohmannLogging.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/DerivedTypes.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +/* ============== TEST FIXTURE ============== */ +class LLVMTypeHierarchySerialization + : public ::testing::TestWithParam { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("type_hierarchies/"); + const std::vector EntryPoints = {"main"}; + +}; // Test Fixture + +void compareResults(psr::LLVMTypeHierarchy &Orig, + psr::LLVMTypeHierarchy &Deser) { + ASSERT_EQ(Orig.getAllTypes().size(), Deser.getAllTypes().size()); + ASSERT_EQ(Orig.getAllVTables().size(), Deser.getAllVTables().size()); + + for (const auto &OrigCurrentType : Orig.getAllTypes()) { + // check types + EXPECT_EQ(OrigCurrentType, Deser.getType(OrigCurrentType->getName().str())); + + // check edges + for (const auto &OrigEdgeCurrentType : Orig.getAllTypes()) { + // Deser.isSubType can take the same arguments as Orig.isSubType, since + // Deser should have the same types + + bool ExpectedValue = Orig.isSubType(OrigCurrentType, OrigEdgeCurrentType); + bool DeserializedValue = + Deser.isSubType(Deser.getType(OrigCurrentType->getName().str()), + Deser.getType(OrigEdgeCurrentType->getName().str())); + + EXPECT_EQ(ExpectedValue, DeserializedValue); + } + } +} + +TEST_P(LLVMTypeHierarchySerialization, OrigAndDeserEqual) { + using namespace std::string_literals; + + psr::LLVMProjectIRDB IRDB(PathToLlFiles + GetParam()); + psr::LLVMTypeHierarchy TypeHierarchy(IRDB); + + std::string Ser; + llvm::raw_string_ostream StringStream(Ser); + + TypeHierarchy.printAsJson(StringStream); + + psr::LLVMTypeHierarchy DeserializedTypeHierarchy( + IRDB, psr::LLVMTypeHierarchyData::loadJsonString(Ser)); + + compareResults(TypeHierarchy, DeserializedTypeHierarchy); +} + +static constexpr std::string_view TypeHierarchyTestFiles[] = { + "type_hierarchy_1_cpp_dbg.ll", "type_hierarchy_2_cpp_dbg.ll", + "type_hierarchy_3_cpp_dbg.ll", "type_hierarchy_4_cpp_dbg.ll", + "type_hierarchy_5_cpp_dbg.ll", "type_hierarchy_6_cpp_dbg.ll", + "type_hierarchy_7_cpp_dbg.ll", "type_hierarchy_7_b_cpp_dbg.ll", + "type_hierarchy_8_cpp_dbg.ll", "type_hierarchy_9_cpp_dbg.ll", + "type_hierarchy_10_cpp_dbg.ll", "type_hierarchy_11_cpp_dbg.ll", + "type_hierarchy_12_cpp_dbg.ll", "type_hierarchy_12_b_cpp_dbg.ll", + "type_hierarchy_12_c_cpp_dbg.ll", "type_hierarchy_13_cpp_dbg.ll", + "type_hierarchy_14_cpp_dbg.ll", "type_hierarchy_15_cpp_dbg.ll", + "type_hierarchy_16_cpp_dbg.ll", "type_hierarchy_17_cpp_dbg.ll", + "type_hierarchy_18_cpp_dbg.ll", "type_hierarchy_19_cpp_dbg.ll", + "type_hierarchy_20_cpp_dbg.ll", "type_hierarchy_21_cpp_dbg.ll", +}; + +INSTANTIATE_TEST_SUITE_P(LLVMTypeHierarchySerializationTest, + LLVMTypeHierarchySerialization, + ::testing::ValuesIn(TypeHierarchyTestFiles)); + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + auto Res = RUN_ALL_TESTS(); + return Res; +}