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