├── .gitconfig ├── demo ├── pdg.png └── test.c ├── test └── pdg_test │ ├── build.sh │ ├── bitcode │ └── test_malloc_anno.bc │ ├── test_malloc_anno.c │ ├── err.log │ └── llvm_ll │ └── test_malloc_anno.ll ├── include ├── PDGCommandLineOptions.hpp ├── CallWrapper.hpp ├── AllPasses.hpp ├── PDGEnums.hpp ├── ArgumentWrapper.hpp ├── ControlDependencyGraph.hpp ├── DependencyGraph.hpp ├── PDGUtils.hpp ├── FunctionWrapper.hpp ├── DataDependencyGraph.hpp ├── PDGExceptions.hpp ├── DependencyNode.hpp ├── ProgramDependencyGraph.hpp └── InstructionWrapper.hpp ├── Makefile ├── .gitignore ├── src ├── CallWrapper.cpp ├── DependencyNode.tpp ├── PDGUtils.cpp ├── DependencyGraph.tpp ├── FunctionWrapper.cpp ├── ArgumentWrapper.cpp ├── ControlDependencyGraph.cpp ├── DataDependencyGraph.cpp ├── DepPrinter.cpp └── ProgramDependencyGraph.cpp ├── .vscode └── settings.json ├── LICENSE ├── CMakeLists.txt ├── lib └── catch2 │ ├── catch_reporter_automake.hpp │ ├── catch_reporter_teamcity.hpp │ └── catch_reporter_tap.hpp └── README.md /.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | email = paz215@lehigh.edu 3 | name = pantea zardoshti 4 | -------------------------------------------------------------------------------- /demo/pdg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZiwenWan/Program-Dependence-Graph-in-LLVM/HEAD/demo/pdg.png -------------------------------------------------------------------------------- /test/pdg_test/build.sh: -------------------------------------------------------------------------------- 1 | clang -emit-llvm -S -g *.c 2 | 3 | for f in *.ll; do 4 | llvm-as $f 5 | done 6 | 7 | mv *.ll ./llvm_ll 8 | mv *.bc ./bitcode 9 | -------------------------------------------------------------------------------- /test/pdg_test/bitcode/test_malloc_anno.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZiwenWan/Program-Dependence-Graph-in-LLVM/HEAD/test/pdg_test/bitcode/test_malloc_anno.bc -------------------------------------------------------------------------------- /include/PDGCommandLineOptions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDLINEOPTIONS_H_ 2 | #define COMMANDLINEOPTIONS_H_ 3 | #include "llvm/Support/CommandLine.h" 4 | 5 | namespace pdg { 6 | // command line options 7 | extern int EXPAND_LEVEL; 8 | extern int USEDEBUGINFO; 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ODIR = ./build 2 | output_folder := $(shell mkdir -p $(ODIR)) 3 | 4 | all: libplugin.so 5 | 6 | libplugin.so: 7 | @echo Configuring... 8 | @cd $(ODIR) && cmake .. 9 | @echo Building... 10 | @$(MAKE) -C $(ODIR) 11 | 12 | clean: 13 | @echo Cleaning up... 14 | @rm -rf $(ODIR) 15 | 16 | -------------------------------------------------------------------------------- /test/pdg_test/test_malloc_anno.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((noinline)) 4 | void *pz_malloc(size_t size) { return malloc(size);} 5 | 6 | __attribute__((noinline)) 7 | void pz_free(void* p) { free(p); } 8 | 9 | int main(int argc, char **argv) { 10 | __attribute__((annotate("persist"))) 11 | int* p_r2 = (int*)pz_malloc(sizeof(int)); 12 | *p_r2 = 7; 13 | pz_free(p_r2); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | .vscode 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | # Java 30 | *.class 31 | /build 32 | -------------------------------------------------------------------------------- /demo/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct clothes { 4 | char color[10]; 5 | int length; 6 | } Clothes; 7 | 8 | typedef struct person_t { 9 | int age; 10 | char name[10]; 11 | Clothes *s; 12 | } Person; 13 | 14 | void f(Person *p1) { 15 | char *name = p1->name; 16 | char *color = p1->s->color; 17 | p1->age = 10; 18 | printf("%s is wearing %s today.", name, color); 19 | } 20 | 21 | int main() { 22 | Clothes c = {"red", 5}; 23 | Person p = {10, "Jack", &c}; 24 | Person *pt = &p; 25 | f(pt); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/pdg_test/err.log: -------------------------------------------------------------------------------- 1 | WARNING: You're attempting to print out a bitcode file. 2 | This is inadvisable as it may cause display problems. If 3 | you REALLY want to taste LLVM bitcode first-hand, you 4 | can force output with the `-f' option. 5 | 6 | ARGW size: 1 7 | ARGW size: 2 8 | %7 = bitcast i32** %6 to i8* 9 | %9 = bitcast i8* %8 to i32* 10 | %12 = bitcast i32* %11 to i8* 11 | %7 = bitcast i32** %6 to i8* 12 | %9 = bitcast i8* %8 to i32* 13 | %12 = bitcast i32* %11 to i8* 14 | ARGW size: 1 15 | ARGW size: 3 16 | pz_malloc: 1 17 | pz_free: 2 18 | main: 1 19 | main: 3 20 | Writing 'pdgragh.pz_malloc.dot'... 21 | Writing 'pdgragh.pz_free.dot'... 22 | Writing 'pdgragh.main.dot'... 23 | -------------------------------------------------------------------------------- /include/CallWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CALLWRAPPER_H_ 2 | #define CALLWRAPPER_H_ 3 | #include "llvm/IR/Function.h" 4 | #include "llvm/IR/Instructions.h" 5 | #include "InstructionWrapper.hpp" 6 | #include "ArgumentWrapper.hpp" 7 | 8 | namespace pdg 9 | { 10 | class CallWrapper 11 | { 12 | public: 13 | CallWrapper() = delete; 14 | CallWrapper(llvm::CallInst *CI); 15 | CallWrapper(llvm::CallInst *CI, std::vector indirect_call_candidates); 16 | llvm::CallInst *getCallInst() { return CI; } 17 | std::vector &getArgWList() { return argWList; } 18 | 19 | private: 20 | llvm::CallInst *CI; 21 | std::vector argWList; 22 | }; 23 | } // namespace pdg 24 | 25 | #endif -------------------------------------------------------------------------------- /include/AllPasses.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ALLPASS_H_ 2 | #define ALLPASS_H_ 3 | #include "llvm/Pass.h" 4 | 5 | namespace pdg 6 | { 7 | class ControlDependencyGraph; 8 | class DataDependencyGraph; 9 | class ProgramDependencyGraph; 10 | 11 | ControlDependencyGraph *CreateControlDependencyGraphPass(); 12 | DataDependencyGraph *CreateDataDependencyGraphPass(); 13 | ProgramDependencyGraph *CreateProgramDependencyGraphPass(); 14 | } // namespace pdg 15 | 16 | namespace llvm { 17 | void initializeControlDependencyGraphPass(PassRegistry &Registry); 18 | class PassRegistry; 19 | void initializeControlDependencyGraphPass(PassRegistry &Registry); 20 | void initializeDataDependencyGraphPass(PassRegistry &Registry); 21 | void initializeProgramDependencyGraphPass(PassRegistry &Registry); 22 | void initializeProgramDependencyPrinterPass(PassRegistry &Registry); 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/CallWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "CallWrapper.hpp" 2 | 3 | using namespace llvm; 4 | 5 | pdg::CallWrapper::CallWrapper(llvm::CallInst *CI) 6 | { 7 | this->CI = CI; 8 | for (Function::arg_iterator argIt = CI->getCalledFunction()->arg_begin(); 9 | argIt != CI->getCalledFunction()->arg_end(); ++argIt) 10 | { 11 | Argument *arg = &*argIt; 12 | ArgumentWrapper *argW = new ArgumentWrapper(arg); 13 | argWList.push_back(argW); 14 | } 15 | } 16 | 17 | pdg::CallWrapper::CallWrapper(CallInst *CI, std::vector indirect_call_candidates) 18 | { 19 | this->CI = CI; 20 | // constructor for indirect call instruction 21 | Function *candidate_func = indirect_call_candidates[0]; 22 | for (Function::arg_iterator argIt = candidate_func->arg_begin(); 23 | argIt != candidate_func->arg_end(); ++argIt) 24 | { 25 | Argument *arg = &*argIt; 26 | ArgumentWrapper *argW = new ArgumentWrapper(arg); 27 | argWList.push_back(argW); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /include/PDGEnums.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PDGENUMS_H_ 2 | #define PDGENUMS_H_ 3 | 4 | namespace pdg 5 | { 6 | enum class DependencyType 7 | { 8 | CALL, 9 | CONTROL, 10 | DATA_GENERAL, 11 | DATA_DEF_USE, 12 | DATA_RAW, 13 | DATA_READ, 14 | DATA_ALIAS, 15 | DATA_CALL_PARA, 16 | PARAMETER, 17 | STRUCT_FIELDS, 18 | NO_DEPENDENCY, 19 | GLOBAL_DEP 20 | }; 21 | 22 | enum class GraphNodeType 23 | { 24 | INST, 25 | FORMAL_IN, 26 | FORMAL_OUT, 27 | ACTUAL_IN, 28 | ACTUAL_OUT, 29 | RETURN, 30 | POINTER_RW, 31 | PARAMETER_FIELD, 32 | ENTRY, 33 | STRUCT_FIELD, 34 | GLOBAL_VALUE 35 | }; 36 | 37 | enum class ControlType 38 | { 39 | CTRUE, 40 | CFALSE, 41 | OTHER 42 | }; 43 | 44 | enum class AccessType 45 | { 46 | NOACCESS = 0, 47 | READ, 48 | WRITE 49 | }; 50 | 51 | enum class TreeType 52 | { 53 | ACTUAL_IN_TREE, 54 | ACTUAL_OUT_TREE, 55 | FORMAL_IN_TREE, 56 | FORMAL_OUT_TREE 57 | }; 58 | 59 | enum class ArgumentMatchType { 60 | NOTCONTAINED, 61 | CONTAINED, 62 | EQUAL 63 | }; 64 | 65 | } // namespace pdg 66 | 67 | #endif -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "__bit_reference": "cpp", 4 | "__split_buffer": "cpp", 5 | "__tree": "cpp", 6 | "array": "cpp", 7 | "deque": "cpp", 8 | "initializer_list": "cpp", 9 | "iterator": "cpp", 10 | "map": "cpp", 11 | "regex": "cpp", 12 | "set": "cpp", 13 | "string": "cpp", 14 | "string_view": "cpp", 15 | "vector": "cpp", 16 | "cctype": "cpp", 17 | "clocale": "cpp", 18 | "cmath": "cpp", 19 | "cstddef": "cpp", 20 | "cstdio": "cpp", 21 | "cstdlib": "cpp", 22 | "ctime": "cpp", 23 | "cwchar": "cpp", 24 | "cwctype": "cpp", 25 | "atomic": "cpp", 26 | "*.tcc": "cpp", 27 | "cstdint": "cpp", 28 | "exception": "cpp", 29 | "memory_resource": "cpp", 30 | "fstream": "cpp", 31 | "iosfwd": "cpp", 32 | "iostream": "cpp", 33 | "istream": "cpp", 34 | "limits": "cpp", 35 | "memory": "cpp", 36 | "ostream": "cpp", 37 | "sstream": "cpp", 38 | "stdexcept": "cpp", 39 | "streambuf": "cpp", 40 | "typeinfo": "cpp" 41 | } 42 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2019] [PSU SOS Lab] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/DependencyNode.tpp: -------------------------------------------------------------------------------- 1 | using namespace pdg; 2 | 3 | template 4 | void DependencyNode::addDependencyTo(DependencyNode *pNode, DependencyType type) 5 | { 6 | if (pNode == this) 7 | return; 8 | DependencyLink link = DependencyLink(pNode, type); 9 | if (std::find(dependencyList.begin(), dependencyList.end(), link) == dependencyList.end()) 10 | { 11 | dependencyList.push_back(link); 12 | } 13 | } 14 | 15 | template 16 | bool DependencyNode::isDepends(const DependencyNode *dNode) 17 | { 18 | if (dNode == nullptr) 19 | { 20 | throw DependencyNodeIsNullptrException("Dependency Node is nullptr."); 21 | } 22 | for (auto link : dependencyList) 23 | { 24 | if (link.first == dNode) 25 | { 26 | return true; 27 | } 28 | } 29 | return false; 30 | } 31 | 32 | template 33 | DependencyType DependencyNode::getDependencyType(const DependencyNode *dNode) const 34 | { 35 | if (dNode == nullptr) 36 | { 37 | throw DependencyNodeIsNullptrException("Dependency Node is nullptr."); 38 | } 39 | 40 | for (auto link : dependencyList) 41 | { 42 | if (link.first == dNode) 43 | { 44 | return link.second; 45 | } 46 | } 47 | 48 | return DependencyType::NO_DEPENDENCY; 49 | } -------------------------------------------------------------------------------- /include/ArgumentWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARGUMENTWRAPPER_H_ 2 | #define ARGUMENTWRAPPER_H_ 3 | #include "llvm/IR/Argument.h" 4 | #include "InstructionWrapper.hpp" 5 | #include "PDGEnums.hpp" 6 | #include "tree.hh" 7 | 8 | namespace pdg 9 | { 10 | class ArgumentWrapper 11 | { 12 | private: 13 | llvm::Argument *arg; 14 | llvm::Function *Func; 15 | tree formalInTree; 16 | tree formalOutTree; 17 | tree actualInTree; 18 | tree actualOutTree; 19 | std::vector> paramCallInstPairs; 20 | public: 21 | ArgumentWrapper() = delete; 22 | explicit ArgumentWrapper(llvm::Argument *arg); 23 | llvm::Argument *getArg(); 24 | tree &getTree(TreeType treeTy); 25 | std::vector> getParamCallInstPair() const { return paramCallInstPairs; } 26 | void addParamCallInstW(std::pair paramCallPair) { paramCallInstPairs.push_back(paramCallPair); } 27 | void copyTree(const tree &srcTree, TreeType treeTy); 28 | tree::iterator tree_begin(TreeType treeTy); 29 | tree::iterator tree_end(TreeType treeTy); 30 | }; 31 | 32 | } // namespace pdg 33 | 34 | #endif -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(pdg) 3 | find_package(LLVM REQUIRED CONFIG) 4 | add_definitions(${LLVM_DEFINITIONS}) 5 | include_directories(${LLVM_INCLUDE_DIRS}) 6 | link_directories(${LLVM_LIBRARY_DIRS}) 7 | set (CMAKE_CXX_STANDARD 11) 8 | 9 | # 10 | # We will build one library: libtmplugin.so. It corresponds to a plugin that we 11 | # run when compiling. 12 | # 13 | #option(USE_CXX_EXCEPTIONS "Enable C++ exception support" ON) 14 | # 15 | # Files associated with libtmplugin.so 16 | # 17 | 18 | include_directories("include") 19 | include_directories("src") 20 | 21 | file(GLOB TPPSRC "src/*.tpp") 22 | file(GLOB SOURCES "src/*.cpp") 23 | file(GLOB HEADERS "include/*.hpp") 24 | 25 | #build static libray to be used by pdgtest 26 | add_library(pdgStatic STATIC 27 | include/tree.hh 28 | ${HEADERS} 29 | ${TPPSRC} 30 | ${SOURCES} 31 | ) 32 | 33 | # build plugin to be used by opt 34 | add_library(pdg MODULE 35 | include/tree.hh 36 | ${HEADERS} 37 | ${TPPSRC} 38 | ${SOURCES} 39 | ) 40 | 41 | # 42 | # Turn on C++11, turn off C++ RTTI. 43 | # 44 | target_compile_features(pdg PRIVATE cxx_range_for cxx_auto_type) 45 | set_target_properties(pdg PROPERTIES COMPILE_FLAGS "-fno-rtti") 46 | 47 | # 48 | # OS X-specific configuration 49 | # 50 | if(APPLE) 51 | set_target_properties(pdg PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") 52 | endif(APPLE) 53 | 54 | -------------------------------------------------------------------------------- /include/ControlDependencyGraph.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONTROLDEPENDENCYGRAPH_H_ 2 | #define CONTROLDEPENDENCYGRAPH_H_ 3 | #include "llvm/Analysis/PostDominators.h" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/PassAnalysisSupport.h" 7 | #include "llvm/Pass.h" 8 | 9 | #include "DependencyGraph.hpp" 10 | #include "CallWrapper.hpp" 11 | #include "FunctionWrapper.hpp" 12 | 13 | namespace pdg { 14 | class ControlDependencyGraph : public llvm::FunctionPass 15 | { 16 | public: 17 | static char ID; 18 | ControlDependencyGraph() : llvm::FunctionPass(ID) 19 | { 20 | CDG = new DependencyGraph(); 21 | } 22 | 23 | ~ControlDependencyGraph() 24 | { 25 | delete CDG; 26 | } 27 | 28 | bool runOnFunction(llvm::Function &F); 29 | void getAnalysisUsage(llvm::AnalysisUsage &AU) const; 30 | llvm::StringRef getPassName() const; 31 | void computeDependencies(llvm::Function &F); 32 | void addInstToBBDependency(InstructionWrapper* from, llvm::BasicBlock *to, DependencyType depType); 33 | void addBBToBBDependency(llvm::BasicBlock *from, llvm::BasicBlock *to, DependencyType depType); 34 | DependencyGraph *_getCDG() { return CDG; } 35 | 36 | private: 37 | DependencyGraph *CDG; 38 | llvm::PostDominatorTree *PDT; 39 | llvm::Function *Func; 40 | }; 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /include/DependencyGraph.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEPENDENCYGRAPH_H_ 2 | #define DEPENDENCYGRAPH_H_ 3 | #include "DependencyNode.hpp" 4 | #include "PDGUtils.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace pdg 10 | { 11 | template 12 | class DependencyGraph 13 | { 14 | public: 15 | using nodes_iterator = typename std::vector *>::iterator; 16 | using const_nodes_iterator = typename std::vector *>::const_iterator; 17 | DependencyGraph() = default; 18 | ~DependencyGraph(); 19 | std::vector *> getNodeSet() const { return nodeSet; } 20 | void addNode(const NodeT *dNode); 21 | DependencyNode *getNodeByData(const NodeT *data); 22 | typename DependencyNode::DependencyLinkList getNodeDepList(const NodeT *data); 23 | void addDependency(const NodeT *from, const NodeT *to, DependencyType depType); 24 | bool isDepends(const NodeT *data1, const NodeT *data2); 25 | DependencyType getDepType(const NodeT *data1, const NodeT *data2); 26 | nodes_iterator begin_child() { return nodes_iterator(nodeSet.begin()); } 27 | nodes_iterator end_child() { return nodes_iterator(nodeSet.end()); } 28 | 29 | private: 30 | std::vector *> nodeSet; 31 | std::map *> DataToNodeMap; 32 | }; 33 | } // namespace pdg 34 | 35 | #include "DependencyGraph.tpp" 36 | #endif -------------------------------------------------------------------------------- /include/PDGUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PDGUTILS_H_ 2 | #define PDGUTILS_H_ 3 | #include "llvm/IR/Instruction.h" 4 | #include "llvm/IR/Module.h" 5 | #include "FunctionWrapper.hpp" 6 | #include "CallWrapper.hpp" 7 | #include 8 | #include 9 | 10 | namespace pdg { 11 | class PDGUtils final 12 | { 13 | private: 14 | std::map G_instMap; 15 | std::set G_globalInstsSet; 16 | std::map> G_funcInstWMap; 17 | std::map G_funcMap; 18 | std::map G_callMap; 19 | 20 | public: 21 | PDGUtils() = default; 22 | PDGUtils(const PDGUtils &) = delete; 23 | PDGUtils(PDGUtils &&) = delete; 24 | PDGUtils &operator=(const PDGUtils&) = delete; 25 | PDGUtils &operator=(PDGUtils &&) = delete; 26 | 27 | static PDGUtils& getInstance() 28 | { 29 | static PDGUtils pdgUtils { }; 30 | return pdgUtils; 31 | }; 32 | 33 | std::map &getInstMap() { return G_instMap; } 34 | std::set &getGlobalInstsSet() { return G_globalInstsSet; } 35 | std::map> &getFuncInstWMap() { return G_funcInstWMap; } 36 | std::map &getFuncMap() { return G_funcMap; } 37 | std::map &getCallMap() { return G_callMap; } 38 | void collectGlobalInsts(llvm::Module &M); 39 | void categorizeInstInFunc(llvm::Function &F); 40 | void constructInstMap(llvm::Function &F); 41 | void constructFuncMap(llvm::Module &M); 42 | }; 43 | } // namespace pdg 44 | #endif -------------------------------------------------------------------------------- /src/PDGUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "PDGUtils.hpp" 2 | #include "llvm/IR/InstIterator.h" 3 | 4 | using namespace llvm; 5 | 6 | void pdg::PDGUtils::constructInstMap(Function &F) 7 | { 8 | for (inst_iterator I = inst_begin(F); I != inst_end(F); ++I) 9 | { 10 | if (G_instMap.find(&*I) == G_instMap.end()) 11 | { 12 | InstructionWrapper *instW = new InstructionWrapper(&*I, GraphNodeType::INST); 13 | G_instMap[&*I] = instW; 14 | G_funcInstWMap[&F].insert(instW); 15 | } 16 | } 17 | } 18 | 19 | void pdg::PDGUtils::constructFuncMap(Module &M) 20 | { 21 | for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) 22 | { 23 | if (FI->isDeclaration()) 24 | continue; 25 | constructInstMap(*FI); 26 | if (G_funcMap.find(&*FI) == G_funcMap.end()) 27 | { 28 | FunctionWrapper *funcW = new FunctionWrapper(&*FI); 29 | G_funcMap[&*FI] = funcW; 30 | } 31 | } 32 | } 33 | 34 | void pdg::PDGUtils::collectGlobalInsts(Module &M) 35 | { 36 | for (Module::global_iterator globalIt = M.global_begin(); globalIt != M.global_end(); ++globalIt) 37 | { 38 | InstructionWrapper *globalW = new InstructionWrapper(dyn_cast(&(*globalIt)), GraphNodeType::GLOBAL_VALUE); 39 | G_globalInstsSet.insert(globalW); 40 | } 41 | } 42 | 43 | void pdg::PDGUtils::categorizeInstInFunc(Function &F) 44 | { 45 | // sort store/load/return/CallInst in function 46 | for (inst_iterator I = inst_begin(F), IE = inst_end(F); I != IE; ++I) 47 | { 48 | Instruction *inst = dyn_cast(&*I); 49 | if (isa(inst)) 50 | G_funcMap[&F]->addStoreInst(inst); 51 | 52 | if (isa(inst)) 53 | G_funcMap[&F]->addLoadInst(inst); 54 | 55 | if (isa(inst)) 56 | G_funcMap[&F]->addReturnInst(inst); 57 | 58 | if (isa(inst)) 59 | G_funcMap[&F]->addCallInst(inst); 60 | 61 | if (isa(inst)) 62 | G_funcMap[&F]->addCastInst(inst); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/DependencyGraph.tpp: -------------------------------------------------------------------------------- 1 | 2 | using namespace pdg; 3 | 4 | template 5 | DependencyGraph::~DependencyGraph() 6 | { 7 | nodeSet.clear(); 8 | DataToNodeMap.clear(); 9 | } 10 | 11 | template 12 | void DependencyGraph::addNode(const NodeT *dNode) 13 | { 14 | DataToNodeMap[dNode] = new DependencyNode(dNode); 15 | nodeSet.push_back(DataToNodeMap[dNode]); 16 | } 17 | 18 | template 19 | DependencyNode *DependencyGraph::getNodeByData(const NodeT *data) 20 | { 21 | auto it = DataToNodeMap.find(data); 22 | if (it == DataToNodeMap.end()) 23 | { 24 | addNode(data); 25 | } 26 | 27 | return DataToNodeMap[data]; 28 | } 29 | 30 | template 31 | typename DependencyNode::DependencyLinkList DependencyGraph::getNodeDepList(const NodeT *data) 32 | { 33 | DependencyNode* dNode = getNodeByData(data); 34 | return dNode->getDependencyList(); 35 | } 36 | 37 | 38 | template 39 | void DependencyGraph::addDependency(const NodeT *from, const NodeT *to, DependencyType depType) 40 | { 41 | DependencyNode *fromNode = getNodeByData(from); 42 | DependencyNode *toNode = getNodeByData(to); 43 | fromNode->addDependencyTo(toNode, depType); 44 | } 45 | 46 | template 47 | bool DependencyGraph::isDepends(const NodeT *data1, const NodeT *data2) 48 | { 49 | bool hasDepends = false; 50 | try 51 | { 52 | hasDepends = DataToNodeMap[data1]->isDepends(DataToNodeMap[data2]); 53 | } 54 | catch (std::exception &e) 55 | { 56 | llvm::errs() << e.what() << "\n"; 57 | } 58 | return hasDepends; 59 | } 60 | 61 | template 62 | DependencyType DependencyGraph::getDepType(const NodeT *data1, const NodeT *data2) 63 | { 64 | try 65 | { 66 | DependencyType depType = DataToNodeMap[data1]->getDependencyType(DataToNodeMap[data2]); 67 | return depType; 68 | } 69 | catch (std::exception &e) 70 | { 71 | llvm::errs() << e.what() << "\n"; 72 | } 73 | } -------------------------------------------------------------------------------- /src/FunctionWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "FunctionWrapper.hpp" 2 | 3 | using namespace llvm; 4 | pdg::FunctionWrapper::FunctionWrapper(Function *Func) 5 | { 6 | this->Func = Func; 7 | this->entryW = nullptr; 8 | for (Function::arg_iterator argIt = Func->arg_begin(), argE = Func->arg_end(); 9 | argIt != argE; 10 | ++argIt) 11 | { 12 | ArgumentWrapper *argW = new ArgumentWrapper(&*argIt); 13 | argWList.push_back(argW); 14 | } 15 | } 16 | 17 | bool pdg::FunctionWrapper::hasTrees() 18 | { 19 | return treeFlag; 20 | } 21 | 22 | bool pdg::FunctionWrapper::isVisited() 23 | { 24 | return visited; 25 | } 26 | 27 | pdg::ArgumentWrapper *pdg::FunctionWrapper::getArgWByArg(Argument &arg) 28 | { 29 | for (auto argW : argWList) 30 | { 31 | if (argW->getArg() == &arg) { 32 | return argW; 33 | } 34 | } 35 | 36 | errs() << "ERROR: cannot find argW by arg in Function " << Func->getName() << "\n"; 37 | return nullptr; 38 | } 39 | 40 | void pdg::FunctionWrapper::addStoreInst(Instruction *inst) 41 | { 42 | if (StoreInst *st = dyn_cast(inst)) 43 | storeInstList.push_back(st); 44 | } 45 | 46 | void pdg::FunctionWrapper::addLoadInst(Instruction *inst) 47 | { 48 | if (LoadInst *li = dyn_cast(inst)) 49 | loadInstList.push_back(li); 50 | } 51 | 52 | void pdg::FunctionWrapper::addReturnInst(Instruction *inst) 53 | { 54 | if (ReturnInst *ri = dyn_cast(inst)) 55 | returnInstList.push_back(ri); 56 | } 57 | 58 | void pdg::FunctionWrapper::addCallInst(Instruction *inst) { 59 | if (CallInst *ci = dyn_cast(inst)) 60 | callInstList.push_back(ci); 61 | } 62 | 63 | void pdg::FunctionWrapper::addCastInst(Instruction *inst) 64 | { 65 | if (CastInst* csi = dyn_cast(inst)) 66 | castInstList.push_back(csi); 67 | } 68 | 69 | pdg::ArgumentWrapper *pdg::FunctionWrapper::getArgWByIdx(int idx) { 70 | if (idx > argWList.size()) 71 | { 72 | errs() << "request index excess argW list length... Return nullptr" << "\n"; 73 | return nullptr; 74 | } 75 | return argWList[idx]; 76 | } -------------------------------------------------------------------------------- /include/FunctionWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTIONWRAPPER_H_ 2 | #define FUNCTIONWRAPPER_H_ 3 | #include "llvm/IR/Function.h" 4 | #include "llvm/IR/Argument.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "InstructionWrapper.hpp" 7 | #include "tree.hh" 8 | #include 9 | #include "ArgumentWrapper.hpp" 10 | 11 | namespace pdg 12 | { 13 | class FunctionWrapper 14 | { 15 | public: 16 | FunctionWrapper() = delete; 17 | FunctionWrapper(llvm::Function *Func); 18 | bool hasTrees(); 19 | void setTreeFlag(bool treeFlag) { this->treeFlag = treeFlag; } 20 | bool isVisited(); 21 | void setVisited(bool visited) { this->visited = visited; } 22 | void setEntryW(InstructionWrapper *entryW) { this->entryW = entryW; } 23 | InstructionWrapper *getEntryW() { return entryW; } 24 | std::vector &getStoreInstList() { return storeInstList; } 25 | std::vector &getLoadInstList() { return loadInstList; } 26 | std::vector &getReturnInstList() { return returnInstList; } 27 | std::vector &getCallInstList() { return callInstList; } 28 | std::vector &getCastInstList() { return castInstList; } 29 | std::vector &getArgWList() { return argWList; } 30 | void addStoreInst(llvm::Instruction *inst); 31 | void addLoadInst(llvm::Instruction *inst); 32 | void addReturnInst(llvm::Instruction *inst); 33 | void addCallInst(llvm::Instruction *inst); 34 | void addCastInst(llvm::Instruction* inst); 35 | ArgumentWrapper *getArgWByArg(llvm::Argument &arg); 36 | ArgumentWrapper *getArgWByIdx(int idx); 37 | 38 | private: 39 | llvm::Function *Func; 40 | InstructionWrapper *entryW; 41 | std::vector storeInstList; 42 | std::vector loadInstList; 43 | std::vector returnInstList; 44 | std::vector callInstList; 45 | std::vector castInstList; 46 | std::vector argWList; 47 | std::set dependent_funcs; 48 | std::set ptrSet; 49 | bool treeFlag; 50 | bool RWFlag; 51 | bool visited; 52 | }; 53 | } // namespace pdg 54 | 55 | #endif -------------------------------------------------------------------------------- /include/DataDependencyGraph.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DATADEPENDENCYGRAPH_H_ 2 | #define DATADEPENDENCYGRAPH_H_ 3 | #include "llvm/IR/Function.h" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/Instructions.h" 6 | 7 | #include "llvm/ADT/SmallVector.h" 8 | #include "llvm/Analysis/MemoryBuiltins.h" 9 | #include "llvm/Analysis/MemoryDependenceAnalysis.h" 10 | #include "llvm/Analysis/CFLSteensAliasAnalysis.h" 11 | #include "llvm/Analysis/CFLAndersAliasAnalysis.h" 12 | 13 | #include "DependencyGraph.hpp" 14 | #include "CallWrapper.hpp" 15 | #include "FunctionWrapper.hpp" 16 | 17 | namespace pdg 18 | { 19 | class DataDependencyGraph : public llvm::FunctionPass 20 | { 21 | public: 22 | static char ID; 23 | DataDependencyGraph() : FunctionPass(ID) 24 | { 25 | DDG = new DependencyGraph(); 26 | } 27 | 28 | ~DataDependencyGraph() 29 | { 30 | delete DDG; 31 | } 32 | 33 | void initializeMemoryDependencyPasses(); 34 | void constructFuncMapAndCreateFunctionEntry(); 35 | void collectDefUseDependency(llvm::Instruction *inst); 36 | void collectCallInstDependency(llvm::Instruction *inst); 37 | void collectWriteToDependency(llvm::Instruction *loadInst); 38 | std::vector getRAWDepList(llvm::Instruction *loadInst); 39 | void collectRAWDependency(llvm::Instruction *inst); 40 | void collectReadFromDependency(llvm::Instruction *inst); 41 | void collectNonLocalDependency(llvm::Instruction *inst); 42 | void collectDataDependencyInFunc(); 43 | void collectAliasDependencies(); 44 | DependencyNode *getNodeByData(llvm::Instruction *inst); 45 | typename DependencyNode::DependencyLinkList getNodeDepList(llvm::Instruction *inst); 46 | virtual bool runOnFunction(llvm::Function &Func); 47 | virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const; 48 | virtual llvm::StringRef getPassName() const { return "Data Dependency Graph"; } 49 | DependencyGraph *_getDDG() {return DDG;} 50 | 51 | private: 52 | DependencyGraph *DDG; 53 | llvm::Function *Func; 54 | llvm::CFLSteensAAResult *steenAA; 55 | llvm::CFLAndersAAResult *andersAA; 56 | llvm::MemoryDependenceResults *MD; 57 | }; 58 | } // namespace pdg 59 | 60 | #endif -------------------------------------------------------------------------------- /include/PDGExceptions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PDGEXCEPTIONS_H_ 2 | #define PDGEXCEPTIONS_H_ 3 | #include 4 | #include 5 | 6 | namespace pdg 7 | { 8 | class DependencyNodeIsNullptrException : public std::exception 9 | { 10 | private: 11 | std::string _msg; 12 | 13 | public: 14 | DependencyNodeIsNullptrException(const std::string &msg) : _msg(msg) {} 15 | virtual const char *what() const noexcept override 16 | { 17 | return _msg.c_str(); 18 | } 19 | }; 20 | 21 | class TreeNodeTypeIsNull : public std::exception 22 | { 23 | private: 24 | std::string _msg; 25 | 26 | public: 27 | TreeNodeTypeIsNull(const std::string &msg) : _msg(msg) {} 28 | virtual const char *what() const noexcept override 29 | { 30 | return _msg.c_str(); 31 | } 32 | }; 33 | 34 | class NullPtrException : public std::exception 35 | { 36 | private: 37 | std::string _msg; 38 | 39 | public: 40 | NullPtrException(const std::string &msg) : _msg(msg) {} 41 | virtual const char *what() const noexcept override 42 | { 43 | return _msg.c_str(); 44 | } 45 | }; 46 | 47 | class ArgHasNoDITypeException : public std::exception 48 | { 49 | private: 50 | std::string _msg; 51 | 52 | public: 53 | ArgHasNoDITypeException(const std::string &msg) : _msg(msg) {} 54 | virtual const char *what() const noexcept override 55 | { 56 | return _msg.c_str(); 57 | } 58 | }; 59 | 60 | class ArgParameterTreeSizeIsZero : public std::exception 61 | { 62 | private: 63 | std::string _msg; 64 | 65 | public: 66 | ArgParameterTreeSizeIsZero(const std::string &msg) : _msg(msg) {} 67 | virtual const char *what() const noexcept override 68 | { 69 | return _msg.c_str(); 70 | } 71 | }; 72 | 73 | class ArgWrapperIsNullPtr : public std::exception 74 | { 75 | private: 76 | std::string _msg; 77 | 78 | public: 79 | ArgWrapperIsNullPtr(const std::string &msg) : _msg(msg) {} 80 | virtual const char *what() const noexcept override 81 | { 82 | return _msg.c_str(); 83 | } 84 | }; 85 | 86 | class DITypeIsNullPtr : public std::exception 87 | { 88 | private: 89 | std::string _msg; 90 | 91 | public: 92 | DITypeIsNullPtr(const std::string &msg) : _msg(msg) {} 93 | virtual const char *what() const noexcept override 94 | { 95 | return _msg.c_str(); 96 | } 97 | }; 98 | } // namespace pdg 99 | 100 | #endif -------------------------------------------------------------------------------- /lib/catch2/catch_reporter_automake.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Justin R. Wilson on 2/19/2017. 3 | * Copyright 2017 Justin R. Wilson. All rights reserved. 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | */ 8 | #ifndef TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED 9 | #define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED 10 | 11 | // Don't #include any Catch headers here - we can assume they are already 12 | // included before this header. 13 | // This is not good practice in general but is necessary in this case so this 14 | // file can be distributed as a single header that works with the main 15 | // Catch single header. 16 | 17 | namespace Catch { 18 | 19 | struct AutomakeReporter : StreamingReporterBase { 20 | AutomakeReporter( ReporterConfig const& _config ) 21 | : StreamingReporterBase( _config ) 22 | {} 23 | 24 | ~AutomakeReporter() override; 25 | 26 | static std::string getDescription() { 27 | return "Reports test results in the format of Automake .trs files"; 28 | } 29 | 30 | void assertionStarting( AssertionInfo const& ) override {} 31 | 32 | bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; } 33 | 34 | void testCaseEnded( TestCaseStats const& _testCaseStats ) override { 35 | // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. 36 | stream << ":test-result: "; 37 | if (_testCaseStats.totals.assertions.allPassed()) { 38 | stream << "PASS"; 39 | } else if (_testCaseStats.totals.assertions.allOk()) { 40 | stream << "XFAIL"; 41 | } else { 42 | stream << "FAIL"; 43 | } 44 | stream << ' ' << _testCaseStats.testInfo.name << '\n'; 45 | StreamingReporterBase::testCaseEnded( _testCaseStats ); 46 | } 47 | 48 | void skipTest( TestCaseInfo const& testInfo ) override { 49 | stream << ":test-result: SKIP " << testInfo.name << '\n'; 50 | } 51 | 52 | }; 53 | 54 | #ifdef CATCH_IMPL 55 | AutomakeReporter::~AutomakeReporter() {} 56 | #endif 57 | 58 | CATCH_REGISTER_REPORTER( "automake", AutomakeReporter) 59 | 60 | } // end namespace Catch 61 | 62 | #endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED 63 | -------------------------------------------------------------------------------- /include/DependencyNode.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEPENDENCY_NODE_H_ 2 | #define DEPENDENCY_NODE_H_ 3 | #include "PDGExceptions.hpp" 4 | #include "PDGEnums.hpp" 5 | #include "InstructionWrapper.hpp" 6 | #include 7 | 8 | namespace pdg 9 | { 10 | template 11 | class DependencyLinkIterator; 12 | 13 | template 14 | class DependencyNode 15 | { 16 | public: 17 | using DependencyLink = std::pair *, DependencyType>; 18 | using DependencyLinkList = std::vector; 19 | using iterator = DependencyLinkIterator; 20 | using const_iterator = DependencyLinkIterator; 21 | 22 | DependencyNode() = delete; 23 | DependencyNode(const NodeT *pData) : dataNode(pData) {} 24 | void addDependencyTo(DependencyNode *pNode, DependencyType type); 25 | const NodeT *getData() const { return dataNode; } 26 | DependencyLinkList &getDependencyList() { return dependencyList; } 27 | bool isDepends(const DependencyNode *dNode); 28 | DependencyType getDependencyType(const DependencyNode *dNode) const; 29 | 30 | private: 31 | const NodeT *dataNode; 32 | DependencyLinkList dependencyList; 33 | }; 34 | 35 | template 36 | class DependencyLinkIterator : public std::iterator 37 | { 38 | using InnerIterator = typename DependencyNode::DependencyLinkList::const_iterator; 39 | 40 | public: 41 | DependencyLinkIterator() : itr() {} 42 | 43 | DependencyLinkIterator(const InnerIterator &r) : itr(r) {} 44 | 45 | DependencyLinkIterator &operator++() 46 | { 47 | ++itr; 48 | return *this; 49 | } 50 | 51 | DependencyLinkIterator operator++(int) 52 | { 53 | DependencyLinkIterator old = *this; 54 | ++itr; 55 | return old; 56 | } 57 | 58 | DependencyNode *operator->() 59 | { 60 | typename DependencyNode::DependencyLink L = *itr; 61 | return L.first; 62 | } 63 | 64 | DependencyNode *operator*() 65 | { 66 | typename DependencyNode::DependencyLink L = *itr; 67 | return L.first; 68 | } 69 | 70 | bool operator!=(const DependencyLinkIterator &r) const 71 | { 72 | return itr != r.itr; 73 | } 74 | 75 | bool operator==(const DependencyLinkIterator &r) const 76 | { 77 | return !(operator!=(r)); 78 | } 79 | 80 | DependencyType getDependencyType() const 81 | { 82 | typename DependencyNode::DependencyLink L = *itr; 83 | return L.second; 84 | } 85 | 86 | const NodeT *getDependencyNode() const 87 | { 88 | typename DependencyNode::DependencyLink L = *itr; 89 | return L.first->getData(); 90 | } 91 | 92 | private: 93 | InnerIterator itr; 94 | }; 95 | } // namespace pdg 96 | #include "DependencyNode.tpp" 97 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parameter-tree based Program Dependence Graph (PDG) 2 | 3 | ## Introduction 4 | 5 | This project is a key component of our PtrSplit and Program-mandering works. It aims at building a modular inter-procedural program dependence graph (PDG) for practical use. 6 | Our program dependence graph is field senstive, context-insensitive and flow-insensitive. For more details, welcome to read our CCS'17 paper about PtrSplit: 7 | [http://www.cse.psu.edu/~gxt29/papers/ptrsplit.pdf] If you find this tool useful, please cite the PtrSplit paper in your publication. Here's the bibtex entry: 8 | 9 | @inproceedings{LiuTJ17Ptrsplit, 10 | 11 | author = {Shen Liu and Gang Tan and Trent Jaeger}, 12 | 13 | title = {{PtrSplit}: Supporting General Pointers in Automatic Program Partitioning}, 14 | 15 | booktitle = {24th ACM Conference on Computer and Communications Security ({CCS})}, 16 | 17 | pages = {2359--2371}, 18 | 19 | year = {2017} 20 | 21 | } 22 | 23 | 24 | We have upgraded the implementation to LLVM 9.0.0. Currently, we only support building PDGs for C programs. 25 | 26 | A PDG example looks like this (the blue part corresponds to the parameter tree): 27 | 28 | ![](https://bitbucket.org/psu_soslab/program-dependence-graph-in-llvm/raw/4000cf407e9aeb44491eb41b2e808b16e61dc192/demo/pdg.png) 29 | 30 | ## Getting started quickly 31 | 32 | ```shell 33 | mkdir build 34 | cd build 35 | cmake .. 36 | make 37 | opt -load libpdg.so -dot-pdg < test.bc 38 | ``` 39 | 40 | Once you finish these operations a dot file will be created. You can open it with [Graphviz](http://www.graphviz.org/). 41 | 42 | ## LLVM IR compilation 43 | 44 | For simple C programs(e.g., test.c), do 45 | 46 | > **clang -emit-llvm -S test.c -o test.bc** 47 | 48 | Now you have a binary format LLVM bitcode file which can be directly used as the input for PDG generation. 49 | 50 | You can also generate a human-readable bitcode file(.ll) if you would like to: 51 | 52 | > **llvm-dis test.bc** 53 | 54 | This will generate a human-readable format bitcode file (test.ll) for your debugging and testing. 55 | 56 | For those large C software (e.g., wget), you can refer to this great article for help: 57 | 58 | http://gbalats.github.io/2015/12/10/compiling-autotooled-projects-to-LLVM-bitcode.html 59 | 60 | (We successfully compiled SPECCPU 2006 INT/thttpd/wget/telnet/openssh/curl/nginx/sqlite, thanks to the author!) 61 | 62 | ## Avaliable Passes 63 | 64 | **-pdg:** generate the program dependence graph (inter-procedural) 65 | 66 | **-cdg:** generate the control dependence graph (intra-procedural) 67 | 68 | **-ddg:** generate the data dependence graph (intra-procedural) 69 | 70 | **-dot-*:** for visualization. (dot) 71 | 72 | For those large software, generating a visualizable PDG is not easy. Graphviz often fails to generate the .dot file for a program with 73 | more than 1000 lines of C code. Fortunately, we rarely need such a large .dot file but only do kinds of analyses on the PDG, which is always in memory. 74 | 75 | ## Running tests 76 | We use catch2 to build the project. 77 | Catch2 is a lightweight C++ testing framework. As catch2 can be used with a couple stand alone header files, they are included in the project. 78 | It is put under directory lib. 79 | When building the project, the test is also built. 80 | We build all tests into an executable. User can verify the basic utitlies in PDG by running the following command: 81 | > ./build/test/pdg-test 82 | 83 | The test case is built in the pdgtest.cpp file, which is placed under test directory. 84 | -------------------------------------------------------------------------------- /include/ProgramDependencyGraph.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAMDEPENDENCYGRAPH_H_ 2 | #define PROGRAMDEPENDENCYGRAPH_H_ 3 | #include "llvm/IR/Module.h" 4 | #include "llvm/PassAnalysisSupport.h" 5 | #include "ControlDependencyGraph.hpp" 6 | #include "DataDependencyGraph.hpp" 7 | #include "llvm/IR/DebugInfo.h" 8 | #include "llvm/IR/DebugInfoMetadata.h" 9 | #include "llvm/Support/Debug.h" 10 | #include "DependencyGraph.hpp" 11 | #include "PDGCommandLineOptions.hpp" 12 | 13 | namespace pdg 14 | { 15 | class ProgramDependencyGraph : public llvm::ModulePass 16 | { 17 | public: 18 | static char ID; 19 | ProgramDependencyGraph() : llvm::ModulePass(ID) { PDG = new DependencyGraph(); } 20 | ~ProgramDependencyGraph() { delete PDG; } 21 | bool runOnModule(llvm::Module &M); 22 | void getAnalysisUsage(llvm::AnalysisUsage &AU) const; 23 | llvm::StringRef getPassName() { return "Program Dependency Graph"; } 24 | // PDG processing 25 | bool processCallInst(InstructionWrapper *instW); 26 | bool processIndirectCallInst(llvm::CallInst *CI, InstructionWrapper *instW); 27 | void addNodeDependencies(InstructionWrapper *instW); 28 | // parameter tree building 29 | std::vector collectIndirectCallCandidates(llvm::FunctionType *funcType); 30 | void buildActualParameterTrees(llvm::CallInst *CI); 31 | void drawActualParameterTree(llvm::CallInst *CI, TreeType treeTy); 32 | void buildFormalTreeForFunc(llvm::Function *Func); 33 | void buildFormalTreeForArg(llvm::Argument &arg, TreeType treeTy); 34 | bool hasRecursiveType(ArgumentWrapper *argW, tree::iterator insert_loc); 35 | bool isFilePtrOrFuncTy(llvm::Type* ty); 36 | InstructionWrapper* buildPointerTypeNode(ArgumentWrapper *argW, InstructionWrapper *curTyNode, tree::iterator); 37 | InstructionWrapper *buildPointerTypeNodeWithDI(ArgumentWrapper *argW, InstructionWrapper *curTyNode, tree::iterator, llvm::DIType *dt); 38 | void buildTypeTree(llvm::Argument &arg, InstructionWrapper *treeTyW, TreeType TreeType); 39 | void drawFormalParameterTree(llvm::Function *Func, TreeType treeTy); 40 | void connectFunctionAndFormalTrees(llvm::Function *callee); 41 | bool connectAllPossibleFunctions(llvm::CallInst *CI, std::vector indirect_call_candidates); 42 | bool connectCallerAndCallee(InstructionWrapper *instW, llvm::Function *callee); 43 | void connectActualTrees(InstructionWrapper *callInstW); 44 | void connectInOutTrees(ArgumentWrapper *CIArgW, ArgumentWrapper *funcArgW); 45 | // field sensitive related functions 46 | std::set getAllRelevantGEP(llvm::Argument &arg); 47 | InstructionWrapper *getTreeNodeGEP(llvm::Argument &arg, unsigned field_offset, llvm::Type *treeNodeTy, llvm::Type *parentNodeTy); 48 | std::vector getArgStoreInsts(llvm::Argument &arg); 49 | // tree building helper functions 50 | bool isFuncTypeMatch(llvm::FunctionType *funcTy1, llvm::FunctionType *funcTy2); 51 | tree::iterator getInstInsertLoc(ArgumentWrapper *argW, InstructionWrapper *tyW, TreeType treeTy); 52 | // dep printer related functions 53 | std::vector *> getNodeSet() { return PDG->getNodeSet(); } 54 | DependencyGraph *_getPDG() { return PDG; } 55 | typename DependencyNode::DependencyLinkList getNodeDepList(llvm::Instruction *inst); 56 | 57 | private: 58 | llvm::Module *module; 59 | DependencyGraph *PDG; 60 | ControlDependencyGraph *cdg; 61 | DataDependencyGraph *ddg; 62 | }; 63 | } // namespace pdg 64 | 65 | #endif -------------------------------------------------------------------------------- /src/ArgumentWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "ArgumentWrapper.hpp" 2 | #include "PDGUtils.hpp" 3 | 4 | using namespace llvm; 5 | 6 | pdg::ArgumentWrapper::ArgumentWrapper(Argument *arg) 7 | { 8 | this->arg = arg; 9 | this->Func = arg->getParent(); 10 | } 11 | 12 | Argument *pdg::ArgumentWrapper::getArg() 13 | { 14 | return arg; 15 | } 16 | 17 | tree &pdg::ArgumentWrapper::getTree(TreeType treeTy) 18 | { 19 | switch (treeTy) 20 | { 21 | case TreeType::FORMAL_IN_TREE: 22 | return formalInTree; 23 | case TreeType::FORMAL_OUT_TREE: 24 | return formalOutTree; 25 | case TreeType::ACTUAL_IN_TREE: 26 | return actualInTree; 27 | case TreeType::ACTUAL_OUT_TREE: 28 | return actualOutTree; 29 | default: 30 | return formalInTree; 31 | } 32 | } 33 | 34 | void pdg::ArgumentWrapper::copyTree(const tree &srcTree, TreeType treeTy) 35 | { 36 | if (srcTree.empty()) 37 | { 38 | errs() << arg->getParent()->getName() << " arg : " << *arg << " srcTree is empty!\n"; 39 | return; 40 | } 41 | 42 | GraphNodeType instWTy; 43 | //formal_out actual_in/out 44 | // choose new argument. CallInst should get arg from CallSite instead of formal function. 45 | Argument *newArg = nullptr; 46 | switch (treeTy) 47 | { 48 | case TreeType::FORMAL_IN_TREE: 49 | errs() << "FORMAL_IN_TREE can't be copied\n"; 50 | break; 51 | case TreeType::FORMAL_OUT_TREE: 52 | formalOutTree = srcTree; 53 | newArg = ((TreeTypeWrapper*)(*srcTree.begin()))->getArgument(); 54 | instWTy = GraphNodeType::FORMAL_OUT; 55 | break; 56 | case TreeType::ACTUAL_IN_TREE: 57 | actualInTree = srcTree; 58 | newArg = this->getArg(); 59 | instWTy = GraphNodeType::ACTUAL_IN; 60 | break; 61 | case TreeType::ACTUAL_OUT_TREE: 62 | actualOutTree = srcTree; 63 | newArg = this->getArg(); 64 | instWTy = GraphNodeType::ACTUAL_OUT; 65 | break; 66 | } 67 | 68 | // formalOutTree = formalInTree; 69 | tree::iterator SI = srcTree.begin(); 70 | tree::iterator TI = getTree(treeTy).begin(); 71 | for (; SI != srcTree.end() && TI != getTree(treeTy).end(); ++SI, ++TI) 72 | { 73 | InstructionWrapper *treeTypeW; 74 | InstructionWrapper *srcTreeW = (*SI); 75 | if (SI == srcTree.begin()) 76 | { 77 | treeTypeW = new TreeTypeWrapper(srcTreeW->getFunction(), instWTy, 78 | newArg, 79 | ((TreeTypeWrapper *)srcTreeW)->getTreeNodeType(), 80 | ((TreeTypeWrapper *)srcTreeW)->getParentTreeNodeType(), 81 | ((TreeTypeWrapper *)srcTreeW)->getNodeOffset()); 82 | } 83 | else 84 | { 85 | treeTypeW = new TreeTypeWrapper(srcTreeW->getFunction(), GraphNodeType::PARAMETER_FIELD, 86 | newArg, 87 | ((TreeTypeWrapper *)srcTreeW)->getTreeNodeType(), 88 | ((TreeTypeWrapper *)srcTreeW)->getParentTreeNodeType(), 89 | ((TreeTypeWrapper *)srcTreeW)->getNodeOffset()); 90 | } 91 | *TI = treeTypeW; 92 | PDGUtils::getInstance().getFuncInstWMap()[srcTreeW->getFunction()].insert(treeTypeW); 93 | } 94 | } 95 | 96 | tree::iterator pdg::ArgumentWrapper::tree_begin(TreeType treeTy) 97 | { 98 | return getTree(treeTy).begin(); 99 | } 100 | 101 | tree::iterator pdg::ArgumentWrapper::tree_end(TreeType treeTy) 102 | { 103 | return getTree(treeTy).end(); 104 | } -------------------------------------------------------------------------------- /src/ControlDependencyGraph.cpp: -------------------------------------------------------------------------------- 1 | #include "ControlDependencyGraph.hpp" 2 | 3 | using namespace llvm; 4 | 5 | StringRef pdg::ControlDependencyGraph::getPassName() const 6 | { 7 | return "Control Dependency Graph"; 8 | } 9 | 10 | void pdg::ControlDependencyGraph::getAnalysisUsage(AnalysisUsage &AU) const 11 | { 12 | AU.addRequired(); 13 | AU.setPreservesAll(); 14 | } 15 | 16 | void pdg::ControlDependencyGraph::addInstToBBDependency(InstructionWrapper *from, BasicBlock *to, DependencyType depType) 17 | { 18 | for (BasicBlock::iterator ii = to->begin(), ie = to->end(); ii != ie; ++ii) 19 | { 20 | if (Instruction *Ins = dyn_cast(ii)) 21 | { 22 | InstructionWrapper *iw = PDGUtils::getInstance().getInstMap()[Ins]; 23 | CDG->addDependency(from, iw, depType); 24 | } 25 | } 26 | } 27 | 28 | void pdg::ControlDependencyGraph::addBBToBBDependency(BasicBlock *from, BasicBlock *to, DependencyType type) 29 | { 30 | Instruction *Ins = from->getTerminator(); 31 | InstructionWrapper *iw = PDGUtils::getInstance().getInstMap()[Ins]; 32 | // self loop 33 | if (from == to) 34 | { 35 | for (BasicBlock::iterator ii = from->begin(), ie = from->end(); ii != ie; ++ii) 36 | { 37 | Instruction *inst = dyn_cast(ii); 38 | InstructionWrapper *iwTo = PDGUtils::getInstance().getInstMap()[inst]; 39 | CDG->addDependency(iw, iwTo, type); 40 | } 41 | } 42 | else 43 | { 44 | for (BasicBlock::iterator ii = to->begin(), ie = to->end(); ii != ie; ++ii) 45 | { 46 | Instruction *inst = dyn_cast(ii); 47 | InstructionWrapper *iwTo = PDGUtils::getInstance().getInstMap()[inst]; 48 | CDG->addDependency(iw, iwTo, type); 49 | } 50 | } 51 | } 52 | 53 | void pdg::ControlDependencyGraph::computeDependencies(Function &F) 54 | { 55 | PDGUtils::getInstance().constructFuncMap(*F.getParent()); 56 | if (PDGUtils::getInstance().getFuncMap()[&F]->getEntryW() != nullptr) 57 | { 58 | return; 59 | } 60 | 61 | InstructionWrapper *entryW = new InstructionWrapper(&F, GraphNodeType::ENTRY); 62 | PDGUtils::getInstance().getFuncInstWMap()[&F].insert(entryW); 63 | PDGUtils::getInstance().getFuncMap()[&F]->setEntryW(entryW); 64 | 65 | DomTreeNodeBase *node = PDT->getNode(&F.getEntryBlock()); 66 | while (node && node->getBlock()) { 67 | // Walking the path backward and adding dependencies. 68 | addInstToBBDependency(entryW, node->getBlock(), DependencyType::CONTROL); 69 | node = node->getIDom(); 70 | } 71 | std::vector> EdgeSet; 72 | 73 | for (Function::iterator BI = F.begin(), E = F.end(); BI != E; ++BI) 74 | { 75 | BasicBlock *I = dyn_cast(BI); 76 | for (succ_iterator SI = succ_begin(I), SE = succ_end(I); SI != SE; ++SI) 77 | { 78 | assert(I && *SI); 79 | if (!PDT->dominates(*SI, I)) 80 | { 81 | BasicBlock *B_second = dyn_cast(*SI); 82 | EdgeSet.push_back(std::make_pair(I, B_second)); 83 | } 84 | } 85 | } 86 | 87 | for (auto Edge : EdgeSet) { 88 | BasicBlock *L = PDT->findNearestCommonDominator(Edge.first, Edge.second); 89 | 90 | // capture loop dependence 91 | if (L == Edge.first) 92 | { 93 | addBBToBBDependency(Edge.first, L, DependencyType::CONTROL); 94 | } 95 | DomTreeNode *domNode = PDT->getNode(Edge.second); 96 | if (domNode == nullptr) 97 | { 98 | continue; 99 | } 100 | while (domNode->getBlock() != L) 101 | { 102 | addBBToBBDependency(Edge.first, domNode->getBlock(), DependencyType::CONTROL); 103 | domNode = domNode->getIDom(); 104 | } 105 | } 106 | 107 | EdgeSet.clear(); 108 | for (Function::iterator FI = F.begin(), E = F.end(); FI != E; ++FI) 109 | { 110 | // Zhiyuan comment: find adjacent BasicBlock pairs in CFG, but the predecessor 111 | //does not dominate successor. 112 | BasicBlock *I = dyn_cast(FI); 113 | for (succ_iterator SI = succ_begin(I), SE = succ_end(I); SI != SE; ++SI) 114 | { 115 | assert(I && *SI); 116 | if (!PDT->dominates(*SI, I)) 117 | { 118 | BasicBlock *B_second = dyn_cast(*SI); 119 | EdgeSet.push_back(std::make_pair(I, B_second)); 120 | } 121 | } 122 | } 123 | } 124 | 125 | bool pdg::ControlDependencyGraph::runOnFunction(Function &F) 126 | { 127 | PDGUtils::getInstance().constructInstMap(F); 128 | PDT = &getAnalysis().getPostDomTree(); 129 | computeDependencies(F); 130 | return false; 131 | } 132 | 133 | ControlDependencyGraph *CreateControlDependencyGraphPass() 134 | { 135 | return new ControlDependencyGraph(); 136 | } 137 | 138 | char ControlDependencyGraph::ID = 0; 139 | 140 | static RegisterPass 141 | CDG("cdg", "Control Dependency Graph Construction", false, true); 142 | -------------------------------------------------------------------------------- /include/InstructionWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INSTRUCTIONWRAPPER_H_ 2 | #define INSTRUCTIONWRAPPER_H_ 3 | #include "llvm/IR/BasicBlock.h" 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/IR/InstIterator.h" 7 | #include "llvm/IR/Module.h" 8 | #include "llvm/IR/DerivedTypes.h" 9 | #include "llvm/IR/Argument.h" 10 | #include "llvm/ADT/GraphTraits.h" 11 | #include "llvm/Analysis/AliasAnalysis.h" 12 | #include "llvm/Support/raw_ostream.h" 13 | #include "PDGEnums.hpp" 14 | 15 | namespace pdg 16 | { 17 | class InstructionWrapper { 18 | public: 19 | InstructionWrapper(llvm::Function *Func, GraphNodeType nodetype) 20 | { 21 | this->Inst = nullptr; 22 | this->Func = Func; 23 | this->BB = nullptr; 24 | this->value = nullptr; 25 | this->nodetype = nodetype; 26 | this->isVisited = false; 27 | this->access_type = AccessType::NOACCESS; 28 | } 29 | 30 | InstructionWrapper(llvm::Instruction *Inst, GraphNodeType nodeType) 31 | { 32 | this->Inst = Inst; 33 | this->Func = Inst->getFunction(); 34 | this->BB = Inst->getParent(); 35 | this->value = llvm::cast(Inst); 36 | this->nodetype = nodeType; 37 | this->isVisited = false; 38 | this->access_type = AccessType::NOACCESS; 39 | } 40 | 41 | InstructionWrapper(llvm::Value *value, GraphNodeType nodeType) 42 | { 43 | this->Inst = nullptr; 44 | this->Func = nullptr; 45 | this->BB = nullptr; 46 | this->value = value; 47 | this->nodetype = nodeType; 48 | this->isVisited = false; 49 | this->access_type = AccessType::NOACCESS; 50 | } 51 | 52 | llvm::BasicBlock *getBasicBlock() const { return BB; } 53 | llvm::Instruction *getInstruction() const { return Inst; } 54 | llvm::Function *getFunction() const { return Func; } 55 | llvm::Value *getValue() const { return value; } 56 | GraphNodeType getGraphNodeType() const { return nodetype; } 57 | bool getVisited() const { return isVisited; } 58 | void setVisited(const bool _isVisited) { isVisited = _isVisited; } 59 | AccessType getAccessType() { return access_type; } 60 | void setAccessType(AccessType _access_type) { access_type = _access_type; } 61 | virtual llvm::Type *getTreeNodeType() const { return nullptr; } 62 | virtual llvm::Type *getParentTreeNodeType() const { return nullptr; } 63 | virtual llvm::Argument *getArgument() const { return nullptr; } 64 | virtual InstructionWrapper *getGEPInstW() const { return nullptr; } 65 | virtual int getNodeOffset() const { return -1; } 66 | virtual llvm::DIType *getDIType() const { return nullptr; } 67 | 68 | private: 69 | llvm::Instruction *Inst; 70 | llvm::Value *value; 71 | llvm::BasicBlock *BB; 72 | llvm::Function *Func; 73 | GraphNodeType nodetype; 74 | bool isVisited; 75 | AccessType access_type; 76 | }; 77 | 78 | class TreeTypeWrapper : public InstructionWrapper 79 | { 80 | public: 81 | TreeTypeWrapper(llvm::Function *Func, 82 | GraphNodeType nodetype, 83 | llvm::Argument *arg, 84 | llvm::Type *treeNodeType, 85 | llvm::Type *parentTreeNodeType, 86 | int node_offset) : InstructionWrapper(Func, nodetype) 87 | { 88 | this->arg = arg; 89 | this->treeNodeType = treeNodeType; 90 | this->parentTreeNodeType = parentTreeNodeType; 91 | this->node_offset = node_offset; 92 | this->gepInstW = nullptr; 93 | this->dt = nullptr; 94 | } 95 | 96 | TreeTypeWrapper(llvm::Function *Func, 97 | GraphNodeType nodetype, 98 | llvm::Argument *arg, 99 | llvm::Type *treeNodeType, 100 | llvm::Type *parentTreeNodeType, 101 | int node_offset, 102 | llvm::DIType* dt) : InstructionWrapper(Func, nodetype) 103 | { 104 | this->arg = arg; 105 | this->treeNodeType = treeNodeType; 106 | this->parentTreeNodeType = parentTreeNodeType; 107 | this->node_offset = node_offset; 108 | this->gepInstW = nullptr; 109 | this->dt = dt; 110 | } 111 | 112 | TreeTypeWrapper(llvm::Function *Func, 113 | GraphNodeType nodetype, 114 | llvm::Argument *arg, 115 | llvm::Type *treeNodeType, 116 | llvm::Type *parentTreeNodeType, 117 | int node_offset, 118 | InstructionWrapper* gepInstW) : InstructionWrapper(Func, nodetype) 119 | { 120 | this->arg = arg; 121 | this->treeNodeType = treeNodeType; 122 | this->parentTreeNodeType = parentTreeNodeType; 123 | this->node_offset = node_offset; 124 | this->gepInstW = gepInstW; 125 | this->dt = nullptr; 126 | } 127 | 128 | TreeTypeWrapper(llvm::Function *Func, 129 | GraphNodeType nodetype, 130 | llvm::Argument *arg, 131 | llvm::Type *treeNodeType, 132 | llvm::Type *parentTreeNodeType, 133 | int node_offset, 134 | InstructionWrapper* gepInstW, 135 | llvm::DIType* dt) : InstructionWrapper(Func, nodetype) 136 | { 137 | this->arg = arg; 138 | this->treeNodeType = treeNodeType; 139 | this->parentTreeNodeType = parentTreeNodeType; 140 | this->node_offset = node_offset; 141 | this->gepInstW = gepInstW; 142 | this->dt = dt; 143 | } 144 | 145 | llvm::Type *getTreeNodeType() const override { return treeNodeType; } 146 | llvm::Type *getParentTreeNodeType() const override { return parentTreeNodeType; } 147 | llvm::Argument *getArgument() const override { return arg; } 148 | InstructionWrapper *getGEPInstW() const override { return gepInstW; } 149 | int getNodeOffset() const override { return node_offset; } 150 | llvm::DIType *getDIType() const override { return dt; } 151 | 152 | private: 153 | llvm::Argument *arg; 154 | InstructionWrapper *gepInstW; 155 | llvm::Type *treeNodeType; 156 | llvm::Type *parentTreeNodeType; 157 | int node_offset; 158 | llvm::DIType *dt; 159 | }; 160 | 161 | } // namespace pdg 162 | #endif -------------------------------------------------------------------------------- /test/pdg_test/llvm_ll/test_malloc_anno.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'test_malloc_anno.c' 2 | source_filename = "test_malloc_anno.c" 3 | target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx10.15.0" 5 | 6 | @.str = private unnamed_addr constant [8 x i8] c"persist\00", section "llvm.metadata" 7 | @.str.1 = private unnamed_addr constant [19 x i8] c"test_malloc_anno.c\00", section "llvm.metadata" 8 | 9 | ; Function Attrs: noinline nounwind optnone ssp uwtable 10 | define i8* @pz_malloc(i64) #0 !dbg !11 { 11 | %2 = alloca i64, align 8 12 | store i64 %0, i64* %2, align 8 13 | call void @llvm.dbg.declare(metadata i64* %2, metadata !20, metadata !DIExpression()), !dbg !21 14 | %3 = load i64, i64* %2, align 8, !dbg !22 15 | %4 = call i8* @malloc(i64 %3) #5, !dbg !23 16 | ret i8* %4, !dbg !24 17 | } 18 | 19 | ; Function Attrs: nounwind readnone speculatable 20 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 21 | 22 | ; Function Attrs: allocsize(0) 23 | declare i8* @malloc(i64) #2 24 | 25 | ; Function Attrs: noinline nounwind optnone ssp uwtable 26 | define void @pz_free(i8*) #0 !dbg !25 { 27 | %2 = alloca i8*, align 8 28 | store i8* %0, i8** %2, align 8 29 | call void @llvm.dbg.declare(metadata i8** %2, metadata !28, metadata !DIExpression()), !dbg !29 30 | %3 = load i8*, i8** %2, align 8, !dbg !30 31 | call void @free(i8* %3), !dbg !31 32 | ret void, !dbg !32 33 | } 34 | 35 | declare void @free(i8*) #3 36 | 37 | ; Function Attrs: noinline nounwind optnone ssp uwtable 38 | define i32 @main(i32, i8**) #0 !dbg !33 { 39 | %3 = alloca i32, align 4 40 | %4 = alloca i32, align 4 41 | %5 = alloca i8**, align 8 42 | %6 = alloca i32*, align 8 43 | store i32 0, i32* %3, align 4 44 | store i32 %0, i32* %4, align 4 45 | call void @llvm.dbg.declare(metadata i32* %4, metadata !39, metadata !DIExpression()), !dbg !40 46 | store i8** %1, i8*** %5, align 8 47 | call void @llvm.dbg.declare(metadata i8*** %5, metadata !41, metadata !DIExpression()), !dbg !42 48 | call void @llvm.dbg.declare(metadata i32** %6, metadata !43, metadata !DIExpression()), !dbg !44 49 | %7 = bitcast i32** %6 to i8*, !dbg !45 50 | call void @llvm.var.annotation(i8* %7, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.1, i32 0, i32 0), i32 11), !dbg !45 51 | %8 = call i8* @pz_malloc(i64 4), !dbg !46 52 | %9 = bitcast i8* %8 to i32*, !dbg !47 53 | store i32* %9, i32** %6, align 8, !dbg !44 54 | %10 = load i32*, i32** %6, align 8, !dbg !48 55 | store i32 7, i32* %10, align 4, !dbg !49 56 | %11 = load i32*, i32** %6, align 8, !dbg !50 57 | %12 = bitcast i32* %11 to i8*, !dbg !50 58 | call void @pz_free(i8* %12), !dbg !51 59 | ret i32 0, !dbg !52 60 | } 61 | 62 | ; Function Attrs: nounwind 63 | declare void @llvm.var.annotation(i8*, i8*, i8*, i32) #4 64 | 65 | attributes #0 = { noinline nounwind optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 66 | attributes #1 = { nounwind readnone speculatable } 67 | attributes #2 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 68 | attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 69 | attributes #4 = { nounwind } 70 | attributes #5 = { allocsize(0) } 71 | 72 | !llvm.dbg.cu = !{!0} 73 | !llvm.module.flags = !{!6, !7, !8, !9} 74 | !llvm.ident = !{!10} 75 | 76 | !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) 77 | !1 = !DIFile(filename: "test_malloc_anno.c", directory: "/Users/yongzhehuang/Documents/llvm_versions/program-dependence-graph-in-llvm/test/pdg_test") 78 | !2 = !{} 79 | !3 = !{!4} 80 | !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) 81 | !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 82 | !6 = !{i32 2, !"Dwarf Version", i32 4} 83 | !7 = !{i32 2, !"Debug Info Version", i32 3} 84 | !8 = !{i32 1, !"wchar_size", i32 4} 85 | !9 = !{i32 7, !"PIC Level", i32 2} 86 | !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} 87 | !11 = distinct !DISubprogram(name: "pz_malloc", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) 88 | !12 = !DISubroutineType(types: !13) 89 | !13 = !{!14, !15} 90 | !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) 91 | !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_t", file: !16, line: 31, baseType: !17) 92 | !16 = !DIFile(filename: "/usr/include/sys/_types/_size_t.h", directory: "") 93 | !17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_size_t", file: !18, line: 92, baseType: !19) 94 | !18 = !DIFile(filename: "/usr/include/i386/_types.h", directory: "") 95 | !19 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) 96 | !20 = !DILocalVariable(name: "size", arg: 1, scope: !11, file: !1, line: 4, type: !15) 97 | !21 = !DILocation(line: 4, column: 24, scope: !11) 98 | !22 = !DILocation(line: 4, column: 46, scope: !11) 99 | !23 = !DILocation(line: 4, column: 39, scope: !11) 100 | !24 = !DILocation(line: 4, column: 32, scope: !11) 101 | !25 = distinct !DISubprogram(name: "pz_free", scope: !1, file: !1, line: 7, type: !26, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) 102 | !26 = !DISubroutineType(types: !27) 103 | !27 = !{null, !14} 104 | !28 = !DILocalVariable(name: "p", arg: 1, scope: !25, file: !1, line: 7, type: !14) 105 | !29 = !DILocation(line: 7, column: 20, scope: !25) 106 | !30 = !DILocation(line: 7, column: 30, scope: !25) 107 | !31 = !DILocation(line: 7, column: 25, scope: !25) 108 | !32 = !DILocation(line: 7, column: 34, scope: !25) 109 | !33 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 9, type: !34, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) 110 | !34 = !DISubroutineType(types: !35) 111 | !35 = !{!5, !5, !36} 112 | !36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !37, size: 64) 113 | !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !38, size: 64) 114 | !38 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) 115 | !39 = !DILocalVariable(name: "argc", arg: 1, scope: !33, file: !1, line: 9, type: !5) 116 | !40 = !DILocation(line: 9, column: 14, scope: !33) 117 | !41 = !DILocalVariable(name: "argv", arg: 2, scope: !33, file: !1, line: 9, type: !36) 118 | !42 = !DILocation(line: 9, column: 27, scope: !33) 119 | !43 = !DILocalVariable(name: "p_r2", scope: !33, file: !1, line: 11, type: !4) 120 | !44 = !DILocation(line: 11, column: 9, scope: !33) 121 | !45 = !DILocation(line: 10, column: 4, scope: !33) 122 | !46 = !DILocation(line: 11, column: 22, scope: !33) 123 | !47 = !DILocation(line: 11, column: 16, scope: !33) 124 | !48 = !DILocation(line: 12, column: 5, scope: !33) 125 | !49 = !DILocation(line: 12, column: 10, scope: !33) 126 | !50 = !DILocation(line: 13, column: 13, scope: !33) 127 | !51 = !DILocation(line: 13, column: 5, scope: !33) 128 | !52 = !DILocation(line: 14, column: 5, scope: !33) 129 | -------------------------------------------------------------------------------- /lib/catch2/catch_reporter_teamcity.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Phil Nash on 19th December 2014 3 | * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | */ 8 | #ifndef TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED 9 | #define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED 10 | 11 | // Don't #include any Catch headers here - we can assume they are already 12 | // included before this header. 13 | // This is not good practice in general but is necessary in this case so this 14 | // file can be distributed as a single header that works with the main 15 | // Catch single header. 16 | 17 | #include 18 | 19 | #ifdef __clang__ 20 | # pragma clang diagnostic push 21 | # pragma clang diagnostic ignored "-Wpadded" 22 | #endif 23 | 24 | namespace Catch { 25 | 26 | struct TeamCityReporter : StreamingReporterBase { 27 | TeamCityReporter( ReporterConfig const& _config ) 28 | : StreamingReporterBase( _config ) 29 | { 30 | m_reporterPrefs.shouldRedirectStdOut = true; 31 | } 32 | 33 | static std::string escape( std::string const& str ) { 34 | std::string escaped = str; 35 | replaceInPlace( escaped, "|", "||" ); 36 | replaceInPlace( escaped, "'", "|'" ); 37 | replaceInPlace( escaped, "\n", "|n" ); 38 | replaceInPlace( escaped, "\r", "|r" ); 39 | replaceInPlace( escaped, "[", "|[" ); 40 | replaceInPlace( escaped, "]", "|]" ); 41 | return escaped; 42 | } 43 | ~TeamCityReporter() override; 44 | 45 | static std::string getDescription() { 46 | return "Reports test results as TeamCity service messages"; 47 | } 48 | 49 | void skipTest( TestCaseInfo const& /* testInfo */ ) override { 50 | } 51 | 52 | void noMatchingTestCases( std::string const& /* spec */ ) override {} 53 | 54 | void testGroupStarting( GroupInfo const& groupInfo ) override { 55 | StreamingReporterBase::testGroupStarting( groupInfo ); 56 | stream << "##teamcity[testSuiteStarted name='" 57 | << escape( groupInfo.name ) << "']\n"; 58 | } 59 | void testGroupEnded( TestGroupStats const& testGroupStats ) override { 60 | StreamingReporterBase::testGroupEnded( testGroupStats ); 61 | stream << "##teamcity[testSuiteFinished name='" 62 | << escape( testGroupStats.groupInfo.name ) << "']\n"; 63 | } 64 | 65 | 66 | void assertionStarting( AssertionInfo const& ) override {} 67 | 68 | bool assertionEnded( AssertionStats const& assertionStats ) override { 69 | AssertionResult const& result = assertionStats.assertionResult; 70 | if( !result.isOk() ) { 71 | 72 | ReusableStringStream msg; 73 | if( !m_headerPrintedForThisSection ) 74 | printSectionHeader( msg.get() ); 75 | m_headerPrintedForThisSection = true; 76 | 77 | msg << result.getSourceInfo() << "\n"; 78 | 79 | switch( result.getResultType() ) { 80 | case ResultWas::ExpressionFailed: 81 | msg << "expression failed"; 82 | break; 83 | case ResultWas::ThrewException: 84 | msg << "unexpected exception"; 85 | break; 86 | case ResultWas::FatalErrorCondition: 87 | msg << "fatal error condition"; 88 | break; 89 | case ResultWas::DidntThrowException: 90 | msg << "no exception was thrown where one was expected"; 91 | break; 92 | case ResultWas::ExplicitFailure: 93 | msg << "explicit failure"; 94 | break; 95 | 96 | // We shouldn't get here because of the isOk() test 97 | case ResultWas::Ok: 98 | case ResultWas::Info: 99 | case ResultWas::Warning: 100 | CATCH_ERROR( "Internal error in TeamCity reporter" ); 101 | // These cases are here to prevent compiler warnings 102 | case ResultWas::Unknown: 103 | case ResultWas::FailureBit: 104 | case ResultWas::Exception: 105 | CATCH_ERROR( "Not implemented" ); 106 | } 107 | if( assertionStats.infoMessages.size() == 1 ) 108 | msg << " with message:"; 109 | if( assertionStats.infoMessages.size() > 1 ) 110 | msg << " with messages:"; 111 | for( auto const& messageInfo : assertionStats.infoMessages ) 112 | msg << "\n \"" << messageInfo.message << "\""; 113 | 114 | 115 | if( result.hasExpression() ) { 116 | msg << 117 | "\n " << result.getExpressionInMacro() << "\n" 118 | "with expansion:\n" << 119 | " " << result.getExpandedExpression() << "\n"; 120 | } 121 | 122 | if( currentTestCaseInfo->okToFail() ) { 123 | msg << "- failure ignore as test marked as 'ok to fail'\n"; 124 | stream << "##teamcity[testIgnored" 125 | << " name='" << escape( currentTestCaseInfo->name )<< "'" 126 | << " message='" << escape( msg.str() ) << "'" 127 | << "]\n"; 128 | } 129 | else { 130 | stream << "##teamcity[testFailed" 131 | << " name='" << escape( currentTestCaseInfo->name )<< "'" 132 | << " message='" << escape( msg.str() ) << "'" 133 | << "]\n"; 134 | } 135 | } 136 | stream.flush(); 137 | return true; 138 | } 139 | 140 | void sectionStarting( SectionInfo const& sectionInfo ) override { 141 | m_headerPrintedForThisSection = false; 142 | StreamingReporterBase::sectionStarting( sectionInfo ); 143 | } 144 | 145 | void testCaseStarting( TestCaseInfo const& testInfo ) override { 146 | m_testTimer.start(); 147 | StreamingReporterBase::testCaseStarting( testInfo ); 148 | stream << "##teamcity[testStarted name='" 149 | << escape( testInfo.name ) << "']\n"; 150 | stream.flush(); 151 | } 152 | 153 | void testCaseEnded( TestCaseStats const& testCaseStats ) override { 154 | StreamingReporterBase::testCaseEnded( testCaseStats ); 155 | if( !testCaseStats.stdOut.empty() ) 156 | stream << "##teamcity[testStdOut name='" 157 | << escape( testCaseStats.testInfo.name ) 158 | << "' out='" << escape( testCaseStats.stdOut ) << "']\n"; 159 | if( !testCaseStats.stdErr.empty() ) 160 | stream << "##teamcity[testStdErr name='" 161 | << escape( testCaseStats.testInfo.name ) 162 | << "' out='" << escape( testCaseStats.stdErr ) << "']\n"; 163 | stream << "##teamcity[testFinished name='" 164 | << escape( testCaseStats.testInfo.name ) << "' duration='" 165 | << m_testTimer.getElapsedMilliseconds() << "']\n"; 166 | stream.flush(); 167 | } 168 | 169 | private: 170 | void printSectionHeader( std::ostream& os ) { 171 | assert( !m_sectionStack.empty() ); 172 | 173 | if( m_sectionStack.size() > 1 ) { 174 | os << getLineOfChars<'-'>() << "\n"; 175 | 176 | std::vector::const_iterator 177 | it = m_sectionStack.begin()+1, // Skip first section (test case) 178 | itEnd = m_sectionStack.end(); 179 | for( ; it != itEnd; ++it ) 180 | printHeaderString( os, it->name ); 181 | os << getLineOfChars<'-'>() << "\n"; 182 | } 183 | 184 | SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; 185 | 186 | if( !lineInfo.empty() ) 187 | os << lineInfo << "\n"; 188 | os << getLineOfChars<'.'>() << "\n\n"; 189 | } 190 | 191 | // if string has a : in first line will set indent to follow it on 192 | // subsequent lines 193 | static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) { 194 | std::size_t i = _string.find( ": " ); 195 | if( i != std::string::npos ) 196 | i+=2; 197 | else 198 | i = 0; 199 | os << Column( _string ) 200 | .indent( indent+i) 201 | .initialIndent( indent ) << "\n"; 202 | } 203 | private: 204 | bool m_headerPrintedForThisSection = false; 205 | Timer m_testTimer; 206 | }; 207 | 208 | #ifdef CATCH_IMPL 209 | TeamCityReporter::~TeamCityReporter() {} 210 | #endif 211 | 212 | CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) 213 | 214 | } // end namespace Catch 215 | 216 | #ifdef __clang__ 217 | # pragma clang diagnostic pop 218 | #endif 219 | 220 | #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED 221 | -------------------------------------------------------------------------------- /src/DataDependencyGraph.cpp: -------------------------------------------------------------------------------- 1 | #include "DataDependencyGraph.hpp" 2 | 3 | using namespace llvm; 4 | 5 | char pdg::DataDependencyGraph::ID = 0; 6 | 7 | void pdg::DataDependencyGraph::initializeMemoryDependencyPasses() 8 | { 9 | steenAA = &getAnalysis().getResult(); 10 | andersAA = &getAnalysis().getResult(); 11 | MD = &getAnalysis().getMemDep(); 12 | } 13 | 14 | void pdg::DataDependencyGraph::constructFuncMapAndCreateFunctionEntry() 15 | { 16 | auto& pdgUtils = PDGUtils::getInstance(); 17 | if (pdgUtils.getFuncMap()[Func]->getEntryW() == nullptr) 18 | { 19 | InstructionWrapper *entryW = new InstructionWrapper(Func, GraphNodeType::ENTRY); 20 | pdgUtils.getFuncInstWMap()[Func].insert(entryW); 21 | pdgUtils.getFuncMap()[Func]->setEntryW(entryW); 22 | } 23 | } 24 | 25 | void pdg::DataDependencyGraph::collectDataDependencyInFunc() 26 | { 27 | for (inst_iterator instIt = inst_begin(Func); instIt != inst_end(Func); ++instIt) 28 | { 29 | getNodeByData(&*instIt); 30 | Instruction *inst = dyn_cast(&*instIt); 31 | collectDefUseDependency(inst); 32 | collectCallInstDependency(inst); 33 | 34 | if (isa(inst)) 35 | { 36 | collectReadFromDependency(inst); 37 | collectRAWDependency(inst); 38 | collectNonLocalDependency(inst); 39 | } 40 | } 41 | } 42 | 43 | void pdg::DataDependencyGraph::collectAliasDependencies() 44 | { 45 | auto &pdgUtils = PDGUtils::getInstance(); 46 | auto funcMap = pdgUtils.getFuncMap()[Func]; 47 | auto instMap = pdgUtils.getInstMap(); 48 | auto storeVec = funcMap->getStoreInstList(); 49 | auto loadVec = funcMap->getLoadInstList(); 50 | auto castVec = funcMap->getCastInstList(); 51 | 52 | for (StoreInst *si : storeVec) 53 | { 54 | MemoryLocation s_loc = MemoryLocation::get(si); 55 | for (LoadInst *li : loadVec) 56 | { 57 | MemoryLocation l_loc = MemoryLocation::get(li); 58 | AliasResult andersAAResult = andersAA->query(s_loc, l_loc); 59 | // AliasResult steensAAResult = steenAA->alias(s_loc, l_loc); 60 | if (andersAAResult != NoAlias) 61 | { 62 | InstructionWrapper *loadInstW = instMap[li]; 63 | InstructionWrapper *storeInstW = instMap[si]; 64 | DDG->addDependency(storeInstW, loadInstW, DependencyType::DATA_ALIAS); 65 | DDG->addDependency(loadInstW, storeInstW, DependencyType::DATA_ALIAS); 66 | } 67 | } 68 | 69 | for (StoreInst *si1 : storeVec) { 70 | if (si == si1) 71 | continue; 72 | MemoryLocation s1_loc = MemoryLocation::get(si1); 73 | AliasResult andersAAResult = andersAA->query(s_loc, s1_loc); 74 | if (andersAAResult != NoAlias) { 75 | InstructionWrapper *store1InstW = PDGUtils::getInstance().getInstMap()[si]; 76 | InstructionWrapper *store2InstW = PDGUtils::getInstance().getInstMap()[si1]; 77 | DDG->addDependency(store1InstW, store2InstW, DependencyType::DATA_ALIAS); 78 | DDG->addDependency(store2InstW, store1InstW, DependencyType::DATA_ALIAS); 79 | } 80 | } 81 | } 82 | 83 | // add alias info for two load instructions 84 | for (LoadInst *li1 : loadVec) 85 | { 86 | for (LoadInst *li2 : loadVec) 87 | { 88 | if (li1 == li2) 89 | { 90 | continue; 91 | } 92 | MemoryLocation li1_loc = MemoryLocation::get(li1); 93 | MemoryLocation li2_loc = MemoryLocation::get(li2); 94 | 95 | Type *li1LocTy = li1->getPointerOperandType(); 96 | Type *li2LocTy = li2->getPointerOperandType(); 97 | 98 | if (li1 != li2) 99 | { 100 | continue; 101 | } 102 | AliasResult AA_result = andersAA->query(li1_loc, li2_loc); 103 | if (AA_result != NoAlias) 104 | { 105 | InstructionWrapper *loadInstW1 = instMap[li1]; 106 | InstructionWrapper *loadInstW2 = instMap[li2]; 107 | DDG->addDependency(loadInstW1, loadInstW2, DependencyType::DATA_ALIAS); 108 | } 109 | } 110 | } 111 | 112 | for (CastInst *csi : castVec) 113 | { 114 | errs() << *csi << "\n"; 115 | auto srcInst = dyn_cast(csi->getOperand(0)); 116 | auto destInst = csi; 117 | 118 | InstructionWrapper *srcInstW = instMap[srcInst]; 119 | InstructionWrapper *destInstW = instMap[destInst]; 120 | DDG->addDependency(srcInstW, destInstW, DependencyType::DATA_ALIAS); 121 | DDG->addDependency(destInstW, srcInstW, DependencyType::DATA_ALIAS); 122 | } 123 | } 124 | 125 | void pdg::DataDependencyGraph::collectReadFromDependency(llvm::Instruction *inst) 126 | { 127 | if (LoadInst *li = dyn_cast(inst)) 128 | { 129 | if (Instruction *pInst = dyn_cast(li->getPointerOperand())) 130 | { 131 | DDG->addDependency(PDGUtils::getInstance().getInstMap()[pInst], 132 | PDGUtils::getInstance().getInstMap()[inst], 133 | DependencyType::DATA_READ); 134 | } 135 | } 136 | } 137 | 138 | void pdg::DataDependencyGraph::collectDefUseDependency(llvm::Instruction *inst) 139 | { 140 | // check for def-use dependencies 141 | for (Instruction::const_op_iterator cuit = inst->op_begin(); 142 | cuit != inst->op_end(); ++cuit) 143 | { 144 | if (Instruction *pInst = dyn_cast(*cuit)) 145 | { 146 | // add info flow from the instruction to current instruction 147 | DDG->addDependency(PDGUtils::getInstance().getInstMap()[pInst], 148 | PDGUtils::getInstance().getInstMap()[inst], 149 | DependencyType::DATA_DEF_USE); 150 | } 151 | } 152 | } 153 | 154 | void pdg::DataDependencyGraph::collectCallInstDependency(llvm::Instruction *inst) 155 | { 156 | if (CallInst *callInst = dyn_cast(inst)) 157 | { 158 | if (callInst->getCalledFunction() != nullptr && callInst->getCalledFunction()->isDeclaration()) 159 | return; 160 | 161 | for (auto arg_iter = callInst->arg_begin(); arg_iter != callInst->arg_end(); ++arg_iter) 162 | { 163 | if (Instruction *tmpInst = dyn_cast(&*arg_iter)) 164 | { 165 | // DDG->addDependency(PDGUtils::getInstance().getInstMap()[tmpInst], 166 | // PDGUtils::getInstance().getInstMap()[inst], 167 | // DependencyType::DATA_CALL_PARA); 168 | DDG->addDependency(PDGUtils::getInstance().getInstMap()[inst], 169 | PDGUtils::getInstance().getInstMap()[tmpInst], 170 | DependencyType::DATA_CALL_PARA); 171 | } 172 | } 173 | } 174 | } 175 | 176 | std::vector pdg::DataDependencyGraph::getRAWDepList(Instruction *pLoadInst) 177 | { 178 | std::vector _flowdep_set; 179 | std::vector StoreVec = PDGUtils::getInstance().getFuncMap()[Func]->getStoreInstList(); 180 | // for each Load Instruction, find related Store Instructions(alias considered) 181 | LoadInst *LI = dyn_cast(pLoadInst); 182 | MemoryLocation LI_Loc = MemoryLocation::get(LI); 183 | for (StoreInst *SI : StoreVec) 184 | { 185 | MemoryLocation SI_Loc = MemoryLocation::get(SI); 186 | AliasResult andersAAResult = andersAA->query(LI_Loc, SI_Loc); 187 | AliasResult steensAAResult = steenAA->query(LI_Loc, SI_Loc); 188 | if (andersAAResult != NoAlias || steensAAResult != NoAlias) 189 | { 190 | _flowdep_set.push_back(SI); 191 | } 192 | } 193 | return _flowdep_set; 194 | } 195 | 196 | void pdg::DataDependencyGraph::collectRAWDependency(llvm::Instruction *inst) 197 | { 198 | // dealing with dependencies in a function 199 | std::vector flowdep_set = getRAWDepList(inst); 200 | 201 | for (unsigned i = 0; i < flowdep_set.size(); i++) 202 | { 203 | DDG->addDependency(PDGUtils::getInstance().getInstMap()[flowdep_set[i]], 204 | PDGUtils::getInstance().getInstMap()[inst], 205 | DependencyType::DATA_RAW); 206 | } 207 | 208 | flowdep_set.clear(); 209 | } 210 | 211 | void pdg::DataDependencyGraph::collectNonLocalDependency(llvm::Instruction *inst) 212 | { 213 | // dealing with non local pointer dependency, nonLocalPointer dep is stored in result small vector 214 | SmallVector result; 215 | // the return result is NonLocalDepResult. can use getAddress function 216 | MD->getNonLocalPointerDependency(inst, result); 217 | // now result stores all possible 218 | for (NonLocalDepResult &I : result) 219 | { 220 | const MemDepResult &nonLocal_res = I.getResult(); 221 | InstructionWrapper *itInst = PDGUtils::getInstance().getInstMap()[inst]; 222 | InstructionWrapper *parentInst = PDGUtils::getInstance().getInstMap()[nonLocal_res.getInst()]; 223 | 224 | if (nonLocal_res.getInst() != nullptr) 225 | { 226 | DDG->addDependency(itInst, parentInst, DependencyType::DATA_GENERAL); 227 | } 228 | // ignore nullptr return res 229 | } 230 | } 231 | 232 | pdg::DependencyNode *pdg::DataDependencyGraph::getNodeByData(Instruction *inst) 233 | { 234 | return DDG->getNodeByData(PDGUtils::getInstance().getInstMap()[inst]); 235 | } 236 | 237 | typename pdg::DependencyNode::DependencyLinkList pdg::DataDependencyGraph::getNodeDepList(Instruction *inst) 238 | { 239 | return DDG->getNodeDepList(PDGUtils::getInstance().getInstMap()[inst]); 240 | } 241 | 242 | bool pdg::DataDependencyGraph::runOnFunction(Function &F) 243 | { 244 | Func = &F; 245 | PDGUtils::getInstance().constructFuncMap(*F.getParent()); 246 | initializeMemoryDependencyPasses(); 247 | constructFuncMapAndCreateFunctionEntry(); 248 | collectDataDependencyInFunc(); 249 | collectAliasDependencies(); 250 | return false; 251 | } 252 | 253 | void pdg::DataDependencyGraph::getAnalysisUsage(AnalysisUsage &AU) const 254 | { 255 | AU.addRequired(); 256 | AU.addRequired(); 257 | AU.addRequired(); 258 | AU.setPreservesAll(); 259 | } 260 | 261 | static RegisterPass 262 | DDG("ddg", "Data Dependency Graph Construction", false, true); -------------------------------------------------------------------------------- /lib/catch2/catch_reporter_tap.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Colton Wolkins on 2015-08-15. 3 | * Copyright 2015 Martin Moene. All rights reserved. 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | */ 8 | #ifndef TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED 9 | #define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED 10 | 11 | 12 | // Don't #include any Catch headers here - we can assume they are already 13 | // included before this header. 14 | // This is not good practice in general but is necessary in this case so this 15 | // file can be distributed as a single header that works with the main 16 | // Catch single header. 17 | 18 | #include 19 | 20 | namespace Catch { 21 | 22 | struct TAPReporter : StreamingReporterBase { 23 | 24 | using StreamingReporterBase::StreamingReporterBase; 25 | 26 | ~TAPReporter() override; 27 | 28 | static std::string getDescription() { 29 | return "Reports test results in TAP format, suitable for test harnesses"; 30 | } 31 | 32 | ReporterPreferences getPreferences() const override { 33 | return m_reporterPrefs; 34 | } 35 | 36 | void noMatchingTestCases( std::string const& spec ) override { 37 | stream << "# No test cases matched '" << spec << "'" << std::endl; 38 | } 39 | 40 | void assertionStarting( AssertionInfo const& ) override {} 41 | 42 | bool assertionEnded( AssertionStats const& _assertionStats ) override { 43 | ++counter; 44 | 45 | AssertionPrinter printer( stream, _assertionStats, counter ); 46 | printer.print(); 47 | stream << " # " << currentTestCaseInfo->name ; 48 | 49 | stream << std::endl; 50 | return true; 51 | } 52 | 53 | void testRunEnded( TestRunStats const& _testRunStats ) override { 54 | printTotals( _testRunStats.totals ); 55 | stream << "\n" << std::endl; 56 | StreamingReporterBase::testRunEnded( _testRunStats ); 57 | } 58 | 59 | private: 60 | std::size_t counter = 0; 61 | class AssertionPrinter { 62 | public: 63 | AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; 64 | AssertionPrinter( AssertionPrinter const& ) = delete; 65 | AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter ) 66 | : stream( _stream ) 67 | , result( _stats.assertionResult ) 68 | , messages( _stats.infoMessages ) 69 | , itMessage( _stats.infoMessages.begin() ) 70 | , printInfoMessages( true ) 71 | , counter(_counter) 72 | {} 73 | 74 | void print() { 75 | itMessage = messages.begin(); 76 | 77 | switch( result.getResultType() ) { 78 | case ResultWas::Ok: 79 | printResultType( passedString() ); 80 | printOriginalExpression(); 81 | printReconstructedExpression(); 82 | if ( ! result.hasExpression() ) 83 | printRemainingMessages( Colour::None ); 84 | else 85 | printRemainingMessages(); 86 | break; 87 | case ResultWas::ExpressionFailed: 88 | if (result.isOk()) { 89 | printResultType(passedString()); 90 | } else { 91 | printResultType(failedString()); 92 | } 93 | printOriginalExpression(); 94 | printReconstructedExpression(); 95 | if (result.isOk()) { 96 | printIssue(" # TODO"); 97 | } 98 | printRemainingMessages(); 99 | break; 100 | case ResultWas::ThrewException: 101 | printResultType( failedString() ); 102 | printIssue( "unexpected exception with message:" ); 103 | printMessage(); 104 | printExpressionWas(); 105 | printRemainingMessages(); 106 | break; 107 | case ResultWas::FatalErrorCondition: 108 | printResultType( failedString() ); 109 | printIssue( "fatal error condition with message:" ); 110 | printMessage(); 111 | printExpressionWas(); 112 | printRemainingMessages(); 113 | break; 114 | case ResultWas::DidntThrowException: 115 | printResultType( failedString() ); 116 | printIssue( "expected exception, got none" ); 117 | printExpressionWas(); 118 | printRemainingMessages(); 119 | break; 120 | case ResultWas::Info: 121 | printResultType( "info" ); 122 | printMessage(); 123 | printRemainingMessages(); 124 | break; 125 | case ResultWas::Warning: 126 | printResultType( "warning" ); 127 | printMessage(); 128 | printRemainingMessages(); 129 | break; 130 | case ResultWas::ExplicitFailure: 131 | printResultType( failedString() ); 132 | printIssue( "explicitly" ); 133 | printRemainingMessages( Colour::None ); 134 | break; 135 | // These cases are here to prevent compiler warnings 136 | case ResultWas::Unknown: 137 | case ResultWas::FailureBit: 138 | case ResultWas::Exception: 139 | printResultType( "** internal error **" ); 140 | break; 141 | } 142 | } 143 | 144 | private: 145 | static Colour::Code dimColour() { return Colour::FileName; } 146 | 147 | static const char* failedString() { return "not ok"; } 148 | static const char* passedString() { return "ok"; } 149 | 150 | void printSourceInfo() const { 151 | Colour colourGuard( dimColour() ); 152 | stream << result.getSourceInfo() << ":"; 153 | } 154 | 155 | void printResultType( std::string const& passOrFail ) const { 156 | if( !passOrFail.empty() ) { 157 | stream << passOrFail << ' ' << counter << " -"; 158 | } 159 | } 160 | 161 | void printIssue( std::string const& issue ) const { 162 | stream << " " << issue; 163 | } 164 | 165 | void printExpressionWas() { 166 | if( result.hasExpression() ) { 167 | stream << ";"; 168 | { 169 | Colour colour( dimColour() ); 170 | stream << " expression was:"; 171 | } 172 | printOriginalExpression(); 173 | } 174 | } 175 | 176 | void printOriginalExpression() const { 177 | if( result.hasExpression() ) { 178 | stream << " " << result.getExpression(); 179 | } 180 | } 181 | 182 | void printReconstructedExpression() const { 183 | if( result.hasExpandedExpression() ) { 184 | { 185 | Colour colour( dimColour() ); 186 | stream << " for: "; 187 | } 188 | std::string expr = result.getExpandedExpression(); 189 | std::replace( expr.begin(), expr.end(), '\n', ' '); 190 | stream << expr; 191 | } 192 | } 193 | 194 | void printMessage() { 195 | if ( itMessage != messages.end() ) { 196 | stream << " '" << itMessage->message << "'"; 197 | ++itMessage; 198 | } 199 | } 200 | 201 | void printRemainingMessages( Colour::Code colour = dimColour() ) { 202 | if (itMessage == messages.end()) { 203 | return; 204 | } 205 | 206 | // using messages.end() directly (or auto) yields compilation error: 207 | std::vector::const_iterator itEnd = messages.end(); 208 | const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); 209 | 210 | { 211 | Colour colourGuard( colour ); 212 | stream << " with " << pluralise( N, "message" ) << ":"; 213 | } 214 | 215 | for(; itMessage != itEnd; ) { 216 | // If this assertion is a warning ignore any INFO messages 217 | if( printInfoMessages || itMessage->type != ResultWas::Info ) { 218 | stream << " '" << itMessage->message << "'"; 219 | if ( ++itMessage != itEnd ) { 220 | Colour colourGuard( dimColour() ); 221 | stream << " and"; 222 | } 223 | } 224 | } 225 | } 226 | 227 | private: 228 | std::ostream& stream; 229 | AssertionResult const& result; 230 | std::vector messages; 231 | std::vector::const_iterator itMessage; 232 | bool printInfoMessages; 233 | std::size_t counter; 234 | }; 235 | 236 | void printTotals( const Totals& totals ) const { 237 | if( totals.testCases.total() == 0 ) { 238 | stream << "1..0 # Skipped: No tests ran."; 239 | } else { 240 | stream << "1.." << counter; 241 | } 242 | } 243 | }; 244 | 245 | #ifdef CATCH_IMPL 246 | TAPReporter::~TAPReporter() {} 247 | #endif 248 | 249 | CATCH_REGISTER_REPORTER( "tap", TAPReporter ) 250 | 251 | } // end namespace Catch 252 | 253 | #endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED 254 | -------------------------------------------------------------------------------- /src/DepPrinter.cpp: -------------------------------------------------------------------------------- 1 | #include "ProgramDependencyGraph.hpp" 2 | #include "llvm/Analysis/DOTGraphTraitsPass.h" 3 | #include "llvm/ADT/GraphTraits.h" 4 | #include "llvm/Support/TypeName.h" 5 | 6 | namespace llvm 7 | { 8 | template <> 9 | struct GraphTraits *> 10 | { 11 | using NodeRef = pdg::DependencyNode *; 12 | using ChildIteratorType = pdg::DependencyNode::iterator; 13 | using nodes_iterator = pdg::DependencyNode::iterator; 14 | 15 | static NodeRef getEntryNode(pdg::DependencyNode *N) { return N; } 16 | static inline ChildIteratorType child_begin(pdg::DependencyNode *N) { return ChildIteratorType(N->getDependencyList().begin()); } 17 | static inline ChildIteratorType child_end(pdg::DependencyNode *N) { return ChildIteratorType(N->getDependencyList().end()); } 18 | static nodes_iterator nodes_begin(pdg::DependencyNode *N) { return nodes_iterator(N->getDependencyList().begin()); } 19 | static nodes_iterator nodes_end(pdg::DependencyNode *N) { return nodes_iterator(N->getDependencyList().end()); } 20 | }; 21 | 22 | template <> 23 | struct GraphTraits *> : public GraphTraits *> 24 | { 25 | static NodeRef getEntryNode(pdg::DependencyGraph *N) { return *(N->getNodeSet().begin()); } 26 | using nodes_iterator = DependencyGraph::nodes_iterator; 27 | static nodes_iterator nodes_begin(pdg::DependencyGraph *N) { return nodes_iterator(N->getNodeSet().begin()); } 28 | static nodes_iterator nodes_end(pdg::DependencyGraph *N) { return nodes_iterator(N->getNodeSet().end()); } 29 | }; 30 | 31 | // DDG 32 | template <> 33 | struct GraphTraits : public GraphTraits *> 34 | { 35 | static NodeRef getEntryNode(pdg::DataDependencyGraph *DG) 36 | { 37 | return *(DG->_getDDG()->begin_child()); 38 | } 39 | 40 | static nodes_iterator nodes_begin(pdg::DataDependencyGraph *DG) 41 | { 42 | return DG->_getDDG()->begin_child(); 43 | } 44 | 45 | static nodes_iterator nodes_end(pdg::DataDependencyGraph *DG) 46 | { 47 | return DG->_getDDG()->end_child(); 48 | } 49 | }; 50 | 51 | // CDG 52 | template <> 53 | struct GraphTraits : public GraphTraits *> 54 | { 55 | static NodeRef getEntryNode(pdg::ControlDependencyGraph *CG) 56 | { 57 | return *(CG->_getCDG()->begin_child()); 58 | } 59 | 60 | static nodes_iterator nodes_begin(pdg::ControlDependencyGraph *CG) 61 | { 62 | return CG->_getCDG()->begin_child(); 63 | } 64 | 65 | static nodes_iterator nodes_end(pdg::ControlDependencyGraph *CG) 66 | { 67 | return CG->_getCDG()->end_child(); 68 | } 69 | }; 70 | 71 | // PDG 72 | template <> 73 | struct GraphTraits : public GraphTraits *> 74 | { 75 | static NodeRef getEntryNode(pdg::ProgramDependencyGraph *PG) 76 | { 77 | return *(PG->_getPDG()->begin_child()); 78 | } 79 | 80 | static nodes_iterator nodes_begin(pdg::ProgramDependencyGraph *PG) 81 | { 82 | return PG->_getPDG()->begin_child(); 83 | } 84 | 85 | static nodes_iterator nodes_end(pdg::ProgramDependencyGraph *PG) 86 | { 87 | return PG->_getPDG()->end_child(); 88 | } 89 | }; 90 | 91 | template <> 92 | struct DOTGraphTraits *> : public DefaultDOTGraphTraits 93 | { 94 | DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} 95 | 96 | std::string getNodeLabel(pdg::DependencyNode *Node, pdg::DependencyNode *Graph) 97 | { 98 | using namespace pdg; 99 | const InstructionWrapper *instW = Node->getData(); 100 | if (instW == nullptr) 101 | { 102 | errs() << "instW " << instW << "\n"; 103 | return "null instW"; 104 | } 105 | 106 | std::string Str; 107 | raw_string_ostream OS(Str); 108 | 109 | switch (instW->getGraphNodeType()) 110 | { 111 | case GraphNodeType::ENTRY: 112 | { 113 | return ("<> " + instW->getFunction()->getName().str()); 114 | } 115 | case GraphNodeType::GLOBAL_VALUE: 116 | { 117 | OS << *instW->getValue(); 118 | return ("GLOBAL_VALUE:" + OS.str()); 119 | } 120 | case GraphNodeType::FORMAL_IN: 121 | { 122 | llvm::Argument *arg = instW->getArgument(); 123 | int arg_pos = arg->getArgNo(); 124 | OS << *instW->getArgument()->getType(); 125 | return ("FORMAL_IN: " + std::to_string(arg_pos) + " " + OS.str()); 126 | } 127 | case GraphNodeType::ACTUAL_IN: 128 | { 129 | llvm::Argument *arg = instW->getArgument(); 130 | int arg_pos = arg->getArgNo(); 131 | OS << *instW->getArgument()->getType(); 132 | return ("ACTUAL_IN: " + std::to_string(arg_pos) + " " + OS.str()); 133 | } 134 | case GraphNodeType::FORMAL_OUT: 135 | { 136 | llvm::Argument *arg = instW->getArgument(); 137 | int arg_pos = arg->getArgNo(); 138 | OS << *instW->getArgument()->getType(); 139 | return ("FORMAL_OUT: " + std::to_string(arg_pos) + " " + OS.str()); 140 | } 141 | 142 | case GraphNodeType::ACTUAL_OUT: 143 | { 144 | llvm::Argument *arg = instW->getArgument(); 145 | int arg_pos = arg->getArgNo(); 146 | OS << *instW->getArgument()->getType(); 147 | return ("ACTUAL_OUT: " + std::to_string(arg_pos) + " " + OS.str()); 148 | } 149 | case GraphNodeType::PARAMETER_FIELD: 150 | { 151 | llvm::Argument *arg = instW->getArgument(); 152 | int arg_pos = arg->getArgNo(); 153 | OS << *instW->getTreeNodeType() << " arg_pos: " << arg_pos << " - " 154 | << "f_id: " << instW->getNodeOffset(); 155 | return OS.str(); 156 | } 157 | case GraphNodeType::POINTER_RW: 158 | { 159 | OS << *instW->getArgument()->getType(); 160 | return ("POINTER READ/WRITE : *" + OS.str()); 161 | } 162 | //for pointer node, add a "*" sign before real node content 163 | //if multi level pointer, use a loop instead here 164 | 165 | case GraphNodeType::STRUCT_FIELD: 166 | { 167 | llvm::Instruction *inst = instW->getInstruction(); 168 | llvm::AllocaInst *allocaInst = dyn_cast(inst); 169 | // processing differently when get a struct pointer 170 | llvm::StringRef struct_name = ""; 171 | if (allocaInst->getAllocatedType()->isPointerTy()) 172 | { 173 | llvm::PointerType *pt = dyn_cast(allocaInst->getAllocatedType()); 174 | struct_name = pt->getElementType()->getStructName(); 175 | } 176 | else 177 | { 178 | struct_name = allocaInst->getAllocatedType()->getStructName(); 179 | } 180 | 181 | std::string struct_string = struct_name.str(); 182 | std::vector TYPE_NAMES = { 183 | "VoidTy", ///< 0: type with no size 184 | "HalfTy", ///< 1: 16-bit floating point type 185 | "FloatTy", ///< 2: 32-bit floating point type 186 | "DoubleTy", ///< 3: 64-bit floating point type 187 | "X86_FP80Ty", ///< 4: 80-bit floating point type (X87) 188 | "FP128Ty", ///< 5: 128-bit floating point type (112-bit mantissa) 189 | "PPC_FP128Ty", ///< 6: 128-bit floating point type (two 64-bits, PowerPC) 190 | "LabelTy", ///< 7: Labels 191 | "MetadataTy", ///< 8: Metadata 192 | "X86_MMXTy", ///< 9: MMX vectors (64 bits, X86 specific) 193 | "TokenTy", ///< 10: Tokens 194 | 195 | // Derived types... see DerivedTypes.h file. 196 | // Make sure FirstDerivedTyID stays up to date! 197 | "IntegerTy", ///< 11: Arbitrary bit width integers 198 | "FunctionTy", ///< 12: Functions 199 | "StructTy", ///< 13: Structures 200 | "ArrayTy", ///< 14: Arrays 201 | "PointerTy", ///< 15: Pointers 202 | "VectorTy"}; 203 | llvm::Type *field_type = instW->getTreeNodeType(); 204 | std::string type_name = TYPE_NAMES.at(field_type->getTypeID()); 205 | 206 | std::string ret_string = ""; 207 | std::string field_pos = std::to_string(instW->getNodeOffset()); 208 | ret_string = struct_string + " (" + type_name + ") : " + std::to_string(instW->getNodeOffset()); 209 | return (ret_string); 210 | } 211 | default: 212 | break; 213 | } 214 | 215 | //llvm::Instruction *inst = Node->getData()->getInstruction(); 216 | llvm::Instruction *inst = instW->getInstruction(); 217 | 218 | if (inst == nullptr) 219 | return OS.str(); 220 | if (isSimple() && !inst->getName().empty()) 221 | return inst->getName().str(); 222 | else 223 | { 224 | std::string Str; 225 | raw_string_ostream OS(Str); 226 | OS << *inst; 227 | return OS.str(); 228 | } 229 | } 230 | }; 231 | 232 | template <> 233 | struct DOTGraphTraits *> : public DOTGraphTraits *> 234 | { 235 | DOTGraphTraits(bool isSimple = false) : DOTGraphTraits *>(isSimple) {} 236 | 237 | 238 | std::string getNodeLabel(pdg::DependencyNode *Node, pdg::DependencyGraph *Graph) 239 | { 240 | return DOTGraphTraits *>::getNodeLabel(Node, *(Graph->begin_child())); 241 | } 242 | }; 243 | 244 | // CDG 245 | template <> 246 | struct DOTGraphTraits : public DOTGraphTraits *> 247 | { 248 | DOTGraphTraits(bool isSimple = false) : DOTGraphTraits *>(isSimple) {} 249 | 250 | static std::string getGraphName(pdg::ControlDependencyGraph *) 251 | { 252 | return "Control Dependency Graph"; 253 | } 254 | 255 | std::string getNodeLabel(pdg::DependencyNode *Node, pdg::ControlDependencyGraph *Graph) 256 | { 257 | return DOTGraphTraits *>::getNodeLabel(Node, Graph->_getCDG()); 258 | } 259 | }; 260 | 261 | // DDG 262 | template <> 263 | struct DOTGraphTraits : public DOTGraphTraits *> 264 | { 265 | DOTGraphTraits(bool isSimple = false) : DOTGraphTraits *>(isSimple) {} 266 | 267 | static std::string getGraphName(pdg::DataDependencyGraph *) 268 | { 269 | return "Data Dependency Graph"; 270 | } 271 | 272 | std::string getNodeLabel(pdg::DependencyNode *Node, pdg::DataDependencyGraph *Graph) 273 | { 274 | return DOTGraphTraits *>::getNodeLabel(Node, Graph->_getDDG()); 275 | } 276 | }; 277 | 278 | // PDG 279 | template <> 280 | struct DOTGraphTraits : public DOTGraphTraits *> 281 | { 282 | //using nodes_itr = std::vector *, pdg::DependencyType>>::iterator; 283 | DOTGraphTraits(bool isSimple = false) : DOTGraphTraits *>(isSimple) {} 284 | 285 | static std::string getGraphName(pdg::ProgramDependencyGraph *) 286 | { 287 | return "Program Dependency Graph"; 288 | } 289 | 290 | std::string getNodeLabel(pdg::DependencyNode *Node, pdg::ProgramDependencyGraph *Graph) 291 | { 292 | return DOTGraphTraits *>::getNodeLabel(Node, Graph->_getPDG()); 293 | } 294 | 295 | std::string getEdgeAttributes(pdg::DependencyNode *Node, 296 | pdg::DependencyLinkIterator &IW, 297 | pdg::ProgramDependencyGraph *PD) 298 | { 299 | using namespace pdg; 300 | switch (IW.getDependencyType()) 301 | { 302 | case DependencyType::CONTROL: 303 | return ""; 304 | case DependencyType::DATA_GENERAL: 305 | return "style=dotted, label = \"{D_general}\""; 306 | case DependencyType::GLOBAL_DEP: 307 | return "style=dotted"; 308 | case DependencyType::PARAMETER: 309 | return "style=dashed, color=\"blue\""; 310 | case DependencyType::DATA_DEF_USE: 311 | { 312 | Instruction *pFromInst = Node->getData()->getInstruction(); 313 | return "style=dotted,label = \"{DEF_USE}\" "; 314 | } 315 | case DependencyType::DATA_RAW: 316 | { 317 | Instruction *pInstruction = (*IW)->getData()->getInstruction(); 318 | // pTo Node must be a LoadInst 319 | std::string ret_str; 320 | if (isa(pInstruction)) 321 | { 322 | LoadInst *LI = dyn_cast(pInstruction); 323 | Value *valLI = LI->getPointerOperand(); 324 | ret_str = "style=dotted,label = \"{RAW} " + valLI->getName().str() + "\""; 325 | } 326 | else if (isa(pInstruction)) 327 | { 328 | ret_str = "style=dotted,label = \"{RAW}\""; 329 | } 330 | else 331 | errs() << "incorrect instruction for DATA_RAW node!" 332 | << "\n"; 333 | return ret_str; 334 | } 335 | case DependencyType::DATA_ALIAS: 336 | { 337 | return "style=dotted, label=\"{D_ALIAS}\", color=\"red\", penwidth=\"2.0\""; 338 | } 339 | default: 340 | return ""; 341 | //return "style=dotted,label=\"{UNDEFINED}\""; 342 | } 343 | } 344 | 345 | std::string getNodeAttributes(pdg::DependencyNode *Node, pdg::ProgramDependencyGraph *Graph) 346 | { 347 | using namespace pdg; 348 | 349 | auto instW = Node->getData(); 350 | 351 | if (instW == nullptr) 352 | { 353 | //errs() << "instW " << instW << "\n"; 354 | return "null instW"; 355 | } 356 | 357 | switch (instW->getGraphNodeType()) 358 | { 359 | case GraphNodeType::ENTRY: 360 | return ""; 361 | case GraphNodeType::GLOBAL_VALUE: 362 | return ""; 363 | case GraphNodeType::FORMAL_IN: 364 | return "color=\"blue\""; 365 | case GraphNodeType::ACTUAL_IN: 366 | return "color=\"blue\""; 367 | case GraphNodeType::FORMAL_OUT: 368 | return "color=\"blue\""; 369 | case GraphNodeType::ACTUAL_OUT: 370 | return "color=\"blue\""; 371 | case GraphNodeType::PARAMETER_FIELD: 372 | return "color=\"blue\""; 373 | case GraphNodeType::POINTER_RW: 374 | return "color=\"red\""; 375 | case GraphNodeType::STRUCT_FIELD: 376 | return ""; 377 | default: 378 | return ""; 379 | } 380 | } 381 | 382 | std::string getGraphProperties(pdg::ProgramDependencyGraph *Graph) 383 | { 384 | return "graph [ splines=true ]"; 385 | } 386 | }; 387 | } // namespace llvm 388 | 389 | struct ControlDependencyPrinter : public llvm::DOTGraphTraitsPrinter { 390 | static char ID; 391 | ControlDependencyPrinter() : DOTGraphTraitsPrinter("cdgragh", ID) {} 392 | }; 393 | 394 | char ControlDependencyPrinter::ID = 0; 395 | static llvm::RegisterPass 396 | CDGPrinter("dot-cdg", 397 | "Print control dependency graph of function to 'dot' file", 398 | false, false); 399 | 400 | 401 | struct DataDependencyPrinter : public llvm::DOTGraphTraitsPrinter { 402 | static char ID; 403 | DataDependencyPrinter() : DOTGraphTraitsPrinter("ddgragh", ID) {} 404 | }; 405 | 406 | char DataDependencyPrinter::ID = 0; 407 | static llvm::RegisterPass 408 | DDGPrinter("dot-ddg", 409 | "Print data dependency graph of function to 'dot' file", 410 | false, false); 411 | 412 | struct ProgramDependencyPrinter : public llvm::DOTGraphTraitsPrinter 413 | { 414 | static char ID; 415 | ProgramDependencyPrinter() : llvm::DOTGraphTraitsPrinter("pdgragh", ID) {} 416 | }; 417 | 418 | char ProgramDependencyPrinter::ID = 0; 419 | static llvm::RegisterPass 420 | PDGPrinter("dot-pdg", 421 | "Print instruction-level program dependency graph of " 422 | "function to 'dot' file", 423 | false, false); 424 | -------------------------------------------------------------------------------- /src/ProgramDependencyGraph.cpp: -------------------------------------------------------------------------------- 1 | #include "ProgramDependencyGraph.hpp" 2 | 3 | using namespace llvm; 4 | 5 | char pdg::ProgramDependencyGraph::ID = 0; 6 | 7 | int pdg::EXPAND_LEVEL; 8 | llvm::cl::opt expandLevel("l", llvm::cl::desc("Parameter tree expand level"), llvm::cl::value_desc("level")); 9 | 10 | void pdg::ProgramDependencyGraph::getAnalysisUsage(AnalysisUsage &AU) const 11 | { 12 | AU.addRequired(); 13 | AU.addRequired(); 14 | AU.setPreservesAll(); 15 | } 16 | 17 | bool pdg::ProgramDependencyGraph::runOnModule(Module &M) 18 | { 19 | if (!expandLevel) 20 | expandLevel = 4; 21 | EXPAND_LEVEL = expandLevel; 22 | 23 | module = &M; 24 | auto &pdgUtils = PDGUtils::getInstance(); 25 | pdgUtils.constructFuncMap(M); 26 | pdgUtils.collectGlobalInsts(M); 27 | int user_def_func_num = 0; 28 | // copy dependencies from DDG/CDG to PDG 29 | for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) 30 | { 31 | Function *Func = dyn_cast(FI); 32 | if (Func->isDeclaration()) 33 | continue; 34 | 35 | user_def_func_num++; // count function has definition as user defined 36 | pdgUtils.categorizeInstInFunc(*Func); 37 | cdg = &getAnalysis(*Func); 38 | ddg = &getAnalysis(*Func); 39 | 40 | for (InstructionWrapper *instW : pdgUtils.getFuncInstWMap()[Func]) 41 | { 42 | addNodeDependencies(instW); 43 | } 44 | 45 | if (!pdgUtils.getFuncMap()[Func]->hasTrees()) 46 | { 47 | buildFormalTreeForFunc(Func); 48 | drawFormalParameterTree(Func, TreeType::FORMAL_IN_TREE); 49 | drawFormalParameterTree(Func, TreeType::FORMAL_OUT_TREE); 50 | connectFunctionAndFormalTrees(Func); 51 | pdgUtils.getFuncMap()[Func]->setTreeFlag(true); 52 | } 53 | } 54 | 55 | // start process CallInst 56 | for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) 57 | { 58 | Function *Func = dyn_cast(FI); 59 | if (Func->isDeclaration()) 60 | continue; 61 | 62 | auto callInstsList = pdgUtils.getFuncMap()[Func]->getCallInstList(); 63 | for (CallInst *inst : callInstsList) 64 | { 65 | if (!processCallInst(pdgUtils.getInstMap()[inst])) 66 | continue; 67 | } 68 | } 69 | 70 | for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) 71 | { 72 | if (FI->isDeclaration()) 73 | continue; 74 | 75 | auto argWList = pdgUtils.getFuncMap()[&*FI]->getArgWList(); 76 | for (auto argW : argWList) { 77 | errs() << FI->getName() << ": " << argW->getTree(TreeType::FORMAL_IN_TREE).size() << "\n"; 78 | } 79 | } 80 | return false; 81 | } 82 | 83 | bool pdg::ProgramDependencyGraph::processIndirectCallInst(CallInst *CI, InstructionWrapper *instW) 84 | { 85 | auto &pdgUtils = PDGUtils::getInstance(); 86 | Type *t = CI->getCalledValue()->getType(); 87 | FunctionType *funcTy = cast(cast(t)->getElementType()); 88 | // collect all possible function with same function signature 89 | std::vector indirect_call_candidates = collectIndirectCallCandidates(funcTy); 90 | if (indirect_call_candidates.size() == 0) 91 | { 92 | errs() << "cannot find possible indirect call candidates.." << "\n"; 93 | return false; 94 | } 95 | CallWrapper *callW = new CallWrapper(CI, indirect_call_candidates); 96 | pdgUtils.getCallMap()[CI] = callW; 97 | errs() << "indirect call, called Type t = " << *t << "\n"; 98 | // build formal tree for all candidiates. 99 | for (Function *indirect_called_func : indirect_call_candidates) 100 | { 101 | if (indirect_called_func->isDeclaration()) 102 | continue; 103 | if (indirect_called_func->arg_empty()) 104 | continue; 105 | if (pdgUtils.getFuncMap()[indirect_called_func]->hasTrees()) 106 | continue; 107 | errs() << "Building tree for indirect func: " << indirect_called_func->getName() << "\n"; 108 | buildFormalTreeForFunc(indirect_called_func); 109 | drawFormalParameterTree(indirect_called_func, TreeType::FORMAL_IN_TREE); 110 | drawFormalParameterTree(indirect_called_func, TreeType::FORMAL_OUT_TREE); 111 | connectFunctionAndFormalTrees(indirect_called_func); 112 | pdgUtils.getFuncMap()[indirect_called_func]->setTreeFlag(true); 113 | } 114 | buildActualParameterTrees(CI); 115 | drawActualParameterTree(CI, TreeType::ACTUAL_IN_TREE); 116 | drawActualParameterTree(CI, TreeType::ACTUAL_OUT_TREE); 117 | // connect actual tree with all possible candidaites. 118 | if (connectAllPossibleFunctions(CI, indirect_call_candidates)) 119 | { 120 | instW->setVisited(true); 121 | } 122 | return true; 123 | } 124 | 125 | bool pdg::ProgramDependencyGraph::processCallInst(InstructionWrapper *instW) 126 | { 127 | auto &pdgUtils = PDGUtils::getInstance(); 128 | llvm::Instruction *inst = instW->getInstruction(); 129 | if (inst != nullptr && isa(inst) && !instW->getVisited()) 130 | { 131 | CallInst *CI = dyn_cast(inst); 132 | Function *callee = CI->getCalledFunction(); 133 | 134 | if (callee == nullptr) 135 | return processIndirectCallInst(CI, instW); // indirect function call get func type for indirect call inst 136 | 137 | // handle intrinsic functions 138 | if (callee->isIntrinsic()) 139 | return false; 140 | 141 | // special cases done, common function 142 | CallWrapper *callW = new CallWrapper(CI); 143 | pdgUtils.getCallMap()[CI] = callW; 144 | if (!callee->isDeclaration()) 145 | { 146 | if (!callee->arg_empty()) 147 | { 148 | if (pdgUtils.getFuncMap()[callee]->hasTrees() != true) 149 | { 150 | buildFormalTreeForFunc(callee); 151 | drawFormalParameterTree(callee, TreeType::FORMAL_IN_TREE); 152 | drawFormalParameterTree(callee, TreeType::FORMAL_OUT_TREE); 153 | connectFunctionAndFormalTrees(callee); 154 | pdgUtils.getFuncMap()[callee]->setTreeFlag(true); 155 | } 156 | buildActualParameterTrees(CI); 157 | drawActualParameterTree(CI, TreeType::ACTUAL_IN_TREE); 158 | drawActualParameterTree(CI, TreeType::ACTUAL_OUT_TREE); 159 | } // end if !callee 160 | 161 | try 162 | { 163 | connectCallerAndCallee(instW, callee); 164 | } 165 | catch (std::exception &e) 166 | { 167 | errs() << e.what() << "\n"; 168 | exit(0); 169 | } 170 | // link typenode inst with argument inst 171 | std::vector argList = pdgUtils.getFuncMap()[callee]->getArgWList(); 172 | for (ArgumentWrapper *argW : argList) 173 | { 174 | tree::iterator TI = argW->getTree(TreeType::FORMAL_IN_TREE).begin(); 175 | tree::iterator TE = argW->getTree(TreeType::FORMAL_IN_TREE).end(); 176 | for (; TI != TE; ++TI) 177 | { 178 | if (PDG->isDepends(instW, *TI)) 179 | { 180 | PDG->addDependency(instW, *TI, DependencyType::STRUCT_FIELDS); 181 | } 182 | } 183 | } 184 | } 185 | } 186 | return true; 187 | } 188 | 189 | void pdg::ProgramDependencyGraph::addNodeDependencies(InstructionWrapper *instW) 190 | { 191 | auto &pdgUtils = PDGUtils::getInstance(); 192 | // processing Global instruction 193 | if (instW->getInstruction() != nullptr) 194 | { 195 | if (LoadInst *LDInst = dyn_cast(instW->getInstruction())) 196 | { 197 | for (auto GlobalInstW : pdgUtils.getGlobalInstsSet()) 198 | { 199 | // iterate users of the global value 200 | for (User *U : GlobalInstW->getValue()->users()) 201 | { 202 | if (Instruction *userInst = dyn_cast(U)) 203 | { 204 | InstructionWrapper *userInstW = pdgUtils.getInstMap()[userInst]; 205 | PDG->addDependency(GlobalInstW, userInstW, DependencyType::GLOBAL_DEP); 206 | } 207 | } 208 | } 209 | } 210 | } 211 | 212 | // copy data dependency 213 | auto dataDList = ddg->getNodeDepList(instW->getInstruction()); 214 | for (auto dependencyPair : dataDList) 215 | { 216 | InstructionWrapper *DNodeW2 = const_cast(dependencyPair.first->getData()); 217 | PDG->addDependency(instW, DNodeW2, dependencyPair.second); 218 | } 219 | 220 | // copy control dependency 221 | if (instW->getGraphNodeType() == GraphNodeType::ENTRY) 222 | { 223 | Function *parentFunc = instW->getFunction(); 224 | for (InstructionWrapper *instW2 : pdgUtils.getFuncInstWMap()[parentFunc]) 225 | { 226 | PDG->addDependency(instW, instW2, DependencyType::CONTROL); 227 | } 228 | } 229 | } 230 | 231 | void pdg::ProgramDependencyGraph::buildFormalTreeForFunc(Function *Func) 232 | { 233 | auto &pdgUtils = PDGUtils::getInstance(); 234 | for (auto argW : pdgUtils.getFuncMap()[Func]->getArgWList()) 235 | { 236 | // build formal in tree first 237 | buildFormalTreeForArg(*argW->getArg(), TreeType::FORMAL_IN_TREE); 238 | // then, copy formal in tree content to formal out tree 239 | argW->copyTree(argW->getTree(TreeType::FORMAL_IN_TREE), TreeType::FORMAL_OUT_TREE); 240 | } 241 | pdgUtils.getFuncMap()[Func]->setTreeFlag(true); 242 | } 243 | 244 | void pdg::ProgramDependencyGraph::buildFormalTreeForArg(Argument &arg, TreeType treeTy) 245 | { 246 | auto &pdgUtils = PDGUtils::getInstance(); 247 | Function *Func = arg.getParent(); 248 | try 249 | { 250 | InstructionWrapper *treeTyW = new TreeTypeWrapper(arg.getParent(), GraphNodeType::FORMAL_IN, &arg, arg.getType(), nullptr, 0); 251 | pdgUtils.getFuncInstWMap()[Func].insert(treeTyW); 252 | //find the right arg, and set tree root 253 | ArgumentWrapper *argW = pdgUtils.getFuncMap()[Func]->getArgWByArg(arg); 254 | auto treeRoot = argW->getTree(treeTy).set_head(treeTyW); 255 | if (argW->getTree(treeTy).size() == 0) { 256 | std::string err_msg = "Function " + Func->getName().str() + 257 | " has param tree of size 0. Abort..."; 258 | errs() << err_msg << "\n" ; 259 | exit(0); 260 | } 261 | std::string Str; 262 | raw_string_ostream OS(Str); 263 | //FILE*, bypass, no need to buildTypeTree 264 | if ("%struct._IO_FILE*" == OS.str() || "%struct._IO_marker*" == OS.str()) 265 | { 266 | errs() << "OS.str() = " << OS.str() << " FILE* appears, stop buildTypeTree\n"; 267 | } 268 | else if (treeTyW->getTreeNodeType()->isPointerTy() && treeTyW->getTreeNodeType()->getContainedType(0)->isFunctionTy()) 269 | { 270 | errs() << *arg.getParent()->getFunctionType() << " DEBUG 312: in buildFormalTree: function pointer arg = " << *treeTyW->getTreeNodeType() << "\n"; 271 | } 272 | else 273 | { 274 | buildTypeTree(arg, treeTyW, treeTy); 275 | errs() << "ARGW size: " << argW->getTree(treeTy).size() << "\n"; 276 | } 277 | } catch (std::exception &e) { 278 | errs() << e.what() << "\n"; 279 | } 280 | } 281 | 282 | bool pdg::ProgramDependencyGraph::hasRecursiveType(ArgumentWrapper *argW, tree::iterator insert_loc) 283 | { 284 | TreeType treeTy = TreeType::FORMAL_IN_TREE; 285 | int height = argW->getTree(treeTy).depth(insert_loc); 286 | if (height != 0) 287 | { 288 | bool recursion_flag = false; 289 | tree::iterator backTreeIt = insert_loc; 290 | while (height > 0) 291 | { 292 | backTreeIt = argW->getTree(treeTy).parent(backTreeIt); 293 | if ((*insert_loc)->getTreeNodeType() == (*backTreeIt)->getTreeNodeType()) 294 | { 295 | recursion_flag = true; 296 | break; 297 | } 298 | height -= 1; 299 | } 300 | // process next type, because this type brings in a recursion 301 | if (recursion_flag) 302 | return true; 303 | } 304 | return false; 305 | } 306 | 307 | bool pdg::ProgramDependencyGraph::isFilePtrOrFuncTy(Type *ty) 308 | { 309 | //if field is a function Ptr 310 | if (ty->isFunctionTy()) 311 | { 312 | std::string Str; 313 | raw_string_ostream OS(Str); 314 | OS << ty; 315 | return true; 316 | } 317 | 318 | if (ty->isPointerTy()) 319 | { 320 | Type *childEleTy = dyn_cast(ty)->getElementType(); 321 | if (childEleTy->isStructTy()) 322 | { 323 | std::string Str; 324 | raw_string_ostream OS(Str); 325 | OS << ty; 326 | //FILE*, bypass, no need to buildTypeTree 327 | if ("%struct._IO_FILE*" == OS.str() || "%struct._IO_marker*" == OS.str()) 328 | return true; 329 | } 330 | } 331 | return false; 332 | } 333 | 334 | InstructionWrapper *pdg::ProgramDependencyGraph::buildPointerTypeNode(ArgumentWrapper *argW, InstructionWrapper *curTyNode, tree::iterator insert_loc) 335 | { 336 | auto &pdgUtils = PDGUtils::getInstance(); 337 | TreeType treeTy = TreeType::FORMAL_IN_TREE; 338 | Argument &arg = *argW->getArg(); 339 | PointerType *pt = dyn_cast(curTyNode->getTreeNodeType()); 340 | Type *pointedNodeTy = pt->getElementType(); 341 | InstructionWrapper *pointedTypeW = new TreeTypeWrapper(arg.getParent(), 342 | GraphNodeType::PARAMETER_FIELD, 343 | &arg, 344 | pointedNodeTy, 345 | curTyNode->getTreeNodeType(), 346 | 0); 347 | pdgUtils.getFuncInstWMap()[arg.getParent()].insert(pointedTypeW); 348 | argW->getTree(treeTy).append_child(insert_loc, pointedTypeW); 349 | return pointedTypeW; 350 | } 351 | 352 | void pdg::ProgramDependencyGraph::buildTypeTree(Argument &arg, InstructionWrapper *treeTyW, TreeType treeTy) 353 | { 354 | auto &pdgUtils = PDGUtils::getInstance(); 355 | Function *Func = arg.getParent(); 356 | // setup instWQ to avoid recusion processing 357 | std::queue instWQ; 358 | instWQ.push(treeTyW); 359 | ArgumentWrapper *argW = pdgUtils.getFuncMap()[Func]->getArgWByArg(arg); 360 | 361 | if (argW == nullptr) 362 | throw new ArgWrapperIsNullPtr("Argument Wrapper is nullptr"); 363 | 364 | tree::iterator insert_loc; // insert location in the parameter tree for the type wrapper 365 | int depth = 0; 366 | while (!instWQ.empty()) 367 | { 368 | if (depth >= EXPAND_LEVEL) 369 | return; 370 | depth += 1; 371 | int qSize = instWQ.size(); 372 | while (qSize > 0) 373 | { 374 | qSize -= 1; 375 | InstructionWrapper *curTyNode = instWQ.front(); 376 | instWQ.pop(); 377 | insert_loc = getInstInsertLoc(argW, curTyNode, treeTy); 378 | // handle recursion type using 1-limit approach 379 | // track back from child to parent, if find same type, stop building. 380 | // The type used here is form llvm type system. 381 | if (hasRecursiveType(argW, insert_loc)) 382 | continue; 383 | // if is pointer type, create node for the pointed type 384 | Type *curNodeTy = curTyNode->getTreeNodeType(); 385 | if (curNodeTy->isPointerTy()) 386 | { 387 | InstructionWrapper *pointedTypeW = buildPointerTypeNode(argW, curTyNode, insert_loc); 388 | instWQ.push(pointedTypeW); // put the pointed node to queue 389 | continue; 390 | } 391 | // compose for struct 392 | if (!curNodeTy->isStructTy()) 393 | continue; 394 | // processs non-pointer type 395 | Type *parentType = nullptr; 396 | // for struct type, insert all children to the tree 397 | for (unsigned int child_offset = 0; child_offset < curNodeTy->getNumContainedTypes(); child_offset++) 398 | { 399 | parentType = curTyNode->getTreeNodeType(); 400 | // field sensitive processing. Get correspond gep and link tree node with gep. 401 | Type *childType = curNodeTy->getContainedType(child_offset); 402 | InstructionWrapper *gepInstW = getTreeNodeGEP(arg, child_offset, childType, parentType); 403 | InstructionWrapper *typeFieldW = new TreeTypeWrapper(arg.getParent(), GraphNodeType::PARAMETER_FIELD, &arg, childType, parentType, child_offset, gepInstW); 404 | // link gep with tree node 405 | if (gepInstW != nullptr) 406 | PDG->addDependency(typeFieldW, gepInstW, DependencyType::STRUCT_FIELDS); 407 | 408 | pdgUtils.getFuncInstWMap()[arg.getParent()].insert(typeFieldW); 409 | // start inserting formal tree instructions 410 | argW->getTree(treeTy).append_child(insert_loc, typeFieldW); 411 | 412 | //skip function ptr, FILE* 413 | if (isFilePtrOrFuncTy(childType)) 414 | continue; 415 | 416 | instWQ.push(typeFieldW); 417 | } 418 | } 419 | } 420 | } 421 | 422 | void pdg::ProgramDependencyGraph::drawFormalParameterTree(Function *Func, TreeType treeTy) 423 | { 424 | auto &pdgUtils = PDGUtils::getInstance(); 425 | auto argWList = pdgUtils.getFuncMap()[Func]->getArgWList(); 426 | for (ArgumentWrapper *argW : argWList) 427 | { 428 | for (tree::iterator 429 | TI = argW->getTree(treeTy).begin(), 430 | TE = argW->getTree(treeTy).end(); 431 | TI != TE; ++TI) 432 | { 433 | for (unsigned i = 0; i < TI.number_of_children(); i++) 434 | { 435 | InstructionWrapper *childW = *argW->getTree(treeTy).child(TI, i); 436 | PDG->addDependency(*TI, childW, DependencyType::PARAMETER); 437 | } 438 | } 439 | } 440 | } 441 | 442 | void pdg::ProgramDependencyGraph::connectFunctionAndFormalTrees(Function *callee) 443 | { 444 | auto &pdgUtils = PDGUtils::getInstance(); 445 | for (std::vector::iterator argI = pdgUtils.getFuncMap()[callee]->getArgWList().begin(), 446 | argE = pdgUtils.getFuncMap()[callee]->getArgWList().end(); 447 | argI != argE; ++argI) 448 | { 449 | auto formalInTreeBeginI = (*argI)->tree_begin(TreeType::FORMAL_IN_TREE); 450 | auto formalInTreeEndI = (*argI)->tree_end(TreeType::FORMAL_IN_TREE); 451 | auto formalOutTreeBeginI = (*argI)->tree_begin(TreeType::FORMAL_OUT_TREE); 452 | InstructionWrapper *formal_inW = *formalInTreeBeginI; 453 | InstructionWrapper *formal_outW = *formalOutTreeBeginI; 454 | 455 | // connect Function's EntryNode with formal in/out tree roots 456 | PDG->addDependency(pdgUtils.getFuncMap()[callee]->getEntryW(), formal_inW, DependencyType::PARAMETER); 457 | PDG->addDependency(pdgUtils.getFuncMap()[callee]->getEntryW(), formal_outW, DependencyType::PARAMETER); 458 | 459 | // two things: (1) formal-in --> callee's Store; (2) callee's Load --> formal-out 460 | for (tree::iterator 461 | formal_in_TI = formalInTreeBeginI, 462 | formal_in_TE = formalInTreeEndI, 463 | formal_out_TI = formalOutTreeBeginI; 464 | formal_in_TI != formal_in_TE; ++formal_in_TI, ++formal_out_TI) 465 | { 466 | // connect formal-in and formal-out nodes formal-in --> formal-out 467 | PDG->addDependency(*formal_in_TI, *formal_out_TI, DependencyType::PARAMETER); 468 | 469 | // must handle nullptr case first 470 | if ((*formal_in_TI)->getTreeNodeType() == nullptr) 471 | { 472 | errs() << "connectFunctionAndFormalTrees: formal_in_TI->getFieldType() == nullptr !\n"; 473 | break; 474 | } 475 | // connect formal-in-tree type nodes with storeinst in call_func 476 | if (tree::depth(formal_in_TI) == 0) 477 | { 478 | for (auto userIter = (*argI)->getArg()->user_begin(); 479 | userIter != (*argI)->getArg()->user_end(); ++userIter) 480 | { 481 | if (Instruction *tmpInst = dyn_cast(*userIter)) 482 | { 483 | PDG->addDependency(*formal_in_TI, pdgUtils.getInstMap()[tmpInst], DependencyType::DATA_GENERAL); 484 | (*formal_in_TI)->setVisited(true); 485 | } 486 | } 487 | } 488 | 489 | // 2. Callee's LoadInsts --> FORMAL_OUT in Callee function 490 | // must handle nullptr case first 491 | if ((*formal_out_TI)->getTreeNodeType() == nullptr) 492 | { 493 | errs() << "connectFunctionAndFormalTrees: LoadInst->FORMAL_OUT: " 494 | "formal_out_TI->getFieldType() == nullptr!\n"; 495 | break; 496 | } 497 | 498 | if ((*formal_out_TI)->getTreeNodeType() != nullptr) 499 | { 500 | for (LoadInst *loadInst : pdgUtils.getFuncMap()[callee]->getLoadInstList()) 501 | { 502 | if ((*formal_out_TI)->getTreeNodeType() == loadInst->getPointerOperand()->getType()->getContainedType(0)) 503 | { 504 | PDG->addDependency(pdgUtils.getInstMap()[loadInst], 505 | *formal_out_TI, 506 | DependencyType::DATA_GENERAL); 507 | } 508 | } 509 | } 510 | } 511 | } 512 | } 513 | 514 | bool pdg::ProgramDependencyGraph::connectAllPossibleFunctions(CallInst *CI, std::vector indirect_call_candidates) 515 | { 516 | auto &pdgUtils = PDGUtils::getInstance(); 517 | InstructionWrapper *CInstW = pdgUtils.getInstMap()[CI]; 518 | for (Function *func : indirect_call_candidates) 519 | { 520 | if (func->isDeclaration() || func->empty()) 521 | continue; 522 | if (!connectCallerAndCallee(CInstW, func)) 523 | return false; 524 | } 525 | return true; 526 | } 527 | 528 | bool pdg::ProgramDependencyGraph::connectCallerAndCallee(InstructionWrapper *callInstW, Function *callee) 529 | { 530 | auto &pdgUtils = PDGUtils::getInstance(); 531 | if (callInstW == nullptr || callInstW == nullptr) 532 | return false; 533 | 534 | // callInst in caller --> Entry Node in callee 535 | PDG->addDependency(callInstW, pdgUtils.getFuncMap()[callee]->getEntryW(), DependencyType::CONTROL); 536 | Function *caller = callInstW->getInstruction()->getFunction(); 537 | // ReturnInst in callee --> CallInst in caller 538 | for (Instruction *retInst : pdgUtils.getFuncMap()[callee]->getReturnInstList()) 539 | { 540 | for (InstructionWrapper *tmpInstW : pdgUtils.getFuncInstWMap()[caller]) 541 | { 542 | if (retInst == tmpInstW->getInstruction()) 543 | { 544 | if (dyn_cast(tmpInstW->getInstruction())->getReturnValue() != nullptr) 545 | PDG->addDependency(tmpInstW, callInstW, DependencyType::DATA_GENERAL); 546 | else 547 | errs() << "void ReturnInst: " << *tmpInstW->getInstruction(); 548 | } 549 | } 550 | } 551 | 552 | // connect caller InstW with ACTUAL IN/OUT parameter trees 553 | CallInst *CI = dyn_cast(callInstW->getInstruction()); 554 | connectActualTrees(callInstW); 555 | // old way, process four trees at the same time, remove soon 556 | std::vector::iterator func_argI = pdgUtils.getFuncMap()[callee]->getArgWList().begin(); 557 | std::vector::iterator callInst_argI = pdgUtils.getCallMap()[CI]->getArgWList().begin(); 558 | std::vector::iterator func_argE = pdgUtils.getFuncMap()[callee]->getArgWList().end(); 559 | 560 | for (; func_argI != func_argE; ++func_argI, ++callInst_argI) 561 | { 562 | // intra-connection between ACTUAL/FORMAL IN/OUT trees 563 | // connect trees: antual-in --> formal-in, formal-out --> actual-out 564 | connectInOutTrees(*callInst_argI, *func_argI); 565 | 566 | // 3. ACTUAL_OUT --> LoadInsts in #Caller# function 567 | for (tree::iterator 568 | actual_out_TI = (*callInst_argI)->getTree(TreeType::ACTUAL_OUT_TREE).begin(), 569 | actual_out_TE = (*callInst_argI)->getTree(TreeType::ACTUAL_OUT_TREE).end(); 570 | actual_out_TI != actual_out_TE; ++actual_out_TI) 571 | { 572 | // must handle nullptr case first 573 | if ((*actual_out_TI)->getTreeNodeType() == nullptr) 574 | { 575 | throw new TreeNodeTypeIsNull("TreeNode Type is Null"); 576 | } 577 | 578 | for (LoadInst *loadInst : pdgUtils.getFuncMap()[callInstW->getFunction()]->getLoadInstList()) 579 | { 580 | if ((*actual_out_TI)->getTreeNodeType() != loadInst->getType()) 581 | continue; 582 | 583 | for (InstructionWrapper *tmpInstW : pdgUtils.getFuncInstWMap()[callee]) 584 | { 585 | if (tmpInstW->getInstruction() == dyn_cast(loadInst)) 586 | PDG->addDependency(*actual_out_TI, tmpInstW, DependencyType::DATA_GENERAL); 587 | } 588 | } 589 | } 590 | } 591 | 592 | // add return edge from the return instruction to the call instruction of caller. 593 | auto retInstList = pdgUtils.getFuncMap()[callee]->getReturnInstList(); 594 | for (ReturnInst* retInst : retInstList) 595 | { 596 | auto retW = pdgUtils.getInstMap()[retInst]; 597 | PDG->addDependency(retW, callInstW, DependencyType::DATA_GENERAL); 598 | } 599 | 600 | return true; 601 | } 602 | 603 | void pdg::ProgramDependencyGraph::connectActualTrees(InstructionWrapper *callInstW) 604 | { 605 | auto &pdgUtils = PDGUtils::getInstance(); 606 | CallInst *CI = dyn_cast(callInstW->getInstruction()); 607 | for (ArgumentWrapper *argW : pdgUtils.getCallMap()[CI]->getArgWList()) 608 | { 609 | InstructionWrapper *actual_inW = *(argW->tree_begin(TreeType::ACTUAL_IN_TREE)); 610 | InstructionWrapper *actual_outW = *(argW->tree_begin(TreeType::ACTUAL_OUT_TREE)); 611 | 612 | if (callInstW == actual_inW || callInstW == actual_outW) 613 | continue; 614 | 615 | PDG->addDependency(callInstW, actual_inW, DependencyType::PARAMETER); 616 | PDG->addDependency(callInstW, actual_outW, DependencyType::PARAMETER); 617 | } 618 | } 619 | 620 | void pdg::ProgramDependencyGraph::connectInOutTrees(ArgumentWrapper *CIArgW, ArgumentWrapper *funcArgW) 621 | { 622 | auto &pdgUtils = PDGUtils::getInstance(); 623 | auto CIInTI = CIArgW->tree_begin(TreeType::ACTUAL_IN_TREE); 624 | auto funcInTI = funcArgW->tree_begin(TreeType::FORMAL_IN_TREE); 625 | auto funcOutTI = funcArgW->tree_begin(TreeType::FORMAL_OUT_TREE); 626 | auto CIOutTI = CIArgW->tree_begin(TreeType::ACTUAL_OUT_TREE); 627 | 628 | for (;CIInTI != CIArgW->tree_end(TreeType::ACTUAL_IN_TREE); 629 | CIInTI++, funcInTI++, funcOutTI++, CIOutTI++) 630 | { 631 | PDG->addDependency(*CIInTI, *funcInTI, DependencyType::PARAMETER); 632 | PDG->addDependency(*funcOutTI, *CIOutTI, DependencyType::PARAMETER); 633 | } 634 | } 635 | 636 | void pdg::ProgramDependencyGraph::buildActualParameterTrees(CallInst *CI) 637 | { 638 | auto &pdgUtils = PDGUtils::getInstance(); 639 | // need to obtained called function and then copy the formal tree 640 | Function *called_func; 641 | // processing indirect call. Pick the first candidate function 642 | if (CI->getCalledFunction() == nullptr) 643 | { 644 | std::vector indirect_call_candidate = collectIndirectCallCandidates(CI->getFunctionType()); 645 | if (indirect_call_candidate.size() == 0) 646 | { 647 | errs() << "Parameter num 0, no need to build actual parameter tree" 648 | << "\n"; 649 | return; 650 | } 651 | // get the first possible candidate 652 | called_func = indirect_call_candidate[0]; 653 | } 654 | else 655 | { 656 | called_func = CI->getCalledFunction(); 657 | } 658 | 659 | auto argI = pdgUtils.getCallMap()[CI]->getArgWList().begin(); 660 | auto argE = pdgUtils.getCallMap()[CI]->getArgWList().end(); 661 | 662 | auto argFI = pdgUtils.getFuncMap()[called_func]->getArgWList().begin(); 663 | auto argFE = pdgUtils.getFuncMap()[called_func]->getArgWList().end(); 664 | 665 | //copy Formal Tree to Actual Tree. Actual trees are used by call site. 666 | for (; argI != argE && argFI != argFE; ++argI, ++argFI) 667 | { 668 | (*argI)->copyTree((*argFI)->getTree(TreeType::FORMAL_IN_TREE), TreeType::ACTUAL_IN_TREE); 669 | (*argI)->copyTree((*argFI)->getTree(TreeType::FORMAL_IN_TREE), TreeType::ACTUAL_OUT_TREE); 670 | } 671 | } 672 | 673 | void pdg::ProgramDependencyGraph::drawActualParameterTree(CallInst *CI, pdg::TreeType treeTy) 674 | { 675 | auto &pdgUtils = PDGUtils::getInstance(); 676 | int ARG_POS = 0; 677 | for (std::vector::iterator argWI = pdgUtils.getCallMap()[CI]->getArgWList().begin(); 678 | argWI != pdgUtils.getCallMap()[CI]->getArgWList().end(); 679 | ++argWI) 680 | { 681 | Value *tmp_val = CI->getOperand(ARG_POS); // get the corresponding argument 682 | if (Instruction *tmpInst = dyn_cast(tmp_val)) 683 | { 684 | Function *func = (*argWI)->getArg()->getParent(); 685 | auto treeBegin = (*argWI)->getTree(TreeType::ACTUAL_IN_TREE).begin(); 686 | // link each argument's instruction with actual tree head 687 | PDG->addDependency(pdgUtils.getInstMap()[tmpInst], *treeBegin, DependencyType::PARAMETER); 688 | } 689 | for (tree::iterator TI = (*argWI)->getTree(treeTy).begin(); 690 | TI != (*argWI)->getTree(treeTy).end(); 691 | ++TI) 692 | { 693 | for (unsigned i = 0; i < TI.number_of_children(); i++) 694 | { 695 | InstructionWrapper *childW = *(*argWI)->getTree(treeTy).child(TI, i); 696 | PDG->addDependency(*TI, childW, DependencyType::PARAMETER); 697 | } 698 | } 699 | 700 | ARG_POS++; 701 | } 702 | } 703 | 704 | std::vector pdg::ProgramDependencyGraph::collectIndirectCallCandidates(FunctionType *funcType) 705 | { 706 | auto &pdgUtils = PDGUtils::getInstance(); 707 | std::vector indirectCallList; 708 | std::map::iterator FI = pdgUtils.getFuncMap().begin(); 709 | std::map::iterator FE = pdgUtils.getFuncMap().end(); 710 | for (; FI != FE; ++FI) 711 | { 712 | Function *curFunc = const_cast((*FI).first); 713 | // get Function type 714 | if (curFunc->getName() == "main") 715 | continue; 716 | // compare the indirect call function type with each function 717 | if (isFuncTypeMatch(funcType, curFunc->getFunctionType())) 718 | indirectCallList.push_back(curFunc); 719 | } 720 | 721 | return indirectCallList; 722 | } 723 | 724 | // ------------------------------- 725 | // 726 | // Field sensitive functions 727 | // 728 | // ------------------------------- 729 | 730 | std::set pdg::ProgramDependencyGraph::getAllRelevantGEP(Argument &arg) 731 | { 732 | std::vector initialStoreInsts = getArgStoreInsts(arg); 733 | std::set relevantGEPs; 734 | std::queue instWQ; 735 | auto &pdgUtils = PDGUtils::getInstance(); 736 | 737 | //errs() << depInstW->getInstruction()->getFunction()->getName() << " " << *depInstW->getInstruction() << "\n"; 738 | for (Instruction *storeInst : initialStoreInsts) 739 | { 740 | instWQ.push(pdgUtils.getInstMap()[storeInst]); // push the initial store instruction to the instQ 741 | auto dataDList = PDG->getNodeDepList(pdgUtils.getInstMap()[storeInst]); 742 | for (auto depPair : dataDList) 743 | { 744 | DependencyType depType = depPair.second; 745 | if (depType == DependencyType::DATA_ALIAS) 746 | { 747 | InstructionWrapper *depInstW = const_cast(depPair.first->getData()); 748 | instWQ.push(depInstW); 749 | } 750 | } 751 | } 752 | 753 | while (!instWQ.empty()) 754 | { 755 | InstructionWrapper *instW = instWQ.front(); 756 | instWQ.pop(); 757 | 758 | auto dataDList = PDG->getNodeDepList(instW); 759 | for (auto depPair : dataDList) 760 | { 761 | DependencyType depType = depPair.second; 762 | if (depType == DependencyType::DATA_DEF_USE) 763 | { 764 | InstructionWrapper *depInstW = const_cast(depPair.first->getData()); 765 | instWQ.push(depInstW); 766 | if (depInstW->getInstruction() != nullptr && isa(depInstW->getInstruction())) 767 | relevantGEPs.insert(depInstW); 768 | } 769 | } 770 | } 771 | 772 | return relevantGEPs; 773 | } 774 | 775 | InstructionWrapper *pdg::ProgramDependencyGraph::getTreeNodeGEP(Argument &arg, unsigned field_offset, Type *treeNodeTy, Type *parentNodeTy) 776 | { 777 | std::set RelevantGEPList = getAllRelevantGEP(arg); 778 | for (auto GEPInstW : RelevantGEPList) 779 | { 780 | int operand_num = GEPInstW->getInstruction()->getNumOperands(); 781 | llvm::Value *last_idx = GEPInstW->getInstruction()->getOperand(operand_num - 1); 782 | // cast the last_idx to int type 783 | if (llvm::ConstantInt *constInt = dyn_cast(last_idx)) 784 | { 785 | // make sure type is matched 786 | if (!isa(GEPInstW->getInstruction()) || parentNodeTy == nullptr) 787 | continue; 788 | auto GEP = dyn_cast(GEPInstW->getInstruction()); 789 | llvm::Type *GEPResTy = GEP->getResultElementType(); 790 | llvm::Type *GEPSrcTy = GEP->getSourceElementType(); 791 | 792 | // get access field idx from GEP 793 | int field_idx = constInt->getSExtValue(); 794 | // plus one. Since for struct, the 0 index is used by the parent struct 795 | // type parent_type must be a pointer. Since only sub fields can have 796 | // parent that is not nullptr 797 | if (parentNodeTy->isPointerTy()) 798 | parentNodeTy = parentNodeTy->getPointerElementType(); 799 | 800 | // check the src type in GEP inst is equal to parent_type (GET FROM) 801 | // check if the offset is equal 802 | bool srcTypeMatch = (GEPSrcTy == parentNodeTy); 803 | bool resTypeMatch = (GEPResTy == treeNodeTy); 804 | bool offsetMatch = field_idx == field_offset; 805 | 806 | if (offsetMatch && resTypeMatch && srcTypeMatch) 807 | return GEPInstW; 808 | } 809 | } 810 | 811 | return nullptr; 812 | } 813 | 814 | std::vector pdg::ProgramDependencyGraph::getArgStoreInsts(Argument &arg) 815 | { 816 | std::vector initialStoreInsts; 817 | for (auto UI = arg.user_begin(); UI != arg.user_end(); ++UI) 818 | { 819 | if (isa(*UI)) 820 | { 821 | Instruction *st = dyn_cast(*UI); 822 | initialStoreInsts.push_back(st); 823 | } 824 | } 825 | 826 | return initialStoreInsts; 827 | } 828 | 829 | bool pdg::ProgramDependencyGraph::isFuncTypeMatch(FunctionType *funcTy1, FunctionType *funcTy2) 830 | { 831 | if (funcTy1->getNumParams() != funcTy2->getNumParams()) 832 | { 833 | return false; 834 | } 835 | 836 | if (funcTy1->getReturnType() != funcTy2->getReturnType()) 837 | { 838 | return false; 839 | } 840 | 841 | unsigned param_len = funcTy1->getNumParams(); 842 | for (unsigned i = 0; i < param_len; ++i) 843 | { 844 | if (funcTy1->getParamType(i) != funcTy2->getParamType(i)) 845 | { 846 | return false; 847 | } 848 | } 849 | return true; 850 | } 851 | 852 | tree::iterator pdg::ProgramDependencyGraph::getInstInsertLoc(pdg::ArgumentWrapper *argW, InstructionWrapper *tyW, TreeType treeTy) 853 | { 854 | tree::iterator insert_loc = argW->getTree(treeTy).begin(); 855 | while ((*insert_loc) != tyW && insert_loc != argW->getTree(treeTy).end()) 856 | { 857 | insert_loc++; 858 | } 859 | return insert_loc; 860 | } 861 | 862 | typename pdg::DependencyNode::DependencyLinkList pdg::ProgramDependencyGraph::getNodeDepList(Instruction *inst) 863 | { 864 | return PDG->getNodeDepList(PDGUtils::getInstance().getInstMap()[inst]); 865 | } 866 | 867 | static RegisterPass 868 | PDG("pdg", "Program Dependency Graph Construction", false, true); --------------------------------------------------------------------------------