├── .gitignore ├── lab0 ├── CMakeLists.txt ├── include │ └── Prereqs.h ├── src │ └── Prereqs.cpp └── test │ ├── Makefile │ └── simple0.c ├── lab1 ├── CMakeLists.txt ├── include │ ├── DataflowAnalysis.h │ ├── DivZeroAnalysis.h │ └── Domain.h ├── src │ ├── DataflowAnalysis.cpp │ ├── DivZeroAnalysis.cpp │ └── Domain.cpp └── test │ ├── Makefile │ ├── simple0.c │ ├── simple1.c │ ├── simple10.c │ ├── simple11.c │ ├── simple2.c │ ├── simple3.c │ ├── simple4.c │ ├── simple5.c │ ├── simple6.c │ ├── simple7.c │ ├── simple8.c │ └── simple9.c ├── lab10 ├── CMakeLists.txt ├── include │ ├── Instrument.h │ └── Utils.h ├── lib │ └── runtime.c ├── reference │ ├── InstrumentPass.so │ └── fuzzer ├── src │ └── Delta.cpp └── test │ ├── Makefile │ ├── fuzz0.c │ ├── fuzz1.c │ ├── fuzz2.c │ ├── fuzz_input │ └── seed.txt │ ├── simple0.c │ └── simple1.c ├── lab11 ├── CMakeLists.txt ├── include │ ├── Instrument.h │ ├── Runtime.h │ ├── Strategy.h │ └── SymbolicInterpreter.h ├── src │ ├── DSE.cpp │ ├── Instrument.cpp │ ├── Runtime.cpp │ ├── Strategy.cpp │ └── SymbolicInterpreter.cpp └── test │ ├── Makefile │ ├── branch0.c │ ├── branch1.c │ ├── branch2.c │ ├── infeasable.c │ ├── simple0.c │ └── simple1.c ├── lab12 ├── CMakeLists.txt ├── include │ ├── Extractor.h │ ├── Utils.h │ └── Verifier.h ├── src │ ├── Extractor.cpp │ ├── Utils.cpp │ └── Verifier.cpp └── test │ ├── Makefile │ ├── simple0.c │ ├── simple1.c │ ├── simple2.c │ ├── test.c │ └── test2.c ├── lab2 ├── CMakeLists.txt ├── include │ └── Instrument.h ├── lib │ └── runtime.c ├── src │ └── Instrument.cpp └── test │ ├── Makefile │ ├── calc.c │ ├── simple0.c │ ├── simple1.c │ ├── simple2.c │ ├── simple3.c │ ├── simple4.c │ ├── simple5.c │ ├── simple6.c │ ├── simple7.c │ ├── simple8.c │ └── simple9.c ├── lab3 ├── CMakeLists.txt ├── include │ ├── Instrument.h │ ├── Mutate.h │ └── Utils.h ├── lib │ └── runtime.c ├── reference │ └── InstrumentPass.so ├── src │ ├── Fuzzer.cpp │ └── Mutate.cpp └── test │ ├── Makefile │ ├── easy │ ├── easy.c │ ├── easy2 │ ├── easy2.c │ ├── fuzz_input │ └── seed.txt │ ├── hidden1 │ ├── hidden2 │ ├── hidden3 │ ├── sanity │ └── sanity.c ├── lab4 ├── CMakeLists.txt ├── include │ ├── Instrument.h │ ├── Mutate.h │ └── Utils.h ├── lib │ └── runtime.c ├── reference │ ├── InstrumentPass.so │ └── libMutate.so ├── src │ ├── Fuzzer.cpp │ └── Mutate.cpp └── test │ ├── Makefile │ ├── easy.c │ ├── easy2.c │ ├── fuzz_input │ └── seed.txt │ ├── hidden1 │ ├── hidden2 │ ├── hidden3 │ ├── path.c │ ├── path2.c │ ├── path3.c │ └── sanity.c ├── lab5 ├── CMakeLists.txt ├── include │ ├── DataflowAnalysis.h │ ├── DivZeroAnalysis.h │ └── Domain.h ├── reference │ └── libRefDomain.so ├── src │ ├── DataflowAnalysis.cpp │ ├── DivZeroAnalysis.cpp │ └── Domain.cpp └── test │ ├── Makefile │ ├── branch0.c │ ├── branch1.c │ ├── branch2.c │ ├── branch3.c │ ├── branch4.c │ ├── branch5.c │ ├── branch6.c │ ├── input0.c │ ├── loop0.c │ ├── loop1.c │ ├── simple0.c │ └── simple1.c ├── lab6 ├── CMakeLists.txt ├── include │ ├── DataflowAnalysis.h │ ├── DivZeroAnalysis.h │ ├── Domain.h │ └── PointerAnalysis.h ├── reference │ └── libRefDomain.so ├── src │ ├── DataflowAnalysis.cpp │ ├── DivZeroAnalysis.cpp │ ├── Domain.cpp │ └── PointerAnalysis.cpp └── test │ ├── Makefile │ ├── branch0.c │ ├── branch1.c │ ├── branch2.c │ ├── branch3.c │ ├── branch4.c │ ├── branch5.c │ ├── branch6.c │ ├── input0.c │ ├── loop0.c │ ├── loop1.c │ ├── pointer0.c │ ├── pointer1.c │ ├── pointer2.c │ ├── pointer3.c │ ├── pointer4.c │ ├── pointer5.c │ ├── pointer6.c │ ├── simple0.c │ └── simple1.c ├── lab7 ├── CMakeLists.txt ├── include │ ├── Extractor.h │ └── Utils.h ├── src │ ├── Constraint.cpp │ ├── Extractor.cpp │ └── Utils.cpp └── test │ ├── Makefile │ ├── branch0.c │ ├── branch1.c │ ├── branch2.c │ ├── loop0.c │ ├── loop1.c │ ├── prelude.h │ ├── simple0.c │ └── simple1.c ├── lab8 ├── CMakeLists.txt ├── include │ ├── DummyLLParser.h │ ├── Extractor.h │ ├── LLLexer.h │ ├── LLToken.h │ └── Parser.h ├── lib │ ├── LLLexer.cpp │ ├── LLParser.cpp │ ├── LLVMBuild.txt │ └── Parser.cpp ├── src │ ├── Extractor.cpp │ └── TypeSystem.cpp └── test │ ├── Makefile │ ├── branch0.c │ ├── function0.c │ ├── simple0.c │ └── simple1.ll └── lab9 ├── CMakeLists.txt ├── include ├── CBIInstrument.h └── Utils.h ├── lib └── runtime.c ├── reference ├── InstrumentPass.so └── fuzzer ├── src ├── CBI.cpp └── CBIInstrument.cpp └── test ├── Makefile ├── fuzz0.c ├── fuzz1.c ├── fuzz2.c ├── fuzz3.c ├── fuzz_input └── seed.txt ├── simple0.c └── simple1.c /.gitignore: -------------------------------------------------------------------------------- 1 | # built binaries 2 | build 3 | 4 | # bitcode and analysis output 5 | *.ll 6 | *.out 7 | *.err 8 | *.cov 9 | *.delta 10 | *.cbi 11 | fuzz_output 12 | formula.smt2 13 | input.txt 14 | branch.txt 15 | log.txt 16 | 17 | *.out 18 | *.err 19 | simple0 20 | simple1 21 | branch0 22 | branch1 23 | fuzz0 24 | fuzz1 25 | fuzz2 26 | 27 | # vim 28 | .*.swp 29 | .ycm_extra_conf.py 30 | compile_commands.json 31 | -------------------------------------------------------------------------------- /lab0/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS}) 13 | 14 | add_llvm_library(PrereqPass MODULE 15 | src/Prereqs.cpp 16 | ) 17 | -------------------------------------------------------------------------------- /lab0/include/Prereqs.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Module.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace prereqs { 6 | struct Prereqs : public ModulePass { 7 | static char ID; 8 | Prereqs(); 9 | 10 | bool runOnModule(Module &M); 11 | void print(Module &M); 12 | 13 | int NumOfFunctions = 0; 14 | int NumOfInstructions = 0; 15 | }; 16 | } // namespace prereqs 17 | -------------------------------------------------------------------------------- /lab0/src/Prereqs.cpp: -------------------------------------------------------------------------------- 1 | #include "Prereqs.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace prereqs { 6 | Prereqs::Prereqs() : ModulePass(ID) {} 7 | 8 | void Prereqs::print(Module &M) { 9 | outs() << "Analytics of Module " << M.getName() << "\n"; 10 | outs() << " # Functions : " << NumOfFunctions << "\n"; 11 | outs() << " # Instructions : " << NumOfInstructions << "\n"; 12 | } 13 | 14 | bool Prereqs::runOnModule(Module &M) { 15 | /* Add your code here */ 16 | 17 | /* DO NOT EDIT BELOW THIS LINE */ 18 | print(M); 19 | return false; 20 | } 21 | 22 | char Prereqs::ID = 1; 23 | static RegisterPass X("Prereqs", "Prereqs", false, false); 24 | } // namespace prereqs 25 | -------------------------------------------------------------------------------- /lab0/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=simple0 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< 7 | opt -load ../build/PrereqPass.so -Prereqs -S $@.ll -disable-output 8 | 9 | clean: 10 | rm -f *.ll 11 | -------------------------------------------------------------------------------- /lab0/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | int c = a + 1; 5 | int d = b / a; // Divide by zero 6 | if (c) { 7 | int a = 1; 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) 13 | 14 | add_llvm_library(DataflowPass MODULE 15 | src/DataflowAnalysis.cpp 16 | src/DivZeroAnalysis.cpp 17 | src/Domain.cpp 18 | ) 19 | -------------------------------------------------------------------------------- /lab1/include/DataflowAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAFLOW_ANALYSIS_H 2 | #define DATAFLOW_ANALYSIS_H 3 | 4 | #include "llvm/ADT/SetVector.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/InstIterator.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/ValueMap.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "Domain.h" 18 | 19 | using namespace llvm; 20 | 21 | namespace dataflow { 22 | 23 | using Memory = std::map; 24 | 25 | std::string deref(Value *); 26 | std::string variable(Value *); 27 | std::string address(Value *); 28 | 29 | struct DataflowAnalysis : public FunctionPass { 30 | ValueMap InMap; 31 | ValueMap OutMap; 32 | SetVector ErrorInsts; 33 | 34 | DataflowAnalysis(char ID); 35 | void collectErrorInsts(Function &F); 36 | bool runOnFunction(Function &F) override; 37 | 38 | protected: 39 | virtual void transfer(Instruction *I, const Memory *In, Memory *NOut) = 0; 40 | virtual void doAnalysis(Function &F) = 0; 41 | virtual bool check(Instruction *I) = 0; 42 | virtual std::string getAnalysisName() = 0; 43 | }; 44 | 45 | 46 | inline bool isInput(Instruction *I) { 47 | if (CallInst *CI = dyn_cast(I)) { 48 | return CI->getCalledFunction()->getName().equals("fgetc"); 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | /** 55 | * Get the Predecessors of a given instruction in the control-flow graph. 56 | */ 57 | inline std::vector getPredecessors(Instruction *I) { 58 | std::vector Ret; 59 | BasicBlock *BB = I->getParent(); 60 | for (BasicBlock::reverse_iterator It = BB->rbegin(), E = BB->rend(); It != E; 61 | ++It) { 62 | if (&(*It) == I) { 63 | ++It; 64 | if (It == E) { 65 | for (pred_iterator Pre = pred_begin(BB), BE = pred_end(BB); Pre != BE; 66 | ++Pre) 67 | Ret.push_back(&(*((*Pre)->rbegin()))); 68 | } else { 69 | Ret.push_back(&(*It)); 70 | } 71 | break; 72 | } 73 | } 74 | return Ret; 75 | } 76 | 77 | /** 78 | * Get the successors of a given instruction in the control-flow graph. 79 | */ 80 | inline std::vector getSuccessors(Instruction *I) { 81 | std::vector Ret; 82 | BasicBlock *BB = I->getParent(); 83 | for (BasicBlock::iterator It = BB->begin(), E = BB->end(); It != E; ++It) { 84 | if (&(*It) == I) { 85 | ++It; 86 | if (It == E) { 87 | for (succ_iterator Succ = succ_begin(BB), BS = succ_end(BB); Succ != BS; 88 | ++Succ) 89 | Ret.push_back(&(*((*Succ)->begin()))); 90 | } else { 91 | Ret.push_back(&(*It)); 92 | } 93 | break; 94 | } 95 | } 96 | return Ret; 97 | } 98 | } // namespace dataflow 99 | 100 | #endif // DATAFLOW_ANALYSIS_H 101 | -------------------------------------------------------------------------------- /lab1/include/DivZeroAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DIV_ZERO_ANALYSIS_H 2 | #define DIV_ZERO_ANALYSIS_H 3 | 4 | #include "DataflowAnalysis.h" 5 | 6 | namespace dataflow { 7 | struct DivZeroAnalysis : public DataflowAnalysis { 8 | static char ID; 9 | DivZeroAnalysis() : DataflowAnalysis(ID) {} 10 | 11 | protected: 12 | void transfer(Instruction *I, const Memory *In, Memory *NOut) override; 13 | 14 | void doAnalysis(Function &F) override; 15 | 16 | bool check(Instruction *I) override; 17 | 18 | std::string getAnalysisName() override { return "DivZero"; } 19 | }; 20 | } // namespace dataflow 21 | 22 | #endif // DIV_ZERO_ANALYSIS_H 23 | -------------------------------------------------------------------------------- /lab1/include/Domain.h: -------------------------------------------------------------------------------- 1 | #ifndef DOMAIN_H 2 | #define DOMAIN_H 3 | 4 | namespace dataflow { 5 | 6 | //===----------------------------------------------------------------------===// 7 | // Abstract Domain Implementation 8 | //===----------------------------------------------------------------------===// 9 | 10 | /* 11 | * Implement your abstract domain. 12 | */ 13 | class Domain { 14 | /* Add your code here */ 15 | }; 16 | } // namespace dataflow 17 | 18 | #endif // DOMAIN_H 19 | -------------------------------------------------------------------------------- /lab1/src/DataflowAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DataflowAnalysis.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace dataflow { 6 | 7 | //===----------------------------------------------------------------------===// 8 | // Memory Access 9 | //===----------------------------------------------------------------------===// 10 | 11 | const char *WhiteSpaces = " \t\n\r"; 12 | 13 | std::string deref(Value *V) { 14 | std::string Code; 15 | raw_string_ostream SS(Code); 16 | V->print(SS); 17 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 18 | Code = "*(" + Code + ")"; 19 | return Code; 20 | } 21 | 22 | std::string variable(Value *V) { 23 | std::string Code; 24 | raw_string_ostream SS(Code); 25 | V->print(SS); 26 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 27 | return Code; 28 | } 29 | 30 | std::string address(Value *V) { 31 | std::string Code; 32 | raw_string_ostream SS(Code); 33 | V->print(SS); 34 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 35 | Code = "@(" + Code + ")"; 36 | return Code; 37 | } 38 | 39 | //===----------------------------------------------------------------------===// 40 | // Dataflow Analysis Implementation 41 | //===----------------------------------------------------------------------===// 42 | 43 | DataflowAnalysis::DataflowAnalysis(char ID) : FunctionPass(ID) {} 44 | 45 | void DataflowAnalysis::collectErrorInsts(Function &F) { 46 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 47 | if (check(&*I)) 48 | ErrorInsts.insert(&*I); 49 | } 50 | } 51 | 52 | bool DataflowAnalysis::runOnFunction(Function &F) { 53 | outs() << "Running " << getAnalysisName() << " on " << F.getName() << "\n"; 54 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 55 | InMap[&(*I)] = new Memory; 56 | OutMap[&(*I)] = new Memory; 57 | } 58 | 59 | doAnalysis(F); 60 | 61 | collectErrorInsts(F); 62 | outs() << "Instructions that potentially divide by zero: \n"; 63 | for (auto I : ErrorInsts) { 64 | outs() << *I << "\n"; 65 | } 66 | 67 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 68 | delete InMap[&(*I)]; 69 | delete OutMap[&(*I)]; 70 | } 71 | return false; 72 | } 73 | } // namespace dataflow 74 | -------------------------------------------------------------------------------- /lab1/src/DivZeroAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DivZeroAnalysis.h" 2 | 3 | namespace dataflow { 4 | 5 | //===----------------------------------------------------------------------===// 6 | // DivZero Analysis Implementation 7 | //===----------------------------------------------------------------------===// 8 | 9 | /** 10 | * Implement your data-flow analysis. 11 | * 1. Define "transfer" that computes the semantics of each instruction. 12 | * 2. Define "doAnalysis" that stores your results in "InMap" and "OutMap". 13 | * 3. Define "check" that checks if a given instruction is erroneous or not. 14 | */ 15 | 16 | void DivZeroAnalysis::transfer(Instruction *I, const Memory *In, Memory *NOut) { 17 | /* Add your code here */ 18 | } 19 | 20 | void DivZeroAnalysis::doAnalysis(Function &F) { /* Add your code here */ } 21 | 22 | bool DivZeroAnalysis::check(Instruction *I) { 23 | /* Add your code here */ 24 | return false; 25 | } 26 | 27 | char DivZeroAnalysis::ID = 1; 28 | static RegisterPass X("DivZero", "Divide-by-zero Analysis", 29 | false, false); 30 | } // namespace dataflow 31 | -------------------------------------------------------------------------------- /lab1/src/Domain.cpp: -------------------------------------------------------------------------------- 1 | #include "Domain.h" 2 | 3 | //===----------------------------------------------------------------------===// 4 | // Abstract Domain Implementation 5 | //===----------------------------------------------------------------------===// 6 | 7 | /* Add your code here */ 8 | -------------------------------------------------------------------------------- /lab1/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll 2 | 3 | all: simple0.out simple1.out simple2.out simple3.out simple4.out simple5.out simple6.out simple7.out simple8.out simple9.c simple10.out simple11.out 4 | 5 | %.ll: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@ $< 7 | 8 | %.out: %.ll 9 | opt -load ../build/DataflowPass.so -DivZero $< -disable-output > $@ 2> $*.err 10 | 11 | clean: 12 | rm -f *.ll *.out *.err 13 | -------------------------------------------------------------------------------- /lab1/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | int c = a + 1; 5 | int d = b / a; // Divide by zero 6 | if (c) { 7 | int a = 1; 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab1/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | int c = a == b; 5 | int d = b / c; 6 | int e = d / d; // divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab1/test/simple10.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | z = y / x; // divide-by-zero within branch 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lab1/test/simple11.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int x = 2 * fgetc(stdin) - 2; 5 | int y = 5 / x; // Divide byb zero 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /lab1/test/simple2.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | z = y / x; // divide-by-zero within branch 7 | } else { 8 | z = z / x; // divide-by-zero within branch 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lab1/test/simple3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | int d = 5; 5 | int c = a == b; 6 | int e = d / (c * 0); // divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab1/test/simple4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int b = 0; 3 | int a = b / 5; 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /lab1/test/simple5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int y = 1, z = 1; 5 | int un; 6 | int x = un + 1; 7 | if (x == 0) { 8 | z = y / x; // Divide by zero 9 | } 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /lab1/test/simple6.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a, b; 3 | int c = 0; 4 | b = c; 5 | a = b; 6 | int d = a / c; // Divide by zero 7 | c = c + 1; 8 | int e = a / c; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab1/test/simple7.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a, b; 3 | int c = 0; 4 | b = c; 5 | a = b; 6 | int d = a / c; // Divide by zero 7 | c = c + 1; 8 | c = c * 0; 9 | int e = a / c; // Divide by zero 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /lab1/test/simple8.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = a / 0; // Divide by zero 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /lab1/test/simple9.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int u1 = fgetc(stdin); 5 | int u2 = 4, d; 6 | if (u1 != 0) { 7 | d = u2 / u1; // Divide by zero 8 | } else { 9 | int d = u2 / (u1 + 1); // Divide by zero 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /lab10/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/reference) 13 | 14 | add_executable(delta 15 | src/Delta.cpp 16 | ) 17 | 18 | add_library(runtime MODULE 19 | lib/runtime.c 20 | ) 21 | 22 | add_custom_target(reference ALL 23 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/* ${CMAKE_CURRENT_BINARY_DIR}/ 24 | ) 25 | -------------------------------------------------------------------------------- /lab10/include/Instrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | struct Instrument : public FunctionPass { 13 | static char ID; 14 | static const char *checkFunctionName; 15 | 16 | Instrument() : FunctionPass(ID) {} 17 | 18 | bool runOnFunction(Function &F) override; 19 | }; 20 | } // namespace instrument 21 | -------------------------------------------------------------------------------- /lab10/include/Utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::string readOneFile(std::string &Path) { 7 | std::ifstream SeedFile(Path); 8 | std::string Line((std::istreambuf_iterator(SeedFile)), 9 | std::istreambuf_iterator()); 10 | return Line; 11 | } 12 | 13 | int runTarget(std::string &Target, std::string &Input) { 14 | std::string Cmd = Target + " > /dev/null 2>&1"; 15 | FILE *F = popen(Cmd.c_str(), "w"); 16 | fprintf(F, "%s", Input.c_str()); 17 | return pclose(F); 18 | } 19 | -------------------------------------------------------------------------------- /lab10/lib/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __dbz_sanitizer__(int divisor, int line, int col) { 7 | if (divisor == 0) { 8 | printf("Divide-by-zero detected at line %d and col %d\n", line, col); 9 | exit(1); 10 | } 11 | } 12 | 13 | void __coverage__(int line, int col) { 14 | char exe[1024]; 15 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 16 | if (ret == -1) { 17 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 18 | exit(1); 19 | } 20 | exe[ret] = 0; 21 | 22 | char logfile[1024]; 23 | int len = strlen(exe); 24 | strncpy(logfile, exe, len); 25 | logfile[len] = 0; 26 | strcat(logfile, ".cov"); 27 | FILE *f = fopen(logfile, "a"); 28 | fprintf(f, "%d,%d\n", line, col); 29 | fclose(f); 30 | } 31 | 32 | void __cbi_branch__(int line, int col, int cond) { 33 | char exe[1024]; 34 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 35 | if (ret == -1) { 36 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 37 | exit(1); 38 | } 39 | exe[ret] = 0; 40 | 41 | char logfile[1024]; 42 | int len = strlen(exe); 43 | strncpy(logfile, exe, len); 44 | logfile[len] = 0; 45 | strcat(logfile, ".cbi"); 46 | FILE *f = fopen(logfile, "a"); 47 | fprintf(f, "branch,%d,%d,%d\n", line, col, cond); 48 | fclose(f); 49 | } 50 | 51 | void __cbi_return__(int line, int col, int rv) { 52 | char exe[1024]; 53 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 54 | if (ret == -1) { 55 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 56 | exit(1); 57 | } 58 | exe[ret] = 0; 59 | 60 | char logfile[1024]; 61 | int len = strlen(exe); 62 | strncpy(logfile, exe, len); 63 | logfile[len] = 0; 64 | strcat(logfile, ".cbi"); 65 | FILE *f = fopen(logfile, "a"); 66 | fprintf(f, "return,%d,%d,%d\n", line, col, rv); 67 | fclose(f); 68 | } 69 | -------------------------------------------------------------------------------- /lab10/reference/InstrumentPass.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab10/reference/InstrumentPass.so -------------------------------------------------------------------------------- /lab10/reference/fuzzer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab10/reference/fuzzer -------------------------------------------------------------------------------- /lab10/src/Delta.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Utils.h" 8 | 9 | /* 10 | * Implement the delta-debugging algorithm. 11 | */ 12 | std::string delta(std::string &Target, std::string &Input) { 13 | /* Add your code here */ 14 | return Input; 15 | } 16 | 17 | // ./delta [exe file] [crashing input file] 18 | int main(int argc, char **argv) { 19 | if (argc != 3) { 20 | fprintf(stderr, "Invalid usage\n"); 21 | return 1; 22 | } 23 | 24 | struct stat Buffer; 25 | if (stat(argv[1], &Buffer)) { 26 | fprintf(stderr, "%s not found\n", argv[1]); 27 | return 1; 28 | } 29 | 30 | if (stat(argv[2], &Buffer)) { 31 | fprintf(stderr, "%s not found\n", argv[2]); 32 | return 1; 33 | } 34 | 35 | std::string Target(argv[1]); 36 | std::string InputFile(argv[2]); 37 | std::string Input = readOneFile(InputFile); 38 | if (!runTarget(Target, Input)) { 39 | fprintf(stderr, "Sanity check failed: the program does not crash with the " 40 | "initial input\n"); 41 | return 1; 42 | } 43 | 44 | std::string DeltaOutput = delta(Target, Input); 45 | 46 | std::string Path = InputFile + ".delta"; 47 | std::ofstream OutFile(Path); 48 | OutFile << DeltaOutput; 49 | OutFile.close(); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /lab10/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=simple0 simple1 fuzz0 fuzz1 fuzz2 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< -g 7 | opt -load ../build/InstrumentPass.so -Instrument -S $@.ll -o $@.instrumented.ll 8 | clang -o $@ -L${PWD}/../build -lruntime $@.instrumented.ll 9 | 10 | clean: 11 | rm -f *.ll *.cov ${TARGETS} 12 | -------------------------------------------------------------------------------- /lab10/test/fuzz0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char input[65536]; 5 | fgets(input, sizeof(input), stdin); 6 | int x = 0; 7 | int y = 2; 8 | int z = y / x; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab10/test/fuzz1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | 11 | if (strlen(input) % 7 == 0) { 12 | z = y / x; 13 | } 14 | 15 | if (strlen(input) % 13 == 0) { 16 | z = y / ++x; 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /lab10/test/fuzz2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) > 10 && input[5] == 'a') { 11 | z = y / x; 12 | } 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /lab10/test/fuzz_input/seed.txt: -------------------------------------------------------------------------------- 1 | This is the seed input file. 2 | Multiple lines are also possible. 3 | 9124 4 | 1lk24 90KJ!@(jkl1j2 5 15'25 ) 5 | -------------------------------------------------------------------------------- /lab10/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | int y = x; 4 | int z = y / x; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /lab10/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | if (argc > 2) { 3 | int x = 0; 4 | int y = x; 5 | int z = y / x; 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | set(Z3_DIR $ENV{Z3_DIR}) 11 | get_filename_component(Z3_DIR ${Z3_DIR} ABSOLUTE) 12 | set(Z3_CXX_INCLUDE_DIRS ${Z3_DIR}/include) 13 | set(Z3_LIBRARIES ${Z3_DIR}/bin/libz3.so) 14 | message(STATUS "Z3_DIR: ${Z3_DIR}") 15 | 16 | add_definitions(${LLVM_DEFINITIONS}) 17 | include_directories(${LLVM_INCLUDE_DIRS} include) 18 | include_directories(${Z3_CXX_INCLUDE_DIRS}) 19 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${Z3_LIBRARIES}) 20 | 21 | add_executable(dse 22 | src/DSE.cpp 23 | src/Strategy.cpp 24 | ) 25 | 26 | add_llvm_library(InstrumentPass MODULE 27 | src/Instrument.cpp 28 | ) 29 | 30 | llvm_map_components_to_libnames(llvm_libs support core irreader) 31 | 32 | target_link_libraries(dse ${llvm_libs} ${Z3_LIBRARIES}) 33 | 34 | add_library(runtime MODULE 35 | src/SymbolicInterpreter.cpp 36 | src/Runtime.cpp 37 | ) 38 | 39 | target_link_libraries(runtime ${llvm_libs} ${Z3_LIBRARIES}) 40 | -------------------------------------------------------------------------------- /lab11/include/Instrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | static const char *DSEInitFunctionName = "__DSE_Init__"; 13 | static const char *DSEAllocaFunctionName = "__DSE_Alloca__"; 14 | static const char *DSEStoreFunctionName = "__DSE_Store__"; 15 | static const char *DSELoadFunctionName = "__DSE_Load__"; 16 | static const char *DSEConstFunctionName = "__DSE_Const__"; 17 | static const char *DSERegisterFunctionName = "__DSE_Register__"; 18 | static const char *DSEICmpFunctionName = "__DSE_ICmp__"; 19 | static const char *DSEBranchFunctionName = "__DSE_Branch__"; 20 | static const char *DSEBinOpFunctionName = "__DSE_BinOp__"; 21 | 22 | int RegisterID = 0; 23 | std::map RegisterMap; 24 | int BranchID = 0; 25 | std::map BranchMap; 26 | 27 | int getRegisterID(Value *I) { 28 | if (RegisterMap.find(I) == RegisterMap.end()) { 29 | RegisterMap[I] = RegisterID; 30 | return RegisterID++; 31 | } else { 32 | return RegisterMap[I]; 33 | } 34 | } 35 | 36 | int getBranchID(Instruction *I) { 37 | if (BranchMap.find(I) == BranchMap.end()) { 38 | BranchMap[I] = BranchID; 39 | return BranchID++; 40 | } else { 41 | return BranchMap[I]; 42 | } 43 | } 44 | 45 | struct Instrument : public FunctionPass { 46 | static char ID; 47 | static const char *checkFunctionName; 48 | 49 | Instrument() : FunctionPass(ID) {} 50 | 51 | bool runOnFunction(Function &F) override; 52 | }; 53 | } // namespace instrument 54 | -------------------------------------------------------------------------------- /lab11/include/Runtime.h: -------------------------------------------------------------------------------- 1 | void __DSE_Input__(int *x, int ID); 2 | 3 | #define DSE_Input(x) __DSE_Input__(&x, __COUNTER__) 4 | -------------------------------------------------------------------------------- /lab11/include/Strategy.h: -------------------------------------------------------------------------------- 1 | #include "z3++.h" 2 | 3 | void searchStrategy(z3::expr_vector &OldVec); 4 | -------------------------------------------------------------------------------- /lab11/include/SymbolicInterpreter.h: -------------------------------------------------------------------------------- 1 | #ifndef SYMBOLIC_INTERPRETER_H 2 | #define SYMBOLIC_INTERPRETER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "z3++.h" 10 | 11 | static const char *FormulaFile = "formula.smt2"; 12 | static const char *InputFile = "input.txt"; 13 | static const char *LogFile = "log.txt"; 14 | static const char *BranchFile = "branch.txt"; 15 | 16 | class Address { 17 | public: 18 | enum Ty { Memory, Register }; 19 | Address(int *Ptr) : Type(Memory), Addr((uintptr_t)Ptr) {} 20 | Address(int ID) : Type(Register), Addr(ID) {} 21 | Address(z3::expr &R) 22 | : Type(Register), Addr(std::stoi(R.to_string().substr(1))) {} 23 | 24 | bool operator<(const Address &RHS) const { 25 | return (Type < RHS.Type) || (Type == RHS.Type && Addr < RHS.Addr); 26 | } 27 | friend std::ostream &operator<<(std::ostream &OS, const Address &SE); 28 | 29 | private: 30 | Ty Type; 31 | uintptr_t Addr; 32 | }; 33 | 34 | using MemoryTy = std::map; 35 | 36 | class SymbolicInterpreter { 37 | public: 38 | int NewInput(int *Ptr, int ID); 39 | MemoryTy &getMemory() { return Mem; } 40 | std::map &getInputs() { return Inputs; } 41 | z3::context &getContext() { return Ctx; } 42 | std::stack &getStack() { return Stack; } 43 | std::vector> &getPathCondition() { 44 | return PathCondition; 45 | } 46 | 47 | private: 48 | MemoryTy Mem; 49 | std::map Inputs; 50 | int NumOfInputs = 0; 51 | std::stack Stack; 52 | std::vector> PathCondition; 53 | 54 | z3::context Ctx; 55 | }; 56 | 57 | #endif // SYMBOLIC_INTERPRETER_H 58 | -------------------------------------------------------------------------------- /lab11/src/DSE.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "z3++.h" 7 | 8 | #include "Strategy.h" 9 | #include "SymbolicInterpreter.h" 10 | 11 | z3::context Ctx; 12 | z3::solver Solver(Ctx); 13 | 14 | void storeInput() { 15 | std::ofstream OS(InputFile); 16 | z3::model Model = Solver.get_model(); 17 | for (int I = 0; I < Model.size(); I++) { 18 | const z3::func_decl E = Model[I]; 19 | z3::expr Input = Model.get_const_interp(E); 20 | if (Input.kind() == Z3_NUMERAL_AST) { 21 | int I = Input.get_numeral_int(); 22 | OS << E.name() << "," << I << std::endl; 23 | } 24 | } 25 | } 26 | 27 | void printNewPathCondition(z3::expr_vector &Vec) { 28 | std::ofstream Log; 29 | Log.open(LogFile, std::ofstream::out | std::ofstream::app); 30 | Log << std::endl; 31 | Log << "=== New Path Condition ===" << std::endl; 32 | for (auto E : Vec) { 33 | Log << E << std::endl; 34 | } 35 | } 36 | 37 | void generateInput() { 38 | z3::expr_vector Vec = Ctx.parse_file(FormulaFile); 39 | 40 | while (true) { 41 | searchStrategy(Vec); 42 | 43 | for (const auto &E : Vec) { 44 | Solver.add(E); 45 | } 46 | z3::check_result Result = Solver.check(); 47 | if (Result == z3::sat) { 48 | storeInput(); 49 | printNewPathCondition(Vec); 50 | break; 51 | } 52 | } 53 | } 54 | 55 | int main(int argc, char **argv) { 56 | if (argc < 2) { 57 | std::cerr << "Expected an argument - executable file name" << std::endl; 58 | return 1; 59 | } 60 | 61 | struct stat Buffer; 62 | if (stat(argv[1], &Buffer)) { 63 | std::cerr << argv[1] << " not found\n" << std::endl; 64 | return 1; 65 | } 66 | 67 | int MaxIter = INT_MAX; 68 | if (argc == 3) { 69 | MaxIter = atoi(argv[2]); 70 | } 71 | 72 | int Iter = 0; 73 | while (Iter < MaxIter) { 74 | int Ret = std::system(argv[1]); 75 | if (Ret) { 76 | std::cout << "Crashing input found (" << Iter << " iters)" << std::endl; 77 | break; 78 | } 79 | if (stat(FormulaFile, &Buffer)) { 80 | std::cerr << FormulaFile << " not found" << std::endl; 81 | return 1; 82 | } 83 | generateInput(); 84 | Iter++; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lab11/src/Instrument.cpp: -------------------------------------------------------------------------------- 1 | #include "Instrument.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace instrument { 6 | 7 | /* 8 | * Implement your instrumentation for dynamic symbolic execution engine 9 | */ 10 | bool Instrument::runOnFunction(Function &F) { 11 | /* Add your code here */ 12 | return true; 13 | } 14 | 15 | char Instrument::ID = 1; 16 | static RegisterPass 17 | X("Instrument", "Instrumentations for Dynamic Symbolic Execution", false, 18 | false); 19 | 20 | } // namespace instrument 21 | -------------------------------------------------------------------------------- /lab11/src/Runtime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "llvm/IR/InstrTypes.h" 4 | #include "llvm/IR/Instruction.h" 5 | 6 | #include "SymbolicInterpreter.h" 7 | 8 | extern SymbolicInterpreter SI; 9 | 10 | /* 11 | * Implement your transfer functions. 12 | */ 13 | extern "C" void __DSE_Alloca__(int R, int *Ptr) { /* Add your code here */ } 14 | 15 | extern "C" void __DSE_Store__(int *X) { /* Add your code here */ } 16 | 17 | extern "C" void __DSE_Load__(int Y, int *X) { /* Add your code here */ } 18 | 19 | extern "C" void __DSE_ICmp__(int R, int Op) { /* Add your code here */ } 20 | 21 | extern "C" void __DSE_BinOp__(int R, int Op) { /* Add your code here */ } 22 | -------------------------------------------------------------------------------- /lab11/src/Strategy.cpp: -------------------------------------------------------------------------------- 1 | #include "Strategy.h" 2 | 3 | /* 4 | * Implement your search strategy. 5 | */ 6 | void searchStrategy(z3::expr_vector &OldVec) { /* Add your code here */ } 7 | -------------------------------------------------------------------------------- /lab11/src/SymbolicInterpreter.cpp: -------------------------------------------------------------------------------- 1 | #include "SymbolicInterpreter.h" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &operator<<(std::ostream &OS, const Address &A) { 7 | if (A.Type == A.Memory) { 8 | OS << A.Addr; 9 | } else { 10 | OS << "R" << A.Addr; 11 | } 12 | return OS; 13 | } 14 | 15 | int SymbolicInterpreter::NewInput(int *Ptr, int ID) { 16 | int Ret = 0; 17 | if (Inputs.find(ID) != Inputs.end()) { 18 | Ret = Inputs[ID]; 19 | } else { 20 | Ret = std::rand(); 21 | Inputs[ID] = Ret; 22 | } 23 | Address X(Ptr); 24 | std::string InputName = "X" + std::to_string(NumOfInputs); 25 | z3::expr SE = Ctx.int_const(InputName.c_str()); 26 | Mem.insert(std::make_pair(X, SE)); 27 | NumOfInputs++; 28 | return Ret; 29 | } 30 | 31 | SymbolicInterpreter SI; 32 | 33 | void print(std::ostream &OS) { 34 | OS << "=== Inputs ===" << std::endl; 35 | int Idx = 0; 36 | for (auto &E : SI.getInputs()) { 37 | OS << "X" << E.first << " : " << E.second << std::endl; 38 | } 39 | OS << std::endl; 40 | OS << "=== Symbolic Memory ===" << std::endl; 41 | for (auto &E : SI.getMemory()) { 42 | OS << E.first << " : " << E.second << std::endl; 43 | } 44 | OS << std::endl; 45 | 46 | OS << "=== Path Condition ===" << std::endl; 47 | for (auto &E : SI.getPathCondition()) { 48 | std::string BID = "B" + std::to_string(E.first); 49 | OS << BID << " : " << E.second << std::endl; 50 | } 51 | } 52 | 53 | extern "C" void __DSE_Exit__() { 54 | z3::solver Solver(SI.getContext()); 55 | std::ofstream Branch(BranchFile); 56 | for (auto &E : SI.getPathCondition()) { 57 | std::string BID = "B" + std::to_string(E.first); 58 | Solver.add(E.second); 59 | Branch << BID << "\n"; 60 | } 61 | std::ofstream Smt2(FormulaFile); 62 | Smt2 << Solver.to_smt2(); 63 | std::ofstream Log(LogFile); 64 | print(Log); 65 | } 66 | 67 | extern "C" void __DSE_Init__() { 68 | std::srand(std::time(nullptr)); 69 | std::string Line; 70 | std::ifstream Input(InputFile); 71 | if (Input.is_open()) { 72 | while (getline(Input, Line)) { 73 | int ID = std::stoi(Line.substr(1, Line.find(","))); 74 | int Val = std::stoi(Line.substr(Line.find(",") + 1)); 75 | SI.getInputs()[ID] = Val; 76 | } 77 | } 78 | std::atexit(__DSE_Exit__); 79 | } 80 | 81 | extern "C" void __DSE_Input__(int *X, int ID) { *X = (int)SI.NewInput(X, ID); } 82 | 83 | extern "C" void __DSE_Branch__(int BID, int RID, int B) { 84 | MemoryTy &Mem = SI.getMemory(); 85 | Address Addr(RID); 86 | z3::expr SE = Mem.at(Addr); 87 | z3::expr Cond = 88 | B ? SI.getContext().bool_val(true) : SI.getContext().bool_val(false); 89 | SI.getPathCondition().push_back(std::make_pair(BID, SE == Cond)); 90 | } 91 | 92 | extern "C" void __DSE_Const__(int X) { 93 | z3::expr SE = SI.getContext().int_val(X); 94 | SI.getStack().push(SE); 95 | } 96 | 97 | extern "C" void __DSE_Register__(int X) { 98 | std::string Name = "R" + std::to_string(X); 99 | z3::expr SE = SI.getContext().int_const(Name.c_str()); 100 | SI.getStack().push(SE); 101 | } 102 | -------------------------------------------------------------------------------- /lab11/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll %.instrumented.ll 2 | 3 | TARGETS=simple0 simple1 infeasable branch0 branch1 branch2 4 | 5 | all: ${TARGETS} 6 | 7 | %: %.c 8 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< 9 | opt -load ../build/InstrumentPass.so -Instrument -S $*.ll -o $*.instrumented.ll 10 | clang -o $@ -L${PWD}/../build -lruntime $*.instrumented.ll 11 | 12 | clean: 13 | rm -f *.ll *.out *.err *.smt2 input.txt branch.txt ${TARGETS} 14 | -------------------------------------------------------------------------------- /lab11/test/branch0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | int y; 9 | DSE_Input(y); 10 | int z; 11 | DSE_Input(z); 12 | 13 | if (x == 0) { 14 | if (y == z) { 15 | x = x / (y-z); 16 | } 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /lab11/test/branch1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | int y; 9 | DSE_Input(y); 10 | int z; 11 | DSE_Input(z); 12 | 13 | if (x == y && y == z) { 14 | x = x / (y-z); 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /lab11/test/branch2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | int y; 9 | DSE_Input(y); 10 | int z; 11 | DSE_Input(z); 12 | 13 | if (x > y && y > z && z == 0) { 14 | x = x / z; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /lab11/test/infeasable.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | 9 | //c is a product of two primes 10 | int c = 181 * 191; 11 | 12 | int y = 1; 13 | 14 | for(int i=0; i 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | int y = x; 9 | if (y == 1024) { 10 | int z = 4 / (y - 1024); 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /lab11/test/simple1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/Runtime.h" 4 | 5 | int main() { 6 | int x; 7 | DSE_Input(x); 8 | int y; 9 | DSE_Input(y); 10 | if (x < 0) { 11 | if (y == 1024) { 12 | int z = 4 / (y - 1024); 13 | } 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /lab12/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | set(Z3_DIR $ENV{Z3_DIR}) 11 | get_filename_component(Z3_DIR ${Z3_DIR} ABSOLUTE) 12 | set(Z3_CXX_INCLUDE_DIRS ${Z3_DIR}/include) 13 | set(Z3_LIBRARIES ${Z3_DIR}/bin/libz3.so) 14 | message(STATUS "Z3_DIR: ${Z3_DIR}") 15 | 16 | add_definitions(${LLVM_DEFINITIONS}) 17 | include_directories(${LLVM_INCLUDE_DIRS} include) 18 | include_directories(${Z3_CXX_INCLUDE_DIRS}) 19 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) 20 | 21 | add_executable(verifier 22 | src/Verifier.cpp 23 | src/Extractor.cpp 24 | src/Utils.cpp 25 | ) 26 | 27 | llvm_map_components_to_libnames(llvm_libs support core irreader) 28 | 29 | target_link_libraries(verifier ${llvm_libs} ${Z3_LIBRARIES}) 30 | -------------------------------------------------------------------------------- /lab12/include/Extractor.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTRACTOR_H 2 | #define EXTRACTOR_H 3 | 4 | #include "z3++.h" 5 | #include "llvm/ADT/MapVector.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/IR/Type.h" 9 | #include 10 | 11 | #include "Utils.h" 12 | 13 | using namespace llvm; 14 | 15 | using InstMapTy = std::map; 16 | using DefMapTy = std::map>; 17 | 18 | class Extractor { 19 | public: 20 | Extractor() : AllVariableVector(C), Queries(C) { 21 | Solver = new z3::fixedpoint(C); 22 | Params = new z3::params(C); 23 | Params->set("engine", "spacer"); 24 | Solver->set(*Params); 25 | } 26 | 27 | ~Extractor() { 28 | delete Solver; 29 | delete Params; 30 | } 31 | 32 | z3::fixedpoint *getSolver() { return Solver; } 33 | z3::context &getContext() { return C; } 34 | z3::func_decl_vector &getQueries() { return Queries; } 35 | 36 | void initialize(Function &F); 37 | void extractConstraints(Instruction *I, z3::expr_vector &Assertions); 38 | void extractConstraints(BasicBlock *BB); 39 | void addQuery(z3::func_decl &Q) { Queries.push_back(Q); } 40 | z3::expr_vector transition(BasicBlock *BB, BasicBlock *Succ); 41 | 42 | private: 43 | z3::context C; 44 | z3::fixedpoint *Solver; 45 | z3::params *Params; 46 | z3::check_result Result; 47 | z3::func_decl_vector Queries; 48 | std::map> FreeVariables; 49 | std::map BBRelations; 50 | std::map FreeVariableVector; 51 | z3::expr_vector AllVariableVector; 52 | }; 53 | 54 | #endif // EXTRACTOR_H 55 | -------------------------------------------------------------------------------- /lab12/include/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "llvm/IR/Instructions.h" 5 | 6 | using namespace llvm; 7 | 8 | std::string toString(Value *I); 9 | 10 | bool isAssertFail(CallInst *CI); 11 | 12 | bool isAssume(CallInst *CI); 13 | 14 | #endif // UTILS_H 15 | -------------------------------------------------------------------------------- /lab12/include/Verifier.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int input(); 4 | extern void assume(int); 5 | -------------------------------------------------------------------------------- /lab12/src/Extractor.cpp: -------------------------------------------------------------------------------- 1 | #include "Extractor.h" 2 | 3 | #include "llvm/IR/CFG.h" 4 | #include "llvm/IR/Instruction.h" 5 | 6 | #include "Utils.h" 7 | 8 | /* Implement your extractor */ 9 | void Extractor::extractConstraints(Instruction *I, 10 | z3::expr_vector &Assertions) { 11 | /* Add your code here */ 12 | } 13 | 14 | void Extractor::initialize(Function &F) { /* Add your code here */ } 15 | 16 | z3::expr_vector Extractor::transition(BasicBlock *BB, BasicBlock *Succ) { 17 | z3::expr_vector Vec(C); 18 | /* Add your code here */ 19 | return Vec; 20 | } 21 | 22 | void Extractor::extractConstraints(BasicBlock *BB) { /* Add your code here */ } 23 | -------------------------------------------------------------------------------- /lab12/src/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | 3 | #include "llvm/IR/CFG.h" 4 | 5 | const char *WhiteSpaces = " \t\n\r"; 6 | 7 | std::string toString(Value *I) { 8 | std::string Str; 9 | raw_string_ostream SS(Str); 10 | I->print(SS); 11 | Str.erase(0, Str.find_first_not_of(WhiteSpaces)); 12 | return SS.str().substr(0, Str.find(" =")); 13 | } 14 | 15 | bool isAssertFail(CallInst *CI) { 16 | return CI->getCalledFunction()->getName().equals("__assert_fail"); 17 | } 18 | 19 | bool isAssume(CallInst *CI) { 20 | return CI->getCalledFunction()->getName().equals("assume"); 21 | } 22 | -------------------------------------------------------------------------------- /lab12/src/Verifier.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/AsmParser/Parser.h" 2 | #include "llvm/IR/InstIterator.h" 3 | #include "llvm/IR/Module.h" 4 | #include "llvm/Support/SourceMgr.h" 5 | #include 6 | 7 | #include "Extractor.h" 8 | 9 | using namespace llvm; 10 | 11 | int main(int argc, char **argv) { 12 | if (argc > 3) { 13 | errs() << "Expected an argument - IR file name\n"; 14 | exit(1); 15 | } 16 | 17 | LLVMContext Context; 18 | SMDiagnostic Err; 19 | StringRef FileName(argv[1]); 20 | 21 | std::unique_ptr Mod = parseAssemblyFile(FileName, Err, Context); 22 | 23 | if (!Mod) { 24 | Err.print(argv[0], errs()); 25 | return 1; 26 | } 27 | 28 | Extractor Ext; 29 | z3::fixedpoint *Solver = Ext.getSolver(); 30 | z3::context &C = Ext.getContext(); 31 | 32 | for (auto &F : *Mod) { 33 | if (F.size() == 0) 34 | continue; 35 | Ext.initialize(F); 36 | for (auto &BB : F) { 37 | Ext.extractConstraints(&BB); 38 | } 39 | } 40 | 41 | std::ofstream smt2("formula.smt2"); 42 | smt2 << Solver->to_string() << std::endl; 43 | smt2 << ";;; query" << std::endl; 44 | 45 | for (int I = 0; I < Ext.getQueries().size(); I++) { 46 | smt2 << "(query " << Ext.getQueries()[I].name().str() << ")" << std::endl; 47 | } 48 | 49 | z3::check_result R = Solver->query(Ext.getQueries()); 50 | std::cout << R << std::endl; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /lab12/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll %.opt.ll 2 | 3 | TARGETS=simple0 simple1 simple2 4 | 5 | all: ${TARGETS} 6 | 7 | %: %.c 8 | clang -emit-llvm -S -fno-discard-value-names -Xclang -disable-O0-optnone -c -o $@.ll $< 9 | opt -mem2reg -S $*.ll -o $*.opt.ll 10 | 11 | clean: 12 | rm -f *.ll *.out *.err *.smt2 input.txt branch.txt ${TARGETS} 13 | -------------------------------------------------------------------------------- /lab12/test/simple0.c: -------------------------------------------------------------------------------- 1 | #include "../include/Verifier.h" 2 | 3 | int main() { 4 | int x = input(); 5 | assume(x > 10); 6 | while (x > 0) { 7 | x = x - 1; 8 | } 9 | assert(x == 0); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /lab12/test/simple1.c: -------------------------------------------------------------------------------- 1 | #include "../include/Verifier.h" 2 | 3 | int main() { 4 | int n, k, j; 5 | n = input(); 6 | assume(n > 0); 7 | k = input(); 8 | assume(k > n); 9 | j = 0; 10 | while (j < n) { 11 | j++; 12 | k--; 13 | } 14 | assert(k >= 0); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /lab12/test/simple2.c: -------------------------------------------------------------------------------- 1 | #include "../include/Verifier.h" 2 | 3 | int main() { 4 | int n, k, j; 5 | n = input(); 6 | k = input(); 7 | assume(k >= 2); 8 | j = 0; 9 | while (j < n) { 10 | j++; 11 | k--; 12 | } 13 | assert(k >= 3); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /lab12/test/test.c: -------------------------------------------------------------------------------- 1 | extern int input(); 2 | int main() { 3 | int x = input(); 4 | int y; 5 | if (x > 0) 6 | y = 0; 7 | else 8 | y = x; 9 | return y; 10 | } 11 | -------------------------------------------------------------------------------- /lab12/test/test2.c: -------------------------------------------------------------------------------- 1 | #include "../include/Verifier.h" 2 | 3 | int main() { 4 | int x = input(); 5 | assume(x > 1); 6 | assert(x > 0); 7 | return x; 8 | } 9 | -------------------------------------------------------------------------------- /lab2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS}) 13 | 14 | add_llvm_library(InstrumentPass MODULE 15 | src/Instrument.cpp 16 | ) 17 | 18 | add_library(runtime MODULE 19 | lib/runtime.c 20 | ) 21 | -------------------------------------------------------------------------------- /lab2/include/Instrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | struct Instrument : public FunctionPass { 13 | static char ID; 14 | static const char *checkFunctionName; 15 | 16 | Instrument() : FunctionPass(ID) {} 17 | 18 | bool runOnFunction(Function &F) override; 19 | }; 20 | } // namespace instrument 21 | -------------------------------------------------------------------------------- /lab2/lib/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __dbz_sanitizer__(int divisor, int line, int col) { 7 | if (divisor == 0) { 8 | printf("Divide-by-zero detected at line %d and col %d\n", line, col); 9 | exit(1); 10 | } 11 | } 12 | 13 | void __coverage__(int line, int col) { 14 | char exe[1024]; 15 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 16 | if (ret == -1) { 17 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 18 | exit(1); 19 | } 20 | exe[ret] = 0; 21 | 22 | char logfile[1024]; 23 | int len = strlen(exe); 24 | strncpy(logfile, exe, len); 25 | logfile[len] = 0; 26 | strcat(logfile, ".cov"); 27 | FILE *f = fopen(logfile, "a"); 28 | fprintf(f, "%d,%d\n", line, col); 29 | fclose(f); 30 | } 31 | -------------------------------------------------------------------------------- /lab2/src/Instrument.cpp: -------------------------------------------------------------------------------- 1 | #include "Instrument.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace instrument { 6 | 7 | static const char *SanitizerFunctionName = "__dbz_sanitizer__"; 8 | static const char *CoverageFunctionName = "__coverage__"; 9 | 10 | /* 11 | * Implement divide-by-zero sanitizer. 12 | */ 13 | void instrumentSanitizer(Module *M, Function &F, Instruction &I) { 14 | /* Add you code here */ 15 | } 16 | 17 | /* 18 | * Implement code coverage instrumentation. 19 | */ 20 | void instrumentCoverage(Module *M, Function &F, Instruction &I) { 21 | /* Add you code here */ 22 | } 23 | 24 | bool Instrument::runOnFunction(Function &F) { 25 | /* Add you code here */ 26 | return true; 27 | } 28 | 29 | char Instrument::ID = 1; 30 | static RegisterPass 31 | X("Instrument", "Instrumentations for Dynamic Analysis", false, false); 32 | 33 | } // namespace instrument 34 | -------------------------------------------------------------------------------- /lab2/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=simple0 simple1 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< -g 7 | opt -load ../build/InstrumentPass.so -Instrument -S $@.ll -o $@.instrumented.ll 8 | clang -o $@ -L${PWD}/../build -lruntime $@.instrumented.ll 9 | 10 | clean: 11 | rm -f *.ll *.cov ${TARGETS} 12 | -------------------------------------------------------------------------------- /lab2/test/calc.c: -------------------------------------------------------------------------------- 1 | # include 2 | int main() { 3 | char operator; 4 | int firstNumber,secondNumber; 5 | 6 | do { 7 | printf("Enter an operator (+, -, *, /): "); 8 | scanf(" %c", &operator); 9 | printf("Enter two operands: "); 10 | scanf("%d %d", &firstNumber, &secondNumber); 11 | switch (operator) { 12 | case '+': 13 | printf("%d + %d = %d\n",firstNumber, secondNumber, firstNumber + secondNumber); 14 | break; 15 | case '-': 16 | printf("%d - %d = %d\n",firstNumber, secondNumber, firstNumber - secondNumber); 17 | break; 18 | case '*': 19 | printf("%d * %d = %d\n",firstNumber, secondNumber, firstNumber * secondNumber); 20 | break; 21 | case '/': 22 | printf("%d / %d = %d\n",firstNumber, secondNumber, firstNumber / secondNumber); // Divide by zero 23 | break; 24 | default: 25 | printf("Error! operator is not correct"); 26 | } 27 | } while(1); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /lab2/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | int y = x; 4 | int z = y / x; // Divide by zero 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /lab2/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | if (argc > 2) { 3 | int x = 0; 4 | int y = x; 5 | int z = y / x; // Divide by zero 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab2/test/simple2.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | z = y / x; // divide-by-zero within branch 7 | } else { 8 | z = z / x; 9 | } 10 | } 11 | 12 | int main() { 13 | f(); 14 | } 15 | -------------------------------------------------------------------------------- /lab2/test/simple3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | int d = 5; 5 | int c = a == b; 6 | int e = d / (c * 0); // divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab2/test/simple4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a, b; 3 | int c = 0; 4 | b = c; 5 | a = b; 6 | int d = a / c; // Divide by zero 7 | c = c + 1; 8 | c = c * 0; 9 | int e = a / c; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /lab2/test/simple5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int y = 1, z = 1; 5 | int un; 6 | scanf("%d", &un); 7 | int x = un + 1; 8 | z = y / x; // Divide by zero 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab2/test/simple6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int u1 = fgetc(stdin); 5 | int u2 = 4, d; 6 | if (u1 != 0) { 7 | d = u2 / u1; 8 | } else { 9 | int d = u2 / (u1 + 1); 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /lab2/test/simple7.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int x = 0, y, z; 5 | scanf("%d%d", &y, &x); 6 | if (y > 10) 7 | y = 0; 8 | else 9 | y = 1; 10 | if (x < 1) { 11 | z = y / x; // divide-by-zero 12 | } 13 | } 14 | 15 | int main() { 16 | f(); 17 | } 18 | -------------------------------------------------------------------------------- /lab2/test/simple8.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int x = 2 * fgetc(stdin) - 180; 5 | int y = 5 / x; // Divide by zero 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /lab2/test/simple9.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int i, a = 0, b = fgetc(stdin); 5 | for (i = 10000; i > 0; i--) 6 | printf("%d\n", b * b / (i - b)); // Divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SRC_DIR}/reference) 13 | 14 | add_executable(fuzzer 15 | src/Fuzzer.cpp 16 | src/Mutate.cpp 17 | ) 18 | 19 | add_library(runtime MODULE 20 | lib/runtime.c 21 | ) 22 | 23 | add_custom_target(reference ALL 24 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/* ${CMAKE_CURRENT_BINARY_DIR}/ 25 | ) 26 | -------------------------------------------------------------------------------- /lab3/include/Instrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | struct Instrument : public FunctionPass { 13 | static char ID; 14 | static const char *checkFunctionName; 15 | 16 | Instrument() : FunctionPass(ID) {} 17 | 18 | bool runOnFunction(Function &F) override; 19 | }; 20 | } // namespace instrument 21 | -------------------------------------------------------------------------------- /lab3/include/Mutate.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum Campaign { MutationA, MutationB, MutationC }; 4 | 5 | std::string mutate(std::string Origin, Campaign &FuzzCamp); 6 | 7 | bool toCampaign(std::string Str, Campaign &FuzzCampaign); 8 | -------------------------------------------------------------------------------- /lab3/include/Utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | std::string readOneFile(std::string &Path) { 12 | std::ifstream SeedFile(Path); 13 | std::string Line((std::istreambuf_iterator(SeedFile)), 14 | std::istreambuf_iterator()); 15 | return Line; 16 | } 17 | 18 | int runTarget(std::string &Target, std::string &Input) { 19 | std::string Cmd = Target + " > /dev/null 2>&1"; 20 | FILE *F = popen(Cmd.c_str(), "w"); 21 | fprintf(F, "%s", Input.c_str()); 22 | return pclose(F); 23 | } 24 | 25 | std::vector SeedInputs; 26 | 27 | int readSeedInputs(std::string &SeedInputDir) { 28 | DIR *Directory; 29 | struct dirent *Ent; 30 | if ((Directory = opendir(SeedInputDir.c_str())) != NULL) { 31 | while ((Ent = readdir(Directory)) != NULL) { 32 | if (!(Ent->d_type == DT_REG)) 33 | continue; 34 | std::string Path = SeedInputDir + "/" + std::string(Ent->d_name); 35 | std::string Line = readOneFile(Path); 36 | SeedInputs.push_back(Line); 37 | } 38 | closedir(Directory); 39 | return 0; 40 | } else { 41 | return 1; 42 | } 43 | } 44 | 45 | int successCount = 1; 46 | int failureCount = 1; 47 | 48 | void initialize(std::string &OutDir) { 49 | int Status; 50 | std::string SuccessDir = OutDir + "/success"; 51 | std::string FailureDir = OutDir + "/failure"; 52 | mkdir(SuccessDir.c_str(), 0755); 53 | mkdir(FailureDir.c_str(), 0755); 54 | } 55 | 56 | void storePassingInput(std::string &Input, std::string &CampaignStr, std::string &OutDir) { 57 | std::string Path = OutDir + "/success/input" + std::to_string(successCount++) + "-" + CampaignStr; 58 | std::ofstream OutFile(Path); 59 | OutFile << Input; 60 | OutFile.close(); 61 | } 62 | 63 | void storeCrashingInput(std::string &Input, std::string &CampaignStr, std::string &OutDir) { 64 | std::string Path = OutDir + "/failure/input" + std::to_string(failureCount++) + "-" + CampaignStr; 65 | std::ofstream OutFile(Path); 66 | OutFile << Input; 67 | OutFile.close(); 68 | } 69 | -------------------------------------------------------------------------------- /lab3/lib/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __dbz_sanitizer__(int divisor, int line, int col) { 7 | if (divisor == 0) { 8 | printf("Divide-by-zero detected at line %d and col %d\n", line, col); 9 | exit(1); 10 | } 11 | } 12 | 13 | void __coverage__(int line, int col) { 14 | char exe[1024]; 15 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 16 | if (ret == -1) { 17 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 18 | exit(1); 19 | } 20 | exe[ret] = 0; 21 | 22 | char logfile[1024]; 23 | int len = strlen(exe); 24 | strncpy(logfile, exe, len); 25 | logfile[len] = 0; 26 | strcat(logfile, ".cov"); 27 | FILE *f = fopen(logfile, "a"); 28 | fprintf(f, "%d,%d\n", line, col); 29 | fclose(f); 30 | } 31 | -------------------------------------------------------------------------------- /lab3/reference/InstrumentPass.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/reference/InstrumentPass.so -------------------------------------------------------------------------------- /lab3/src/Fuzzer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Mutate.h" 8 | #include "Utils.h" 9 | 10 | int Freq = 1000000; 11 | int Count = 0; 12 | 13 | bool test(std::string &Target, std::string &Input, std::string &CampaignStr, std::string &OutDir) { 14 | Count++; 15 | int ReturnCode = runTarget(Target, Input); 16 | switch (ReturnCode) { 17 | case 0: 18 | if (Count % Freq == 0) 19 | storePassingInput(Input, CampaignStr, OutDir); 20 | return true; 21 | case 256: 22 | fprintf(stderr, "%d crashes found\n", failureCount); 23 | storeCrashingInput(Input, CampaignStr, OutDir); 24 | return false; 25 | case 127: 26 | fprintf(stderr, "%s not found\n", Target.c_str()); 27 | exit(1); 28 | } 29 | } 30 | 31 | // ./fuzzer [exe file] [seed input dir] [output dir] 32 | int main(int argc, char **argv) { 33 | if (argc < 5) { 34 | printf("usage %s [exe file] [seed input dir] [output dir] [campaign]\n", argv[0]); 35 | return 1; 36 | } 37 | 38 | struct stat Buffer; 39 | if (stat(argv[1], &Buffer)) { 40 | fprintf(stderr, "%s not found\n", argv[1]); 41 | return 1; 42 | } 43 | 44 | if (stat(argv[2], &Buffer)) { 45 | fprintf(stderr, "%s not found\n", argv[2]); 46 | return 1; 47 | } 48 | 49 | if (stat(argv[3], &Buffer)) { 50 | fprintf(stderr, "%s not found\n", argv[3]); 51 | return 1; 52 | } 53 | 54 | if (argc >= 6) { 55 | Freq = strtol(argv[5],NULL,10); 56 | } 57 | 58 | std::string Target(argv[1]); 59 | std::string SeedInputDir(argv[2]); 60 | std::string OutDir(argv[3]); 61 | 62 | std::string CampaignStr(argv[4]); 63 | Campaign FuzzCampaign; 64 | if (!toCampaign(CampaignStr, FuzzCampaign)) { 65 | return 1; 66 | } 67 | 68 | initialize(OutDir); 69 | 70 | if (readSeedInputs(SeedInputDir)) { 71 | fprintf(stderr, "Cannot read seed input directory\n"); 72 | return 1; 73 | } 74 | 75 | while (true) { 76 | for (auto i = 0; i < SeedInputs.size(); i++) { 77 | auto I = SeedInputs[i]; 78 | std::string Mutant = mutate(I, FuzzCampaign); 79 | test(Target, Mutant, CampaignStr, OutDir); 80 | SeedInputs.push_back(Mutant); 81 | } 82 | } 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /lab3/src/Mutate.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutate.h" 2 | 3 | #include 4 | #include 5 | 6 | std::map to_campaign = 7 | {{"MutationA", MutationA}, {"MutationB", MutationB}, {"MutationC", MutationC}}; 8 | 9 | bool toCampaign(std::string Str, Campaign& FuzzCampaign) { 10 | auto I = to_campaign.find(Str); 11 | if (I == to_campaign.end()) { 12 | fprintf(stderr, "\"%s\" not a valid fuzz campaign, choice options are: ", Str.c_str()); 13 | for (auto &I2 : to_campaign) { 14 | fprintf(stderr, "%s ", I2.first.c_str()); 15 | } 16 | fprintf(stderr, "\n"); 17 | return false; 18 | } 19 | FuzzCampaign = I->second; 20 | return true; 21 | } 22 | 23 | /* 24 | * Implement your mutation algorithms. 25 | */ 26 | 27 | std::string mutateA(std::string Origin) { 28 | return Origin; 29 | } 30 | 31 | std::string mutateB(std::string Origin) { 32 | return Origin; 33 | } 34 | 35 | std::string mutateC(std::string Origin) { 36 | return Origin; 37 | } 38 | 39 | std::string mutate(std::string Origin, Campaign& FuzzCampaign) { 40 | std::string Mutant; 41 | switch (FuzzCampaign) { 42 | case MutationA: 43 | return mutateA(Origin); 44 | case MutationB: 45 | return mutateB(Origin); 46 | case MutationC: 47 | return mutateC(Origin); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lab3/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=sanity easy easy2 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< -g 7 | opt -load ../build/InstrumentPass.so -Instrument -S $@.ll > $@.instrumented.ll 8 | clang -o $@ -L${PWD}/../build -lruntime $@.instrumented.ll 9 | 10 | clean: 11 | rm -f *.ll *.cov ${TARGETS} 12 | -------------------------------------------------------------------------------- /lab3/test/easy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/easy -------------------------------------------------------------------------------- /lab3/test/easy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) % 7 == 0) { 11 | z = y / x; 12 | } 13 | 14 | if (strlen(input) % 13 == 0) { 15 | z = y / ++x; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /lab3/test/easy2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/easy2 -------------------------------------------------------------------------------- /lab3/test/easy2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 13; 8 | int z = 21; 9 | 10 | if (strlen(input) % 13 == 0) { 11 | z = x / 0; 12 | } 13 | 14 | if (strlen(input) > 100 && input[25] == 'a') { 15 | z = x / 0; 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /lab3/test/fuzz_input/seed.txt: -------------------------------------------------------------------------------- 1 | When, in the course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the laws of nature and of nature’s God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation. We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable rights, that among these are life, liberty and the pursuit of happiness. 2 | -------------------------------------------------------------------------------- /lab3/test/hidden1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/hidden1 -------------------------------------------------------------------------------- /lab3/test/hidden2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/hidden2 -------------------------------------------------------------------------------- /lab3/test/hidden3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/hidden3 -------------------------------------------------------------------------------- /lab3/test/sanity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab3/test/sanity -------------------------------------------------------------------------------- /lab3/test/sanity.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char input[65536]; 5 | fgets(input, sizeof(input), stdin); 6 | int x = 0; 7 | int y = 2; 8 | int z = y / x; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | option(USE_REFERENCE "Build with reference solution" OFF) 11 | 12 | add_definitions(${LLVM_DEFINITIONS}) 13 | include_directories(${LLVM_INCLUDE_DIRS} include) 14 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/reference) 15 | 16 | if (USE_REFERENCE) 17 | message(STATUS "Use reference solution") 18 | add_executable(fuzzer 19 | src/Fuzzer.cpp 20 | ) 21 | add_custom_target(RefMutate ALL 22 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/libMutate.so ${CMAKE_CURRENT_BINARY_DIR}/ 23 | ) 24 | target_link_libraries(fuzzer Mutate) 25 | else (USE_REFERENCE) 26 | add_executable(fuzzer 27 | src/Fuzzer.cpp 28 | src/Mutate.cpp 29 | ) 30 | endif (USE_REFERENCE) 31 | 32 | add_custom_target(Instrument ALL 33 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/InstrumentPass.so ${CMAKE_CURRENT_BINARY_DIR}/ 34 | ) 35 | 36 | add_library(runtime MODULE 37 | lib/runtime.c 38 | ) 39 | -------------------------------------------------------------------------------- /lab4/include/Instrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | struct Instrument : public FunctionPass { 13 | static char ID; 14 | static const char *checkFunctionName; 15 | 16 | Instrument() : FunctionPass(ID) {} 17 | 18 | bool runOnFunction(Function &F) override; 19 | }; 20 | } // namespace instrument 21 | -------------------------------------------------------------------------------- /lab4/include/Mutate.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum Campaign { MutationA, MutationB, MutationC, NumCampaigns }; 5 | 6 | std::string mutate(std::string Origin, Campaign &FuzzCamp); 7 | 8 | bool toCampaign(std::string Str, Campaign &FuzzCamp); 9 | -------------------------------------------------------------------------------- /lab4/include/Utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | std::string readOneFile(std::string &Path) { 12 | std::ifstream SeedFile(Path); 13 | std::string Line((std::istreambuf_iterator(SeedFile)), 14 | std::istreambuf_iterator()); 15 | return Line; 16 | } 17 | 18 | int runTarget(std::string &Target, std::string &Input) { 19 | std::string Cmd = Target + " > /dev/null 2>&1"; 20 | FILE *F = popen(Cmd.c_str(), "w"); 21 | fprintf(F, "%s", Input.c_str()); 22 | return pclose(F); 23 | } 24 | 25 | std::map> SeedInputs; 26 | 27 | int readSeedInputs(std::string &SeedInputDir) { 28 | DIR *Directory; 29 | struct dirent *Ent; 30 | if ((Directory = opendir(SeedInputDir.c_str())) != NULL) { 31 | while ((Ent = readdir(Directory)) != NULL) { 32 | if (!(Ent->d_type == DT_REG)) 33 | continue; 34 | std::string Path = SeedInputDir + "/" + std::string(Ent->d_name); 35 | std::string Line = readOneFile(Path); 36 | SeedInputs[MutationA].push_back(Line); 37 | SeedInputs[MutationB].push_back(Line); 38 | SeedInputs[MutationC].push_back(Line); 39 | } 40 | closedir(Directory); 41 | return 0; 42 | } else { 43 | return 1; 44 | } 45 | } 46 | 47 | int successCount = 1; 48 | int failureCount = 1; 49 | 50 | void initialize(std::string &OutDir) { 51 | int Status; 52 | std::string SuccessDir = OutDir + "/success"; 53 | std::string FailureDir = OutDir + "/failure"; 54 | mkdir(SuccessDir.c_str(), 0755); 55 | mkdir(FailureDir.c_str(), 0755); 56 | } 57 | 58 | void storePassingInput(std::string &Input, const std::string &CampaignStr, std::string &OutDir) { 59 | std::string Path = OutDir + "/success/input" + std::to_string(successCount++) + "-" + CampaignStr; 60 | std::ofstream OutFile(Path); 61 | OutFile << Input; 62 | OutFile.close(); 63 | } 64 | 65 | void storeCrashingInput(std::string &Input, const std::string &CampaignStr, std::string &OutDir) { 66 | std::string Path = OutDir + "/failure/input" + std::to_string(failureCount++) + "-" + CampaignStr; 67 | std::ofstream OutFile(Path); 68 | OutFile << Input; 69 | OutFile.close(); 70 | } 71 | -------------------------------------------------------------------------------- /lab4/lib/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __dbz_sanitizer__(int divisor, int line, int col) { 7 | if (divisor == 0) { 8 | printf("Divide-by-zero detected at line %d and col %d\n", line, col); 9 | exit(1); 10 | } 11 | } 12 | 13 | void __coverage__(int line, int col) { 14 | char exe[1024]; 15 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 16 | if (ret == -1) { 17 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 18 | exit(1); 19 | } 20 | exe[ret] = 0; 21 | 22 | char logfile[1024]; 23 | int len = strlen(exe); 24 | strncpy(logfile, exe, len); 25 | logfile[len] = 0; 26 | strcat(logfile, ".cov"); 27 | FILE *f = fopen(logfile, "a"); 28 | fprintf(f, "%d,%d\n", line, col); 29 | fclose(f); 30 | } 31 | -------------------------------------------------------------------------------- /lab4/reference/InstrumentPass.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab4/reference/InstrumentPass.so -------------------------------------------------------------------------------- /lab4/reference/libMutate.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab4/reference/libMutate.so -------------------------------------------------------------------------------- /lab4/src/Fuzzer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Mutate.h" 9 | #include "Utils.h" 10 | 11 | #include 12 | 13 | std::string CampaignToStr(Campaign &FuzzCamp) { 14 | switch (FuzzCamp) { 15 | case MutationA: 16 | return "MutationA"; 17 | case MutationB: 18 | return "MutationB"; 19 | case MutationC: 20 | return "MutationC"; 21 | } 22 | } 23 | 24 | 25 | /* 26 | * Implement your feedback-directed seed update algorithm. 27 | */ 28 | std::pair selectSeedAndCampaign() { 29 | 30 | std::string Seed = SeedInputs[MutationA].back(); 31 | Campaign FuzzCamp = MutationA; 32 | 33 | return std::make_pair(Seed,FuzzCamp); 34 | } 35 | 36 | /* 37 | * Implement your feedback-directed seed update algorithm. 38 | */ 39 | void updateSeedInputs(std::string &Target, std::string &Mutated, Campaign &FuzzCamp, bool Success) { 40 | } 41 | 42 | int Freq = 1000; 43 | int Count = 0; 44 | 45 | bool test(std::string &Target, std::string &Input, Campaign &FuzzCamp, std::string &OutDir) { 46 | // Clean up old coverage file before running 47 | std::string CoveragePath = Target + ".cov"; 48 | std::remove(CoveragePath.c_str()); 49 | Count++; 50 | 51 | int ReturnCode = runTarget(Target, Input); 52 | switch (ReturnCode) { 53 | case 0: 54 | if (Count % Freq == 0) 55 | storePassingInput(Input, CampaignToStr(FuzzCamp), OutDir); 56 | return true; 57 | case 256: 58 | fprintf(stderr, "%d crashes found\n", failureCount); 59 | storeCrashingInput(Input, CampaignToStr(FuzzCamp), OutDir); 60 | return false; 61 | case 127: 62 | fprintf(stderr, "%s not found\n", Target.c_str()); 63 | exit(1); 64 | } 65 | } 66 | 67 | // ./fuzzer [exe file] [seed input dir] [output dir] 68 | int main(int argc, char **argv) { 69 | if (argc < 4) { 70 | printf("usage %s [exe file] [seed input dir] [output dir]\n", argv[0]); 71 | return 1; 72 | } 73 | 74 | srand(time(NULL)); 75 | 76 | struct stat Buffer; 77 | if (stat(argv[1], &Buffer)) { 78 | fprintf(stderr, "%s not found\n", argv[1]); 79 | return 1; 80 | } 81 | 82 | if (stat(argv[2], &Buffer)) { 83 | fprintf(stderr, "%s not found\n", argv[2]); 84 | return 1; 85 | } 86 | 87 | if (stat(argv[3], &Buffer)) { 88 | fprintf(stderr, "%s not found\n", argv[3]); 89 | return 1; 90 | } 91 | 92 | if (argc >= 5) { 93 | Freq = strtol(argv[5], NULL, 10); 94 | } 95 | 96 | std::string Target(argv[1]); 97 | std::string SeedInputDir(argv[2]); 98 | std::string OutDir(argv[3]); 99 | 100 | initialize(OutDir); 101 | 102 | if (readSeedInputs(SeedInputDir)) { 103 | fprintf(stderr, "Cannot read seed input directory\n"); 104 | return 1; 105 | } 106 | 107 | while (true) { 108 | // NOTE: You should feel free to manipulate this run loop 109 | std::pair SC = selectSeedAndCampaign(); 110 | auto Mutant = mutate(SC.first, SC.second); 111 | auto Success = test(Target, Mutant, SC.second, OutDir); 112 | updateSeedInputs(Target, Mutant, SC.second, Success); 113 | } 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /lab4/src/Mutate.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutate.h" 2 | 3 | #include 4 | #include 5 | 6 | /* 7 | * Implement your mutation algorithm. 8 | */ 9 | 10 | std::map to_campaign = { 11 | {"MutationA", MutationA}, 12 | {"MutationB", MutationB}, 13 | {"MutationC", MutationC}, 14 | }; 15 | 16 | bool toCampaign(std::string Str, Campaign& FuzzCampaign) { 17 | auto I = to_campaign.find(Str); 18 | if (I == to_campaign.end()) { 19 | fprintf(stderr, "\"%s\" not a valid fuzz campaign, choice options are: ", Str.c_str()); 20 | for (auto &I2 : to_campaign) { 21 | fprintf(stderr, "%s ", I2.first.c_str()); 22 | } 23 | fprintf(stderr, "\n"); 24 | return false; 25 | } 26 | FuzzCampaign = I->second; 27 | return true; 28 | } 29 | 30 | std::string mutateA(std::string Origin) { 31 | return Origin; 32 | } 33 | 34 | std::string mutateB(std::string Origin) { 35 | return Origin; 36 | } 37 | 38 | std::string mutateC(std::string Origin) { 39 | return Origin; 40 | } 41 | 42 | std::string mutate(std::string Origin, Campaign& FuzzCampaign) { 43 | std::string Mutant; 44 | switch (FuzzCamp) { 45 | case MutationA: 46 | return mutateA(Origin); 47 | case MutationB: 48 | return mutateB(Origin); 49 | case MutationC: 50 | return mutateC(Origin); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lab4/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=sanity easy easy2 path path2 path3 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< -g 7 | opt -load ../build/InstrumentPass.so -Instrument -S $@.ll > $@.instrumented.ll 8 | clang -o $@ -L${PWD}/../build -lruntime $@.instrumented.ll 9 | 10 | clean: 11 | rm -f *.ll *.cov ${TARGETS} 12 | -------------------------------------------------------------------------------- /lab4/test/easy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) % 7 == 0) { 11 | z = y / x; 12 | } 13 | 14 | if (strlen(input) % 13 == 0) { 15 | z = y / ++x; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /lab4/test/easy2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 13; 8 | int z = 21; 9 | 10 | if (strlen(input) % 13 == 0) { 11 | z = x / 0; 12 | } 13 | 14 | if (strlen(input) > 100 && input[25] == 'a') { 15 | z = x / 0; 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /lab4/test/fuzz_input/seed.txt: -------------------------------------------------------------------------------- 1 | When, in the course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the laws of nature and of nature’s God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation. We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable rights, that among these are life, liberty and the pursuit of happiness. 2 | -------------------------------------------------------------------------------- /lab4/test/hidden1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab4/test/hidden1 -------------------------------------------------------------------------------- /lab4/test/hidden2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab4/test/hidden2 -------------------------------------------------------------------------------- /lab4/test/hidden3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab4/test/hidden3 -------------------------------------------------------------------------------- /lab4/test/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) > 50) { 11 | if (strlen(input) > 60) { 12 | if (strlen(input) > 70) { 13 | if (strlen(input) > 80) { 14 | if (strlen(input) > 90) { 15 | if (strlen(input) > 100) { 16 | if (strlen(input) > 110) { 17 | if (strlen(input) > 120) { 18 | if (strlen(input) > 130) { 19 | if (strlen(input) > 140) { 20 | z = y / x; 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /lab4/test/path2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) > 50) { 11 | if (strlen(input) > 60) { 12 | if (strlen(input) > 70) { 13 | if (strlen(input) > 80) { 14 | if (strlen(input) > 90) { 15 | if (strlen(input) > 100) { 16 | if (strlen(input) > 110) { 17 | if (strlen(input) > 120) { 18 | if (strlen(input) > 130) { 19 | if (strlen(input) > 140) { 20 | if (strlen(input) > 150) { 21 | if (strlen(input) > 160) { 22 | if (strlen(input) > 170) { 23 | if (strlen(input) > 180) { 24 | if (strlen(input) > 190) { 25 | if (strlen(input) > 200) { 26 | if (strlen(input) > 210) { 27 | if (strlen(input) > 220) { 28 | if (strlen(input) > 230) { 29 | if (strlen(input) > 240) { 30 | if (input[25] == 'a' || input[25] == 'b' || input[25] == 'c') { 31 | z = y / x; 32 | } 33 | } } } } } } } } } } } } } } } } } } } } 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /lab4/test/path3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int x, y, z; 6 | char buf0[6000], buf1[6000], buf2[6000]; 7 | int a = 0; 8 | int r = 43; 9 | 10 | fgets(buf0, sizeof(buf0), stdin); 11 | fgets(buf1, sizeof(buf1), stdin); 12 | fgets(buf2, sizeof(buf2), stdin); 13 | 14 | int b = 0; 15 | 16 | printf("%d, %d, %d\n", strlen(buf0), strlen(buf1), strlen(buf2)); 17 | 18 | if (strlen(buf0) < 100) 19 | if (strlen(buf0) > 10) 20 | if (strlen(buf0) < 70) 21 | if (strlen(buf0) > 20) 22 | if (strlen(buf1) < 250) 23 | if (strlen(buf1) < 200) 24 | if (strlen(buf1) > 20) 25 | if (strlen(buf1) > 30) 26 | if (strlen(buf2) < 350) 27 | if (strlen(buf2) < 300) 28 | if (strlen(buf2) > 100) 29 | if (strlen(buf2) > 120) 30 | b = 1; 31 | if (b) 32 | printf("%d\n", r/a); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /lab4/test/sanity.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char input[65536]; 5 | fgets(input, sizeof(input), stdin); 6 | int x = 0; 7 | int y = 2; 8 | int z = y / x; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | option(USE_REFERENCE "Build with reference solution" OFF) 11 | 12 | add_definitions(${LLVM_DEFINITIONS}) 13 | include_directories(${LLVM_INCLUDE_DIRS} include) 14 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/reference) 15 | 16 | if (USE_REFERENCE) 17 | message(STATUS "Use reference solution") 18 | add_llvm_library(DataflowPass MODULE 19 | src/DataflowAnalysis.cpp 20 | src/DivZeroAnalysis.cpp 21 | ) 22 | 23 | target_link_libraries(DataflowPass RefDomain) 24 | 25 | add_custom_target(RefDomain ALL 26 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/* ${CMAKE_CURRENT_BINARY_DIR}/ 27 | ) 28 | else (USE_REFERENCE) 29 | add_llvm_library(DataflowPass MODULE 30 | src/DataflowAnalysis.cpp 31 | src/DivZeroAnalysis.cpp 32 | src/Domain.cpp 33 | ) 34 | endif (USE_REFERENCE) 35 | -------------------------------------------------------------------------------- /lab5/include/DataflowAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAFLOW_ANALYSIS_H 2 | #define DATAFLOW_ANALYSIS_H 3 | 4 | #include "llvm/ADT/SetVector.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/InstIterator.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/ValueMap.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "Domain.h" 18 | 19 | using namespace llvm; 20 | 21 | namespace dataflow { 22 | 23 | using Memory = std::map; 24 | 25 | std::string deref(Value *); 26 | std::string variable(Value *); 27 | std::string address(Value *); 28 | 29 | struct DataflowAnalysis : public FunctionPass { 30 | ValueMap InMap; 31 | ValueMap OutMap; 32 | SetVector ErrorInsts; 33 | 34 | DataflowAnalysis(char ID); 35 | void collectErrorInsts(Function &F); 36 | bool runOnFunction(Function &F) override; 37 | 38 | protected: 39 | virtual void transfer(Instruction *I, const Memory *In, Memory *NOut) = 0; 40 | virtual void doAnalysis(Function &F) = 0; 41 | virtual bool check(Instruction *I) = 0; 42 | virtual std::string getAnalysisName() = 0; 43 | }; 44 | 45 | 46 | inline bool isInput(Instruction *I) { 47 | if (CallInst *CI = dyn_cast(I)) { 48 | return CI->getCalledFunction()->getName().equals("fgetc"); 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | /** 55 | * Get the Predecessors of a given instruction in the control-flow graph. 56 | */ 57 | inline std::vector getPredecessors(Instruction *I) { 58 | std::vector Ret; 59 | BasicBlock *BB = I->getParent(); 60 | for (BasicBlock::reverse_iterator It = BB->rbegin(), E = BB->rend(); It != E; 61 | ++It) { 62 | if (&(*It) == I) { 63 | ++It; 64 | if (It == E) { 65 | for (pred_iterator Pre = pred_begin(BB), BE = pred_end(BB); Pre != BE; 66 | ++Pre) 67 | Ret.push_back(&(*((*Pre)->rbegin()))); 68 | } else { 69 | Ret.push_back(&(*It)); 70 | } 71 | break; 72 | } 73 | } 74 | return Ret; 75 | } 76 | 77 | /** 78 | * Get the successors of a given instruction in the control-flow graph. 79 | */ 80 | inline std::vector getSuccessors(Instruction *I) { 81 | std::vector Ret; 82 | BasicBlock *BB = I->getParent(); 83 | for (BasicBlock::iterator It = BB->begin(), E = BB->end(); It != E; ++It) { 84 | if (&(*It) == I) { 85 | ++It; 86 | if (It == E) { 87 | for (succ_iterator Succ = succ_begin(BB), BS = succ_end(BB); Succ != BS; 88 | ++Succ) 89 | Ret.push_back(&(*((*Succ)->begin()))); 90 | } else { 91 | Ret.push_back(&(*It)); 92 | } 93 | break; 94 | } 95 | } 96 | return Ret; 97 | } 98 | } // namespace dataflow 99 | 100 | #endif // DATAFLOW_ANALYSIS_H 101 | -------------------------------------------------------------------------------- /lab5/include/DivZeroAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DIV_ZERO_ANALYSIS_H 2 | #define DIV_ZERO_ANALYSIS_H 3 | 4 | #include "DataflowAnalysis.h" 5 | 6 | namespace dataflow { 7 | struct DivZeroAnalysis : public DataflowAnalysis { 8 | static char ID; 9 | DivZeroAnalysis() : DataflowAnalysis(ID) {} 10 | 11 | protected: 12 | void transfer(Instruction *I, const Memory *In, Memory *NOut) override; 13 | 14 | void doAnalysis(Function &F) override; 15 | 16 | void flowIn(Instruction *I, Memory *In); 17 | 18 | void flowOut(Instruction *I, Memory *In, Memory *NOut, SetVector &); 19 | 20 | bool check(Instruction *I) override; 21 | 22 | std::string getAnalysisName() override { return "DivZero"; } 23 | }; 24 | } // namespace dataflow 25 | 26 | #endif // DIV_ZERO_ANALYSIS_H 27 | -------------------------------------------------------------------------------- /lab5/include/Domain.h: -------------------------------------------------------------------------------- 1 | #ifndef DOMAIN_H 2 | #define DOMAIN_H 3 | 4 | #include "llvm/Support/raw_ostream.h" 5 | 6 | using namespace llvm; 7 | 8 | namespace dataflow { 9 | 10 | //===----------------------------------------------------------------------===// 11 | // Abstract Domain Implementation 12 | //===----------------------------------------------------------------------===// 13 | 14 | /* 15 | * Implement your abstract domain. 16 | */ 17 | class Domain { 18 | public: 19 | enum Element { Uninit, NonZero, Zero, MaybeZero }; 20 | Domain(); 21 | Domain(Element V); 22 | Element Value; 23 | 24 | static Domain *add(Domain *E1, Domain *E2); 25 | static Domain *sub(Domain *E1, Domain *E2); 26 | static Domain *mul(Domain *E1, Domain *E2); 27 | static Domain *div(Domain *E1, Domain *E2); 28 | static Domain *join(Domain *E1, Domain *E2); 29 | static bool order(Domain E1, Domain E2); 30 | void print(raw_ostream &O); 31 | }; 32 | 33 | raw_ostream &operator<<(raw_ostream &O, Domain V); 34 | 35 | } // namespace dataflow 36 | 37 | #endif // DOMAIN_H 38 | -------------------------------------------------------------------------------- /lab5/reference/libRefDomain.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab5/reference/libRefDomain.so -------------------------------------------------------------------------------- /lab5/src/DataflowAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DataflowAnalysis.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace dataflow { 6 | 7 | //===----------------------------------------------------------------------===// 8 | // Memory Access 9 | //===----------------------------------------------------------------------===// 10 | 11 | const char *WhiteSpaces = " \t\n\r"; 12 | 13 | std::string deref(Value *V) { 14 | std::string Code; 15 | raw_string_ostream SS(Code); 16 | V->print(SS); 17 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 18 | Code = "*(" + Code + ")"; 19 | return Code; 20 | } 21 | 22 | std::string variable(Value *V) { 23 | std::string Code; 24 | raw_string_ostream SS(Code); 25 | V->print(SS); 26 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 27 | return Code; 28 | } 29 | 30 | std::string address(Value *V) { 31 | std::string Code; 32 | raw_string_ostream SS(Code); 33 | V->print(SS); 34 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 35 | Code = "@(" + Code + ")"; 36 | return Code; 37 | } 38 | 39 | //===----------------------------------------------------------------------===// 40 | // Dataflow Analysis Implementation 41 | //===----------------------------------------------------------------------===// 42 | 43 | DataflowAnalysis::DataflowAnalysis(char ID) : FunctionPass(ID) {} 44 | 45 | void DataflowAnalysis::collectErrorInsts(Function &F) { 46 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 47 | if (check(&*I)) 48 | ErrorInsts.insert(&*I); 49 | } 50 | } 51 | 52 | bool DataflowAnalysis::runOnFunction(Function &F) { 53 | outs() << "Running " << getAnalysisName() << " on " << F.getName() << "\n"; 54 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 55 | InMap[&(*I)] = new Memory; 56 | OutMap[&(*I)] = new Memory; 57 | } 58 | 59 | doAnalysis(F); 60 | 61 | collectErrorInsts(F); 62 | outs() << "Potential Instructions by " << getAnalysisName() << ": \n"; 63 | for (auto I : ErrorInsts) { 64 | outs() << *I << "\n"; 65 | } 66 | 67 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 68 | delete InMap[&(*I)]; 69 | delete OutMap[&(*I)]; 70 | } 71 | return false; 72 | } 73 | } // namespace dataflow 74 | -------------------------------------------------------------------------------- /lab5/src/DivZeroAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DivZeroAnalysis.h" 2 | 3 | namespace dataflow { 4 | 5 | //===----------------------------------------------------------------------===// 6 | // DivZero Analysis Implementation 7 | //===----------------------------------------------------------------------===// 8 | 9 | /** 10 | * Implement your data-flow analysis. 11 | * 1. Define "join" that joins the memory state of two flows. 12 | * 2. Define "order" which states if two memory sets are ordered 13 | * 3. Define "flowIn" that joins the memory set of all incomming flows 14 | * 4. Define "transfer" that computes the semantics of each instruction. 15 | * 5. Define "flowOut" that flows the memory set to all outgoing flows 16 | * 6. Define "doAnalysis" that stores your results in "InMap" and "OutMap". 17 | * 7. Define "check" that checks if a given instruction is erroneous or not. 18 | */ 19 | 20 | 21 | void join(Memory *Result, Memory *M1, Memory *M2) { 22 | /* Add your code here */ 23 | } 24 | 25 | bool order(Memory *M1, Memory *M2) { 26 | /* Add your code here */ 27 | } 28 | 29 | 30 | void DivZeroAnalysis::flowIn(Instruction *I, Memory *In) { 31 | /* Add your code here */ 32 | } 33 | 34 | void DivZeroAnalysis::transfer(Instruction *I, const Memory *In, Memory *NOut) { 35 | /* Add your code here */ 36 | } 37 | 38 | void DivZeroAnalysis::flowOut(Instruction *I, Memory *Pre, Memory *Post, SetVector &WorkSet) { 39 | /* Add your code here */ 40 | } 41 | 42 | void DivZeroAnalysis::doAnalysis(Function &F) { 43 | SetVector WorkSet; 44 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 45 | WorkSet.insert(&(*I)); 46 | } 47 | 48 | /* Add your code here */ 49 | 50 | } 51 | 52 | bool DivZeroAnalysis::check(Instruction *I) { 53 | /* Add your code here */ 54 | return false; 55 | } 56 | 57 | char DivZeroAnalysis::ID = 1; 58 | static RegisterPass X("DivZero", "Divide-by-zero Analysis", 59 | false, false); 60 | } // namespace dataflow 61 | -------------------------------------------------------------------------------- /lab5/src/Domain.cpp: -------------------------------------------------------------------------------- 1 | #include "Domain.h" 2 | 3 | //===----------------------------------------------------------------------===// 4 | // Abstract Domain Implementation 5 | //===----------------------------------------------------------------------===// 6 | 7 | /* Add your code here */ 8 | -------------------------------------------------------------------------------- /lab5/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll %.opt.ll 2 | 3 | all: simple0.out simple1.out branch0.out branch1.out branch2.out branch3.out branch4.out branch5.out branch6.out loop0.out loop1.out input0.out 4 | 5 | %.opt.ll: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -Xclang -disable-O0-optnone -c -o $@ $< 7 | opt -mem2reg -S $@ -o $*.opt.ll 8 | 9 | %.out: %.opt.ll 10 | opt -load ../build/DataflowPass.so -DivZero $< -disable-output > $@ 2> $*.err 11 | 12 | clean: 13 | rm -f *.ll *.out *.err 14 | -------------------------------------------------------------------------------- /lab5/test/branch0.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | z = y / x; // divide-by-zero within branch 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lab5/test/branch1.c: -------------------------------------------------------------------------------- 1 | int f() { 2 | int x = 0; 3 | int y = 1; 4 | if (x != 0) { 5 | int z = y / x; // unreachable 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab5/test/branch2.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | y = 1; 7 | } 8 | z = y / x; // divide-by-zero after branch 9 | } 10 | -------------------------------------------------------------------------------- /lab5/test/branch3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int x = fgetc(stdin); 5 | int y = 2; 6 | if (x > 10) { 7 | y = 0; 8 | } 9 | int z = x / y; // divide-by-zero after branch 10 | } 11 | -------------------------------------------------------------------------------- /lab5/test/branch4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | unsigned int a = 10; 6 | unsigned int b = 2; 7 | 8 | if(in > 0){ 9 | b = 0; 10 | }else if(in == 0){ 11 | b = 2 - b; 12 | }else{ 13 | b = -2 + b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab5/test/branch5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | unsigned int a = 10; 6 | unsigned int b = 2; 7 | 8 | if(in > 0){ 9 | b = in + b; 10 | }else if(in == 0){ 11 | b = 0; 12 | }else{ 13 | b = in - b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab5/test/branch6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | int a = 10; 6 | int b = 2; 7 | 8 | if(in > 0){ 9 | b = 100 + b; 10 | }else if(in == 0){ 11 | b = 1; 12 | }else{ 13 | b = a + b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab5/test/input0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int x = fgetc(stdin); 5 | int y = 5 / x; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /lab5/test/loop0.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int i; 3 | int sum = 0; 4 | for (i = 0; i < 10; i++) { 5 | sum += i; 6 | } 7 | int y = sum - 55; 8 | int z = i / y; 9 | } 10 | -------------------------------------------------------------------------------- /lab5/test/loop1.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int i; 3 | int sum = 0; 4 | while(sum < 50){ 5 | sum += i; 6 | } 7 | int y = sum - 55; 8 | int z = i / y; 9 | } 10 | -------------------------------------------------------------------------------- /lab5/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | int c = a + 1; 5 | int d = b / a; // Divide by zero 6 | if (c) { 7 | int a = 1; 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab5/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | int c = a == b; 5 | int d = b / c; 6 | int e = d / d; // divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab6/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | option(USE_REFERENCE "Build with reference solution" OFF) 11 | 12 | add_definitions(${LLVM_DEFINITIONS}) 13 | include_directories(${LLVM_INCLUDE_DIRS} include) 14 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/reference) 15 | 16 | if (USE_REFERENCE) 17 | add_llvm_library(DataflowPass MODULE 18 | src/DataflowAnalysis.cpp 19 | src/PointerAnalysis.cpp 20 | src/DivZeroAnalysis.cpp 21 | ) 22 | 23 | target_link_libraries(DataflowPass RefDomain) 24 | 25 | add_custom_target(RefDomain ALL 26 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/* ${CMAKE_CURRENT_BINARY_DIR}/ 27 | ) 28 | else (USE_REFERENCE) 29 | add_llvm_library(DataflowPass MODULE 30 | src/DataflowAnalysis.cpp 31 | src/DivZeroAnalysis.cpp 32 | src/Domain.cpp 33 | src/PointerAnalysis.cpp 34 | ) 35 | endif (USE_REFERENCE) 36 | -------------------------------------------------------------------------------- /lab6/include/DataflowAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAFLOW_ANALYSIS_H 2 | #define DATAFLOW_ANALYSIS_H 3 | 4 | #include "llvm/ADT/SetVector.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/InstIterator.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/ValueMap.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "Domain.h" 18 | #include "PointerAnalysis.h" 19 | 20 | using namespace llvm; 21 | 22 | namespace dataflow { 23 | 24 | using Memory = std::map; 25 | 26 | std::string deref(Value *); 27 | std::string variable(Value *); 28 | std::string address(Value *); 29 | 30 | struct DataflowAnalysis : public FunctionPass { 31 | ValueMap InMap; 32 | ValueMap OutMap; 33 | SetVector ErrorInsts; 34 | 35 | DataflowAnalysis(char ID); 36 | void collectErrorInsts(Function &F); 37 | bool runOnFunction(Function &F) override; 38 | 39 | protected: 40 | virtual void transfer(Instruction *I, const Memory *In, Memory *NOut, 41 | PointerAnalysis *PA, SetVector PointerSet) = 0; 42 | virtual void doAnalysis(Function &F, PointerAnalysis *PA) = 0; 43 | virtual bool check(Instruction *I) = 0; 44 | virtual std::string getAnalysisName() = 0; 45 | }; 46 | 47 | 48 | inline bool isInput(Instruction *I) { 49 | if (CallInst *CI = dyn_cast(I)) { 50 | return CI->getCalledFunction()->getName().equals("fgetc"); 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | /** 57 | * Get the Predecessors of a given instruction in the control-flow graph. 58 | */ 59 | inline std::vector getPredecessors(Instruction *I) { 60 | std::vector Ret; 61 | BasicBlock *BB = I->getParent(); 62 | for (BasicBlock::reverse_iterator It = BB->rbegin(), E = BB->rend(); It != E; 63 | ++It) { 64 | if (&(*It) == I) { 65 | ++It; 66 | if (It == E) { 67 | for (pred_iterator Pre = pred_begin(BB), BE = pred_end(BB); Pre != BE; 68 | ++Pre) 69 | Ret.push_back(&(*((*Pre)->rbegin()))); 70 | } else { 71 | Ret.push_back(&(*It)); 72 | } 73 | break; 74 | } 75 | } 76 | return Ret; 77 | } 78 | 79 | /** 80 | * Get the successors of a given instruction in the control-flow graph. 81 | */ 82 | inline std::vector getSuccessors(Instruction *I) { 83 | std::vector Ret; 84 | BasicBlock *BB = I->getParent(); 85 | for (BasicBlock::iterator It = BB->begin(), E = BB->end(); It != E; ++It) { 86 | if (&(*It) == I) { 87 | ++It; 88 | if (It == E) { 89 | for (succ_iterator Succ = succ_begin(BB), BS = succ_end(BB); Succ != BS; 90 | ++Succ) 91 | Ret.push_back(&(*((*Succ)->begin()))); 92 | } else { 93 | Ret.push_back(&(*It)); 94 | } 95 | break; 96 | } 97 | } 98 | return Ret; 99 | } 100 | } // namespace dataflow 101 | 102 | #endif // DATAFLOW_ANALYSIS_H 103 | -------------------------------------------------------------------------------- /lab6/include/DivZeroAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DIV_ZERO_ANALYSIS_H 2 | #define DIV_ZERO_ANALYSIS_H 3 | 4 | #include "DataflowAnalysis.h" 5 | 6 | namespace dataflow { 7 | struct DivZeroAnalysis : public DataflowAnalysis { 8 | static char ID; 9 | DivZeroAnalysis() : DataflowAnalysis(ID) {} 10 | 11 | protected: 12 | void transfer(Instruction *I, const Memory *In, Memory *NOut, 13 | PointerAnalysis *PA, SetVector PointerSet) override; 14 | 15 | void doAnalysis(Function &F, PointerAnalysis *PA) override; 16 | 17 | void flowIn(Instruction *I, Memory *In); 18 | 19 | void flowOut(Instruction *I, Memory *In, Memory *NOut, SetVector &); 20 | 21 | 22 | bool check(Instruction *I) override; 23 | 24 | std::string getAnalysisName() override { return "DivZero"; } 25 | }; 26 | } // namespace dataflow 27 | 28 | #endif // REF_DIV_ZERO_ANALYSIS_H 29 | -------------------------------------------------------------------------------- /lab6/include/Domain.h: -------------------------------------------------------------------------------- 1 | #ifndef DOMAIN_H 2 | #define DOMAIN_H 3 | 4 | #include "llvm/Support/raw_ostream.h" 5 | 6 | using namespace llvm; 7 | 8 | namespace dataflow { 9 | 10 | //===----------------------------------------------------------------------===// 11 | // Abstract Domain Implementation 12 | //===----------------------------------------------------------------------===// 13 | 14 | /* 15 | * Implement your abstract domain. 16 | */ 17 | class Domain { 18 | public: 19 | enum Element { Uninit, NonZero, Zero, MaybeZero }; 20 | Domain(); 21 | Domain(Element V); 22 | Element Value; 23 | 24 | static Domain *add(Domain *E1, Domain *E2); 25 | static Domain *sub(Domain *E1, Domain *E2); 26 | static Domain *mul(Domain *E1, Domain *E2); 27 | static Domain *div(Domain *E1, Domain *E2); 28 | static Domain *join(Domain *E1, Domain *E2); 29 | static bool order(Domain E1, Domain E2); 30 | void print(raw_ostream &O); 31 | }; 32 | 33 | raw_ostream &operator<<(raw_ostream &O, Domain V); 34 | 35 | } // namespace dataflow 36 | 37 | #endif // DOMAIN_H 38 | -------------------------------------------------------------------------------- /lab6/include/PointerAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTER_ANALYSIS_H 2 | #define POINTER_ANALYSIS_H 3 | 4 | #include "llvm/IR/Function.h" 5 | #include 6 | 7 | using namespace llvm; 8 | 9 | namespace dataflow { 10 | //===----------------------------------------------------------------------===// 11 | // Pointer Analysis 12 | //===----------------------------------------------------------------------===// 13 | 14 | using PointsToSet = std::set; 15 | using PointsToInfo = std::map; 16 | class PointerAnalysis { 17 | public: 18 | PointerAnalysis(Function &F); 19 | bool alias(std::string &Ptr1, std::string &Ptr2) const; 20 | 21 | private: 22 | PointsToInfo PointsTo; 23 | }; 24 | }; // namespace dataflow 25 | 26 | #endif // POINTER_ANALYSIS_H 27 | -------------------------------------------------------------------------------- /lab6/reference/libRefDomain.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab6/reference/libRefDomain.so -------------------------------------------------------------------------------- /lab6/src/DataflowAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DataflowAnalysis.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace dataflow { 6 | 7 | //===----------------------------------------------------------------------===// 8 | // Memory Access 9 | //===----------------------------------------------------------------------===// 10 | 11 | const char *WhiteSpaces = " \t\n\r"; 12 | 13 | std::string deref(Value *V) { 14 | std::string Code; 15 | raw_string_ostream SS(Code); 16 | V->print(SS); 17 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 18 | Code = "*(" + Code + ")"; 19 | return Code; 20 | } 21 | 22 | std::string variable(Value *V) { 23 | std::string Code; 24 | raw_string_ostream SS(Code); 25 | V->print(SS); 26 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 27 | return Code; 28 | } 29 | 30 | std::string address(Value *V) { 31 | std::string Code; 32 | raw_string_ostream SS(Code); 33 | V->print(SS); 34 | Code.erase(0, Code.find_first_not_of(WhiteSpaces)); 35 | Code = "@(" + Code + ")"; 36 | return Code; 37 | } 38 | 39 | //===----------------------------------------------------------------------===// 40 | // Dataflow Analysis Implementation 41 | //===----------------------------------------------------------------------===// 42 | 43 | DataflowAnalysis::DataflowAnalysis(char ID) : FunctionPass(ID) {} 44 | 45 | void DataflowAnalysis::collectErrorInsts(Function &F) { 46 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 47 | if (check(&*I)) 48 | ErrorInsts.insert(&*I); 49 | } 50 | } 51 | 52 | bool DataflowAnalysis::runOnFunction(Function &F) { 53 | outs() << "Running " << getAnalysisName() << " on " << F.getName() << "\n"; 54 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 55 | InMap[&(*I)] = new Memory; 56 | OutMap[&(*I)] = new Memory; 57 | } 58 | 59 | PointerAnalysis *PA = new PointerAnalysis(F); 60 | doAnalysis(F, PA); 61 | 62 | collectErrorInsts(F); 63 | outs() << "Potential Instructions by " << getAnalysisName() << ": \n"; 64 | for (auto I : ErrorInsts) { 65 | outs() << *I << "\n"; 66 | } 67 | 68 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 69 | delete InMap[&(*I)]; 70 | delete OutMap[&(*I)]; 71 | } 72 | return false; 73 | } 74 | } // namespace dataflow 75 | -------------------------------------------------------------------------------- /lab6/src/DivZeroAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DivZeroAnalysis.h" 2 | 3 | namespace dataflow { 4 | 5 | //===----------------------------------------------------------------------===// 6 | // Dataflow Analysis Implementation 7 | //===----------------------------------------------------------------------===// 8 | 9 | /** 10 | * Implement your data-flow analysis. 11 | * 1. Define "join" that joins the memory state of two flows. 12 | * 2. Define "order" which states if two memory sets are ordered 13 | * 3. Define "flowIn" that joins the memory set of all incomming flows 14 | * 4. Define "transfer" that computes the semantics of each instruction. 15 | * 5. Define "flowOut" that flows the memory set to all outgoing flows 16 | * 6. Define "doAnalysis" that stores your results in "InMap" and "OutMap". 17 | * 7. Define "check" that checks if a given instruction is erroneous or not. 18 | */ 19 | 20 | 21 | void join(Memory *Result, Memory *M1, Memory *M2) { 22 | /* Add your code here */ 23 | } 24 | 25 | bool order(Memory *M1, Memory *M2) { 26 | /* Add your code here */ 27 | } 28 | 29 | 30 | void DivZeroAnalysis::flowIn(Instruction *I, Memory *In) { 31 | /* Add your code here */ 32 | } 33 | 34 | 35 | void DivZeroAnalysis::transfer(Instruction *I, const Memory *In, Memory *NOut, 36 | PointerAnalysis *PA, 37 | SetVector PointerSet) { 38 | /* Add your code here */ 39 | } 40 | 41 | void DivZeroAnalysis::flowOut(Instruction *I, Memory *Pre, Memory *Post, SetVector &WorkSet) { 42 | /* Add your code here */ 43 | } 44 | 45 | void DivZeroAnalysis::doAnalysis(Function &F, PointerAnalysis *PA) { 46 | /* Add your code here */ 47 | SetVector WorkSet; 48 | SetVector PointerSet; 49 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { 50 | WorkSet.insert(&(*I)); 51 | PointerSet.insert(&(*I)); 52 | } 53 | 54 | 55 | } 56 | 57 | bool DivZeroAnalysis::check(Instruction *I) { 58 | /* Add your code here */ 59 | return false; 60 | } 61 | 62 | char DivZeroAnalysis::ID = 1; 63 | static RegisterPass X("DivZero", "Divide-by-zero Analysis", 64 | false, false); 65 | } // namespace dataflow 66 | -------------------------------------------------------------------------------- /lab6/src/Domain.cpp: -------------------------------------------------------------------------------- 1 | #include "Domain.h" 2 | 3 | //===----------------------------------------------------------------------===// 4 | // Abstract Domain Implementation 5 | //===----------------------------------------------------------------------===// 6 | 7 | /* Add your code here */ 8 | -------------------------------------------------------------------------------- /lab6/src/PointerAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "PointerAnalysis.h" 2 | 3 | #include "llvm/IR/InstIterator.h" 4 | #include "llvm/IR/Instructions.h" 5 | 6 | #include "DataflowAnalysis.h" 7 | 8 | namespace dataflow { 9 | 10 | //===----------------------------------------------------------------------===// 11 | // Pointer Analysis Implementation 12 | //===----------------------------------------------------------------------===// 13 | 14 | /* 15 | * Implement your pointer analysis. (Lab 6) 16 | * 1. Define "PointerAnalysis" that stores your results in "PointsTo". 17 | * 2. Define "alias" that checks whether two pointers may alias each other. 18 | */ 19 | 20 | PointerAnalysis::PointerAnalysis(Function &F) { /* Add your code here */ } 21 | 22 | bool PointerAnalysis::alias(std::string &Ptr1, std::string &Ptr2) const { 23 | /* Add your code here */ 24 | return false; 25 | } 26 | }; // namespace dataflow 27 | -------------------------------------------------------------------------------- /lab6/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll %.opt.ll 2 | 3 | all: simple0.out simple1.out branch0.out branch1.out branch2.out branch3.out branch4.out branch5.out branch6.out loop0.out loop1.out input0.out pointer0.out pointer1.out pointer2.out 4 | 5 | %.opt.ll: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -Xclang -disable-O0-optnone -c -o $@ $< 7 | 8 | %.out: %.opt.ll 9 | opt -load ../build/DataflowPass.so -DivZero $< -disable-output > $@ 2> $*.err 10 | 11 | clean: 12 | rm -f *.ll *.out *.err 13 | -------------------------------------------------------------------------------- /lab6/test/branch0.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int x = 0; 3 | int y = 2; 4 | int z; 5 | if (x < 1) { 6 | z = y / x; // divide-by-zero within branch 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lab6/test/branch1.c: -------------------------------------------------------------------------------- 1 | int f() { 2 | int x = 0; 3 | int y = 1; 4 | if (x != 0) { 5 | int z = y / x; // unreachable 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab6/test/branch2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int x = fgetc(stdin); 5 | int y = 2; 6 | if (x > 10) { 7 | y = 0; 8 | } 9 | int z = x / y; // divide-by-zero after branch 10 | } 11 | -------------------------------------------------------------------------------- /lab6/test/branch3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int x = fgetc(stdin); 5 | int y = 0; 6 | if (x > 10) { 7 | y = 1; 8 | } else { 9 | y = 2; 10 | } 11 | int z = x / y; 12 | } 13 | -------------------------------------------------------------------------------- /lab6/test/branch4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | unsigned int a = 10; 6 | unsigned int b = 2; 7 | 8 | if(in > 0){ 9 | b = 0; 10 | }else if(in == 0){ 11 | b = 2 - b; 12 | }else{ 13 | b = -2 + b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab6/test/branch5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | unsigned int a = 10; 6 | unsigned int b = 2; 7 | 8 | if(in > 0){ 9 | b = in + b; 10 | }else if(in == 0){ 11 | b = 0; 12 | }else{ 13 | b = in - b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab6/test/branch6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f() { 4 | int in = fgetc(stdin); 5 | int a = 10; 6 | int b = 2; 7 | 8 | if(in > 0){ 9 | b = 100 + b; 10 | }else if(in == 0){ 11 | b = 1; 12 | }else{ 13 | b = a + b; 14 | } 15 | 16 | int out = a / b; 17 | } 18 | -------------------------------------------------------------------------------- /lab6/test/input0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int x = fgetc(stdin); 5 | int y = 5 / x; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /lab6/test/loop0.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int i; 3 | int sum = 0; 4 | for (i = 0; i < 10; i++) { 5 | sum += 1; 6 | } 7 | int z = i / sum; 8 | } 9 | -------------------------------------------------------------------------------- /lab6/test/loop1.c: -------------------------------------------------------------------------------- 1 | void f() { 2 | int i; 3 | int sum = 0; 4 | while(sum < 50){ 5 | sum += i; 6 | } 7 | int y = sum - 55; 8 | int z = i / y; 9 | } 10 | -------------------------------------------------------------------------------- /lab6/test/pointer0.c: -------------------------------------------------------------------------------- 1 | int f(){ 2 | int a = 1; 3 | int *c = &a; 4 | int *d = &a; 5 | *c = 0; 6 | int x = 1 / *d; 7 | return x; 8 | } 9 | -------------------------------------------------------------------------------- /lab6/test/pointer1.c: -------------------------------------------------------------------------------- 1 | int f(){ 2 | int a; 3 | int *c = &a; 4 | int *d = &a; 5 | int *e = &a; 6 | *c = 0; 7 | int x = 1 / *d; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /lab6/test/pointer2.c: -------------------------------------------------------------------------------- 1 | int f(int arg) { 2 | int a = 0; 3 | int b = 1; 4 | int *x; 5 | if (arg) { 6 | x = &a; 7 | } else { 8 | x = &b; 9 | } 10 | int z = 1 / *x; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /lab6/test/pointer3.c: -------------------------------------------------------------------------------- 1 | int f(int arg) { 2 | int a = 1; 3 | int b = 1; 4 | int *x; 5 | int *y; 6 | if (arg) { 7 | x = &a; 8 | y = &b; 9 | } else { 10 | x = &b; 11 | y = &a; 12 | } 13 | int *z; 14 | if (arg) { 15 | z = x; 16 | } else { 17 | z = y; 18 | } 19 | int z2 = 1 / *z; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /lab6/test/pointer4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int a = 0; 5 | int b = 1; 6 | int* p = &a; 7 | int* q = &b; 8 | 9 | *p = *q; 10 | 11 | int s = b / *p; //not a div by zero 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /lab6/test/pointer5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int in = fgetc(stdin); 5 | int a = 0; 6 | int b = 1; 7 | int* x; 8 | 9 | if(in < 10){ 10 | x = &a; 11 | }else{ 12 | x = &b; 13 | } 14 | 15 | int s = b / *x; //divide by zero possible 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /lab6/test/pointer6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | int stop = fgetc(stdin); 5 | 6 | if (stop > 4){ 7 | stop = 2; 8 | } 9 | 10 | int* point = NULL; 11 | 12 | int a = 1; 13 | int b = 2; 14 | int c = 0; 15 | int d = 3; 16 | 17 | if(stop == 0){ 18 | point = &a; 19 | }else if(stop == 1){ 20 | point = &b; 21 | }else if(stop == 2){ 22 | point = &c; 23 | }else{ 24 | point = &d; 25 | } 26 | 27 | int* e = &a; 28 | int* f = &a; 29 | 30 | int y = *f / *point; 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /lab6/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | int c = a + 1; 5 | int d = b / a; // Divide by zero 6 | if (c) { 7 | int a = 1; 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab6/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | int c = a == b; 5 | int d = b / c; 6 | int e = d / d; // divide by zero 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /lab7/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | set(Z3_DIR $ENV{Z3_DIR}) 11 | get_filename_component(Z3_DIR ${Z3_DIR} ABSOLUTE) 12 | set(Z3_CXX_INCLUDE_DIRS ${Z3_DIR}/include) 13 | set(Z3_LIBRARIES ${Z3_DIR}/bin/libz3.so) 14 | message(STATUS "Z3_DIR: ${Z3_DIR}") 15 | 16 | add_definitions(${LLVM_DEFINITIONS}) 17 | include_directories(${LLVM_INCLUDE_DIRS} include) 18 | include_directories(${Z3_CXX_INCLUDE_DIRS}) 19 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) 20 | 21 | add_executable(constraint 22 | src/Constraint.cpp 23 | src/Extractor.cpp 24 | src/Utils.cpp 25 | ) 26 | 27 | llvm_map_components_to_libnames(llvm_libs support core irreader) 28 | 29 | target_link_libraries(constraint ${llvm_libs} ${Z3_LIBRARIES}) 30 | -------------------------------------------------------------------------------- /lab7/include/Extractor.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTRACTOR_H 2 | #define EXTRACTOR_H 3 | 4 | #include "z3++.h" 5 | #include "llvm/ADT/MapVector.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/IR/Type.h" 9 | #include 10 | 11 | #include "Utils.h" 12 | 13 | using namespace llvm; 14 | 15 | using InstMapTy = std::map; 16 | using DefMapTy = std::map>; 17 | 18 | class Extractor { 19 | public: 20 | Extractor() { 21 | Solver = new z3::fixedpoint(C); 22 | Params = new z3::params(C); 23 | Params->set("engine", "datalog"); 24 | Solver->set(*Params); 25 | } 26 | 27 | ~Extractor() { 28 | delete Solver; 29 | delete Params; 30 | } 31 | 32 | void initialize(); 33 | z3::fixedpoint *getSolver() { return Solver; } 34 | z3::context &getContext() { return C; } 35 | z3::check_result query(unsigned int N) { 36 | z3::expr Q = Alarm(C.bv_val(N, 32)); 37 | return Solver->query(Q); 38 | } 39 | 40 | void addNext(const InstMapTy &InstMap, Instruction *X, Instruction *Y); 41 | void addDef(const InstMapTy &InstMap, Value *X, Instruction *L); 42 | void addUse(const InstMapTy &InstMap, Value *X, Instruction *L); 43 | void addDiv(const InstMapTy &InstMap, Value *X, Instruction *L); 44 | void addTaint(const InstMapTy &InstMap, Instruction *L); 45 | void addSanitizer(const InstMapTy &InstMap, Instruction *L); 46 | void addGen(const InstMapTy &InstMap, Instruction *X, Value *Y); 47 | 48 | void extractConstraints(const InstMapTy &InstMap, Instruction *I); 49 | 50 | void printTuple(std::string Name, Value *V1, Value *V2) { 51 | std::cout << Name << "(\"" << toString(V1) << "\", \"" << toString(V2) 52 | << "\")" << std::endl; 53 | } 54 | 55 | void print(InstMapTy &InstMap) { 56 | std::cout << "=== Reaching Definition (Out) ===" << std::endl; 57 | for (auto &V1 : InstMap) { 58 | for (auto &V2 : InstMap) { 59 | z3::expr Q = Out(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 60 | if (Solver->query(Q) == z3::sat) { 61 | printTuple("Out", V1.first, V2.first); 62 | } 63 | } 64 | } 65 | std::cout << "=== Kill ===" << std::endl; 66 | for (auto &V1 : InstMap) { 67 | for (auto &V2 : InstMap) { 68 | z3::expr Q = Kill(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 69 | if (Solver->query(Q) == z3::sat) { 70 | printTuple("Kill", V1.first, V2.first); 71 | } 72 | } 73 | } 74 | std::cout << "=== Def ===" << std::endl; 75 | for (auto &V1 : InstMap) { 76 | for (auto &V2 : InstMap) { 77 | z3::expr Q = Def(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 78 | if (Solver->query(Q) == z3::sat) { 79 | printTuple("Def", V1.first, V2.first); 80 | } 81 | } 82 | } 83 | std::cout << "=== Use ===" << std::endl; 84 | for (auto &V1 : InstMap) { 85 | for (auto &V2 : InstMap) { 86 | z3::expr Q = Use(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 87 | if (Solver->query(Q) == z3::sat) { 88 | printTuple("Use", V1.first, V2.first); 89 | } 90 | } 91 | } 92 | std::cout << "=== Edge ===" << std::endl; 93 | for (auto &V1 : InstMap) { 94 | for (auto &V2 : InstMap) { 95 | z3::expr Q = Edge(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 96 | if (Solver->query(Q) == z3::sat) { 97 | printTuple("Edge", V1.first, V2.first); 98 | } 99 | } 100 | } 101 | std::cout << "=== Path ===" << std::endl; 102 | for (auto &V1 : InstMap) { 103 | for (auto &V2 : InstMap) { 104 | z3::expr Q = Path(C.bv_val(V1.second, 32), C.bv_val(V2.second, 32)); 105 | if (Solver->query(Q) == z3::sat) { 106 | printTuple("Path", V1.first, V2.first); 107 | } 108 | } 109 | } 110 | } 111 | 112 | private: 113 | std::map> DefMap; 114 | 115 | z3::context C; 116 | z3::fixedpoint *Solver; 117 | z3::params *Params; 118 | z3::check_result Result; 119 | z3::sort LLVMInst = C.bv_sort(32); 120 | 121 | public: 122 | /* Relations for Def and Use */ 123 | z3::func_decl Def = C.function("Def", LLVMInst, LLVMInst, C.bool_sort()); 124 | z3::func_decl Use = C.function("Use", LLVMInst, LLVMInst, C.bool_sort()); 125 | 126 | /* Relations for Reaching Definition */ 127 | z3::func_decl Kill = C.function("Kill", LLVMInst, LLVMInst, C.bool_sort()); 128 | z3::func_decl Gen = C.function("Gen", LLVMInst, LLVMInst, C.bool_sort()); 129 | z3::func_decl Next = C.function("Next", LLVMInst, LLVMInst, C.bool_sort()); 130 | z3::func_decl In = C.function("In", LLVMInst, LLVMInst, C.bool_sort()); 131 | z3::func_decl Out = C.function("Out", LLVMInst, LLVMInst, C.bool_sort()); 132 | 133 | /* Relations for Taint Analysis */ 134 | z3::func_decl Taint = C.function("Taint", LLVMInst, C.bool_sort()); 135 | z3::func_decl Edge = C.function("Edge", LLVMInst, LLVMInst, C.bool_sort()); 136 | z3::func_decl Path = C.function("Path", LLVMInst, LLVMInst, C.bool_sort()); 137 | z3::func_decl Sanitizer = C.function("Sanitizer", LLVMInst, C.bool_sort()); 138 | z3::func_decl Div = C.function("Div", LLVMInst, LLVMInst, C.bool_sort()); 139 | z3::func_decl Alarm = C.function("Alarm", LLVMInst, C.bool_sort()); 140 | }; 141 | 142 | #endif // EXTRACTOR_H 143 | -------------------------------------------------------------------------------- /lab7/include/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "llvm/IR/Instructions.h" 5 | 6 | using namespace llvm; 7 | 8 | std::string toString(Value *I); 9 | 10 | std::vector getPredecessors(Instruction *I); 11 | 12 | bool isTaintedInput(CallInst *CI); 13 | 14 | bool isSanitizer(CallInst *CI); 15 | 16 | #endif // UTILS_H 17 | -------------------------------------------------------------------------------- /lab7/src/Constraint.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/AsmParser/Parser.h" 2 | #include "llvm/IR/InstIterator.h" 3 | #include "llvm/IR/Module.h" 4 | #include "llvm/Support/SourceMgr.h" 5 | #include 6 | 7 | #include "Extractor.h" 8 | 9 | using namespace llvm; 10 | 11 | int main(int argc, char **argv) { 12 | if (argc > 3) { 13 | errs() << "Expected an argument - IR file name\n"; 14 | exit(1); 15 | } 16 | 17 | LLVMContext Context; 18 | SMDiagnostic Err; 19 | StringRef FileName(argv[1]); 20 | 21 | std::unique_ptr Mod = parseAssemblyFile(FileName, Err, Context); 22 | 23 | if (!Mod) { 24 | Err.print(argv[0], errs()); 25 | return 1; 26 | } 27 | 28 | Extractor Ext; 29 | Ext.initialize(); 30 | z3::fixedpoint *Solver = Ext.getSolver(); 31 | z3::context &C = Ext.getContext(); 32 | 33 | InstMapTy InstMap; 34 | unsigned int Counter = 0; 35 | for (auto &F : *Mod) { 36 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; I++) { 37 | InstMap[&*I] = Counter++; 38 | } 39 | } 40 | 41 | for (auto &F : *Mod) { 42 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; I++) { 43 | Ext.extractConstraints(InstMap, &*I); 44 | } 45 | } 46 | 47 | if (argc == 3 && !strcmp(argv[1], "-d")) 48 | Ext.print(InstMap); 49 | 50 | std::cout << "Potential divide-by-zero points:" << std::endl; 51 | for (auto &Entry : InstMap) { 52 | z3::check_result R = Ext.query(Entry.second); 53 | if (R == z3::sat) 54 | std::cout << toString(Entry.first) << std::endl; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lab7/src/Extractor.cpp: -------------------------------------------------------------------------------- 1 | #include "Extractor.h" 2 | 3 | #include "llvm/IR/Instruction.h" 4 | 5 | void Extractor::initialize() { 6 | /* Relations for Def and Use */ 7 | Solver->register_relation(Def); 8 | Solver->register_relation(Use); 9 | 10 | /* Relations for Reaching Definition Analysis */ 11 | Solver->register_relation(Kill); 12 | Solver->register_relation(Gen); 13 | Solver->register_relation(Next); 14 | Solver->register_relation(In); 15 | Solver->register_relation(Out); 16 | 17 | /* Relations for Taint Analysis */ 18 | Solver->register_relation(Taint); 19 | Solver->register_relation(Edge); 20 | Solver->register_relation(Path); 21 | Solver->register_relation(Sanitizer); 22 | Solver->register_relation(Div); 23 | Solver->register_relation(Alarm); 24 | 25 | /* 26 | * Add your code here: 27 | * Define your analysis rules for taint analysis and add the rules to the 28 | * solver. 29 | */ 30 | } 31 | 32 | void Extractor::addDef(const InstMapTy &InstMap, Value *X, Instruction *L) { 33 | if (InstMap.find(X) == InstMap.end()) 34 | return; 35 | unsigned int Arr[2] = {InstMap.at(X), InstMap.at(L)}; 36 | Solver->add_fact(Def, Arr); 37 | } 38 | 39 | void Extractor::addUse(const InstMapTy &InstMap, Value *X, Instruction *L) { 40 | if (Constant *C = dyn_cast(X)) 41 | return; 42 | if (InstMap.find(X) == InstMap.end()) 43 | return; 44 | unsigned int Arr[2] = {InstMap.at(X), InstMap.at(L)}; 45 | Solver->add_fact(Use, Arr); 46 | } 47 | 48 | void Extractor::addDiv(const InstMapTy &InstMap, Value *X, Instruction *L) { 49 | if (Constant *C = dyn_cast(X)) 50 | return; 51 | if (InstMap.find(X) == InstMap.end()) 52 | return; 53 | unsigned int Arr[2] = {InstMap.at(X), InstMap.at(L)}; 54 | Solver->add_fact(Div, Arr); 55 | } 56 | 57 | void Extractor::addTaint(const InstMapTy &InstMap, Instruction *L) { 58 | unsigned int Arr[1] = {InstMap.at(L)}; 59 | Solver->add_fact(Taint, Arr); 60 | } 61 | 62 | void Extractor::addSanitizer(const InstMapTy &InstMap, Instruction *L) { 63 | unsigned int Arr[1] = {InstMap.at(L)}; 64 | Solver->add_fact(Sanitizer, Arr); 65 | } 66 | 67 | void Extractor::addGen(const InstMapTy &InstMap, Instruction *X, Value *Y) { 68 | unsigned int Arr[2] = {InstMap.at(X), InstMap.at(Y)}; 69 | Solver->add_fact(Gen, Arr); 70 | } 71 | 72 | void Extractor::addNext(const InstMapTy &InstMap, Instruction *X, 73 | Instruction *Y) { 74 | unsigned int Arr[2] = {InstMap.at(X), InstMap.at(Y)}; 75 | Solver->add_fact(Next, Arr); 76 | }; 77 | 78 | /* 79 | * Implement the following function that collects Datalog facts for each 80 | * instruction. 81 | */ 82 | void Extractor::extractConstraints(const InstMapTy &InstMap, Instruction *I) { 83 | /* Add your code here */ 84 | } 85 | -------------------------------------------------------------------------------- /lab7/src/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | 3 | #include "llvm/IR/CFG.h" 4 | 5 | const char *WhiteSpaces = " \t\n\r"; 6 | 7 | std::string toString(Value *I) { 8 | std::string Str; 9 | raw_string_ostream SS(Str); 10 | I->print(SS); 11 | Str.erase(0, Str.find_first_not_of(WhiteSpaces)); 12 | return SS.str(); 13 | } 14 | 15 | std::vector getPredecessors(Instruction *I) { 16 | std::vector Ret; 17 | BasicBlock *BB = I->getParent(); 18 | for (BasicBlock::reverse_iterator It = BB->rbegin(), E = BB->rend(); It != E; 19 | ++It) { 20 | if (&(*It) == I) { 21 | ++It; 22 | if (It == E) { 23 | for (pred_iterator Pre = pred_begin(BB), BE = pred_end(BB); Pre != BE; 24 | ++Pre) 25 | Ret.push_back(&(*((*Pre)->rbegin()))); 26 | } else { 27 | Ret.push_back(&(*It)); 28 | } 29 | break; 30 | } 31 | } 32 | return Ret; 33 | } 34 | 35 | bool isTaintedInput(CallInst *CI) { 36 | return CI->getCalledFunction()->getName().equals("tainted_input"); 37 | } 38 | 39 | bool isSanitizer(CallInst *CI) { 40 | return CI->getCalledFunction()->getName().equals("sanitizer"); 41 | } 42 | -------------------------------------------------------------------------------- /lab7/test/Makefile: -------------------------------------------------------------------------------- 1 | .PRECIOUS: %.ll 2 | 3 | TARGETS=simple0.out simple1.out branch0.out loop0.out branch1.out branch2.out loop1.out 4 | 5 | all: ${TARGETS} 6 | 7 | %.ll: %.c 8 | clang -emit-llvm -S -fno-discard-value-names -c -o $@ $< 9 | 10 | %.out: %.ll 11 | ../build/constraint $< > $@ 2> $*.err 12 | 13 | clean: 14 | rm -f *.ll *.out *.err ${TARGETS} 15 | -------------------------------------------------------------------------------- /lab7/test/branch0.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x; 5 | int y; 6 | if (argc > 2) { 7 | x = 0; 8 | y = x; 9 | } else { 10 | x = tainted_input(); 11 | y = x; 12 | } 13 | int z = 4 / y; // alarm 14 | } 15 | -------------------------------------------------------------------------------- /lab7/test/branch1.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x = tainted_input(); 5 | int y; 6 | if (argc > 2) { 7 | x = 0; 8 | y = sanitizer(x); 9 | } else { 10 | y = not_sanitizer(x); 11 | } 12 | int z = 4 / y; // alarm 13 | } 14 | -------------------------------------------------------------------------------- /lab7/test/branch2.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x = tainted_input(); 5 | int y; 6 | if (1) { 7 | y = 0; 8 | } else { 9 | y = 100; 10 | } 11 | int z = 4 / y; // alarm 12 | } 13 | -------------------------------------------------------------------------------- /lab7/test/loop0.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x; 5 | int y; 6 | x = 0; 7 | while (argc > 1) { 8 | x = tainted_input(); 9 | y = x; 10 | argc--; 11 | } 12 | int z = 4 / y; // alarm 13 | } 14 | -------------------------------------------------------------------------------- /lab7/test/loop1.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x; 5 | int y = tainted_input(); 6 | x = 0; 7 | while (x > 0) { 8 | y = sanitizer(y); 9 | } 10 | int z = 4 / y; // alarm 11 | } 12 | -------------------------------------------------------------------------------- /lab7/test/prelude.h: -------------------------------------------------------------------------------- 1 | extern int tainted_input(); 2 | extern int untainted_input(); 3 | extern int sanitizer(int); 4 | extern int not_sanitizer(int); 5 | -------------------------------------------------------------------------------- /lab7/test/simple0.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main() { 4 | int x = tainted_input(); 5 | int y = x; 6 | int z = 4 / y; // alarm 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /lab7/test/simple1.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | int main(int argc, char **argv) { 4 | int x = tainted_input(); 5 | int y = sanitizer(x); 6 | int z = 4 / y; // safe 7 | 8 | y = not_sanitizer(x); 9 | z = 4 / y; // alarm 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /lab8/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | set(Z3_DIR $ENV{Z3_DIR}) 11 | get_filename_component(Z3_DIR ${Z3_DIR} ABSOLUTE) 12 | set(Z3_CXX_INCLUDE_DIRS ${Z3_DIR}/include) 13 | set(Z3_LIBRARIES ${Z3_DIR}/bin/libz3.so) 14 | message(STATUS "Z3_DIR: ${Z3_DIR}") 15 | 16 | add_definitions(${LLVM_DEFINITIONS}) 17 | include_directories(${LLVM_INCLUDE_DIRS} include) 18 | include_directories(${Z3_CXX_INCLUDE_DIRS}) 19 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) 20 | 21 | add_executable(typesystem 22 | src/TypeSystem.cpp 23 | src/Extractor.cpp 24 | ) 25 | 26 | llvm_map_components_to_libnames(llvm_libs support core irreader) 27 | 28 | target_link_libraries(typesystem ${llvm_libs} ${Z3_LIBRARIES} DummyLLVMAsmParser) 29 | 30 | add_llvm_library(DummyLLVMAsmParser 31 | lib/LLLexer.cpp 32 | lib/LLParser.cpp 33 | lib/Parser.cpp 34 | 35 | ADDITIONAL_HEADER_DIRS 36 | ${LLVM_MAIN_INCLUDE_DIR}/llvm/Analysis 37 | 38 | DEPENDS 39 | intrinsics_gen 40 | ) 41 | -------------------------------------------------------------------------------- /lab8/include/DummyLLParser.h: -------------------------------------------------------------------------------- 1 | //===-- DummyLLParser.h - Parser Class -------------------------------*- C++ 2 | //-*-===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | // 11 | // This file defines the parser class for .ll files. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef LLVM_LIB_ASMPARSER_LLPARSER_H 16 | #define LLVM_LIB_ASMPARSER_LLPARSER_H 17 | 18 | #include "LLLexer.h" 19 | #include "llvm/ADT/Optional.h" 20 | #include "llvm/ADT/StringMap.h" 21 | #include "llvm/IR/Attributes.h" 22 | #include "llvm/IR/Instructions.h" 23 | #include "llvm/IR/Module.h" 24 | #include "llvm/IR/ModuleSummaryIndex.h" 25 | #include "llvm/IR/Operator.h" 26 | #include "llvm/IR/Type.h" 27 | #include "llvm/IR/ValueHandle.h" 28 | #include 29 | 30 | namespace llvm { 31 | class Module; 32 | class OpaqueType; 33 | class Function; 34 | class Value; 35 | class BasicBlock; 36 | class Instruction; 37 | class Constant; 38 | class GlobalValue; 39 | class Comdat; 40 | class MDString; 41 | class MDNode; 42 | struct SlotMapping; 43 | class StructType; 44 | 45 | /// ValID - Represents a reference of a definition of some sort with no type. 46 | /// There are several cases where we have to parse the value but where the 47 | /// type can depend on later context. This may either be a numeric reference 48 | /// or a symbolic (%var) reference. This is just a discriminated union. 49 | struct ValID { 50 | enum { 51 | t_LocalID, t_GlobalID, // ID in UIntVal. 52 | t_LocalName, t_GlobalName, // Name in StrVal. 53 | t_APSInt, t_APFloat, // Value in APSIntVal/APFloatVal. 54 | t_Null, t_Undef, t_Zero, t_None, // No value. 55 | t_EmptyArray, // No value: [] 56 | t_Constant, // Value in ConstantVal. 57 | t_InlineAsm, // Value in FTy/StrVal/StrVal2/UIntVal. 58 | t_ConstantStruct, // Value in ConstantStructElts. 59 | t_PackedConstantStruct // Value in ConstantStructElts. 60 | } Kind = t_LocalID; 61 | 62 | LLLexer::LocTy Loc; 63 | unsigned UIntVal; 64 | FunctionType *FTy = nullptr; 65 | std::string StrVal, StrVal2; 66 | APSInt APSIntVal; 67 | APFloat APFloatVal{0.0}; 68 | Constant *ConstantVal; 69 | std::unique_ptr ConstantStructElts; 70 | 71 | ValID() = default; 72 | ValID(const ValID &RHS) 73 | : Kind(RHS.Kind), Loc(RHS.Loc), UIntVal(RHS.UIntVal), FTy(RHS.FTy), 74 | StrVal(RHS.StrVal), StrVal2(RHS.StrVal2), APSIntVal(RHS.APSIntVal), 75 | APFloatVal(RHS.APFloatVal), ConstantVal(RHS.ConstantVal) { 76 | assert(!RHS.ConstantStructElts); 77 | } 78 | 79 | bool operator<(const ValID &RHS) const { 80 | if (Kind == t_LocalID || Kind == t_GlobalID) 81 | return UIntVal < RHS.UIntVal; 82 | assert((Kind == t_LocalName || Kind == t_GlobalName || 83 | Kind == t_ConstantStruct || Kind == t_PackedConstantStruct) && 84 | "Ordering not defined for this ValID kind yet"); 85 | return StrVal < RHS.StrVal; 86 | } 87 | }; 88 | 89 | class DummyLLParser { 90 | public: 91 | typedef LLLexer::LocTy LocTy; 92 | private: 93 | LLVMContext &Context; 94 | LLLexer Lex; 95 | // Module being parsed, null if we are only parsing summary index. 96 | Module *M; 97 | // Summary index being parsed, null if we are only parsing Module. 98 | ModuleSummaryIndex *Index; 99 | SlotMapping *Slots; 100 | bool TypeCheck; 101 | // Instruction metadata resolution. Each instruction can have a list of 102 | // MDRef info associated with them. 103 | // 104 | // The simpler approach of just creating temporary MDNodes and then calling 105 | // RAUW on them when the definition is processed doesn't work because some 106 | // instruction metadata kinds, such as dbg, get stored in the IR in an 107 | // "optimized" format which doesn't participate in the normal value use 108 | // lists. This means that RAUW doesn't work, even on temporary MDNodes 109 | // which otherwise support RAUW. Instead, we defer resolving MDNode 110 | // references until the definitions have been processed. 111 | struct MDRef { 112 | SMLoc Loc; 113 | unsigned MDKind, MDSlot; 114 | }; 115 | 116 | SmallVector InstsWithTBAATag; 117 | 118 | // Type resolution handling data structures. The location is set when we 119 | // have processed a use of the type but not a definition yet. 120 | StringMap > NamedTypes; 121 | std::map > NumberedTypes; 122 | 123 | std::map NumberedMetadata; 124 | std::map> ForwardRefMDNodes; 125 | 126 | // Global Value reference information. 127 | std::map > ForwardRefVals; 128 | std::map > ForwardRefValIDs; 129 | std::vector NumberedVals; 130 | 131 | // Comdat forward reference information. 132 | std::map ForwardRefComdats; 133 | 134 | // References to blockaddress. The key is the function ValID, the value is 135 | // a list of references to blocks in that function. 136 | std::map> ForwardRefBlockAddresses; 137 | class PerFunctionState; 138 | /// Reference to per-function state to allow basic blocks to be 139 | /// forward-referenced by blockaddress instructions within the same 140 | /// function. 141 | PerFunctionState *BlockAddressPFS; 142 | 143 | // Attribute builder reference information. 144 | std::map > ForwardRefAttrGroups; 145 | std::map NumberedAttrBuilders; 146 | 147 | // Summary global value reference information. 148 | std::map>> 149 | ForwardRefValueInfos; 150 | std::map>> 151 | ForwardRefAliasees; 152 | std::vector NumberedValueInfos; 153 | 154 | // Summary type id reference information. 155 | std::map>> 156 | ForwardRefTypeIds; 157 | 158 | // Map of module ID to path. 159 | std::map ModuleIdMap; 160 | 161 | /// Only the llvm-as tool may set this to false to bypass 162 | /// UpgradeDebuginfo so it can generate broken bitcode. 163 | bool UpgradeDebugInfo; 164 | 165 | /// DataLayout string to override that in LLVM assembly. 166 | StringRef DataLayoutStr; 167 | 168 | std::string SourceFileName; 169 | 170 | public: 171 | DummyLLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M, 172 | ModuleSummaryIndex *Index, LLVMContext &Context, 173 | bool TypeCheck = true, SlotMapping *Slots = nullptr, 174 | bool UpgradeDebugInfo = true, StringRef DataLayoutString = "") 175 | : Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index), 176 | TypeCheck(TypeCheck), Slots(Slots), BlockAddressPFS(nullptr), 177 | UpgradeDebugInfo(UpgradeDebugInfo), DataLayoutStr(DataLayoutString) { 178 | if (!DataLayoutStr.empty()) 179 | M->setDataLayout(DataLayoutStr); 180 | } 181 | bool Run(); 182 | 183 | bool parseStandaloneConstantValue(Constant *&C, const SlotMapping *Slots); 184 | 185 | bool parseTypeAtBeginning(Type *&Ty, unsigned &Read, 186 | const SlotMapping *Slots); 187 | 188 | LLVMContext &getContext() { return Context; } 189 | 190 | private: 191 | 192 | bool Error(LocTy L, const Twine &Msg) const { 193 | return Lex.Error(L, Msg); 194 | } 195 | bool TokError(const Twine &Msg) const { 196 | return Error(Lex.getLoc(), Msg); 197 | } 198 | 199 | /// Restore the internal name and slot mappings using the mappings that 200 | /// were created at an earlier parsing stage. 201 | void restoreParsingState(const SlotMapping *Slots); 202 | 203 | /// GetGlobalVal - Get a value with the specified name or ID, creating a 204 | /// forward reference record if needed. This can return null if the value 205 | /// exists but does not have the right type. 206 | GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc, 207 | bool IsCall); 208 | GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc, bool IsCall); 209 | 210 | /// Get a Comdat with the specified name, creating a forward reference 211 | /// record if needed. 212 | Comdat *getComdat(const std::string &Name, LocTy Loc); 213 | 214 | // Helper Routines. 215 | bool ParseToken(lltok::Kind T, const char *ErrMsg); 216 | bool EatIfPresent(lltok::Kind T) { 217 | if (Lex.getKind() != T) return false; 218 | Lex.Lex(); 219 | return true; 220 | } 221 | 222 | FastMathFlags EatFastMathFlagsIfPresent() { 223 | FastMathFlags FMF; 224 | while (true) 225 | switch (Lex.getKind()) { 226 | case lltok::kw_fast: FMF.setFast(); Lex.Lex(); continue; 227 | case lltok::kw_nnan: FMF.setNoNaNs(); Lex.Lex(); continue; 228 | case lltok::kw_ninf: FMF.setNoInfs(); Lex.Lex(); continue; 229 | case lltok::kw_nsz: FMF.setNoSignedZeros(); Lex.Lex(); continue; 230 | case lltok::kw_arcp: FMF.setAllowReciprocal(); Lex.Lex(); continue; 231 | case lltok::kw_contract: 232 | FMF.setAllowContract(true); 233 | Lex.Lex(); 234 | continue; 235 | case lltok::kw_reassoc: FMF.setAllowReassoc(); Lex.Lex(); continue; 236 | case lltok::kw_afn: FMF.setApproxFunc(); Lex.Lex(); continue; 237 | default: return FMF; 238 | } 239 | return FMF; 240 | } 241 | 242 | bool ParseOptionalToken(lltok::Kind T, bool &Present, 243 | LocTy *Loc = nullptr) { 244 | if (Lex.getKind() != T) { 245 | Present = false; 246 | } else { 247 | if (Loc) 248 | *Loc = Lex.getLoc(); 249 | Lex.Lex(); 250 | Present = true; 251 | } 252 | return false; 253 | } 254 | bool ParseStringConstant(std::string &Result); 255 | bool ParseUInt32(unsigned &Val); 256 | bool ParseUInt32(unsigned &Val, LocTy &Loc) { 257 | Loc = Lex.getLoc(); 258 | return ParseUInt32(Val); 259 | } 260 | bool ParseUInt64(uint64_t &Val); 261 | bool ParseUInt64(uint64_t &Val, LocTy &Loc) { 262 | Loc = Lex.getLoc(); 263 | return ParseUInt64(Val); 264 | } 265 | bool ParseFlag(unsigned &Val); 266 | 267 | bool ParseStringAttribute(AttrBuilder &B); 268 | 269 | bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM); 270 | bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM); 271 | bool ParseOptionalUnnamedAddr(GlobalVariable::UnnamedAddr &UnnamedAddr); 272 | bool ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS = 0); 273 | bool ParseOptionalProgramAddrSpace(unsigned &AddrSpace) { 274 | return ParseOptionalAddrSpace( 275 | AddrSpace, M->getDataLayout().getProgramAddressSpace()); 276 | }; 277 | bool ParseOptionalParamAttrs(AttrBuilder &B); 278 | bool ParseOptionalReturnAttrs(AttrBuilder &B); 279 | bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, 280 | unsigned &Visibility, unsigned &DLLStorageClass, 281 | bool &DSOLocal); 282 | void ParseOptionalDSOLocal(bool &DSOLocal); 283 | void ParseOptionalVisibility(unsigned &Res); 284 | void ParseOptionalDLLStorageClass(unsigned &Res); 285 | bool ParseOptionalCallingConv(unsigned &CC); 286 | bool ParseOptionalAlignment(unsigned &Alignment); 287 | bool ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes); 288 | bool ParseScopeAndOrdering(bool isAtomic, SyncScope::ID &SSID, 289 | AtomicOrdering &Ordering); 290 | bool ParseScope(SyncScope::ID &SSID); 291 | bool ParseOrdering(AtomicOrdering &Ordering); 292 | bool ParseOptionalStackAlignment(unsigned &Alignment); 293 | bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); 294 | bool ParseOptionalCommaAddrSpace(unsigned &AddrSpace, LocTy &Loc, 295 | bool &AteExtraComma); 296 | bool ParseOptionalCommaInAlloca(bool &IsInAlloca); 297 | bool parseAllocSizeArguments(unsigned &BaseSizeArg, 298 | Optional &HowManyArg); 299 | bool ParseIndexList(SmallVectorImpl &Indices, 300 | bool &AteExtraComma); 301 | bool ParseIndexList(SmallVectorImpl &Indices) { 302 | bool AteExtraComma; 303 | if (ParseIndexList(Indices, AteExtraComma)) return true; 304 | if (AteExtraComma) 305 | return TokError("expected index"); 306 | return false; 307 | } 308 | 309 | // Top-Level Entities 310 | bool ParseTopLevelEntities(); 311 | bool ValidateEndOfModule(); 312 | bool ValidateEndOfIndex(); 313 | bool ParseTargetDefinition(); 314 | bool ParseModuleAsm(); 315 | bool ParseSourceFileName(); 316 | bool ParseDepLibs(); // FIXME: Remove in 4.0. 317 | bool ParseUnnamedType(); 318 | bool ParseNamedType(); 319 | bool ParseDeclare(); 320 | bool ParseDefine(); 321 | 322 | bool ParseGlobalType(bool &IsConstant); 323 | bool ParseUnnamedGlobal(); 324 | bool ParseNamedGlobal(); 325 | bool ParseGlobal(const std::string &Name, LocTy NameLoc, unsigned Linkage, 326 | bool HasLinkage, unsigned Visibility, 327 | unsigned DLLStorageClass, bool DSOLocal, 328 | GlobalVariable::ThreadLocalMode TLM, 329 | GlobalVariable::UnnamedAddr UnnamedAddr); 330 | bool parseIndirectSymbol(const std::string &Name, LocTy NameLoc, 331 | unsigned L, unsigned Visibility, 332 | unsigned DLLStorageClass, bool DSOLocal, 333 | GlobalVariable::ThreadLocalMode TLM, 334 | GlobalVariable::UnnamedAddr UnnamedAddr); 335 | bool parseComdat(); 336 | bool ParseStandaloneMetadata(); 337 | bool ParseNamedMetadata(); 338 | bool ParseMDString(MDString *&Result); 339 | bool ParseMDNodeID(MDNode *&Result); 340 | bool ParseUnnamedAttrGrp(); 341 | bool ParseFnAttributeValuePairs(AttrBuilder &B, 342 | std::vector &FwdRefAttrGrps, 343 | bool inAttrGrp, LocTy &BuiltinLoc); 344 | 345 | // Module Summary Index Parsing. 346 | bool SkipModuleSummaryEntry(); 347 | bool ParseSummaryEntry(); 348 | bool ParseModuleEntry(unsigned ID); 349 | bool ParseModuleReference(StringRef &ModulePath); 350 | bool ParseGVReference(ValueInfo &VI, unsigned &GVId); 351 | bool ParseGVEntry(unsigned ID); 352 | bool ParseFunctionSummary(std::string Name, GlobalValue::GUID, unsigned ID); 353 | bool ParseVariableSummary(std::string Name, GlobalValue::GUID, unsigned ID); 354 | bool ParseAliasSummary(std::string Name, GlobalValue::GUID, unsigned ID); 355 | bool ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags); 356 | bool ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags); 357 | bool ParseOptionalFFlags(FunctionSummary::FFlags &FFlags); 358 | bool ParseOptionalCalls(std::vector &Calls); 359 | bool ParseHotness(CalleeInfo::HotnessType &Hotness); 360 | bool ParseOptionalTypeIdInfo(FunctionSummary::TypeIdInfo &TypeIdInfo); 361 | bool ParseTypeTests(std::vector &TypeTests); 362 | bool ParseVFuncIdList(lltok::Kind Kind, 363 | std::vector &VFuncIdList); 364 | bool ParseConstVCallList( 365 | lltok::Kind Kind, 366 | std::vector &ConstVCallList); 367 | using IdToIndexMapType = 368 | std::map>>; 369 | bool ParseConstVCall(FunctionSummary::ConstVCall &ConstVCall, 370 | IdToIndexMapType &IdToIndexMap, unsigned Index); 371 | bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId, 372 | IdToIndexMapType &IdToIndexMap, unsigned Index); 373 | bool ParseOptionalRefs(std::vector &Refs); 374 | bool ParseTypeIdEntry(unsigned ID); 375 | bool ParseTypeIdSummary(TypeIdSummary &TIS); 376 | bool ParseTypeTestResolution(TypeTestResolution &TTRes); 377 | bool ParseOptionalWpdResolutions( 378 | std::map &WPDResMap); 379 | bool ParseWpdRes(WholeProgramDevirtResolution &WPDRes); 380 | bool ParseOptionalResByArg( 381 | std::map, WholeProgramDevirtResolution::ByArg> 382 | &ResByArg); 383 | bool ParseArgs(std::vector &Args); 384 | void AddGlobalValueToIndex(std::string Name, GlobalValue::GUID, 385 | GlobalValue::LinkageTypes Linkage, unsigned ID, 386 | std::unique_ptr Summary); 387 | 388 | // Type Parsing. 389 | bool ParseType(Type *&Result, const Twine &Msg, bool AllowVoid = false); 390 | bool ParseType(Type *&Result, bool AllowVoid = false) { 391 | return ParseType(Result, "expected type", AllowVoid); 392 | } 393 | bool ParseType(Type *&Result, const Twine &Msg, LocTy &Loc, 394 | bool AllowVoid = false) { 395 | Loc = Lex.getLoc(); 396 | return ParseType(Result, Msg, AllowVoid); 397 | } 398 | bool ParseType(Type *&Result, LocTy &Loc, bool AllowVoid = false) { 399 | Loc = Lex.getLoc(); 400 | return ParseType(Result, AllowVoid); 401 | } 402 | bool ParseAnonStructType(Type *&Result, bool Packed); 403 | bool ParseStructBody(SmallVectorImpl &Body); 404 | bool ParseStructDefinition(SMLoc TypeLoc, StringRef Name, 405 | std::pair &Entry, 406 | Type *&ResultTy); 407 | 408 | bool ParseArrayVectorType(Type *&Result, bool isVector); 409 | bool ParseFunctionType(Type *&Result); 410 | 411 | // Function Semantic Analysis. 412 | class PerFunctionState { 413 | DummyLLParser &P; 414 | Function &F; 415 | std::map > ForwardRefVals; 416 | std::map > ForwardRefValIDs; 417 | std::vector NumberedVals; 418 | 419 | /// FunctionNumber - If this is an unnamed function, this is the slot 420 | /// number of it, otherwise it is -1. 421 | int FunctionNumber; 422 | public: 423 | PerFunctionState(DummyLLParser &p, Function &f, int functionNumber); 424 | ~PerFunctionState(); 425 | 426 | Function &getFunction() const { return F; } 427 | 428 | bool FinishFunction(); 429 | 430 | /// GetVal - Get a value with the specified name or ID, creating a 431 | /// forward reference record if needed. This can return null if the value 432 | /// exists but does not have the right type. 433 | Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc, bool IsCall); 434 | Value *GetVal(unsigned ID, Type *Ty, LocTy Loc, bool IsCall); 435 | 436 | /// SetInstName - After an instruction is parsed and inserted into its 437 | /// basic block, this installs its name. 438 | bool SetInstName(int NameID, const std::string &NameStr, LocTy NameLoc, 439 | Instruction *Inst); 440 | 441 | /// GetBB - Get a basic block with the specified name or ID, creating a 442 | /// forward reference record if needed. This can return null if the value 443 | /// is not a BasicBlock. 444 | BasicBlock *GetBB(const std::string &Name, LocTy Loc); 445 | BasicBlock *GetBB(unsigned ID, LocTy Loc); 446 | 447 | /// DefineBB - Define the specified basic block, which is either named or 448 | /// unnamed. If there is an error, this returns null otherwise it returns 449 | /// the block being defined. 450 | BasicBlock *DefineBB(const std::string &Name, LocTy Loc); 451 | 452 | bool resolveForwardRefBlockAddresses(); 453 | }; 454 | 455 | bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, 456 | PerFunctionState *PFS, bool IsCall); 457 | 458 | Value *checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty, 459 | Value *Val, bool IsCall); 460 | 461 | bool parseConstantValue(Type *Ty, Constant *&C); 462 | bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); 463 | bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) { 464 | return ParseValue(Ty, V, &PFS); 465 | } 466 | 467 | bool ParseValue(Type *Ty, Value *&V, LocTy &Loc, 468 | PerFunctionState &PFS) { 469 | Loc = Lex.getLoc(); 470 | return ParseValue(Ty, V, &PFS); 471 | } 472 | 473 | bool ParseTypeAndValue(Value *&V, PerFunctionState *PFS); 474 | bool ParseTypeAndValue(Value *&V, PerFunctionState &PFS) { 475 | return ParseTypeAndValue(V, &PFS); 476 | } 477 | bool ParseTypeAndValue(Value *&V, LocTy &Loc, PerFunctionState &PFS) { 478 | Loc = Lex.getLoc(); 479 | return ParseTypeAndValue(V, PFS); 480 | } 481 | bool ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, 482 | PerFunctionState &PFS); 483 | bool ParseTypeAndBasicBlock(BasicBlock *&BB, PerFunctionState &PFS) { 484 | LocTy Loc; 485 | return ParseTypeAndBasicBlock(BB, Loc, PFS); 486 | } 487 | 488 | 489 | struct ParamInfo { 490 | LocTy Loc; 491 | Value *V; 492 | AttributeSet Attrs; 493 | ParamInfo(LocTy loc, Value *v, AttributeSet attrs) 494 | : Loc(loc), V(v), Attrs(attrs) {} 495 | }; 496 | bool ParseParameterList(SmallVectorImpl &ArgList, 497 | PerFunctionState &PFS, 498 | bool IsMustTailCall = false, 499 | bool InVarArgsFunc = false); 500 | 501 | bool 502 | ParseOptionalOperandBundles(SmallVectorImpl &BundleList, 503 | PerFunctionState &PFS); 504 | 505 | bool ParseExceptionArgs(SmallVectorImpl &Args, 506 | PerFunctionState &PFS); 507 | 508 | // Constant Parsing. 509 | bool ParseValID(ValID &ID, PerFunctionState *PFS = nullptr); 510 | bool ParseGlobalValue(Type *Ty, Constant *&C); 511 | bool ParseGlobalTypeAndValue(Constant *&V); 512 | bool ParseGlobalValueVector(SmallVectorImpl &Elts, 513 | Optional *InRangeOp = nullptr); 514 | bool parseOptionalComdat(StringRef GlobalName, Comdat *&C); 515 | bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS); 516 | bool ParseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg, 517 | PerFunctionState *PFS); 518 | bool ParseMetadata(Metadata *&MD, PerFunctionState *PFS); 519 | bool ParseMDTuple(MDNode *&MD, bool IsDistinct = false); 520 | bool ParseMDNode(MDNode *&N); 521 | bool ParseMDNodeTail(MDNode *&N); 522 | bool ParseMDNodeVector(SmallVectorImpl &Elts); 523 | bool ParseMetadataAttachment(unsigned &Kind, MDNode *&MD); 524 | bool ParseInstructionMetadata(Instruction &Inst); 525 | bool ParseGlobalObjectMetadataAttachment(GlobalObject &GO); 526 | bool ParseOptionalFunctionMetadata(Function &F); 527 | 528 | template 529 | bool ParseMDField(LocTy Loc, StringRef Name, FieldTy &Result); 530 | template bool ParseMDField(StringRef Name, FieldTy &Result); 531 | template 532 | bool ParseMDFieldsImplBody(ParserTy parseField); 533 | template 534 | bool ParseMDFieldsImpl(ParserTy parseField, LocTy &ClosingLoc); 535 | bool ParseSpecializedMDNode(MDNode *&N, bool IsDistinct = false); 536 | 537 | #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) \ 538 | bool Parse##CLASS(MDNode *&Result, bool IsDistinct); 539 | #include "llvm/IR/Metadata.def" 540 | 541 | // Function Parsing. 542 | struct ArgInfo { 543 | LocTy Loc; 544 | Type *Ty; 545 | AttributeSet Attrs; 546 | std::string Name; 547 | ArgInfo(LocTy L, Type *ty, AttributeSet Attr, const std::string &N) 548 | : Loc(L), Ty(ty), Attrs(Attr), Name(N) {} 549 | }; 550 | bool ParseArgumentList(SmallVectorImpl &ArgList, bool &isVarArg); 551 | bool ParseFunctionHeader(Function *&Fn, bool isDefine); 552 | bool ParseFunctionBody(Function &Fn); 553 | bool ParseBasicBlock(PerFunctionState &PFS); 554 | 555 | enum TailCallType { TCT_None, TCT_Tail, TCT_MustTail }; 556 | 557 | // Instruction Parsing. Each instruction parsing routine can return with a 558 | // normal result, an error result, or return having eaten an extra comma. 559 | enum InstResult { InstNormal = 0, InstError = 1, InstExtraComma = 2 }; 560 | int ParseInstruction(Instruction *&Inst, BasicBlock *BB, 561 | PerFunctionState &PFS); 562 | bool ParseCmpPredicate(unsigned &P, unsigned Opc); 563 | 564 | bool ParseRet(Instruction *&Inst, BasicBlock *BB, PerFunctionState &PFS); 565 | bool ParseBr(Instruction *&Inst, PerFunctionState &PFS); 566 | bool ParseSwitch(Instruction *&Inst, PerFunctionState &PFS); 567 | bool ParseIndirectBr(Instruction *&Inst, PerFunctionState &PFS); 568 | bool ParseInvoke(Instruction *&Inst, PerFunctionState &PFS); 569 | bool ParseResume(Instruction *&Inst, PerFunctionState &PFS); 570 | bool ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS); 571 | bool ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS); 572 | bool ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS); 573 | bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS); 574 | bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS); 575 | 576 | bool ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc, 577 | unsigned OperandType); 578 | bool ParseArithmetic(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc, 579 | unsigned OperandType); 580 | bool ParseLogical(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc); 581 | bool ParseCompare(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc); 582 | bool ParseCast(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc); 583 | bool ParseSelect(Instruction *&Inst, PerFunctionState &PFS); 584 | bool ParseVA_Arg(Instruction *&Inst, PerFunctionState &PFS); 585 | bool ParseExtractElement(Instruction *&Inst, PerFunctionState &PFS); 586 | bool ParseInsertElement(Instruction *&Inst, PerFunctionState &PFS); 587 | bool ParseShuffleVector(Instruction *&Inst, PerFunctionState &PFS); 588 | int ParsePHI(Instruction *&Inst, PerFunctionState &PFS); 589 | bool ParseLandingPad(Instruction *&Inst, PerFunctionState &PFS); 590 | bool ParseCall(Instruction *&Inst, PerFunctionState &PFS, 591 | CallInst::TailCallKind TCK); 592 | int ParseAlloc(Instruction *&Inst, PerFunctionState &PFS); 593 | int ParseLoad(Instruction *&Inst, PerFunctionState &PFS); 594 | int ParseStore(Instruction *&Inst, PerFunctionState &PFS); 595 | int ParseCmpXchg(Instruction *&Inst, PerFunctionState &PFS); 596 | int ParseAtomicRMW(Instruction *&Inst, PerFunctionState &PFS); 597 | int ParseFence(Instruction *&Inst, PerFunctionState &PFS); 598 | int ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS); 599 | int ParseExtractValue(Instruction *&Inst, PerFunctionState &PFS); 600 | int ParseInsertValue(Instruction *&Inst, PerFunctionState &PFS); 601 | 602 | // Use-list order directives. 603 | bool ParseUseListOrder(PerFunctionState *PFS = nullptr); 604 | bool ParseUseListOrderBB(); 605 | bool ParseUseListOrderIndexes(SmallVectorImpl &Indexes); 606 | bool sortUseListOrder(Value *V, ArrayRef Indexes, SMLoc Loc); 607 | }; 608 | } // End llvm namespace 609 | 610 | #endif 611 | -------------------------------------------------------------------------------- /lab8/include/Extractor.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTRACTOR_H 2 | #define EXTRACTOR_H 3 | 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/IR/Type.h" 7 | 8 | #include "z3++.h" 9 | 10 | using namespace llvm; 11 | 12 | class Extractor { 13 | public: 14 | Extractor() { Solver = new z3::solver(C); } 15 | ~Extractor() { delete Solver; } 16 | 17 | z3::solver *getSolver() { return Solver; } 18 | z3::context &getContext() { return C; } 19 | z3::func_decl &getTypeEnv() { return TypeEnv; } 20 | const z3::expr getTypeVoid() { return TypeVoid; } 21 | const z3::expr getTypeI32() { return TypeI32; } 22 | const z3::expr getTypeI8() { return TypeI8; } 23 | const z3::expr getTypeI1() { return TypeI1; } 24 | const z3::expr getTypePtr() { return TypePtr; } 25 | const z3::expr getTypeApp() { return TypeApp; } 26 | 27 | void extractConstraints(Instruction *I); 28 | 29 | static std::string toString(Value *I) { 30 | std::string Str; 31 | raw_string_ostream SS(Str); 32 | I->print(SS); 33 | return SS.str(); 34 | } 35 | 36 | static std::string toString(Type *T) { 37 | std::string Str; 38 | raw_string_ostream SS(Str); 39 | T->print(SS); 40 | return SS.str(); 41 | } 42 | 43 | private: 44 | const char *TypeVoidSymbol = "void"; 45 | const char *TypeI32Symbol = "i32"; 46 | const char *TypeI8Symbol = "i8"; 47 | const char *TypeI1Symbol = "i1"; 48 | const char *PtrSymbol = "*"; 49 | const char *AppSymbol = "->"; 50 | 51 | z3::context C; 52 | z3::solver *Solver; 53 | z3::check_result Result; 54 | z3::sort LLVMType = C.string_sort(); 55 | z3::sort LLVMExpr = C.string_sort(); 56 | z3::func_decl TypeEnv = C.function("TypeEnv", LLVMExpr, LLVMType); 57 | const z3::expr TypeVoid = C.string_val(TypeVoidSymbol); 58 | const z3::expr TypeI32 = C.string_val(TypeI32Symbol); 59 | const z3::expr TypeI8 = C.string_val(TypeI8Symbol); 60 | const z3::expr TypeI1 = C.string_val(TypeI1Symbol); 61 | const z3::expr TypePtr = C.string_val(PtrSymbol); 62 | const z3::expr TypeApp = C.string_val(AppSymbol); 63 | 64 | z3::expr ptrOf(z3::expr E) { return z3::concat(E, TypePtr); } 65 | 66 | z3::expr retOf(z3::expr E) { 67 | z3::expr I = z3::indexof(E, TypeApp, C.int_val(0)) + C.int_val(2); 68 | return E.extract(I, E.length()); 69 | } 70 | }; 71 | 72 | #endif // EXTRACTOR_H 73 | -------------------------------------------------------------------------------- /lab8/include/LLLexer.h: -------------------------------------------------------------------------------- 1 | //===- LLLexer.h - Lexer for LLVM Assembly Files ----------------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This class represents the Lexer for .ll files. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef LLVM_LIB_ASMPARSER_LLLEXER_H 15 | #define LLVM_LIB_ASMPARSER_LLLEXER_H 16 | 17 | #include "LLToken.h" 18 | #include "llvm/ADT/APFloat.h" 19 | #include "llvm/ADT/APSInt.h" 20 | #include "llvm/Support/SourceMgr.h" 21 | #include 22 | 23 | namespace llvm { 24 | class MemoryBuffer; 25 | class Type; 26 | class SMDiagnostic; 27 | class LLVMContext; 28 | 29 | class LLLexer { 30 | const char *CurPtr; 31 | StringRef CurBuf; 32 | SMDiagnostic &ErrorInfo; 33 | SourceMgr &SM; 34 | LLVMContext &Context; 35 | 36 | // Information about the current token. 37 | const char *TokStart; 38 | lltok::Kind CurKind; 39 | std::string StrVal; 40 | unsigned UIntVal; 41 | Type *TyVal; 42 | APFloat APFloatVal; 43 | APSInt APSIntVal; 44 | 45 | // When false (default), an identifier ending in ':' is a label token. 46 | // When true, the ':' is treated as a separate token. 47 | bool IgnoreColonInIdentifiers; 48 | 49 | public: 50 | explicit LLLexer(StringRef StartBuf, SourceMgr &SM, SMDiagnostic &, 51 | LLVMContext &C); 52 | 53 | lltok::Kind Lex() { 54 | return CurKind = LexToken(); 55 | } 56 | 57 | typedef SMLoc LocTy; 58 | LocTy getLoc() const { return SMLoc::getFromPointer(TokStart); } 59 | lltok::Kind getKind() const { return CurKind; } 60 | const std::string &getStrVal() const { return StrVal; } 61 | Type *getTyVal() const { return TyVal; } 62 | unsigned getUIntVal() const { return UIntVal; } 63 | const APSInt &getAPSIntVal() const { return APSIntVal; } 64 | const APFloat &getAPFloatVal() const { return APFloatVal; } 65 | 66 | void setIgnoreColonInIdentifiers(bool val) { 67 | IgnoreColonInIdentifiers = val; 68 | } 69 | 70 | bool Error(LocTy ErrorLoc, const Twine &Msg) const; 71 | bool Error(const Twine &Msg) const { return Error(getLoc(), Msg); } 72 | 73 | void Warning(LocTy WarningLoc, const Twine &Msg) const; 74 | void Warning(const Twine &Msg) const { return Warning(getLoc(), Msg); } 75 | 76 | private: 77 | lltok::Kind LexToken(); 78 | 79 | int getNextChar(); 80 | void SkipLineComment(); 81 | lltok::Kind ReadString(lltok::Kind kind); 82 | bool ReadVarName(); 83 | 84 | lltok::Kind LexIdentifier(); 85 | lltok::Kind LexDigitOrNegative(); 86 | lltok::Kind LexPositive(); 87 | lltok::Kind LexAt(); 88 | lltok::Kind LexDollar(); 89 | lltok::Kind LexExclaim(); 90 | lltok::Kind LexPercent(); 91 | lltok::Kind LexUIntID(lltok::Kind Token); 92 | lltok::Kind LexVar(lltok::Kind Var, lltok::Kind VarID); 93 | lltok::Kind LexQuote(); 94 | lltok::Kind Lex0x(); 95 | lltok::Kind LexHash(); 96 | lltok::Kind LexCaret(); 97 | 98 | uint64_t atoull(const char *Buffer, const char *End); 99 | uint64_t HexIntToVal(const char *Buffer, const char *End); 100 | void HexToIntPair(const char *Buffer, const char *End, uint64_t Pair[2]); 101 | void FP80HexToIntPair(const char *Buffer, const char *End, uint64_t Pair[2]); 102 | }; 103 | } // end namespace llvm 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /lab8/include/LLToken.h: -------------------------------------------------------------------------------- 1 | //===- LLToken.h - Token Codes for LLVM Assembly Files ----------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file defines the enums for the .ll lexer. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef LLVM_LIB_ASMPARSER_LLTOKEN_H 15 | #define LLVM_LIB_ASMPARSER_LLTOKEN_H 16 | 17 | namespace llvm { 18 | namespace lltok { 19 | enum Kind { 20 | // Markers 21 | Eof, 22 | Error, 23 | 24 | // Tokens with no info. 25 | dotdotdot, // ... 26 | equal, 27 | comma, // = , 28 | star, // * 29 | lsquare, 30 | rsquare, // [ ] 31 | lbrace, 32 | rbrace, // { } 33 | less, 34 | greater, // < > 35 | lparen, 36 | rparen, // ( ) 37 | exclaim, // ! 38 | bar, // | 39 | colon, // : 40 | 41 | kw_x, 42 | kw_true, 43 | kw_false, 44 | kw_declare, 45 | kw_define, 46 | kw_global, 47 | kw_constant, 48 | 49 | kw_dso_local, 50 | kw_dso_preemptable, 51 | 52 | kw_private, 53 | kw_internal, 54 | kw_linkonce, 55 | kw_linkonce_odr, 56 | kw_weak, // Used as a linkage, and a modifier for "cmpxchg". 57 | kw_weak_odr, 58 | kw_appending, 59 | kw_dllimport, 60 | kw_dllexport, 61 | kw_common, 62 | kw_available_externally, 63 | kw_default, 64 | kw_hidden, 65 | kw_protected, 66 | kw_unnamed_addr, 67 | kw_local_unnamed_addr, 68 | kw_externally_initialized, 69 | kw_extern_weak, 70 | kw_external, 71 | kw_thread_local, 72 | kw_localdynamic, 73 | kw_initialexec, 74 | kw_localexec, 75 | kw_zeroinitializer, 76 | kw_undef, 77 | kw_null, 78 | kw_none, 79 | kw_to, 80 | kw_caller, 81 | kw_within, 82 | kw_from, 83 | kw_tail, 84 | kw_musttail, 85 | kw_notail, 86 | kw_target, 87 | kw_triple, 88 | kw_source_filename, 89 | kw_unwind, 90 | kw_deplibs, // FIXME: Remove in 4.0 91 | kw_datalayout, 92 | kw_volatile, 93 | kw_atomic, 94 | kw_unordered, 95 | kw_monotonic, 96 | kw_acquire, 97 | kw_release, 98 | kw_acq_rel, 99 | kw_seq_cst, 100 | kw_syncscope, 101 | kw_nnan, 102 | kw_ninf, 103 | kw_nsz, 104 | kw_arcp, 105 | kw_contract, 106 | kw_reassoc, 107 | kw_afn, 108 | kw_fast, 109 | kw_nuw, 110 | kw_nsw, 111 | kw_exact, 112 | kw_inbounds, 113 | kw_inrange, 114 | kw_align, 115 | kw_addrspace, 116 | kw_section, 117 | kw_alias, 118 | kw_ifunc, 119 | kw_module, 120 | kw_asm, 121 | kw_sideeffect, 122 | kw_alignstack, 123 | kw_inteldialect, 124 | kw_gc, 125 | kw_prefix, 126 | kw_prologue, 127 | kw_c, 128 | 129 | kw_cc, 130 | kw_ccc, 131 | kw_fastcc, 132 | kw_coldcc, 133 | kw_intel_ocl_bicc, 134 | kw_x86_stdcallcc, 135 | kw_x86_fastcallcc, 136 | kw_x86_thiscallcc, 137 | kw_x86_vectorcallcc, 138 | kw_x86_regcallcc, 139 | kw_arm_apcscc, 140 | kw_arm_aapcscc, 141 | kw_arm_aapcs_vfpcc, 142 | kw_aarch64_vector_pcs, 143 | kw_msp430_intrcc, 144 | kw_avr_intrcc, 145 | kw_avr_signalcc, 146 | kw_ptx_kernel, 147 | kw_ptx_device, 148 | kw_spir_kernel, 149 | kw_spir_func, 150 | kw_x86_64_sysvcc, 151 | kw_win64cc, 152 | kw_webkit_jscc, 153 | kw_anyregcc, 154 | kw_swiftcc, 155 | kw_preserve_mostcc, 156 | kw_preserve_allcc, 157 | kw_ghccc, 158 | kw_x86_intrcc, 159 | kw_hhvmcc, 160 | kw_hhvm_ccc, 161 | kw_cxx_fast_tlscc, 162 | kw_amdgpu_vs, 163 | kw_amdgpu_ls, 164 | kw_amdgpu_hs, 165 | kw_amdgpu_es, 166 | kw_amdgpu_gs, 167 | kw_amdgpu_ps, 168 | kw_amdgpu_cs, 169 | kw_amdgpu_kernel, 170 | 171 | // Attributes: 172 | kw_attributes, 173 | kw_allocsize, 174 | kw_alwaysinline, 175 | kw_argmemonly, 176 | kw_sanitize_address, 177 | kw_sanitize_hwaddress, 178 | kw_builtin, 179 | kw_byval, 180 | kw_inalloca, 181 | kw_cold, 182 | kw_convergent, 183 | kw_dereferenceable, 184 | kw_dereferenceable_or_null, 185 | kw_inaccessiblememonly, 186 | kw_inaccessiblemem_or_argmemonly, 187 | kw_inlinehint, 188 | kw_inreg, 189 | kw_jumptable, 190 | kw_minsize, 191 | kw_naked, 192 | kw_nest, 193 | kw_noalias, 194 | kw_nobuiltin, 195 | kw_nocapture, 196 | kw_noduplicate, 197 | kw_noimplicitfloat, 198 | kw_noinline, 199 | kw_norecurse, 200 | kw_nonlazybind, 201 | kw_nonnull, 202 | kw_noredzone, 203 | kw_noreturn, 204 | kw_nocf_check, 205 | kw_nounwind, 206 | kw_optforfuzzing, 207 | kw_optnone, 208 | kw_optsize, 209 | kw_readnone, 210 | kw_readonly, 211 | kw_returned, 212 | kw_returns_twice, 213 | kw_signext, 214 | kw_speculatable, 215 | kw_ssp, 216 | kw_sspreq, 217 | kw_sspstrong, 218 | kw_safestack, 219 | kw_shadowcallstack, 220 | kw_sret, 221 | kw_sanitize_thread, 222 | kw_sanitize_memory, 223 | kw_speculative_load_hardening, 224 | kw_strictfp, 225 | kw_swifterror, 226 | kw_swiftself, 227 | kw_uwtable, 228 | kw_writeonly, 229 | kw_zeroext, 230 | 231 | kw_type, 232 | kw_opaque, 233 | 234 | kw_comdat, 235 | 236 | // Comdat types 237 | kw_any, 238 | kw_exactmatch, 239 | kw_largest, 240 | kw_noduplicates, 241 | kw_samesize, 242 | 243 | kw_eq, 244 | kw_ne, 245 | kw_slt, 246 | kw_sgt, 247 | kw_sle, 248 | kw_sge, 249 | kw_ult, 250 | kw_ugt, 251 | kw_ule, 252 | kw_uge, 253 | kw_oeq, 254 | kw_one, 255 | kw_olt, 256 | kw_ogt, 257 | kw_ole, 258 | kw_oge, 259 | kw_ord, 260 | kw_uno, 261 | kw_ueq, 262 | kw_une, 263 | 264 | // atomicrmw operations that aren't also instruction keywords. 265 | kw_xchg, 266 | kw_nand, 267 | kw_max, 268 | kw_min, 269 | kw_umax, 270 | kw_umin, 271 | 272 | // Instruction Opcodes (Opcode in UIntVal). 273 | kw_fneg, 274 | kw_add, 275 | kw_fadd, 276 | kw_sub, 277 | kw_fsub, 278 | kw_mul, 279 | kw_fmul, 280 | kw_udiv, 281 | kw_sdiv, 282 | kw_fdiv, 283 | kw_urem, 284 | kw_srem, 285 | kw_frem, 286 | kw_shl, 287 | kw_lshr, 288 | kw_ashr, 289 | kw_and, 290 | kw_or, 291 | kw_xor, 292 | kw_icmp, 293 | kw_fcmp, 294 | 295 | kw_phi, 296 | kw_call, 297 | kw_trunc, 298 | kw_zext, 299 | kw_sext, 300 | kw_fptrunc, 301 | kw_fpext, 302 | kw_uitofp, 303 | kw_sitofp, 304 | kw_fptoui, 305 | kw_fptosi, 306 | kw_inttoptr, 307 | kw_ptrtoint, 308 | kw_bitcast, 309 | kw_addrspacecast, 310 | kw_select, 311 | kw_va_arg, 312 | 313 | kw_landingpad, 314 | kw_personality, 315 | kw_cleanup, 316 | kw_catch, 317 | kw_filter, 318 | 319 | kw_ret, 320 | kw_br, 321 | kw_switch, 322 | kw_indirectbr, 323 | kw_invoke, 324 | kw_resume, 325 | kw_unreachable, 326 | kw_cleanupret, 327 | kw_catchswitch, 328 | kw_catchret, 329 | kw_catchpad, 330 | kw_cleanuppad, 331 | 332 | kw_alloca, 333 | kw_load, 334 | kw_store, 335 | kw_fence, 336 | kw_cmpxchg, 337 | kw_atomicrmw, 338 | kw_getelementptr, 339 | 340 | kw_extractelement, 341 | kw_insertelement, 342 | kw_shufflevector, 343 | kw_extractvalue, 344 | kw_insertvalue, 345 | kw_blockaddress, 346 | 347 | // Metadata types. 348 | kw_distinct, 349 | 350 | // Use-list order directives. 351 | kw_uselistorder, 352 | kw_uselistorder_bb, 353 | 354 | // Summary index keywords 355 | kw_path, 356 | kw_hash, 357 | kw_gv, 358 | kw_guid, 359 | kw_name, 360 | kw_summaries, 361 | kw_flags, 362 | kw_linkage, 363 | kw_notEligibleToImport, 364 | kw_live, 365 | kw_dsoLocal, 366 | kw_function, 367 | kw_insts, 368 | kw_funcFlags, 369 | kw_readNone, 370 | kw_readOnly, 371 | kw_noRecurse, 372 | kw_returnDoesNotAlias, 373 | kw_noInline, 374 | kw_calls, 375 | kw_callee, 376 | kw_hotness, 377 | kw_unknown, 378 | kw_hot, 379 | kw_critical, 380 | kw_relbf, 381 | kw_variable, 382 | kw_aliasee, 383 | kw_refs, 384 | kw_typeIdInfo, 385 | kw_typeTests, 386 | kw_typeTestAssumeVCalls, 387 | kw_typeCheckedLoadVCalls, 388 | kw_typeTestAssumeConstVCalls, 389 | kw_typeCheckedLoadConstVCalls, 390 | kw_vFuncId, 391 | kw_offset, 392 | kw_args, 393 | kw_typeid, 394 | kw_summary, 395 | kw_typeTestRes, 396 | kw_kind, 397 | kw_unsat, 398 | kw_byteArray, 399 | kw_inline, 400 | kw_single, 401 | kw_allOnes, 402 | kw_sizeM1BitWidth, 403 | kw_alignLog2, 404 | kw_sizeM1, 405 | kw_bitMask, 406 | kw_inlineBits, 407 | kw_wpdResolutions, 408 | kw_wpdRes, 409 | kw_indir, 410 | kw_singleImpl, 411 | kw_branchFunnel, 412 | kw_singleImplName, 413 | kw_resByArg, 414 | kw_byArg, 415 | kw_uniformRetVal, 416 | kw_uniqueRetVal, 417 | kw_virtualConstProp, 418 | kw_info, 419 | kw_byte, 420 | kw_bit, 421 | kw_varFlags, 422 | 423 | // Unsigned Valued tokens (UIntVal). 424 | GlobalID, // @42 425 | LocalVarID, // %42 426 | AttrGrpID, // #42 427 | SummaryID, // ^42 428 | 429 | // String valued tokens (StrVal). 430 | LabelStr, // foo: 431 | GlobalVar, // @foo @"foo" 432 | ComdatVar, // $foo 433 | LocalVar, // %foo %"foo" 434 | MetadataVar, // !foo 435 | StringConstant, // "foo" 436 | DwarfTag, // DW_TAG_foo 437 | DwarfAttEncoding, // DW_ATE_foo 438 | DwarfVirtuality, // DW_VIRTUALITY_foo 439 | DwarfLang, // DW_LANG_foo 440 | DwarfCC, // DW_CC_foo 441 | EmissionKind, // lineTablesOnly 442 | NameTableKind, // GNU 443 | DwarfOp, // DW_OP_foo 444 | DIFlag, // DIFlagFoo 445 | DISPFlag, // DISPFlagFoo 446 | DwarfMacinfo, // DW_MACINFO_foo 447 | ChecksumKind, // CSK_foo 448 | 449 | // Type valued tokens (TyVal). 450 | Type, 451 | 452 | APFloat, // APFloatVal 453 | APSInt // APSInt 454 | }; 455 | } // end namespace lltok 456 | } // end namespace llvm 457 | 458 | #endif 459 | -------------------------------------------------------------------------------- /lab8/include/Parser.h: -------------------------------------------------------------------------------- 1 | //===-- Parser.h - Parser for LLVM IR text assembly files -------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // These classes are implemented by the lib/AsmParser library. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef LLVM_ASMPARSER_PARSER_H 15 | #define LLVM_ASMPARSER_PARSER_H 16 | 17 | #include "llvm/Support/MemoryBuffer.h" 18 | 19 | using namespace llvm; 20 | 21 | /// This function is a main interface to the LLVM Assembly Parser. It parses 22 | /// an ASCII file that (presumably) contains LLVM Assembly code. It returns a 23 | /// Module (intermediate representation) with the corresponding features. Note 24 | /// that this does not verify that the generated Module is valid, so you should 25 | /// run the verifier after parsing the file to check that it is okay. 26 | /// Parse LLVM Assembly from a file 27 | /// \param Filename The name of the file to parse 28 | /// \param Err Error result info. 29 | /// \param Context Context in which to allocate globals info. 30 | /// \param Slots The optional slot mapping that will be initialized during 31 | /// parsing. 32 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 33 | /// This option should only be set to false by llvm-as 34 | /// for use inside the LLVM testuite! 35 | /// \param DataLayoutString Override datalayout in the llvm assembly. 36 | std::unique_ptr parseAssemblyFile(StringRef Filename, SMDiagnostic &Err, 37 | LLVMContext &Context, 38 | bool TypeCheck = true, 39 | SlotMapping *Slots = nullptr, 40 | bool UpgradeDebugInfo = true, 41 | StringRef DataLayoutString = ""); 42 | 43 | /// The function is a secondary interface to the LLVM Assembly Parser. It parses 44 | /// an ASCII string that (presumably) contains LLVM Assembly code. It returns a 45 | /// Module (intermediate representation) with the corresponding features. Note 46 | /// that this does not verify that the generated Module is valid, so you should 47 | /// run the verifier after parsing the file to check that it is okay. 48 | /// Parse LLVM Assembly from a string 49 | /// \param AsmString The string containing assembly 50 | /// \param Err Error result info. 51 | /// \param Context Context in which to allocate globals info. 52 | /// \param Slots The optional slot mapping that will be initialized during 53 | /// parsing. 54 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 55 | /// This option should only be set to false by llvm-as 56 | /// for use inside the LLVM testuite! 57 | /// \param DataLayoutString Override datalayout in the llvm assembly. 58 | std::unique_ptr parseAssemblyString(StringRef AsmString, 59 | SMDiagnostic &Err, 60 | LLVMContext &Context, 61 | SlotMapping *Slots = nullptr, 62 | bool UpgradeDebugInfo = true, 63 | StringRef DataLayoutString = ""); 64 | 65 | /// Holds the Module and ModuleSummaryIndex returned by the interfaces 66 | /// that parse both. 67 | struct ParsedModuleAndIndex { 68 | std::unique_ptr Mod; 69 | std::unique_ptr Index; 70 | }; 71 | 72 | /// This function is a main interface to the LLVM Assembly Parser. It parses 73 | /// an ASCII file that (presumably) contains LLVM Assembly code, including 74 | /// a module summary. It returns a Module (intermediate representation) and 75 | /// a ModuleSummaryIndex with the corresponding features. Note that this does 76 | /// not verify that the generated Module or Index are valid, so you should 77 | /// run the verifier after parsing the file to check that they are okay. 78 | /// Parse LLVM Assembly from a file 79 | /// \param Filename The name of the file to parse 80 | /// \param Err Error result info. 81 | /// \param Context Context in which to allocate globals info. 82 | /// \param Slots The optional slot mapping that will be initialized during 83 | /// parsing. 84 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 85 | /// This option should only be set to false by llvm-as 86 | /// for use inside the LLVM testuite! 87 | /// \param DataLayoutString Override datalayout in the llvm assembly. 88 | ParsedModuleAndIndex 89 | parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Err, 90 | LLVMContext &Context, SlotMapping *Slots = nullptr, 91 | bool UpgradeDebugInfo = true, 92 | StringRef DataLayoutString = ""); 93 | 94 | /// This function is a main interface to the LLVM Assembly Parser. It parses 95 | /// an ASCII file that (presumably) contains LLVM Assembly code for a module 96 | /// summary. It returns a a ModuleSummaryIndex with the corresponding features. 97 | /// Note that this does not verify that the generated Index is valid, so you 98 | /// should run the verifier after parsing the file to check that it is okay. 99 | /// Parse LLVM Assembly Index from a file 100 | /// \param Filename The name of the file to parse 101 | /// \param Err Error result info. 102 | std::unique_ptr 103 | parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Err); 104 | 105 | /// parseAssemblyFile and parseAssemblyString are wrappers around this function. 106 | /// Parse LLVM Assembly from a MemoryBuffer. 107 | /// \param F The MemoryBuffer containing assembly 108 | /// \param Err Error result info. 109 | /// \param Slots The optional slot mapping that will be initialized during 110 | /// parsing. 111 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 112 | /// This option should only be set to false by llvm-as 113 | /// for use inside the LLVM testuite! 114 | /// \param DataLayoutString Override datalayout in the llvm assembly. 115 | std::unique_ptr parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, 116 | LLVMContext &Context, 117 | SlotMapping *Slots = nullptr, 118 | bool UpgradeDebugInfo = true, 119 | StringRef DataLayoutString = ""); 120 | 121 | /// Parse LLVM Assembly including the summary index from a MemoryBuffer. 122 | /// 123 | /// \param F The MemoryBuffer containing assembly with summary 124 | /// \param Err Error result info. 125 | /// \param Slots The optional slot mapping that will be initialized during 126 | /// parsing. 127 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 128 | /// This option should only be set to false by llvm-as 129 | /// for use inside the LLVM testuite! 130 | /// \param DataLayoutString Override datalayout in the llvm assembly. 131 | /// 132 | /// parseAssemblyFileWithIndex is a wrapper around this function. 133 | ParsedModuleAndIndex parseAssemblyWithIndex(MemoryBufferRef F, 134 | SMDiagnostic &Err, 135 | LLVMContext &Context, 136 | SlotMapping *Slots = nullptr, 137 | bool UpgradeDebugInfo = true, 138 | StringRef DataLayoutString = ""); 139 | 140 | /// Parse LLVM Assembly for summary index from a MemoryBuffer. 141 | /// 142 | /// \param F The MemoryBuffer containing assembly with summary 143 | /// \param Err Error result info. 144 | /// 145 | /// parseSummaryIndexAssemblyFile is a wrapper around this function. 146 | std::unique_ptr 147 | parseSummaryIndexAssembly(MemoryBufferRef F, SMDiagnostic &Err); 148 | 149 | /// This function is the low-level interface to the LLVM Assembly Parser. 150 | /// This is kept as an independent function instead of being inlined into 151 | /// parseAssembly for the convenience of interactive users that want to add 152 | /// recently parsed bits to an existing module. 153 | /// 154 | /// \param F The MemoryBuffer containing assembly 155 | /// \param M The module to add data to. 156 | /// \param Index The index to add data to. 157 | /// \param Err Error result info. 158 | /// \param Slots The optional slot mapping that will be initialized during 159 | /// parsing. 160 | /// \return true on error. 161 | /// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier. 162 | /// This option should only be set to false by llvm-as 163 | /// for use inside the LLVM testuite! 164 | /// \param DataLayoutString Override datalayout in the llvm assembly. 165 | bool parseAssemblyInto(MemoryBufferRef F, Module *M, ModuleSummaryIndex *Index, 166 | SMDiagnostic &Err, SlotMapping *Slots = nullptr, 167 | bool UpgradeDebugInfo = true, 168 | StringRef DataLayoutString = ""); 169 | 170 | /// Parse a type and a constant value in the given string. 171 | /// 172 | /// The constant value can be any LLVM constant, including a constant 173 | /// expression. 174 | /// 175 | /// \param Slots The optional slot mapping that will restore the parsing state 176 | /// of the module. 177 | /// \return null on error. 178 | Constant *parseConstantValue(StringRef Asm, SMDiagnostic &Err, const Module &M, 179 | const SlotMapping *Slots = nullptr); 180 | 181 | /// Parse a type in the given string. 182 | /// 183 | /// \param Slots The optional slot mapping that will restore the parsing state 184 | /// of the module. 185 | /// \return null on error. 186 | Type *parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, 187 | const SlotMapping *Slots = nullptr); 188 | 189 | /// Parse a string \p Asm that starts with a type. 190 | /// \p Read[out] gives the number of characters that have been read to parse 191 | /// the type in \p Asm. 192 | /// 193 | /// \param Slots The optional slot mapping that will restore the parsing state 194 | /// of the module. 195 | /// \return null on error. 196 | Type *parseTypeAtBeginning(StringRef Asm, unsigned &Read, SMDiagnostic &Err, 197 | const Module &M, const SlotMapping *Slots = nullptr); 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /lab8/lib/LLVMBuild.txt: -------------------------------------------------------------------------------- 1 | ;===- ./lib/AsmParser/LLVMBuild.txt ----------------------------*- Conf -*--===; 2 | ; 3 | ; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | ; See https://llvm.org/LICENSE.txt for license information. 5 | ; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | ; 7 | ;===------------------------------------------------------------------------===; 8 | ; 9 | ; This is an LLVMBuild description file for the components in this subdirectory. 10 | ; 11 | ; For more information on the LLVMBuild system, please see: 12 | ; 13 | ; http://llvm.org/docs/LLVMBuild.html 14 | ; 15 | ;===------------------------------------------------------------------------===; 16 | 17 | [component_0] 18 | type = Library 19 | name = AsmParser 20 | parent = Libraries 21 | required_libraries = BinaryFormat Core Support 22 | -------------------------------------------------------------------------------- /lab8/lib/Parser.cpp: -------------------------------------------------------------------------------- 1 | //===- Parser.cpp - Main dispatch module for the Parser library -----------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This library implements the functionality defined in llvm/AsmParser/Parser.h 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "llvm/AsmParser/Parser.h" 15 | #include "DummyLLParser.h" 16 | #include "llvm/ADT/STLExtras.h" 17 | #include "llvm/IR/Module.h" 18 | #include "llvm/IR/ModuleSummaryIndex.h" 19 | #include "llvm/Support/MemoryBuffer.h" 20 | #include "llvm/Support/SourceMgr.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | #include 23 | #include 24 | using namespace llvm; 25 | 26 | bool parseAssemblyInto(MemoryBufferRef F, Module *M, ModuleSummaryIndex *Index, 27 | SMDiagnostic &Err, bool TypeCheck, SlotMapping *Slots, 28 | bool UpgradeDebugInfo, StringRef DataLayoutString) { 29 | SourceMgr SM; 30 | std::unique_ptr Buf = MemoryBuffer::getMemBuffer(F); 31 | SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); 32 | LLVMContext Context; 33 | return DummyLLParser(F.getBuffer(), SM, Err, M, Index, 34 | M ? M->getContext() : Context, TypeCheck, Slots, 35 | UpgradeDebugInfo, DataLayoutString) 36 | .Run(); 37 | } 38 | 39 | std::unique_ptr parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, 40 | LLVMContext &Context, bool TypeCheck, 41 | SlotMapping *Slots, bool UpgradeDebugInfo, 42 | StringRef DataLayoutString) { 43 | std::unique_ptr M = 44 | make_unique(F.getBufferIdentifier(), Context); 45 | 46 | if (parseAssemblyInto(F, M.get(), nullptr, Err, TypeCheck, Slots, 47 | UpgradeDebugInfo, DataLayoutString)) 48 | return nullptr; 49 | 50 | return M; 51 | } 52 | 53 | std::unique_ptr parseAssemblyFile(StringRef Filename, SMDiagnostic &Err, 54 | LLVMContext &Context, bool TypeCheck, 55 | SlotMapping *Slots, 56 | bool UpgradeDebugInfo, 57 | StringRef DataLayoutString) { 58 | ErrorOr> FileOrErr = 59 | MemoryBuffer::getFileOrSTDIN(Filename); 60 | if (std::error_code EC = FileOrErr.getError()) { 61 | Err = SMDiagnostic(Filename, SourceMgr::DK_Error, 62 | "Could not open input file: " + EC.message()); 63 | return nullptr; 64 | } 65 | 66 | return parseAssembly(FileOrErr.get()->getMemBufferRef(), Err, Context, 67 | TypeCheck, Slots, UpgradeDebugInfo, DataLayoutString); 68 | } 69 | 70 | std::unique_ptr 71 | parseAssemblyString(StringRef AsmString, SMDiagnostic &Err, 72 | LLVMContext &Context, SlotMapping *Slots, 73 | bool UpgradeDebugInfo, StringRef DataLayoutString) { 74 | MemoryBufferRef F(AsmString, ""); 75 | return parseAssembly(F, Err, Context, Slots, UpgradeDebugInfo, 76 | DataLayoutString); 77 | } 78 | 79 | static bool parseSummaryIndexAssemblyInto(MemoryBufferRef F, 80 | ModuleSummaryIndex &Index, 81 | SMDiagnostic &Err) { 82 | SourceMgr SM; 83 | std::unique_ptr Buf = MemoryBuffer::getMemBuffer(F); 84 | SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); 85 | 86 | // The parser holds a reference to a context that is unused when parsing the 87 | // index, but we need to initialize it. 88 | LLVMContext unusedContext; 89 | return DummyLLParser(F.getBuffer(), SM, Err, nullptr, &Index, unusedContext) 90 | .Run(); 91 | } 92 | 93 | std::unique_ptr 94 | parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Err) { 95 | ErrorOr> FileOrErr = 96 | MemoryBuffer::getFileOrSTDIN(Filename); 97 | if (std::error_code EC = FileOrErr.getError()) { 98 | Err = SMDiagnostic(Filename, SourceMgr::DK_Error, 99 | "Could not open input file: " + EC.message()); 100 | return nullptr; 101 | } 102 | 103 | return parseSummaryIndexAssembly(FileOrErr.get()->getMemBufferRef(), Err); 104 | } 105 | 106 | Constant *parseConstantValue(StringRef Asm, SMDiagnostic &Err, const Module &M, 107 | const SlotMapping *Slots) { 108 | SourceMgr SM; 109 | std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Asm); 110 | SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); 111 | Constant *C; 112 | if (DummyLLParser(Asm, SM, Err, const_cast(&M), nullptr, 113 | M.getContext()) 114 | .parseStandaloneConstantValue(C, Slots)) 115 | return nullptr; 116 | return C; 117 | } 118 | 119 | Type *parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, 120 | const SlotMapping *Slots) { 121 | unsigned Read; 122 | Type *Ty = parseTypeAtBeginning(Asm, Read, Err, M, Slots); 123 | if (!Ty) 124 | return nullptr; 125 | if (Read != Asm.size()) { 126 | SourceMgr SM; 127 | std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Asm); 128 | SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); 129 | Err = SM.GetMessage(SMLoc::getFromPointer(Asm.begin() + Read), 130 | SourceMgr::DK_Error, "expected end of string"); 131 | return nullptr; 132 | } 133 | return Ty; 134 | } 135 | Type *parseTypeAtBeginning(StringRef Asm, unsigned &Read, SMDiagnostic &Err, 136 | const Module &M, const SlotMapping *Slots) { 137 | SourceMgr SM; 138 | std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Asm); 139 | SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); 140 | Type *Ty; 141 | if (DummyLLParser(Asm, SM, Err, const_cast(&M), nullptr, 142 | M.getContext()) 143 | .parseTypeAtBeginning(Ty, Read, Slots)) 144 | return nullptr; 145 | return Ty; 146 | } 147 | -------------------------------------------------------------------------------- /lab8/src/Extractor.cpp: -------------------------------------------------------------------------------- 1 | #include "Extractor.h" 2 | using namespace llvm; 3 | 4 | /* 5 | * Implement your type constraint extractor 6 | */ 7 | void Extractor::extractConstraints(Instruction *I) { /* Add your code here */ } 8 | -------------------------------------------------------------------------------- /lab8/src/TypeSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Function.h" 2 | #include "llvm/IR/InstIterator.h" 3 | #include "llvm/IR/Instructions.h" 4 | #include "llvm/IR/Module.h" 5 | 6 | #include "llvm/IRReader/IRReader.h" 7 | #include "llvm/Support/SourceMgr.h" 8 | #include 9 | 10 | #include "DummyLLParser.h" 11 | #include "Extractor.h" 12 | #include "Parser.h" 13 | 14 | using namespace llvm; 15 | 16 | int main(int argc, char **argv) { 17 | if (argc < 2) { 18 | errs() << "Expected an argument - IR file name\n"; 19 | exit(1); 20 | } 21 | 22 | LLVMContext Context; 23 | SMDiagnostic Err; 24 | StringRef FileName(argv[1]); 25 | 26 | std::unique_ptr Mod = 27 | parseAssemblyFile(FileName, Err, Context, false); 28 | 29 | if (!Mod) { 30 | Err.print(argv[0], errs()); 31 | return 1; 32 | } 33 | 34 | Extractor Ext; 35 | z3::solver *Solver = Ext.getSolver(); 36 | z3::context &C = Ext.getContext(); 37 | z3::func_decl &TypeEnv = Ext.getTypeEnv(); 38 | 39 | for (auto &F : *Mod) { 40 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; I++) { 41 | Ext.extractConstraints(&*I); 42 | } 43 | } 44 | 45 | std::ofstream smt2("formula.smt2"); 46 | smt2 << Solver->to_smt2() << std::endl; 47 | z3::check_result Result = Solver->check(); 48 | std::cout << Result << std::endl; 49 | if (Result == z3::sat) { 50 | const z3::model &Model = Solver->get_model(); 51 | for (auto &F : *Mod) { 52 | std::cout << " " << F.getName().str() << " : " 53 | << Model.eval(TypeEnv(C.string_val(F.getName()))) << std::endl; 54 | for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; I++) { 55 | if ((*I).getType()->isVoidTy()) 56 | continue; 57 | std::string Exp = Ext.toString(&*I); 58 | std::cout << Exp << " : " 59 | << Model.eval(TypeEnv(C.string_val(Exp.c_str()))) 60 | << std::endl; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lab8/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=simple0 branch0 function0 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< 7 | 8 | clean: 9 | formula.smt2 ${TARGETS} 10 | -------------------------------------------------------------------------------- /lab8/test/branch0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 1; 3 | int y = 2; 4 | int z = x + y; 5 | char *p; 6 | char a = 'a'; 7 | char b = 'b'; 8 | if (z > 0) { 9 | p = &a; 10 | } else { 11 | p = &b; 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /lab8/test/function0.c: -------------------------------------------------------------------------------- 1 | int f(int *x) { return *x + 1; } 2 | char g(char x) { return x; } 3 | void h() {} 4 | 5 | int main() { 6 | int a = 1; 7 | int b = f(&a); 8 | char c = g(1); 9 | int d = b + 1; 10 | char e = c + 1; 11 | h(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /lab8/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 1; 3 | int y = 2; 4 | int z = x + y; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /lab8/test/simple1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'simple0.c' 2 | source_filename = "simple0.c" 3 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-pc-linux-gnu" 5 | 6 | ; Function Attrs: noinline nounwind optnone uwtable 7 | define dso_local i32 @main() #0 { 8 | entry: 9 | %retval = alloca i32, align 4 10 | %x = alloca i32*, align 4 11 | %y = alloca i32, align 4 12 | %z = alloca i32, align 4 13 | store i32 0, i32* %retval, align 4 14 | store i32 1, i32* %x, align 4 15 | store i32 2, i32* %y, align 4 16 | %0 = load i32, i32* %x, align 4 17 | %1 = load i32, i32* %y, align 4 18 | %add = add nsw i32 %0, %1 19 | store i32 %add, i32* %z, align 4 20 | ret i32 0 21 | } 22 | 23 | attributes #0 = { noinline nounwind optnone 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"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 24 | 25 | !llvm.module.flags = !{!0} 26 | !llvm.ident = !{!1} 27 | 28 | !0 = !{i32 1, !"wchar_size", i32 4} 29 | !1 = !{!"clang version 8.0.1-svn369350-1~exp1~20190820121219.79 (branches/release_80)"} 30 | -------------------------------------------------------------------------------- /lab9/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | find_package(LLVM 8 REQUIRED CONFIG) 4 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 5 | include(HandleLLVMOptions) 6 | include(AddLLVM) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | 10 | add_definitions(${LLVM_DEFINITIONS}) 11 | include_directories(${LLVM_INCLUDE_DIRS} include) 12 | link_directories(${LLVM_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/reference) 13 | 14 | add_llvm_library(CBIInstrumentPass MODULE 15 | src/CBIInstrument.cpp 16 | ) 17 | 18 | add_executable(cbi 19 | src/CBI.cpp 20 | ) 21 | 22 | add_library(runtime MODULE 23 | lib/runtime.c 24 | ) 25 | 26 | add_custom_target(reference ALL 27 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/reference/* ${CMAKE_CURRENT_BINARY_DIR}/ 28 | ) 29 | -------------------------------------------------------------------------------- /lab9/include/CBIInstrument.h: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Constants.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | using namespace llvm; 9 | 10 | namespace instrument { 11 | 12 | struct CBIInstrument : public FunctionPass { 13 | static char ID; 14 | 15 | CBIInstrument() : FunctionPass(ID) {} 16 | 17 | bool runOnFunction(Function &F) override; 18 | }; 19 | } // namespace instrument 20 | -------------------------------------------------------------------------------- /lab9/include/Utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::string readOneFile(std::string &Path) { 11 | std::ifstream SeedFile(Path); 12 | std::string Line((std::istreambuf_iterator(SeedFile)), 13 | std::istreambuf_iterator()); 14 | return Line; 15 | } 16 | 17 | int runTarget(std::string &Target, std::string &Path) { 18 | std::string Cmd = Target + " > /dev/null 2>&1"; 19 | FILE *F = popen(Cmd.c_str(), "w"); 20 | std::string Input = readOneFile(Path); 21 | fprintf(F, "%s", Input.c_str()); 22 | return pclose(F); 23 | } 24 | 25 | enum class State { BranchTrue, BranchFalse, ReturnNeg, ReturnZero, ReturnPos }; 26 | std::set SuccessLogs; 27 | std::set FailureLogs; 28 | std::map, double> F; 29 | std::map, double> S; 30 | std::map, double> Failure; 31 | std::map, double> Context; 32 | std::map, double> Increase; 33 | 34 | // Might need these 35 | std::map, double> FObs; 36 | std::map, double> SObs; 37 | 38 | 39 | std::string toString(State S) { 40 | switch (S) { 41 | case State::BranchTrue: 42 | return "BranchTrue"; 43 | case State::BranchFalse: 44 | return "BranchFalse"; 45 | case State::ReturnNeg: 46 | return "ReturnNeg"; 47 | case State::ReturnZero: 48 | return "ReturnZero"; 49 | case State::ReturnPos: 50 | return "ReturnPos"; 51 | } 52 | } 53 | 54 | void printMap(std::map, double> &Map) { 55 | for (auto &Entry : Map) { 56 | std::cout << "Line " << std::get<0>(Entry.first) << ", Col " 57 | << std::get<1>(Entry.first) << ", " 58 | << toString(std::get<2>(Entry.first)) << ": " << Entry.second 59 | << std::endl; 60 | } 61 | } 62 | 63 | void printReport() { 64 | std::cout << "== S(P) ==" << std::endl; 65 | printMap(S); 66 | std::cout << "== F(P) ==" << std::endl; 67 | printMap(F); 68 | 69 | std::cout << "== Failure(P) ==" << std::endl; 70 | printMap(Failure); 71 | std::cout << "== Context(P) ==" << std::endl; 72 | printMap(Context); 73 | std::cout << "== Increase(P) ==" << std::endl; 74 | printMap(Increase); 75 | } 76 | 77 | void generateLogFiles(std::string &Target, std::string &LogDir) { 78 | struct dirent *Ent; 79 | DIR *Directory; 80 | std::string SuccessDir = LogDir + "/success/"; 81 | std::string FailureDir = LogDir + "/failure/"; 82 | 83 | std::string LogFile = Target + ".cbi"; 84 | 85 | unlink(LogFile.c_str()); 86 | 87 | std::cout << "Generating log files..." << std::endl; 88 | Directory = opendir(SuccessDir.c_str()); 89 | if (Directory == NULL) { 90 | fprintf(stderr, "%s directory not found\n", SuccessDir.c_str()); 91 | exit(1); 92 | } 93 | 94 | std::regex Reg("input[0-9]+.*"); 95 | 96 | while ((Ent = readdir(Directory)) != NULL) { 97 | if (!(Ent->d_type == DT_REG)) 98 | continue; 99 | std::string Input(Ent->d_name); 100 | if (std::regex_match(Input, Reg)) { 101 | std::string Path = SuccessDir + "/" + Input; 102 | runTarget(Target, Path); 103 | std::string Dst = Path + ".cbi"; 104 | rename(LogFile.c_str(), Dst.c_str()); 105 | SuccessLogs.insert(Dst); 106 | } 107 | } 108 | closedir(Directory); 109 | 110 | Directory = opendir(FailureDir.c_str()); 111 | if (Directory == NULL) { 112 | fprintf(stderr, "%s directory not found\n", FailureDir.c_str()); 113 | exit(1); 114 | } 115 | 116 | while ((Ent = readdir(Directory)) != NULL) { 117 | if (!(Ent->d_type == DT_REG)) 118 | continue; 119 | std::string Input(Ent->d_name); 120 | if (std::regex_match(Input, Reg)) { 121 | std::string Path = FailureDir + "/" + Input; 122 | runTarget(Target, Path); 123 | std::string Dst = Path + ".cbi"; 124 | rename(LogFile.c_str(), Dst.c_str()); 125 | FailureLogs.insert(Dst); 126 | } 127 | } 128 | closedir(Directory); 129 | } 130 | -------------------------------------------------------------------------------- /lab9/lib/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __dbz_sanitizer__(int divisor, int line, int col) { 7 | if (divisor == 0) { 8 | printf("Divide-by-zero detected at line %d and col %d\n", line, col); 9 | exit(1); 10 | } 11 | } 12 | 13 | void __coverage__(int line, int col) { 14 | char exe[1024]; 15 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 16 | if (ret == -1) { 17 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 18 | exit(1); 19 | } 20 | exe[ret] = 0; 21 | 22 | char logfile[1024]; 23 | int len = strlen(exe); 24 | strncpy(logfile, exe, len); 25 | logfile[len] = 0; 26 | strcat(logfile, ".cov"); 27 | FILE *f = fopen(logfile, "a"); 28 | fprintf(f, "%d,%d\n", line, col); 29 | fclose(f); 30 | } 31 | 32 | void __cbi_branch__(int line, int col, int cond) { 33 | char exe[1024]; 34 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 35 | if (ret == -1) { 36 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 37 | exit(1); 38 | } 39 | exe[ret] = 0; 40 | 41 | char logfile[1024]; 42 | int len = strlen(exe); 43 | strncpy(logfile, exe, len); 44 | logfile[len] = 0; 45 | strcat(logfile, ".cbi"); 46 | FILE *f = fopen(logfile, "a"); 47 | fprintf(f, "branch,%d,%d,%d\n", line, col, cond); 48 | fclose(f); 49 | } 50 | 51 | void __cbi_return__(int line, int col, int rv) { 52 | char exe[1024]; 53 | int ret = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 54 | if (ret == -1) { 55 | fprintf(stderr, "Error: Cannot find /projc/self/exe\n"); 56 | exit(1); 57 | } 58 | exe[ret] = 0; 59 | 60 | char logfile[1024]; 61 | int len = strlen(exe); 62 | strncpy(logfile, exe, len); 63 | logfile[len] = 0; 64 | strcat(logfile, ".cbi"); 65 | FILE *f = fopen(logfile, "a"); 66 | fprintf(f, "return,%d,%d,%d\n", line, col, rv); 67 | fclose(f); 68 | } 69 | -------------------------------------------------------------------------------- /lab9/reference/InstrumentPass.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab9/reference/InstrumentPass.so -------------------------------------------------------------------------------- /lab9/reference/fuzzer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petablox/cis573vm/9419e389f04c3e0884603fa6be7e82bb7dec0a33/lab9/reference/fuzzer -------------------------------------------------------------------------------- /lab9/src/CBI.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Utils.h" 6 | 7 | /* 8 | * Implement your CBI report generator. 9 | */ 10 | void generateReport() { /* Add your code here */ } 11 | 12 | // ./CBI [exe file] [fuzzer output dir] 13 | int main(int argc, char **argv) { 14 | if (argc != 3) { 15 | fprintf(stderr, "Invalid usage\n"); 16 | return 1; 17 | } 18 | 19 | struct stat Buffer; 20 | if (stat(argv[1], &Buffer)) { 21 | fprintf(stderr, "%s not found\n", argv[1]); 22 | return 1; 23 | } 24 | 25 | if (stat(argv[2], &Buffer)) { 26 | fprintf(stderr, "%s not found\n", argv[2]); 27 | return 1; 28 | } 29 | 30 | std::string Target(argv[1]); 31 | std::string OutDir(argv[2]); 32 | 33 | generateLogFiles(Target, OutDir); 34 | generateReport(); 35 | printReport(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /lab9/src/CBIInstrument.cpp: -------------------------------------------------------------------------------- 1 | #include "CBIInstrument.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace instrument { 6 | 7 | static const char *CBIBranchFunctionName = "__cbi_branch__"; 8 | static const char *CBIReturnFunctionName = "__cbi_return__"; 9 | 10 | /* 11 | * Implement instrumentation for the branch scheme of CBI. 12 | */ 13 | void instrumentCBIBranches(Module *M, Function &F, BranchInst &I) { 14 | /* Add your code here */ 15 | } 16 | 17 | /* 18 | * Implement instrumentation for the return scheme of CBI. 19 | */ 20 | void instrumentCBIReturns(Module *M, Function &F, CallInst &I) { 21 | /* Add your code here */ 22 | } 23 | 24 | bool CBIInstrument::runOnFunction(Function &F) { 25 | /* Add your code here */ 26 | return true; 27 | } 28 | 29 | char CBIInstrument::ID = 1; 30 | static RegisterPass X("CBIInstrument", 31 | "Instrumentations for CBI", false, false); 32 | 33 | } // namespace instrument 34 | -------------------------------------------------------------------------------- /lab9/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=simple0 simple1 fuzz0 fuzz1 fuzz2 fuzz3 2 | 3 | all: ${TARGETS} 4 | 5 | %: %.c 6 | clang -emit-llvm -S -fno-discard-value-names -c -o $@.ll $< -g 7 | opt -load ../build/InstrumentPass.so -Instrument -S $@.ll -o $@.instrumented.ll 8 | opt -load ../build/CBIInstrumentPass.so -CBIInstrument -S $@.instrumented.ll -o $@.cbi.instrumented.ll 9 | clang -o $@ -L${PWD}/../build -lruntime $@.cbi.instrumented.ll 10 | 11 | clean: 12 | rm -f *.ll *.cov *.cbi ${TARGETS} 13 | -------------------------------------------------------------------------------- /lab9/test/fuzz0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char input[65536]; 5 | fgets(input, sizeof(input), stdin); 6 | int x = 0; 7 | int y = 2; 8 | int z = y / x; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /lab9/test/fuzz1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[65536]; 6 | fgets(input, sizeof(input), stdin); 7 | int x = 0; 8 | int y = 2; 9 | int z; 10 | if (strlen(input) % 7 == 0) { 11 | z = y / x; 12 | } 13 | 14 | if (strlen(input) % 13 == 0) { 15 | z = y / ++x; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /lab9/test/fuzz2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int xval(char *i) { 5 | if ((strlen(i) % 2) == 0) { 6 | return 1; 7 | } else { 8 | return 0; 9 | } 10 | } 11 | 12 | int main() { 13 | char input[65536]; 14 | fgets(input, sizeof(input), stdin); 15 | int x = 0; 16 | int y = 2; 17 | int z; 18 | 19 | if (xval(input)) { 20 | z = y / x; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /lab9/test/fuzz3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int xval(char *i) { 5 | if ((strlen(i) % 2) == 0) { 6 | return 1; 7 | } else { 8 | return 0; 9 | } 10 | } 11 | 12 | int main() { 13 | char input[65536]; 14 | fgets(input, sizeof(input), stdin); 15 | int x = 0; 16 | int y = 2; 17 | int z; 18 | 19 | if (strlen(input) % 7 == 0) { 20 | z = y / x; 21 | } 22 | 23 | if (strlen(input) % 13 == 0) { 24 | z = y / ++x; 25 | } 26 | 27 | if (xval(input)) { 28 | z = y / x; 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /lab9/test/fuzz_input/seed.txt: -------------------------------------------------------------------------------- 1 | This is the seed input file. 2 | Multiple lines are also possible. 3 | 9124 4 | 1lk24 90KJ!@(jkl1j2 5 15'25 ) 5 | -------------------------------------------------------------------------------- /lab9/test/simple0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | int y = x; 4 | int z = y / x; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /lab9/test/simple1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | if (argc > 2) { 3 | int x = 0; 4 | int y = x; 5 | int z = y / x; 6 | } 7 | return 0; 8 | } 9 | --------------------------------------------------------------------------------