Skip to content

Commit

Permalink
Implemented classes for types in type system. Added handling TypeMana…
Browse files Browse the repository at this point in the history
…ger entity, that can create such these KType's.
  • Loading branch information
S1eGa committed Aug 23, 2022
1 parent b2e8b2a commit ec8aa20
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 0 deletions.
84 changes: 84 additions & 0 deletions include/klee/Module/KType.h
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
1 change: 1 addition & 0 deletions lib/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ klee_add_component(kleeCore
SpecialFunctionHandler.cpp
StatsTracker.cpp
TimingSolver.cpp
TypeManager.cpp
UserSearcher.cpp
)

Expand Down
178 changes: 178 additions & 0 deletions lib/Core/TypeManager.cpp
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();
}
65 changes: 65 additions & 0 deletions lib/Core/TypeManager.h
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 */
1 change: 1 addition & 0 deletions lib/Module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(KLEE_MODULE_COMPONENT_SRCS
IntrinsicCleaner.cpp
KInstruction.cpp
KModule.cpp
KType.cpp
LowerSwitch.cpp
ModuleUtil.cpp
Optimize.cpp
Expand Down
39 changes: 39 additions & 0 deletions lib/Module/KType.cpp
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);
}
}

0 comments on commit ec8aa20

Please sign in to comment.