From 24d8ad338387b5f90d89fe4ec3b968b7e4b01610 Mon Sep 17 00:00:00 2001 From: Anton Vassilev Date: Fri, 28 Aug 2020 12:04:12 -0400 Subject: [PATCH] feat(spec): Spec IR generation gen specs if option set Update SpecLang creation build script Add link and make to specLang Add node linking to spec generation SpecLang add Accessed type setter insert types accessed by node Add more attributes to specLang Add new attributes to spec generation Init spec module only once Remove alloca from spec language --- CMakeLists.txt | 12 ++ include/seadsa/DsaLibFuncInfo.hh | 13 ++ include/seadsa/sea_dsa.h | 15 +- lib/seadsa/DsaAnalysis.cc | 2 +- lib/seadsa/DsaBottomUp.cc | 14 +- lib/seadsa/DsaGlobal.cc | 6 +- lib/seadsa/DsaLibFuncInfo.cc | 269 ++++++++++++++++++++++++++++++- lib/seadsa/DsaLocal.cc | 92 +++++++++-- lib/seadsa/SpecLang.cc | 17 ++ 9 files changed, 420 insertions(+), 20 deletions(-) create mode 100644 lib/seadsa/SpecLang.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 52d2f8f2..e6ecaea7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,3 +178,15 @@ install(DIRECTORY include/seadsa DESTINATION include if (TOP_LEVEL) install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.md DESTINATION .) endif() + +if(CMAKE_C_COMPILER_ID STREQUAL Clang) + +add_library(SpecLang OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/lib/seadsa/SpecLang.cc) +target_compile_options(SpecLang BEFORE PRIVATE -S -emit-llvm) +install(FILES $ + DESTINATION lib + RENAME sea_dsa.ll) + +else() + message (WARNING "Unable to build spec language \n\t Set C compiler to clang with -DCMAKE_C_COMPILER") +endif() diff --git a/include/seadsa/DsaLibFuncInfo.hh b/include/seadsa/DsaLibFuncInfo.hh index 6a325a8d..636866b1 100644 --- a/include/seadsa/DsaLibFuncInfo.hh +++ b/include/seadsa/DsaLibFuncInfo.hh @@ -30,11 +30,20 @@ class AllocWrapInfo; class DsaLibFuncInfo : public llvm::ImmutablePass { using ModuleRef = std::unique_ptr; + using GraphRef = std::shared_ptr; + +private: + void initSpecModule() const; protected: mutable bool m_isInitialized = false; + mutable bool m_genSpecOpt = false; mutable llvm::StringMap m_funcs; mutable std::vector m_modules; + // m_specModule uses defs from m_specLang so it must be deallocated after + // m_specModule + mutable ModuleRef m_specLang; + mutable ModuleRef m_specModule; public: static char ID; @@ -44,8 +53,12 @@ public: void getAnalysisUsage(llvm::AnalysisUsage &AU) const override; llvm::StringRef getPassName() const override { return "SeaDsa Spec Pass"; } + bool genSpecs() const { return m_genSpecOpt; } + bool hasSpecFunc(const llvm::Function &F) const; llvm::Function *getSpecFunc(const llvm::Function &F) const; + void generateSpec(const llvm::Function &F, const GraphRef G) const; + void writeSpecModule() const; }; llvm::Pass *createDsaLibFuncInfoPass(); diff --git a/include/seadsa/sea_dsa.h b/include/seadsa/sea_dsa.h index ef6e8c84..ec2a7c59 100644 --- a/include/seadsa/sea_dsa.h +++ b/include/seadsa/sea_dsa.h @@ -21,12 +21,23 @@ extern void sea_dsa_set_ptrtoint(const void *p); extern void sea_dsa_set_inttoptr(const void *p); // sea-dsa will mark the node pointed to by p as heap memory (H) extern void sea_dsa_set_heap(const void *p); -// sea-dsa will mark the node pointed to by p as stack memory (S) -extern void sea_dsa_set_alloca(const void *p); +// sea-dsa will mark the node pointed to by p as external (E) +extern void sea_dsa_set_external(const void *p); // sea-dsa will collapse the argument's cell extern void sea_dsa_collapse(const void *p); // sea-dsa will return a fresh memory object extern void *sea_dsa_new() __attribute__((malloc)); +// like sea_dsa_new except used for creating a node representation of an +// existing memory object +extern void *sea_dsa_mk(); +// links one cell to another cell. Can be manually extended with +// sea_dsa_link_(void *p, unsigned offset, > *p2) in order to +// describe what type it is linking to +extern void sea_dsa_link(const void *p, unsigned offset, const void *p2); +// access type of p. Can manually extend with +// sea_dsa_access_( *p, unsigned offset) in order to describe the +// type p accesses at an offset +extern void sea_dsa_access(const void *p, unsigned offset); // sea-dsa will mark the node pointed by p as a sequence node of size sz // The noded pointed by p cannot be already a sequence node and its // size must be less or equal than sz. diff --git a/lib/seadsa/DsaAnalysis.cc b/lib/seadsa/DsaAnalysis.cc index b6cdb55e..bdf28651 100644 --- a/lib/seadsa/DsaAnalysis.cc +++ b/lib/seadsa/DsaAnalysis.cc @@ -77,8 +77,8 @@ bool DsaAnalysis::runOnModule(Module &M) { m_tliWrapper = &getAnalysis(); m_allocInfo = &getAnalysis(); m_dsaLibFuncInfo = &getAnalysis(); - m_dsaLibFuncInfo->initialize(M); m_allocInfo->initialize(M, this); + m_dsaLibFuncInfo->initialize(M); auto &cg = getAnalysis().getCallGraph(); switch (DsaGlobalAnalysis) { diff --git a/lib/seadsa/DsaBottomUp.cc b/lib/seadsa/DsaBottomUp.cc index a4ed0074..1cf1b4bf 100644 --- a/lib/seadsa/DsaBottomUp.cc +++ b/lib/seadsa/DsaBottomUp.cc @@ -103,12 +103,13 @@ void BottomUpAnalysis::cloneAndResolveArguments( nc.unify(c); } - auto range = llvm::make_filter_range(callee.args(), [](auto &arg) { return arg.getType()->isPointerTy(); }); + auto range = llvm::make_filter_range( + callee.args(), [](auto &arg) { return arg.getType()->isPointerTy(); }); DsaCallSite::const_actual_iterator AI = CS.actual_begin(), AE = CS.actual_end(); - for (auto FI = range.begin(), FE = range.end(); - FI != FE && AI != AE; ++FI, ++AI) { + for (auto FI = range.begin(), FE = range.end(); FI != FE && AI != AE; + ++FI, ++AI) { const Value *arg = (*AI).get(); const Value *fml = &*FI; if (calleeG.hasCell(*fml)) { @@ -203,6 +204,13 @@ bool BottomUpAnalysis::runOnModule(Module &M, GraphMap &graphs) { if (fGraph) fGraph->compress(); } + if (m_dsaLibFuncInfo.genSpecs()) { + for (auto &KVP : graphs) { + m_dsaLibFuncInfo.generateSpec(*KVP.first, KVP.second); + } + m_dsaLibFuncInfo.writeSpecModule(); + } + LOG( "dsa-bu-graph", for (auto &kv : graphs) { diff --git a/lib/seadsa/DsaGlobal.cc b/lib/seadsa/DsaGlobal.cc index 31b1efe3..8b5a173d 100644 --- a/lib/seadsa/DsaGlobal.cc +++ b/lib/seadsa/DsaGlobal.cc @@ -782,8 +782,8 @@ bool ContextSensitiveGlobalPass::runOnModule(Module &M) { auto &tli = getAnalysis(); auto &allocInfo = getAnalysis(); auto &dsaLibFuncInfo = getAnalysis(); - dsaLibFuncInfo.initialize(M); allocInfo.initialize(M, this); + dsaLibFuncInfo.initialize(M); CallGraph *cg = nullptr; if (UseDsaCallGraph) { cg = &getAnalysis().getCompleteCallGraph(); @@ -818,8 +818,8 @@ bool BottomUpTopDownGlobalPass::runOnModule(Module &M) { auto &tli = getAnalysis(); auto &allocInfo = getAnalysis(); auto &dsaLibFuncInfo = getAnalysis(); - dsaLibFuncInfo.initialize(M); allocInfo.initialize(M, this); + dsaLibFuncInfo.initialize(M); CallGraph *cg = nullptr; if (UseDsaCallGraph) { cg = &getAnalysis().getCompleteCallGraph(); @@ -853,8 +853,8 @@ bool BottomUpGlobalPass::runOnModule(Module &M) { auto &tli = getAnalysis(); auto &allocInfo = getAnalysis(); auto &dsaLibFuncInfo = getAnalysis(); - dsaLibFuncInfo.initialize(M); allocInfo.initialize(M, this); + dsaLibFuncInfo.initialize(M); CallGraph *cg = nullptr; if (UseDsaCallGraph) { cg = &getAnalysis().getCompleteCallGraph(); diff --git a/lib/seadsa/DsaLibFuncInfo.cc b/lib/seadsa/DsaLibFuncInfo.cc index 23733b19..c0056099 100644 --- a/lib/seadsa/DsaLibFuncInfo.cc +++ b/lib/seadsa/DsaLibFuncInfo.cc @@ -1,6 +1,8 @@ #include "llvm/ADT/Twine.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Pass.h" @@ -14,7 +16,9 @@ #include "seadsa/Graph.hh" #include "seadsa/InitializePasses.hh" #include "seadsa/support/Debug.h" +#include #include +#include static llvm::cl::list XSpecFiles("sea-dsa-specfile", llvm::cl::desc(""), @@ -25,6 +29,10 @@ static llvm::cl::opt XUseClibSpec( llvm::cl::desc("Replace clib functions with spec defined by seadsa"), llvm::cl::Optional, llvm::cl::init(false)); +static llvm::cl::opt + XGenSpecs("sea-dsa-gen-specs", llvm::cl::desc(""), + llvm::cl::Optional, llvm::cl::value_desc("filename")); + namespace seadsa { void DsaLibFuncInfo::getAnalysisUsage(llvm::AnalysisUsage &AU) const { @@ -33,20 +41,81 @@ void DsaLibFuncInfo::getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.setPreservesAll(); } +void DsaLibFuncInfo::initSpecModule() const { + auto specFnModify = m_specLang->getFunction("sea_dsa_set_modified"); + auto specFnRead = m_specLang->getFunction("sea_dsa_set_read"); + auto specFnCollapse = m_specLang->getFunction("sea_dsa_collapse"); + auto specFnHeap = m_specLang->getFunction("sea_dsa_set_heap"); + auto specFnP2I = m_specLang->getFunction("sea_dsa_set_ptrtoint"); + auto specFnI2P = m_specLang->getFunction("sea_dsa_set_inttoptr"); + auto specFnExtern = m_specLang->getFunction("sea_dsa_set_external"); + auto specFnAlias = m_specLang->getFunction("sea_dsa_alias"); + auto specFnMk = m_specLang->getFunction("sea_dsa_mk"); + auto specFnLink = m_specLang->getFunction("sea_dsa_link"); + auto specFnAccess = m_specLang->getFunction("sea_dsa_access"); + + assert(specFnModify != nullptr && "Could not find sea_dsa_set_modified"); + assert(specFnRead != nullptr && "Could not find sea_dsa_set_read"); + assert(specFnCollapse != nullptr && "Could not find sea_dsa_set_heap"); + assert(specFnHeap != nullptr && "Could not find sea_dsa_collapse"); + assert(specFnP2I != nullptr && "Could not find sea_dsa_set_ptrtoint"); + assert(specFnI2P != nullptr && "Could not find sea_dsa_set_inttoptr"); + assert(specFnExtern != nullptr && "Could not find sea_dsa_set_external"); + assert(specFnAlias != nullptr && "Could not find sea_dsa_alias"); + assert(specFnMk != nullptr && "Could not find sea_dsa_mk"); + assert(specFnLink != nullptr && "Could not find sea_dsa_link"); + assert(specFnAccess != nullptr && "Could not find sea_dsa_access"); + + m_specModule->getOrInsertFunction(specFnModify->getName(), + specFnModify->getFunctionType()); + m_specModule->getOrInsertFunction(specFnRead->getName(), + specFnRead->getFunctionType()); + m_specModule->getOrInsertFunction(specFnCollapse->getName(), + specFnCollapse->getFunctionType()); + m_specModule->getOrInsertFunction(specFnHeap->getName(), + specFnHeap->getFunctionType()); + m_specModule->getOrInsertFunction(specFnP2I->getName(), + specFnP2I->getFunctionType()); + m_specModule->getOrInsertFunction(specFnI2P->getName(), + specFnI2P->getFunctionType()); + m_specModule->getOrInsertFunction(specFnExtern->getName(), + specFnExtern->getFunctionType()); + m_specModule->getOrInsertFunction(specFnAlias->getName(), + specFnAlias->getFunctionType()); + m_specModule->getOrInsertFunction(specFnMk->getName(), + specFnMk->getFunctionType()); + m_specModule->getOrInsertFunction(specFnLink->getName(), + specFnLink->getFunctionType()); + m_specModule->getOrInsertFunction(specFnAccess->getName(), + specFnAccess->getFunctionType()); +} + void DsaLibFuncInfo::initialize(const llvm::Module &M) const { using namespace llvm::sys::fs; using namespace llvm; - if (m_isInitialized || (XSpecFiles.empty() && !XUseClibSpec)) return; + if (m_isInitialized || + (XSpecFiles.empty() && !XUseClibSpec && XGenSpecs.empty())) + return; m_isInitialized = true; - auto dl = M.getDataLayout(); SMDiagnostic err; + auto &dl = M.getDataLayout(); + auto &ctx = M.getContext(); auto exePath = getMainExecutable(nullptr, nullptr); StringRef exeDir = llvm::sys::path::parent_path(exePath); + const StringRef specLangRel = "../lib/sea_dsa.ll"; + llvm::SmallString<256> specLangAbs = specLangRel; + make_absolute(exeDir, specLangAbs); + m_specLang = parseIRFile(specLangAbs.str(), err, ctx); + + if (m_specLang.get() == 0) + LOG("sea-libFunc", errs() << "Error reading sea_dsa.h bitcode: " + << err.getMessage() << "\n"); + if (XUseClibSpec) { if (dl.getPointerSizeInBits() == 32) { const StringRef libcSpecRel = "../lib/libc-32.spec.bc"; @@ -96,6 +165,14 @@ void DsaLibFuncInfo::initialize(const llvm::Module &M) const { } } } + + if (!XGenSpecs.empty()) { + m_genSpecOpt = true; + m_specModule = std::make_unique(M.getName(), ctx); + m_specModule->setDataLayout(dl); + m_specModule->setSourceFileName(XGenSpecs); + initSpecModule(); + } } // namespace seadsa bool DsaLibFuncInfo::hasSpecFunc(const llvm::Function &F) const { @@ -108,6 +185,194 @@ llvm::Function *DsaLibFuncInfo::getSpecFunc(const llvm::Function &F) const { return it->second; } +void DsaLibFuncInfo::generateSpec(const llvm::Function &F, + const GraphRef G) const { + using namespace llvm; + + auto specFnModify = m_specModule->getFunction("sea_dsa_set_modified"); + auto specFnRead = m_specModule->getFunction("sea_dsa_set_read"); + auto specFnCollapse = m_specModule->getFunction("sea_dsa_collapse"); + auto specFnHeap = m_specModule->getFunction("sea_dsa_set_heap"); + auto specFnP2I = m_specModule->getFunction("sea_dsa_set_ptrtoint"); + auto specFnI2P = m_specModule->getFunction("sea_dsa_set_inttoptr"); + auto specFnExtern = m_specModule->getFunction("sea_dsa_set_external"); + auto specFnAlias = m_specModule->getFunction("sea_dsa_alias"); + auto specFnMk = m_specModule->getFunction("sea_dsa_mk"); + auto specFnLink = m_specModule->getFunction("sea_dsa_link"); + auto specFnAccess = m_specModule->getFunction("sea_dsa_access"); + + if (F.getName() == "main") return; + if (F.isDeclaration() || F.empty()) return; + + auto fnCallee = + m_specModule->getOrInsertFunction(F.getName(), F.getFunctionType()); + + llvm::Function *specFn = cast(fnCallee.getCallee()); + + assert(&specFn->getContext() == &m_specModule->getContext() && + "Contexts different, unable to create calls"); + + llvm::BasicBlock *block = + llvm::BasicBlock::Create(F.getContext(), specFn->getName(), specFn); + + llvm::IRBuilder<> builder(block); + + auto getOrInsertAccessFnTy = [](const ModuleRef &specM, + Type *ty) -> Function * { + if (!ty) return specM->getFunction("sea_dsa_access"); + + std::string tyStr; + llvm::raw_string_ostream rso(tyStr); + ty->print(rso); + + auto str = rso.str(); + Function *baseFn = specM->getFunction("sea_dsa_access"); + + auto baseFnTy = baseFn->getFunctionType(); + llvm::FunctionType *derivedFnTy = llvm::FunctionType::get( + baseFnTy->getReturnType(), {ty, baseFnTy->getParamType(1)}, false); + + return llvm::dyn_cast( + specM->getOrInsertFunction("sea_dsa_access_" + str, derivedFnTy) + .getCallee()); + }; + + auto getOrInsertLinkFnTy = [](const ModuleRef &specM, + Type *ty) -> Function * { + if (!ty) return specM->getFunction("sea_dsa_link"); + + std::string tyStr; + llvm::raw_string_ostream rso(tyStr); + ty->print(rso); + + auto str = rso.str(); + Function *baseFn = specM->getFunction("sea_dsa_link"); + + auto baseFnTy = baseFn->getFunctionType(); + llvm::FunctionType *derivedFnTy = llvm::FunctionType::get( + baseFnTy->getReturnType(), + {baseFnTy->getParamType(0), baseFnTy->getParamType(1), ty}, false); + + return llvm::dyn_cast( + specM->getOrInsertFunction("sea_dsa_link_to" + str, derivedFnTy) + .getCallee()); + }; + + // sets the attributes that the original node has onto the spec graph value + auto setAttributes = [&](const Node *gNode, Value *specVal) { + auto bitCastVal = builder.CreateBitCast(specVal, builder.getInt8PtrTy()); + + if (gNode->isModified()) { builder.CreateCall(specFnModify, bitCastVal); } + if (gNode->isHeap()) { builder.CreateCall(specFnHeap, bitCastVal); } + if (gNode->isRead()) { builder.CreateCall(specFnRead, bitCastVal); } + if (gNode->isOffsetCollapsed()) { + builder.CreateCall(specFnCollapse, bitCastVal); + } + if (gNode->isPtrToInt()) { builder.CreateCall(specFnP2I, bitCastVal); } + if (gNode->isIntToPtr()) { builder.CreateCall(specFnI2P, bitCastVal); } + if (gNode->isExternal()) { builder.CreateCall(specFnExtern, bitCastVal); } + }; + + auto FI = G->formal_begin(); + auto FE = G->formal_end(); + + std::stack> visitStack; + llvm::DenseMap aliasMap; + + auto fIt = F.arg_begin(); + auto specIt = specFn->arg_begin(); + + for (; fIt != F.arg_end(); ++fIt, ++specIt) { + if (!fIt->getType()->isPointerTy()) continue; + if (!G->hasCell(*fIt)) continue; + + Value &v = *specIt; + Value *castVal = builder.CreateBitCast(&v, builder.getInt8PtrTy()); + visitStack.push({G->getCell(*fIt).getNode(), castVal}); + } + + Value *retVal = nullptr; + if (F.getReturnType()->isPointerTy() && G->hasRetCell(F)) { + retVal = builder.CreateCall(specFnMk, llvm::None, "ret"); + visitStack.push({G->getRetCell(F).getNode(), retVal}); + } + + while (!visitStack.empty()) { + auto graphNode = visitStack.top().first; + auto specVal = visitStack.top().second; + visitStack.pop(); + + // we have already visited this node + if (aliasMap.count(graphNode)) { + builder.CreateCall(specFnAlias, + {aliasMap.find(graphNode)->second, specVal}); + } else { + for (auto &link : graphNode->links()) { + Value *newNodeVal = builder.CreateCall(specFnMk); + + Type *ty = link.first.getType().getLLVMType(); + unsigned offset = link.first.getOffset(); + + auto uIntTy = llvm::Type::getInt32Ty(m_specModule->getContext()); + auto llvmOffset = llvm::ConstantInt::get( + uIntTy, llvm::APInt(uIntTy->getIntegerBitWidth(), offset, false)); + + auto linkFn = getOrInsertLinkFnTy(m_specModule, ty); + Value *castChild; + if (ty) + castChild = builder.CreateBitCast(newNodeVal, ty); + else + castChild = builder.CreateBitCast( + newNodeVal, llvm::Type::getInt8PtrTy(m_specModule->getContext())); + builder.CreateCall(linkFn, {specVal, llvmOffset, castChild}); + + visitStack.push({link.second->getNode(), newNodeVal}); + } + + // set all accessed types of the node + for (auto &typeIt : graphNode->types()) { + unsigned offset = typeIt.first; + auto typeSet = typeIt.second; + + auto uIntTy = llvm::Type::getInt32Ty(m_specModule->getContext()); + auto llvmOffset = llvm::ConstantInt::get( + uIntTy, llvm::APInt(uIntTy->getIntegerBitWidth(), offset, false)); + + for (auto type : typeSet) { + if (!type->isPointerTy()) continue; + + auto mutTy = const_cast(type); + Function *accessFn = getOrInsertAccessFnTy(m_specModule, mutTy); + + auto castVal = builder.CreateBitCast(specVal, mutTy); + builder.CreateCall(accessFn, {castVal, llvmOffset}); + } + } + + // set the attributes for the current node + setAttributes(graphNode, specVal); + // assert that we have visited this node + aliasMap.insert({graphNode, specVal}); + } + } + + // handle the return cell + if (G->hasRetCell(F) && F.getReturnType()->isPointerTy()) { + retVal = builder.CreateBitCast(retVal, F.getReturnType(), "castRet"); + builder.CreateRet(retVal); + } else if (!retVal && F.getReturnType()->getTypeID()) { + retVal = builder.CreateAlloca(F.getReturnType(), nullptr); + Value *loadedRet = builder.CreateLoad(retVal); + builder.CreateRet(loadedRet); + } +} + +void DsaLibFuncInfo::writeSpecModule() const { + std::error_code ec; + llvm::raw_fd_ostream ofs(m_specModule->getSourceFileName(), ec); + m_specModule->print(ofs, nullptr); +} + char DsaLibFuncInfo::ID = 0; } // namespace seadsa diff --git a/lib/seadsa/DsaLocal.cc b/lib/seadsa/DsaLocal.cc index 4a59ecbf..72fd27e9 100644 --- a/lib/seadsa/DsaLocal.cc +++ b/lib/seadsa/DsaLocal.cc @@ -424,9 +424,14 @@ enum class SeadsaFn { READ, HEAP, PTR_TO_INT, + INT_TO_PTR, + EXTERN, ALIAS, COLLAPSE, MAKE_SEQ, + LINK, + MAKE, + ACCESS, UNKNOWN }; @@ -476,15 +481,30 @@ class IntraBlockBuilder : public InstVisitor, SeadsaFn getSeaDsaFn(const Function *fn) { if (!fn) return SeadsaFn::UNKNOWN; - return StringSwitch(fn->getName()) - .Case("sea_dsa_set_modified", SeadsaFn::MODIFY) - .Case("sea_dsa_set_read", SeadsaFn::READ) - .Case("sea_dsa_set_heap", SeadsaFn::HEAP) - .Case("sea_dsa_set_ptrtoint", SeadsaFn::PTR_TO_INT) - .Case("sea_dsa_alias", SeadsaFn::ALIAS) - .Case("sea_dsa_collapse", SeadsaFn::COLLAPSE) - .Case("sea_dsa_mk_seq", SeadsaFn::MAKE_SEQ) - .Default(SeadsaFn::UNKNOWN); + SeadsaFn fnType = StringSwitch(fn->getName()) + .Case("sea_dsa_set_modified", SeadsaFn::MODIFY) + .Case("sea_dsa_set_read", SeadsaFn::READ) + .Case("sea_dsa_set_heap", SeadsaFn::HEAP) + .Case("sea_dsa_set_ptrtoint", SeadsaFn::PTR_TO_INT) + .Case("sea_dsa_set_inttoptr", SeadsaFn::INT_TO_PTR) + .Case("sea_dsa_set_extern", SeadsaFn::EXTERN) + .Case("sea_dsa_alias", SeadsaFn::ALIAS) + .Case("sea_dsa_collapse", SeadsaFn::COLLAPSE) + .Case("sea_dsa_mk_seq", SeadsaFn::MAKE_SEQ) + .Case("sea_dsa_mk", SeadsaFn::MAKE) + .Default(SeadsaFn::UNKNOWN); + + if (fnType != SeadsaFn::UNKNOWN) return fnType; + + // the spec generator requires sea_dsa_link to have type information, so we + // may need to define multiple sea_dsa_link types. For example: + // sea_dsa_link_to_charptr(const void *p, unsigned offset, const char* + // p2); + if (fn->getName().startswith("sea_dsa_link")) fnType = SeadsaFn::LINK; + else if (fn->getName().startswith("sea_dsa_access")) + fnType = SeadsaFn::ACCESS; + + return fnType; } /// Returns true if \p F is a \p seadsa_ family of functions @@ -507,6 +527,10 @@ class IntraBlockBuilder : public InstVisitor, return &seadsa::Node::setHeap; case SeadsaFn::PTR_TO_INT: return &seadsa::Node::setPtrToInt; + case SeadsaFn::INT_TO_PTR: + return &seadsa::Node::setIntToPtr; + case SeadsaFn::EXTERN: + return &seadsa::Node::setExternal; default: return nullptr; } @@ -1192,6 +1216,8 @@ void IntraBlockBuilder::visitSeaDsaFnCall(CallSite &CS) { case SeadsaFn::MODIFY: case SeadsaFn::READ: case SeadsaFn::HEAP: + case SeadsaFn::EXTERN: + case SeadsaFn::INT_TO_PTR: case SeadsaFn::PTR_TO_INT: { // sea_dsa_read(const void *p) -- mark the node pointed to by p as read Value *arg = nullptr; @@ -1301,6 +1327,54 @@ void IntraBlockBuilder::visitSeaDsaFnCall(CallSite &CS) { return; } + case SeadsaFn::LINK: { + // seadsa_load(p, off) -- return pointer at offset + Value *arg0 = nullptr; + ConstantInt *arg1 = nullptr; + Value *arg2 = nullptr; + + if (!(match(CS.getArgument(0), m_Value(arg0)) && + arg0->getType()->isPointerTy())) + return; + if (!match(CS.getArgument(1), m_ConstantInt(arg1))) return; + if (!(match(CS.getArgument(2), m_Value(arg2)) && + arg2->getType()->isPointerTy())) + return; + + if (isSkip(*arg0) || isSkip(*arg2)) return; + if (!m_graph.hasCell(*arg0) || !m_graph.hasCell(*arg2)) return; + + seadsa::Node *n = m_graph.getCell(*arg0).getNode(); + seadsa::Cell c2 = m_graph.getCell(*arg2); + n->addLink(Field(arg1->getZExtValue(), FieldType(arg2->getType())), c2); + + return; + } + + case SeadsaFn::MAKE: { + // seadsa_set_type(str_type) -- set the node type to the given type + Node &n = m_graph.mkNode(); + m_graph.mkCell(*CS.getInstruction(), Cell(n, 0)); + return; + } + + case SeadsaFn::ACCESS: { + // seadsa_access_( *p, unsigned o) -- node accesses at o + Value *arg0 = nullptr; + ConstantInt *arg1 = nullptr; + + if (!(match(CS.getArgument(0), m_Value(arg0)) && + arg0->getType()->isPointerTy())) + return; + if (!match(CS.getArgument(1), m_ConstantInt(arg1))) return; + if (isSkip(*arg0)) return; + if (!m_graph.hasCell(*arg0)) return; + + seadsa::Node *n = m_graph.getCell(*arg0).getNode(); + n->addAccessedType(arg1->getZExtValue(), arg0->getType()); + return; + } + default: { visitExternalCall(CS); return; diff --git a/lib/seadsa/SpecLang.cc b/lib/seadsa/SpecLang.cc new file mode 100644 index 00000000..c8e7c56a --- /dev/null +++ b/lib/seadsa/SpecLang.cc @@ -0,0 +1,17 @@ +#include "seadsa/sea_dsa.h" + +int main() { + void *p = sea_dsa_new(); + sea_dsa_collapse(p); + sea_dsa_set_heap(p); + sea_dsa_set_read(p); + sea_dsa_set_modified(p); + sea_dsa_set_ptrtoint(p); + sea_dsa_set_inttoptr(p); + sea_dsa_set_external(p); + sea_dsa_alias(p); + sea_dsa_link(p, 0, p); + sea_dsa_access(p, 0); + void *a = sea_dsa_mk(); + return 0; +} \ No newline at end of file