├── .gitignore ├── clang-cfg ├── CMakeLists.txt └── pybind │ ├── data_struct │ ├── CMakeLists.txt │ ├── Block.cpp │ ├── CFG.cpp │ ├── Block.h │ ├── CFG.h │ ├── AST.h │ └── AST.cpp │ ├── ast │ ├── CMakeLists.txt │ ├── ASTList.h │ ├── ASTConsumerForAST.h │ ├── ASTFrontendActionAST.h │ ├── global.h │ ├── ASTVisitorForAST.h │ └── ASTVisitorForAST.cpp │ ├── extend_cfg │ ├── CMakeLists.txt │ ├── CFGList.h │ ├── global.h │ ├── CFGFrontendAction.h │ ├── ASTConsumerForCFG.h │ ├── FunctionCFG.h │ ├── ASTVisitorForCFG.h │ ├── ASTVisitorForCFG.cpp │ └── FunctionCFG.cpp │ ├── CMakeLists.txt │ ├── ParseHelper.h │ ├── pybind.cpp │ └── ParseHelper.cpp ├── .idea ├── clang-cfg.iml ├── vcs.xml ├── misc.xml ├── modules.xml └── workspace.xml ├── cmake └── external │ ├── python.cmake │ ├── pybind11.cmake │ └── llvm.cmake ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | build 3 | -------------------------------------------------------------------------------- /clang-cfg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(pybind) 2 | -------------------------------------------------------------------------------- /.idea/clang-cfg.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | ADD_LIBRARY(AST SHARED AST.h AST.cpp) 3 | ADD_LIBRARY(BLOCK SHARED Block.h Block.cpp) 4 | ADD_LIBRARY(CFG SHARED CFG.h CFG.cpp) 5 | 6 | ADD_DEPENDENCIES(CFG AST BLOCK) 7 | TARGET_LINK_LIBRARIES(CFG AST BLOCK) -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | ADD_LIBRARY(ast ASTFrontendActionAST.h ASTVisitorForAST.h ASTVisitorForAST.cpp ASTConsumerForAST.h ASTList.h global.h) 3 | 4 | TARGET_LINK_LIBRARIES(ast AST) 5 | SET_TARGET_PROPERTIES(ast PROPERTIES CXX_VISIBILITY_PRESET hidden) 6 | -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/Block.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-25. 3 | // 4 | 5 | #include "Block.h" 6 | 7 | 8 | namespace clang_cfg { 9 | void Block::add_ast(clang_cfg::AST ast) { 10 | this->content.push_back(ast); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_LIBRARY(extend_cfg global.h CFGFrontendAction.h ASTConsumerForCFG.h ASTVisitorForCFG.h ASTVisitorForCFG.cpp CFGList.h FunctionCFG.cpp FunctionCFG.h) 2 | TARGET_LINK_LIBRARIES(extend_cfg) 3 | SET_TARGET_PROPERTIES(extend_cfg PROPERTIES CXX_VISIBILITY_PRESET hidden) 4 | -------------------------------------------------------------------------------- /cmake/external/python.cmake: -------------------------------------------------------------------------------- 1 | 2 | MESSAGE(STATUS "PY_VERSION = ${PY_VERSION}") 3 | FIND_PACKAGE(PythonInterp ${PY_VERSION} REQUIRED) 4 | FIND_PACKAGE(PythonLibs ${PY_VERSION} REQUIRED) 5 | 6 | ADD_LIBRARY(python STATIC IMPORTED GLOBAL) 7 | SET_PROPERTY(TARGET python PROPERTY IMPORTED_LOCATION ${PYTHON_LIBRARIES}) 8 | 9 | INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIR}) 10 | 11 | 12 | -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/CFG.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-25. 3 | // 4 | 5 | #include "CFG.h" 6 | 7 | namespace clang_cfg { 8 | 9 | void CFG::add_block(clang_cfg::Block block) { 10 | this->block_list.push_back(block); 11 | } 12 | 13 | void CFG::add_edge(int u, int v, int type) { 14 | this->edges.push_back(std::make_pair(std::make_pair(u, v), type)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/ASTList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019/11/15. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "global.h" 8 | #include "data_struct/AST.h" 9 | 10 | namespace clang_cfg{ 11 | class ASTList { 12 | public: 13 | static ASTList& getInst() { 14 | static ASTList inst; 15 | return inst; 16 | } 17 | vector vecs; 18 | private: 19 | ASTList() = default; 20 | }; 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/CFGList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "global.h" 8 | #include "data_struct/CFG.h" 9 | 10 | namespace clang_cfg{ 11 | class CFGList { 12 | public: 13 | static CFGList& getInst() { 14 | static CFGList inst; 15 | return inst; 16 | } 17 | vector> vecs; 18 | private: 19 | CFGList() = default; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /cmake/external/pybind11.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(ExternalProject) 2 | 3 | SET(PYBIND_SOURCE_DIR ${THIRD_PARTY_PATH}/pybind11) 4 | INCLUDE_DIRECTORIES(${PYBIND_SOURCE_DIR}/build/include) 5 | 6 | ExternalProject_Add( 7 | extern_pybind 8 | GIT_REPOSITORY "https://github.com/pybind/pybind11.git" 9 | GIT_TAG "v2.2.4" 10 | PREFIX ${PYBIND_SOURCE_DIR} 11 | CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PYBIND_SOURCE_DIR}/build 12 | ) 13 | 14 | ADD_LIBRARY(pybind INTERFACE) 15 | ADD_DEPENDENCIES(pybind extern_pybind) -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/Block.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-25. 3 | // 4 | #pragma once 5 | 6 | #ifndef CLANG_CFG_BLOCK_H 7 | #define CLANG_CFG_BLOCK_H 8 | 9 | #include 10 | #include 11 | 12 | #include "AST.h" 13 | 14 | using std::vector; 15 | 16 | namespace clang_cfg{ 17 | class Block { 18 | public: 19 | int start_lineno, end_lineno; 20 | void add_ast(AST ast); 21 | vector content; 22 | }; 23 | 24 | } 25 | 26 | 27 | #endif //CLANG_CFG_BLOCK_H 28 | -------------------------------------------------------------------------------- /clang-cfg/pybind/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_SUBDIRECTORY(extend_cfg) 2 | ADD_SUBDIRECTORY(ast) 3 | ADD_SUBDIRECTORY(data_struct) 4 | 5 | ADD_LIBRARY(ParseHelper ParseHelper.cpp ParseHelper.h) 6 | 7 | PYTHON_ADD_MODULE(clang_cfg pybind.cpp) 8 | 9 | TARGET_LINK_LIBRARIES(clang_cfg extend_cfg ast CFG ParseHelper) 10 | 11 | TARGET_LINK_LIBRARIES(clang_cfg ${CLANG_LIBS} ${LLVM_LIBS}) 12 | 13 | IF(APPLE) 14 | LIST(APPEND SYSTEM_LIBS pthread dl z curses m xml2) 15 | ELSEIF(UNIX) 16 | LIST(APPEND SYSTEM_LIBS pthread dl tinfo z) 17 | ENDIF() 18 | 19 | TARGET_LINK_LIBRARIES(clang_cfg ${SYSTEM_LIBS}) 20 | SET_TARGET_PROPERTIES(clang_cfg PROPERTIES CXX_VISIBILITY_PRESET hidden) 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/ASTConsumerForAST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019/11/15. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "global.h" 8 | #include "ASTVisitorForAST.h" 9 | #include "ASTList.h" 10 | 11 | #include 12 | 13 | namespace clang_cfg{ 14 | 15 | using std::vector; 16 | class ASTConsumerForAST : public ASTConsumer { 17 | public: 18 | ASTConsumerForAST(ASTContext& ctx, Rewriter& rewriter) : visitor(ctx, rewriter) {} 19 | 20 | void HandleTranslationUnit(ASTContext& context) override { 21 | visitor.TraverseDecl(context.getTranslationUnitDecl()); 22 | } 23 | 24 | private: 25 | ASTVisitorForAST visitor; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/CFG.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-25. 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef CLANG_CFG_CFG_H 8 | #define CLANG_CFG_CFG_H 9 | 10 | #include 11 | #include 12 | 13 | #include "Block.h" 14 | #include "AST.h" 15 | 16 | 17 | namespace clang_cfg { 18 | using std::vector; 19 | using std::pair; 20 | using std::string; 21 | 22 | class CFG{ 23 | public: 24 | void add_block(Block block); 25 | void add_edge(int u, int v, int type); 26 | vector,int>> edges; 27 | vector block_list; 28 | vector call_list; 29 | string func_name; 30 | }; 31 | } 32 | 33 | #endif //CLANG_CFG_CFG_H 34 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/ASTFrontendActionAST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019/11/14. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "global.h" 8 | #include "ASTConsumerForAST.h" 9 | 10 | #include 11 | 12 | namespace clang_cfg 13 | { 14 | using std::vector; 15 | class ASTFrontendActionAST : public ASTFrontendAction { 16 | public: 17 | std::unique_ptr CreateASTConsumer(CompilerInstance& CI, StringRef file) override { 18 | rewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); 19 | return std::make_unique(CI.getASTContext(), rewriter); 20 | } 21 | private: 22 | Rewriter rewriter; 23 | 24 | }; 25 | } 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/global.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Created by zzhzz on 2019-09-26. 4 | // 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "data_struct/AST.h" 23 | 24 | namespace clang_cfg { 25 | using namespace clang; 26 | using namespace clang::driver; 27 | using namespace clang::tooling; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/global.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ParseHelper.h" 23 | #include "data_struct/CFG.h" 24 | 25 | namespace clang_cfg { 26 | using namespace clang; 27 | using namespace clang::driver; 28 | using namespace clang::tooling; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/ASTVisitorForAST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019/11/14. 3 | // 4 | 5 | #ifndef CLANG_CFG_ASTVISITORFORAST_H 6 | #define CLANG_CFG_ASTVISITORFORAST_H 7 | 8 | #include "global.h" 9 | #include "ASTList.h" 10 | 11 | #include 12 | 13 | namespace clang_cfg{ 14 | using std::vector; 15 | using namespace clang; 16 | using namespace clang::tooling; 17 | 18 | class ASTVisitorForAST : public RecursiveASTVisitor { 19 | public: 20 | ASTVisitorForAST(ASTContext& ctx, Rewriter& rewriter) : 21 | context(ctx), rewriter(rewriter) { }; 22 | 23 | bool VisitTranslationUnitDecl(TranslationUnitDecl* decl); 24 | 25 | private: 26 | ASTContext& context; 27 | Rewriter& rewriter; 28 | }; 29 | } 30 | 31 | #endif //CLANG_CFG_ASTVISITORFORAST_H 32 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/CFGFrontendAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | #pragma once 5 | 6 | #ifndef CLANG_CFG_CFGFRONTENDACTION_H 7 | #define CLANG_CFG_CFGFRONTENDACTION_H 8 | 9 | #include "global.h" 10 | #include "ASTConsumerForCFG.h" 11 | 12 | #include 13 | 14 | namespace clang_cfg 15 | { 16 | using std::vector; 17 | class CFGFrontendAction : public ASTFrontendAction{ 18 | public: 19 | std::unique_ptr CreateASTConsumer(CompilerInstance& CI, StringRef file) override { 20 | rewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); 21 | return std::make_unique(CI.getASTContext(), rewriter); 22 | } 23 | private: 24 | Rewriter rewriter; 25 | 26 | }; 27 | } 28 | 29 | 30 | 31 | #endif //CLANG_CFG_CFGFRONTENDACTION_H 32 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.6) 2 | PROJECT(Clang-CFG) 3 | SET(CMAKE_C_COMPILER gcc) 4 | SET(CMAKE_CXX_COMPILER g++) 5 | SET(CMAKE_CXX_STANDARD 14) 6 | 7 | SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 8 | SET(THIRD_PARTY_PATH "${CMAKE_BINARY_DIR}/third_party" CACHE STRING 9 | "A path setting third party libraries download & build directories") 10 | 11 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti -fPIC") 12 | 13 | OPTION(PY_VERSION "Specify python version" ${PY_VERSION}) 14 | 15 | IF(NOT PY_VERSION) 16 | SET(PY_VERSION 3.6) 17 | ENDIF() 18 | 19 | SET(THIRD_PARTY_BUILD_TYPE Release) 20 | 21 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/clang-cfg/pybind) 22 | 23 | INCLUDE(external/python) 24 | INCLUDE(external/pybind11) 25 | INCLUDE(external/llvm) 26 | 27 | LINK_LIBRARIES(${PYTHON_LIBRARIES} ${CLANG_LIBS} ${LLVM_LIBS}) 28 | 29 | ADD_SUBDIRECTORY(clang-cfg) 30 | 31 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/ASTConsumerForCFG.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | #pragma once 5 | 6 | #ifndef CLANG_CFG_ASTCONSUMERFORCFG_H 7 | #define CLANG_CFG_ASTCONSUMERFORCFG_H 8 | 9 | #include "global.h" 10 | #include "ASTVisitorForCFG.h" 11 | #include "CFGList.h" 12 | 13 | #include 14 | 15 | namespace clang_cfg{ 16 | 17 | using std::vector; 18 | class ASTConsumerForCFG : public ASTConsumer { 19 | public: 20 | ASTConsumerForCFG(ASTContext& ctx, Rewriter& rewriter) : visitor(ctx, rewriter) {} 21 | 22 | void HandleTranslationUnit(ASTContext& context) override { 23 | CFGList& list = CFGList::getInst(); 24 | list.vecs.emplace_back(vector()); 25 | visitor.TraverseDecl(context.getTranslationUnitDecl()); 26 | } 27 | 28 | private: 29 | ASTVisitorForCFG visitor; 30 | }; 31 | } 32 | 33 | #endif //CLANG_CFG_ASTCONSUMERFORCFG_H 34 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ParseHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef CLANG_CFG_PARSEHELPER_H 8 | #define CLANG_CFG_PARSEHELPER_H 9 | 10 | 11 | #include 12 | #include 13 | 14 | #include "data_struct/AST.h" 15 | #include "extend_cfg/global.h" 16 | 17 | namespace clang_cfg { 18 | using namespace clang; 19 | using namespace clang::tooling; 20 | using std::string; 21 | using std::set; 22 | class ParseHelper { 23 | public: 24 | static bool isInSystem(ASTContext& context, const FunctionDecl* decl); 25 | static bool canIncludeInGraph(Decl* decl); 26 | static bool canBeCallerInGraph(Decl* decl); 27 | static string getVarName(const Expr* expr); 28 | static Decl* getDeclFromCall(CallExpr* callExpr); 29 | static void type_simplify(AST& ast, int uid, string &type); 30 | }; 31 | } 32 | 33 | 34 | #endif //CLANG_CFG_PARSEHELPER_H 35 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/FunctionCFG.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | #pragma once 5 | 6 | #ifndef CLANG_CFG_FUNCTIONCFG_H 7 | #define CLANG_CFG_FUNCTIONCFG_H 8 | 9 | #include "global.h" 10 | #include "CFGList.h" 11 | 12 | namespace clang_cfg { 13 | using namespace clang; 14 | using namespace llvm; 15 | using std::string; 16 | 17 | class FunctionCFG { 18 | public: 19 | typedef FunctionCFG* FunctionRecord; 20 | FunctionCFG(Decl* d) : decl(d) {} 21 | string getNameAsString() const; 22 | 23 | void addFunction(FunctionRecord record) { 24 | if(std::find(functions.begin(), functions.end(), record) != functions.end()) return; 25 | functions.push_back(record); 26 | } 27 | void getCFG(ASTContext& ctx); 28 | AST transToAST(Stmt* stmt, ASTContext& ctx); 29 | private: 30 | Decl* decl; 31 | SmallVector functions; 32 | }; 33 | } 34 | 35 | 36 | #endif //CLANG_CFG_FUNCTIONCFG_H 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clang-CFG: A tool based on Clang LibTooling 2 | 3 | ## Introduction 4 | The tool is based on clang libtooling technology, used to generate control-flow-graph for C/C++ code. 5 | 6 | The tool is a static python library, which could be invoke directly in python. 7 | 8 | 9 | ## Usage 10 | 11 | * Firstly, download the repository 12 | * use `cd clang-cfg` change into the directory 13 | * use `mkdir build` create a directory for binary files 14 | * use `cd build` change into the binary directory 15 | * use `cmake ..` to create MakeFiles 16 | * use `make` to build the project 17 | 18 | For an alpha version, I haven't provide python wrapper for the project and shoud be import directly 19 | 20 | * run `cd build/clang-cfg/pybind` change into the directory of static library 21 | * run `python -c "import clang_cfg" to test 22 | 23 | ## Tips 24 | 25 | * This project based on llvm, it will take long time to download and build llvm as a third party project 26 | * This project based on pybind11, which needs to open `-frtti` option of compiler. The default compile option of llvm doesn't open it. -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/AST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-23. 3 | // 4 | 5 | #pragma once 6 | 7 | #ifndef CLANG_CFG_EXTENDAST_H 8 | #define CLANG_CFG_EXTENDAST_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using std::vector; 17 | using std::set; 18 | using std::string; 19 | using std::pair; 20 | using std::map; 21 | 22 | namespace clang_cfg { 23 | class AST { 24 | public: 25 | void add_node(string label); 26 | void add_defination(string name); 27 | void add_usage(string name); 28 | void add_edge(int u, int v); 29 | void add_call(int u, string name); 30 | void modify_node(int node_id, string new_value); 31 | int get_parent(int uid); 32 | int get_next(); 33 | string skipspace(string name); 34 | vector> edges; 35 | vector node_labels; 36 | set define_vars, use_vars; 37 | vector> calls; 38 | map parent; 39 | int n; 40 | }; 41 | 42 | } 43 | 44 | 45 | #endif //CLANG_CFG_EXTENDAST_H 46 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/ASTVisitorForCFG.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | #pragma once 5 | 6 | #ifndef CLANG_CFG_ASTVISITORFORCFG_H 7 | #define CLANG_CFG_ASTVISITORFORCFG_H 8 | 9 | #include "global.h" 10 | #include "CFGList.h" 11 | #include "FunctionCFG.h" 12 | 13 | #include 14 | 15 | namespace clang_cfg{ 16 | using std::vector; 17 | using namespace clang; 18 | using namespace clang::tooling; 19 | 20 | class ASTVisitorForCFG : public RecursiveASTVisitor { 21 | public: 22 | ASTVisitorForCFG(ASTContext& ctx, Rewriter& rewriter) : 23 | context(ctx), rewriter(rewriter) { idx = 0; }; 24 | 25 | void addFunction(Decl* d); 26 | FunctionCFG* getOrInsertFunction(Decl* d); 27 | bool VisitFunctionDecl(FunctionDecl* d); 28 | 29 | private: 30 | ASTContext& context; 31 | Rewriter& rewriter; 32 | typedef llvm::DenseMap> RootsMapType; 33 | RootsMapType Roots; 34 | int idx; 35 | std::map hash; 36 | }; 37 | } 38 | 39 | 40 | #endif //CLANG_CFG_ASTVISITORFORCFG_H 41 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/ASTVisitorForCFG.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | 5 | #include "ASTVisitorForCFG.h" 6 | #include "ParseHelper.h" 7 | 8 | namespace clang_cfg { 9 | using namespace clang; 10 | using namespace clang::tooling; 11 | using namespace llvm; 12 | 13 | void ASTVisitorForCFG::addFunction(Decl *d) { 14 | d = d->getCanonicalDecl(); 15 | FunctionCFG* root = getOrInsertFunction(d); 16 | root->getCFG(this->context); 17 | } 18 | 19 | FunctionCFG* ASTVisitorForCFG::getOrInsertFunction(Decl* d) { 20 | d = d->getCanonicalDecl(); 21 | std::shared_ptr& Node = Roots[d]; 22 | if(!Node){ 23 | Node = std::shared_ptr(new FunctionCFG(d)); 24 | hash[d] = (this->idx)++; 25 | } 26 | return Node.get(); 27 | 28 | } 29 | 30 | bool ASTVisitorForCFG::VisitFunctionDecl(FunctionDecl *d) { 31 | if(d->hasBody()){ 32 | if(ParseHelper::isInSystem(this->context, d)){ 33 | return true; 34 | } 35 | if(ParseHelper::canBeCallerInGraph(d) && d->isThisDeclarationADefinition()){ 36 | this->addFunction(d); 37 | } 38 | } 39 | return true; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /clang-cfg/pybind/data_struct/AST.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-23. 3 | // 4 | 5 | #include "AST.h" 6 | 7 | using std::vector; 8 | using std::string; 9 | 10 | namespace clang_cfg { 11 | using std::move; 12 | 13 | int AST::get_next() { 14 | return (int)node_labels.size(); 15 | } 16 | 17 | string AST::skipspace(string name) { 18 | for(int i = 0; i < name.length(); i++){ 19 | if(name[i] == ' ') name[i] = '_'; 20 | } 21 | return name; 22 | } 23 | 24 | void AST::add_node(string label) { 25 | this->n += 1; 26 | this->node_labels.push_back(skipspace(move(label))); 27 | } 28 | 29 | void AST::add_defination(string name) { 30 | if(name.empty()) return; 31 | this->define_vars.insert(skipspace(move(name))); 32 | } 33 | 34 | void AST::add_usage(string name) { 35 | if(name.empty()) return; 36 | this->use_vars.insert(skipspace(move(name))); 37 | } 38 | 39 | void AST::add_edge(int u, int v) { 40 | this->parent[v] = u; 41 | this->edges.push_back(std::make_pair(u, v)); 42 | } 43 | 44 | void AST::add_call(int u, string name) { 45 | this->calls.push_back(std::make_pair(u, skipspace(move(name)))); 46 | } 47 | 48 | void AST::modify_node(int node_id, string new_value) { 49 | this->node_labels[node_id] = new_value; 50 | } 51 | 52 | int AST::get_parent(int uid) { 53 | return this->parent[uid]; 54 | } 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /cmake/external/llvm.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(ExternalProject) 2 | 3 | 4 | SET(LLVM_SOURCE_DIR ${THIRD_PARTY_PATH}/llvm) 5 | SET(LLVM_PREFIX ${LLVM_SOURCE_DIR}/project) 6 | INCLUDE_DIRECTORIES(${LLVM_PREFIX}/src/extern_llvm/include) 7 | SET(SOURCE_SUBDIR llvm) 8 | 9 | ExternalProject_Add( 10 | extern_llvm 11 | GIT_REPOSITORY "https://github.com/llvm/llvm-project.git" 12 | UPDATE_COMMAND "" 13 | SOURCE_DIR ${LLVM_PREFIX}/src/extern_llvm/llvm 14 | SOURCE_SUBDIR ${SOURCE_SUBDIR} 15 | CMAKE_ARGS -DLLVM_ENABLE_PROJECTS=clang 16 | -DCMAKE_INSTALL_PREFIX=${LLVM_PREFIX}/build 17 | -DLLVM_ENABLE_RTTI=ON 18 | -DLLVM_ENABLE_EH=ON 19 | PREFIX ${LLVM_PREFIX} 20 | INSTALL_DIR ${LLVM_PREFIX}/build 21 | ) 22 | 23 | SET(LLVM_PATH ${LLVM_PREFIX}/build) 24 | LINK_DIRECTORIES(${LLVM_PATH}/lib) 25 | 26 | INCLUDE_DIRECTORIES(${LLVM_PATH}/include) 27 | SET(LLVM_BIN ${LLVM_PATH}/bin) 28 | 29 | LIST(APPEND CLANG_LIBS 30 | clang 31 | clangAST 32 | clangAnalysis 33 | clangBasic 34 | clangDriver 35 | clangEdit 36 | clangIndex 37 | clangFrontend 38 | clangFrontendTool 39 | clangLex 40 | clangParse 41 | clangSema 42 | clangEdit 43 | clangASTMatchers 44 | clangRewrite 45 | clangRewriteFrontend 46 | clangStaticAnalyzerFrontend 47 | clangStaticAnalyzerCheckers 48 | clangStaticAnalyzerCore 49 | clangSerialization 50 | clangToolingCore 51 | clangTooling) 52 | 53 | LIST(APPEND LLVM_LIBS 54 | LLVMSupport 55 | LLVMCore 56 | LLVMAnalysis 57 | LLVMOption 58 | LLVMMCParser 59 | LLVMBitReader 60 | LLVMBitstreamReader 61 | LLVMDemangle 62 | LLVMProfileData 63 | LLVMBinaryFormat 64 | LLVMRemarks 65 | LLVMMC 66 | LLVMX86Info 67 | LLVMX86Utils 68 | LLVMX86Desc) 69 | 70 | -------------------------------------------------------------------------------- /clang-cfg/pybind/pybind.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-23. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "data_struct/AST.h" 21 | #include "data_struct/Block.h" 22 | #include "data_struct/CFG.h" 23 | #include "extend_cfg/CFGList.h" 24 | #include "extend_cfg/CFGFrontendAction.h" 25 | 26 | 27 | #include "ast/ASTFrontendActionAST.h" 28 | #include "ast/ASTList.h" 29 | 30 | namespace clang_cfg{ 31 | 32 | namespace py = pybind11; 33 | 34 | using std::vector; 35 | using string = std::string; 36 | 37 | using namespace clang; 38 | using namespace clang::tooling; 39 | 40 | static void abort_handler(void* arg){ 41 | std::cerr << "clang-cfg: Abort, maybe null pointer exception" << std::endl; 42 | throw std::exception(); 43 | } 44 | 45 | std::unique_ptr getCompilationDataBase(StringRef& config_json) { 46 | string error_str; 47 | std::unique_ptr database = 48 | JSONCompilationDatabase::loadFromBuffer(config_json, error_str, JSONCommandLineSyntax::AutoDetect); 49 | if(database == NULL) { 50 | //throw exception 51 | error_str = "clang-cfg: error in compilation json str"; 52 | std::cerr << error_str << std::endl; 53 | } 54 | return database; 55 | } 56 | 57 | class Parser { 58 | public: 59 | Parser() { 60 | sys::AddSignalHandler(abort_handler, nullptr); 61 | } 62 | vector> parse_to_extendcfg(vector file_names, string compile_args) { 63 | CFGList& list = CFGList::getInst(); 64 | list.vecs.clear(); 65 | StringRef compile_json = StringRef(compile_args); 66 | std::unique_ptr database = getCompilationDataBase(compile_json); 67 | vector vs = (*database).getAllCompileCommands(); 68 | ClangTool tool(*database, ArrayRef(file_names)); 69 | tool.run(newFrontendActionFactory().get()); 70 | list = CFGList::getInst(); 71 | vector> vecs = list.vecs; 72 | return vecs; 73 | } 74 | vector parse_to_ast(vector file_names, string compile_args) { 75 | ASTList& list = ASTList::getInst(); 76 | list.vecs.clear(); 77 | StringRef compile_json = StringRef(compile_args); 78 | std::unique_ptr database = getCompilationDataBase(compile_json); 79 | vector vs = (*database).getAllCompileCommands(); 80 | ClangTool tool(*database, ArrayRef(file_names)); 81 | tool.run(newFrontendActionFactory().get()); 82 | list = ASTList::getInst(); 83 | vector vecs = list.vecs; 84 | return vecs; 85 | } 86 | }; 87 | 88 | PYBIND11_MODULE(clang_cfg, m) { 89 | py::class_(m, "Parser") 90 | .def(py::init<>()) 91 | .def("parse_to_extendcfg", &Parser::parse_to_extendcfg) 92 | .def("parse_to_ast", &Parser::parse_to_ast) 93 | ; 94 | 95 | py::class_(m, "CFG") 96 | .def(py::init<>()) 97 | .def_readwrite("edges", &CFG::edges) 98 | .def_readwrite("block_list", &CFG::block_list) 99 | .def_readwrite("call_list", &CFG::call_list) 100 | .def_readwrite("func_name", &CFG::func_name) 101 | ; 102 | 103 | py::class_(m, "Block") 104 | .def(py::init<>()) 105 | .def_readwrite("content", &Block::content) 106 | .def_readwrite("sline", &Block::start_lineno) 107 | .def_readwrite("eline", &Block::end_lineno) 108 | ; 109 | 110 | py::class_(m, "AST") 111 | .def(py::init<>()) 112 | .def_readwrite("edges", &AST::edges) 113 | .def_readwrite("define_vars", &AST::define_vars) 114 | .def_readwrite("use_vars", &AST::use_vars) 115 | .def_readwrite("node_labels", &AST::node_labels) 116 | .def_readwrite("calls", &AST::calls) 117 | ; 118 | 119 | } 120 | } 121 | 122 | 123 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ParseHelper.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | 5 | #include 6 | 7 | #include "extend_cfg/global.h" 8 | #include "ParseHelper.h" 9 | 10 | namespace clang_cfg{ 11 | using namespace clang; 12 | using namespace llvm; 13 | 14 | bool ParseHelper::isInSystem(ASTContext& context, const FunctionDecl* decl) { 15 | if(decl->isInStdNamespace() || decl->isDependentContext()) { 16 | return true; 17 | } 18 | if(decl->getLocation().isValid()){ 19 | if(context.getSourceManager().isInSystemHeader(decl->getLocation())) { 20 | return true; 21 | } else { 22 | return false; 23 | } 24 | } else { 25 | return true; 26 | } 27 | } 28 | 29 | bool ParseHelper::canIncludeInGraph(Decl* decl) { 30 | if(isa(decl)){ 31 | const FunctionDecl* functionDecl = dyn_cast(decl); 32 | if(functionDecl->isDependentContext()) { 33 | return false; 34 | } 35 | IdentifierInfo* identifierInfo = functionDecl->getIdentifier(); 36 | if(identifierInfo && identifierInfo->getName().startswith("__inline")) { 37 | return false; 38 | } 39 | } 40 | return true; 41 | } 42 | 43 | bool ParseHelper::canBeCallerInGraph(Decl* decl) { 44 | if(!decl->hasBody()) { 45 | return false; 46 | } 47 | return canIncludeInGraph(decl); 48 | } 49 | 50 | string ParseHelper::getVarName(const Expr* expr) { 51 | std::queue q; 52 | q.push(expr); 53 | while(!q.empty()){ 54 | const Expr* t = q.front(); 55 | q.pop(); 56 | if(isa(t)){ 57 | const DeclRefExpr* decl = dyn_cast(t); 58 | return decl->getNameInfo().getAsString(); 59 | } 60 | if(isa(t)){ 61 | const ArraySubscriptExpr* array = dyn_cast(t); 62 | q.push(array->getBase()->IgnoreImpCasts()); 63 | } 64 | if(isa(t)){ 65 | const MemberExpr* mem_expr = dyn_cast(t); 66 | q.push(mem_expr->getBase()->IgnoreImpCasts()); 67 | } 68 | } 69 | return ""; 70 | 71 | } 72 | 73 | Decl* ParseHelper::getDeclFromCall(clang::CallExpr *callExpr) { 74 | FunctionDecl* functionDecl = callExpr->getDirectCallee(); 75 | if(functionDecl){ 76 | return functionDecl; 77 | } 78 | Expr* call_expr = callExpr->getCallee()->IgnoreParenCasts(); 79 | if(isa(call_expr)){ 80 | BlockExpr* blockExpr = dyn_cast(call_expr); 81 | return blockExpr->getBlockDecl(); 82 | } 83 | return nullptr; 84 | } 85 | 86 | void replace_all(string& type, const string& pattern, const string& target) { 87 | int pos = -1; 88 | while((pos = type.find(pattern)) != string::npos){ 89 | type.replace(pos, pattern.length(), target); 90 | } 91 | } 92 | 93 | void ParseHelper::type_simplify(AST &ast, int uid, string &type) { 94 | set type_set; 95 | type_set.insert({"int", "float", "double", "long", "char", "struct", "class", "string"}); 96 | if(type_set.find(type) != type_set.end()){ 97 | ast.modify_node(uid, type); 98 | return ; 99 | } 100 | replace_all(type, "long long", "long"); 101 | replace_all(type, "long double", "double"); 102 | replace_all(type, "unsigned", "^"); 103 | replace_all(type, "const", "="); 104 | replace_all(type, "struct", "$"); 105 | replace_all(type, "std", "+"); 106 | replace_all(type, "class", "@"); 107 | replace_all(type, "int", "~"); 108 | replace_all(type, "float", "-"); 109 | replace_all(type, "double", "!"); 110 | replace_all(type, "long", "#"); 111 | replace_all(type, "char", "%"); 112 | replace_all(type, "string", ";"); 113 | replace_all(type, "::", ":"); 114 | replace_all(type, " ", ""); 115 | for(char c: type) { 116 | if(!isalpha(c)) { 117 | ast.add_edge(uid, ast.get_next()); 118 | switch(c){ 119 | case '.': ast.add_node("std"); break; 120 | case '$': ast.add_node("struct"); break; 121 | case '^': ast.add_node("unsigned"); break; 122 | case '=': ast.add_node("const"); break; 123 | case '@': ast.add_node("class"); break; 124 | case '~': ast.add_node("int"); break; 125 | case '-': ast.add_node("float"); break; 126 | case '!': ast.add_node("double"); break; 127 | case '#': ast.add_node("long"); break; 128 | case '%': ast.add_node("char"); break; 129 | case ';': ast.add_node("string"); break; 130 | default: ast.add_node(string(1, c)); 131 | } 132 | } 133 | } 134 | } 135 | 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /clang-cfg/pybind/ast/ASTVisitorForAST.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019/11/14. 3 | // 4 | 5 | #include "ASTVisitorForAST.h" 6 | #include "ParseHelper.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace clang_cfg{ 12 | 13 | using string = std::string; 14 | using std::queue; 15 | 16 | bool ASTVisitorForAST::VisitTranslationUnitDecl(clang::TranslationUnitDecl *root) { 17 | AST ast; 18 | ast.add_node(string(dyn_cast(root)->getDeclKindName())); 19 | for(DeclContext::decl_iterator it = root->decls_begin(); it != root->decls_end(); it++){ 20 | if(*it == nullptr) continue; 21 | Decl *decl = *it; 22 | if(isa(decl)){ 23 | auto* functionDecl = dyn_cast(decl); 24 | if(!ParseHelper::isInSystem(context, functionDecl) && functionDecl->hasBody()){ 25 | string function_name = functionDecl->getNameInfo().getAsString(), 26 | node_label = string(decl->getDeclKindName()); 27 | int function_decl_id = ast.get_next(); 28 | ast.add_node(node_label); 29 | ast.add_edge(0, function_decl_id); 30 | int function_name_id = ast.get_next(); 31 | ast.add_node(function_name); 32 | ast.add_edge(function_decl_id, function_name_id); 33 | Stmt* functionStmt = functionDecl->getBody(); 34 | if(functionStmt == nullptr){ 35 | continue; 36 | } 37 | queue> qstmt; 38 | qstmt.push(std::make_pair(functionStmt, function_decl_id)); 39 | while(!qstmt.empty()){ 40 | int parent = qstmt.front().second; 41 | Stmt* root_stmt = qstmt.front().first; 42 | string root_label = root_stmt->getStmtClassName(); 43 | qstmt.pop(); 44 | int root_id = ast.get_next(); 45 | ast.add_node(root_label); 46 | ast.add_edge(parent, root_id); 47 | 48 | if(isa(root_stmt)){ 49 | string op = dyn_cast(root_stmt)->getOpcodeStr().data(); 50 | int op_id = ast.get_next(); 51 | ast.add_node(op); 52 | ast.add_edge(root_id, op_id); 53 | } 54 | 55 | if(isa(root_stmt)){ 56 | string op = UnaryOperator::getOpcodeStr(dyn_cast(root_stmt)->getOpcode()).data(); 57 | int op_id = ast.get_next(); 58 | ast.add_node(op); 59 | ast.add_edge(root_id, op_id); 60 | } 61 | 62 | if(isa(root_stmt)){ 63 | auto* callExpr = dyn_cast(root_stmt); 64 | FunctionDecl* calleeDecl = callExpr->getDirectCallee(); 65 | string callee; 66 | if(calleeDecl != nullptr){ 67 | callee = calleeDecl->getNameAsString(); 68 | } else { 69 | Decl* otherDecl = callExpr->getCalleeDecl(); 70 | if(otherDecl != nullptr){ 71 | if(isa(otherDecl)){ 72 | callee = dyn_cast(otherDecl)->getNameAsString(); 73 | } 74 | } else { 75 | if(isa(callExpr)){ 76 | callee = dyn_cast(callExpr)->getMethodDecl()->getNameAsString(); 77 | } else if(isa(callExpr)){ 78 | callee = dyn_cast(callExpr)->getUDSuffix()->getName().data(); 79 | } 80 | 81 | } 82 | } 83 | int call_id = ast.get_next(); 84 | ast.add_node(callee); 85 | ast.add_edge(root_id, call_id); 86 | size_t arg_size = callExpr->getNumArgs(); 87 | for(int idx = 0; idx < arg_size; idx++){ 88 | const Expr* expr = callExpr->getArg(idx); 89 | string arg_name = ParseHelper::getVarName(expr->IgnoreImpCasts()); 90 | if(!arg_name.empty()){ 91 | int arg_id = ast.get_next(); 92 | ast.add_node(arg_name); 93 | ast.add_edge(root_id, arg_id); 94 | } 95 | } 96 | } 97 | 98 | if(isa(root_stmt)){ 99 | auto* decls = dyn_cast(root_stmt); 100 | if(decls->isSingleDecl()){ 101 | const Decl* d = decls->getSingleDecl(); 102 | if(auto* vd = dyn_cast(d)){ 103 | string var_name = vd->getNameAsString(); 104 | int var_id = ast.get_next(); 105 | ast.add_node(var_name); 106 | ast.add_edge(root_id, var_id); 107 | } 108 | } 109 | } 110 | 111 | if(isa(root_stmt)){ 112 | auto* declRef = dyn_cast(root_stmt); 113 | string var_name = declRef->getNameInfo().getName().getAsString(); 114 | int var_id = ast.get_next(); 115 | ast.add_node(var_name); 116 | ast.add_edge(root_id, var_id); 117 | } 118 | 119 | for(Stmt::child_iterator stmt_it = root_stmt->child_begin(); stmt_it != root_stmt->child_end(); stmt_it++){ 120 | if(*stmt_it == nullptr) continue; 121 | string label = (*stmt_it)->getStmtClassName(); 122 | if(!label.empty()){ 123 | qstmt.push(std::make_pair(*stmt_it, root_id)); 124 | } 125 | } 126 | } 127 | 128 | for(FunctionDecl::param_iterator param_it = functionDecl->param_begin(); param_it != functionDecl->param_end(); param_it++){ 129 | ParmVarDecl* parmVarDecl = *param_it; 130 | if(parmVarDecl == nullptr) continue; 131 | string param_name = parmVarDecl->getNameAsString(); 132 | if(!param_name.empty()){ 133 | int param_id = ast.get_next(); 134 | ast.add_node(string(parmVarDecl->getDeclKindName())); 135 | ast.add_edge(function_decl_id, param_id); 136 | int param_name_id = ast.get_next(); 137 | ast.add_node(param_name); 138 | ast.add_edge(param_id, param_name_id); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | ASTList::getInst().vecs.push_back(ast); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /clang-cfg/pybind/extend_cfg/FunctionCFG.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zzhzz on 2019-09-26. 3 | // 4 | 5 | #include 6 | #include "FunctionCFG.h" 7 | 8 | namespace clang_cfg { 9 | using namespace llvm; 10 | using std::string; 11 | using std::queue; 12 | using std::pair; 13 | using std::make_pair; 14 | 15 | string FunctionCFG::getNameAsString() const { 16 | if(const FunctionDecl* functionDecl = dyn_cast(decl)){ 17 | return functionDecl->getNameAsString(); 18 | } 19 | } 20 | 21 | void FunctionCFG::getCFG(clang::ASTContext &ctx) { 22 | CFG result_cfg; 23 | result_cfg.func_name = this->getNameAsString(); 24 | Stmt* body = decl->getBody(); 25 | std::unique_ptr cfg_ptr = clang::CFG::buildCFG(decl, body, &ctx, clang::CFG::BuildOptions()); 26 | clang::CFG* cfg = cfg_ptr.get(); 27 | for(clang::CFG::const_iterator it = cfg->begin(); it != cfg->end(); it++) { 28 | clang::CFGBlock* blk = *it; 29 | if(blk == nullptr) 30 | continue; 31 | int block_id = blk->getBlockID(); 32 | Block block; 33 | for(clang::CFGBlock::const_iterator block_it = blk->begin(); block_it != blk->end(); block_it++){ 34 | Optional block_stmt = block_it->getAs(); 35 | if(block_stmt) { 36 | Stmt* stmt = const_cast(block_stmt->getStmt()); 37 | block.start_lineno = ctx.getSourceManager().getSpellingLineNumber(stmt->getBeginLoc()); 38 | block.end_lineno = ctx.getSourceManager().getSpellingLineNumber(stmt->getEndLoc()); 39 | if(stmt != nullptr){ 40 | AST ast = transToAST(stmt, ctx); 41 | block.add_ast(ast); 42 | } 43 | } 44 | } 45 | int edge_type = 0, edge_size = blk->succ_size(); 46 | if(edge_size == 2){ 47 | //True false edge, 1 for false, 2 for true 48 | edge_type = 1; 49 | } else if(edge_size == 1){ 50 | //0 for Sequence execute 51 | edge_type = 0; 52 | } else { 53 | // 3 for dataflow, 4 for function call, >5 for switch edges 54 | edge_type = 5; 55 | } 56 | for(clang::CFGBlock::succ_iterator succ_it = blk->succ_begin(); succ_it != blk->succ_end(); succ_it++){ 57 | CFGBlock* succ_blk = *succ_it; 58 | if(succ_blk == nullptr) 59 | continue; 60 | int v = succ_blk->getBlockID(); 61 | result_cfg.add_edge(block_id, v, edge_type); 62 | edge_type += 1; 63 | } 64 | result_cfg.add_block(block); 65 | } 66 | CFGList& list = CFGList::getInst(); 67 | list.vecs.back().push_back(result_cfg); 68 | } 69 | 70 | AST FunctionCFG::transToAST(clang::Stmt* stmt, clang::ASTContext &ctx) { 71 | AST ast; 72 | string name = stmt->getStmtClassName(); 73 | ast.add_node(name); 74 | queue> que; 75 | while(!que.empty()) que.pop(); 76 | que.push(make_pair(const_cast(stmt), 0)); 77 | while(!que.empty()) { 78 | Stmt* cur_stmt = que.front().first; 79 | int uid = que.front().second; 80 | que.pop(); 81 | if(const BinaryOperator* opstmt = dyn_cast(cur_stmt)){ 82 | ast.modify_node(uid, string(opstmt->getOpcodeStr().data())); 83 | std::string lvalue = ParseHelper::getVarName(opstmt->getLHS()->IgnoreParens()->IgnoreImpCasts()); 84 | std::string rvalue = ParseHelper::getVarName(opstmt->getRHS()->IgnoreParens()->IgnoreImpCasts()); 85 | 86 | if(opstmt->isAssignmentOp() || opstmt->isCompoundAssignmentOp() || opstmt->isShiftAssignOp()){ 87 | ast.add_defination(lvalue); 88 | ast.add_usage(rvalue); 89 | } else { 90 | ast.add_usage(lvalue); 91 | ast.add_usage(rvalue); 92 | } 93 | } 94 | if(const UnaryOperator* unary = dyn_cast(cur_stmt)){ 95 | std::string name = UnaryOperator::getOpcodeStr(unary->getOpcode()).data(); 96 | std::string value = ParseHelper::getVarName(unary->getSubExpr()->IgnoreParens()->IgnoreImpCasts()); 97 | if(unary->isPostfix()){ 98 | name += "_pre"; 99 | } else { 100 | name += "_suf"; 101 | } 102 | ast.modify_node(uid, name); 103 | ast.add_defination(value); 104 | ast.add_usage(value); 105 | } 106 | if(const CallExpr* call_expr = dyn_cast(cur_stmt)){ 107 | const FunctionDecl* calleeDecl = call_expr->getDirectCallee(); 108 | std::string name; 109 | if(calleeDecl != nullptr){ 110 | name = calleeDecl->getNameAsString(); 111 | } else { 112 | if(isa(call_expr)){ 113 | name = dyn_cast(call_expr)->getMethodDecl()->getNameAsString(); 114 | } else if(isa(call_expr)){ 115 | name = dyn_cast(call_expr)->getUDSuffix()->getName().data(); 116 | } 117 | } 118 | if(!name.empty()){ 119 | ast.add_call(uid, name); 120 | } 121 | int sz = call_expr->getNumArgs(); 122 | for(int i = 0; i < sz; i++){ 123 | const Expr* arg = call_expr->getArg(i); 124 | std::string arg_name = ParseHelper::getVarName(arg->IgnoreImpCasts()); 125 | ast.add_usage(arg_name); 126 | } 127 | } 128 | if(const DeclStmt* ds = dyn_cast(cur_stmt)){ 129 | if(ds->isSingleDecl()){ 130 | const Decl* d = ds->getSingleDecl(); 131 | if(const ValueDecl* vd = dyn_cast(d)){ 132 | std::string name = vd->getNameAsString(); 133 | ast.add_defination(name); 134 | std::string type = vd->getType().getUnqualifiedType().getCanonicalType().getAsString(); 135 | ParseHelper::type_simplify(ast, uid, type); 136 | } 137 | } 138 | } 139 | if(const DeclRefExpr* dr = dyn_cast(cur_stmt)){ 140 | const ValueDecl* vd = dr->getDecl(); 141 | if(vd){ 142 | std::string type = vd->getType().getCanonicalType().getAsString(); 143 | ParseHelper::type_simplify(ast, uid, type); 144 | } 145 | } 146 | if(const CastExpr* expr = dyn_cast(cur_stmt)){ 147 | std::string kind = expr->getCastKindName(); 148 | ast.modify_node(uid, kind); 149 | } 150 | if(const IntegerLiteral* literal = dyn_cast(cur_stmt)){ 151 | long long v = *(literal->getValue().getRawData()); 152 | string val = std::to_string(v); 153 | ast.modify_node(uid, "int"); 154 | int pid = ast.get_parent(uid); 155 | for(char c: val){ 156 | ast.add_edge(pid, ast.get_next()); 157 | ast.add_node(string(1, c)); 158 | } 159 | } 160 | if(const FloatingLiteral* literal = dyn_cast(cur_stmt)){ 161 | SmallString<16> str; 162 | literal->getValue().toString(str); 163 | string val = string(str.c_str()); 164 | ast.modify_node(uid, "float"); 165 | int pid = ast.get_parent(uid); 166 | for(char c: val){ 167 | ast.add_edge(pid, ast.get_next()); 168 | ast.add_node(string(1, c)); 169 | } 170 | } 171 | if(const clang::StringLiteral* literal = dyn_cast(cur_stmt)){ 172 | ast.modify_node(uid, "string"); 173 | } 174 | for(Stmt::child_iterator child = cur_stmt->child_begin(); child != cur_stmt->child_end(); child++){ 175 | if(*child == nullptr){ 176 | continue; 177 | } 178 | string classname = (*child)->getStmtClassName(); 179 | if(classname.length() > 0){ 180 | int v = ast.get_next(); 181 | que.push(make_pair(*child, v)); 182 | ast.add_edge(uid, v); 183 | ast.add_node(classname); 184 | } 185 | } 186 | } 187 | return ast; 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 37 | 38 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 74 | 75 | 76 | 77 | 79 | 80 | 81 | 82 | 84 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 94 | 95 | 96 | 97 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 1574773976440 129 | 136 | 137 | 1574774170140 138 | 143 | <<<<<<< HEAD 144 | 145 | 1574781740059 146 | 151 | 152 | 1574781853382 153 | 176 | 177 | 179 | 180 | 191 | 192 | 193 | <<<<<<< HEAD 194 | 195 | 196 | 204 | 205 | --------------------------------------------------------------------------------