forked from klee/klee
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented classes for types in type system. Added handling TypeMana…
…ger entity, that can create such these KType's.
- Loading branch information
Showing
6 changed files
with
368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#ifndef KLEE_KTYPE_H | ||
#define KLEE_KTYPE_H | ||
|
||
#include <unordered_map> | ||
#include <vector> | ||
namespace llvm { | ||
class Type; | ||
class raw_ostream; | ||
} // namespace llvm | ||
|
||
namespace klee { | ||
class Expr; | ||
class TypeManager; | ||
|
||
template <class> class ref; | ||
|
||
enum TypeSystemKind { LLVM }; | ||
class KType { | ||
friend TypeManager; | ||
|
||
protected: | ||
/** | ||
* Represents type of used TypeManager. Required | ||
* for llvm RTTI. | ||
*/ | ||
TypeSystemKind typeSystemKind; | ||
|
||
/** | ||
* Wrapped type. | ||
*/ | ||
llvm::Type *type; | ||
|
||
/** | ||
* Owning type manager system. Note, that only it can | ||
* create instances of KTypes. | ||
*/ | ||
TypeManager *parent; | ||
|
||
/** | ||
* Innner types. Maps type to their offsets in current | ||
* type. Should contain type itself and | ||
* all types, that can be found in that object. | ||
* For example, if object of type A contains object | ||
* of type B, then all types in B can be accessed via A. | ||
*/ | ||
std::unordered_map<KType *, std::vector<uint64_t>> innerTypes; | ||
|
||
KType(llvm::Type *, TypeManager *); | ||
|
||
/** | ||
* Object cannot been created within class, defferent | ||
* from TypeManager, as it is important to have only | ||
* one instance for every llvm::Type. | ||
*/ | ||
KType(const KType &) = delete; | ||
KType &operator=(const KType &) = delete; | ||
KType(KType &&) = delete; | ||
KType &operator=(KType &&) = delete; | ||
|
||
public: | ||
/** | ||
* Method to check if 2 types are compatible. | ||
*/ | ||
virtual bool isAccessableFrom(KType *accessingType) const; | ||
|
||
/** | ||
* Handler for possible memory access. By default does nothing. | ||
*/ | ||
virtual void handleMemoryAccess(KType *, ref<Expr>, ref<Expr>, bool isWrite); | ||
|
||
/** | ||
* Returns the stored raw llvm type. | ||
*/ | ||
llvm::Type *getRawType() const; | ||
|
||
TypeSystemKind getTypeSystemKind() const; | ||
|
||
virtual void print(llvm::raw_ostream &) const; | ||
|
||
virtual ~KType() = default; | ||
}; | ||
} // namespace klee | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#include "TypeManager.h" | ||
|
||
#include "klee/ADT/Ref.h" | ||
#include "klee/Expr/Expr.h" | ||
#include "klee/Expr/ExprHashMap.h" | ||
#include "klee/Module/KInstruction.h" | ||
#include "klee/Module/KModule.h" | ||
#include "klee/Module/KType.h" | ||
|
||
#include "llvm/IR/DerivedTypes.h" | ||
#include "llvm/IR/Instruction.h" | ||
#include "llvm/IR/Module.h" | ||
#include "llvm/IR/Type.h" | ||
#include "llvm/Support/Casting.h" | ||
|
||
#include <unordered_map> | ||
#include <unordered_set> | ||
#include <vector> | ||
|
||
using namespace klee; | ||
|
||
/** | ||
* Initializes type system with raw llvm types. | ||
*/ | ||
TypeManager::TypeManager(KModule *parent) : parent(parent) {} | ||
|
||
/** | ||
* Computes KType for given type, and cache it, if it was not | ||
* inititalized before. So, any two calls with the same argument | ||
* will return same KType's. | ||
*/ | ||
KType *TypeManager::getWrappedType(llvm::Type *type) { | ||
if (typesMap.count(type) == 0) { | ||
types.emplace_back(new KType(type, this)); | ||
typesMap.emplace(type, types.back().get()); | ||
} | ||
return typesMap[type]; | ||
} | ||
|
||
KType *TypeManager::getUnknownType() { return getWrappedType(nullptr); } | ||
|
||
KType *TypeManager::handleAlloc(ref<Expr> size) { return getUnknownType(); } | ||
|
||
KType *TypeManager::handleRealloc(KType *type, ref<Expr>) { return type; } | ||
|
||
/** | ||
* Performs initialization for struct types, including inner types. | ||
* Note, that initialization for structs differs from initialization | ||
* for other types, as types from structs can create cyclic dependencies, | ||
* and that is why it cannot be done in constructor. | ||
*/ | ||
void TypeManager::initTypesFromStructs() { | ||
/* | ||
* To collect information about all inner types | ||
* we will topologically sort dependencies between structures | ||
* (e.g. if struct A contains class B, we will make edge from A to B) | ||
* and pull types to top. | ||
*/ | ||
|
||
std::vector<llvm::StructType *> collectedStructTypes = | ||
parent->module->getIdentifiedStructTypes(); | ||
for (auto &structType : collectedStructTypes) { | ||
getWrappedType(structType); | ||
} | ||
|
||
for (auto &typesToOffsets : typesMap) { | ||
if (llvm::isa<llvm::StructType>(typesToOffsets.first)) { | ||
collectedStructTypes.emplace_back( | ||
llvm::cast<llvm::StructType>(typesToOffsets.first)); | ||
} | ||
} | ||
|
||
std::vector<llvm::StructType *> sortedStructTypesGraph; | ||
std::unordered_set<llvm::Type *> visitedStructTypesGraph; | ||
|
||
std::function<void(llvm::StructType *)> dfs = [this, &sortedStructTypesGraph, | ||
&visitedStructTypesGraph, | ||
&dfs](llvm::StructType *type) { | ||
visitedStructTypesGraph.insert(type); | ||
|
||
for (auto typeTo : type->elements()) { | ||
getWrappedType(typeTo); | ||
if (visitedStructTypesGraph.count(typeTo) == 0 && typeTo->isStructTy()) { | ||
dfs(llvm::cast<llvm::StructType>(typeTo)); | ||
} | ||
} | ||
|
||
sortedStructTypesGraph.push_back(type); | ||
}; | ||
|
||
for (auto &structType : collectedStructTypes) { | ||
dfs(structType); | ||
} | ||
|
||
for (auto structType : sortedStructTypesGraph) { | ||
if (structType->isOpaque()) { | ||
continue; | ||
} | ||
|
||
/* Here we make initializaion for inner types of given structure type */ | ||
const llvm::StructLayout *structLayout = | ||
parent->targetData->getStructLayout(structType); | ||
for (unsigned idx = 0; idx < structType->getNumElements(); ++idx) { | ||
uint64_t offset = structLayout->getElementOffset(idx); | ||
llvm::Type *rawElementType = structType->getElementType(idx); | ||
typesMap[structType]->innerTypes[typesMap[rawElementType]].push_back( | ||
offset); | ||
|
||
/* Provide initialization from types in inner class */ | ||
for (auto &innerStructMemberTypesToOffsets : | ||
typesMap[rawElementType]->innerTypes) { | ||
KType *innerStructMemberType = innerStructMemberTypesToOffsets.first; | ||
const std::vector<uint64_t> &innerTypeOffsets = | ||
innerStructMemberTypesToOffsets.second; | ||
|
||
/* Add offsets from inner class */ | ||
for (uint64_t innerTypeOffset : innerTypeOffsets) { | ||
typesMap[structType]->innerTypes[innerStructMemberType].emplace_back( | ||
offset + innerTypeOffset); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Performs type system initialization for global objects. | ||
*/ | ||
void TypeManager::initTypesFromGlobals() { | ||
for (auto &global : parent->module->getGlobalList()) { | ||
getWrappedType(global.getType()); | ||
} | ||
} | ||
|
||
/** | ||
* Performs type system initialization for all instructions in | ||
* this module. Takes into consideration return and argument types. | ||
*/ | ||
void TypeManager::initTypesFromInstructions() { | ||
for (auto &function : *(parent->module)) { | ||
auto kf = parent->functionMap[&function]; | ||
|
||
for (auto &BasicBlock : function) { | ||
unsigned numInstructions = kf->blockMap[&BasicBlock]->numInstructions; | ||
KBlock *kb = kf->blockMap[&BasicBlock]; | ||
|
||
for (unsigned i = 0; i < numInstructions; ++i) { | ||
llvm::Instruction *inst = kb->instructions[i]->inst; | ||
|
||
/* Register return type */ | ||
getWrappedType(inst->getType()); | ||
|
||
/* Register types for arguments */ | ||
for (auto opb = inst->op_begin(), ope = inst->op_end(); opb != ope; | ||
++opb) { | ||
getWrappedType((*opb)->getType()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
void TypeManager::onFinishInitModule() {} | ||
|
||
/** | ||
* Method to initialize all types in given module. | ||
* Note, that it cannot be called in costructor | ||
* as implementation of getWrappedType can be different | ||
* for high-level languages. Note, that struct types is | ||
* called last, as it is required to know about all | ||
* structure types in code. | ||
*/ | ||
void TypeManager::initModule() { | ||
initTypesFromGlobals(); | ||
initTypesFromInstructions(); | ||
initTypesFromStructs(); | ||
onFinishInitModule(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#ifndef KLEE_TYPEMANAGER_H | ||
#define KLEE_TYPEMANAGER_H | ||
|
||
#include <memory> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
namespace llvm { | ||
class Type; | ||
class Function; | ||
} // namespace llvm | ||
|
||
namespace klee { | ||
|
||
class Expr; | ||
class KType; | ||
class KModule; | ||
struct KInstruction; | ||
|
||
template <class> class ref; | ||
template <class> class ExprHashMap; | ||
|
||
/** | ||
* Default class for managing type system. | ||
* Works with *raw* llvm types. By extending this | ||
* class you can add more rules to type system. | ||
*/ | ||
class TypeManager { | ||
private: | ||
void initTypesFromGlobals(); | ||
void initTypesFromStructs(); | ||
void initTypesFromInstructions(); | ||
|
||
protected: | ||
KModule *parent; | ||
std::vector<std::unique_ptr<KType>> types; | ||
std::unordered_map<llvm::Type *, KType *> typesMap; | ||
|
||
/** | ||
* Make specified post initialization in initModule(). Note, that | ||
* it is intentionally separated from initModule, as initModule | ||
* order of function calls in it important. By default do nothing. | ||
*/ | ||
virtual void onFinishInitModule(); | ||
|
||
public: | ||
TypeManager(KModule *); | ||
|
||
/** | ||
* Initializes type system for current module. | ||
*/ | ||
void initModule(); | ||
|
||
virtual KType *getWrappedType(llvm::Type *); | ||
KType *getUnknownType(); | ||
|
||
virtual KType *handleAlloc(ref<Expr> size); | ||
virtual KType *handleRealloc(KType *, ref<Expr>); | ||
|
||
virtual ~TypeManager() = default; | ||
}; | ||
|
||
} /*namespace klee*/ | ||
|
||
#endif /* KLEE_TYPEMANAGER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#include "klee/Module/KType.h" | ||
|
||
#include "klee/ADT/Ref.h" | ||
#include "klee/Expr/Expr.h" | ||
#include "klee/Module/KModule.h" | ||
|
||
#include "llvm/IR/DataLayout.h" | ||
#include "llvm/IR/DerivedTypes.h" | ||
#include "llvm/IR/Type.h" | ||
#include "llvm/Support/Casting.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
using namespace klee; | ||
using namespace llvm; | ||
|
||
KType::KType(llvm::Type *type, TypeManager *parent) | ||
: type(type), parent(parent) { | ||
typeSystemKind = TypeSystemKind::LLVM; | ||
/* Type itself can be reached at offset 0 */ | ||
innerTypes[this].emplace_back(0); | ||
} | ||
|
||
bool KType::isAccessableFrom(KType *accessingType) const { return true; } | ||
|
||
llvm::Type *KType::getRawType() const { return type; } | ||
|
||
TypeSystemKind KType::getTypeSystemKind() const { | ||
return typeSystemKind; | ||
} | ||
|
||
void KType::handleMemoryAccess(KType *, ref<Expr>, ref<Expr>, bool isWrite) {} | ||
|
||
void KType::print(llvm::raw_ostream &os) const { | ||
if (type == nullptr) { | ||
os << "nullptr"; | ||
} else { | ||
type->print(os); | ||
} | ||
} |