bool ProfilingPass::runOnFunction(Function &F) { LLVMContext& context = F.getContext(); Module *m = F.getParent(); string funcname = F.getNameStr(); string injectfunc("injectFault"); if((profileoption == 'p' || profileoption == 'c' || profileoption == 'i') && (funcname.find(injectfunc) != string::npos)) return false; std::vector<Instruction*> insert_worklist; for (inst_iterator In = inst_begin(F), E = inst_end(F); In != E; ++In) { Instruction *I = dyn_cast<Instruction>(&*In); //errs()<<*I<<"\n"; if(profileoption == 'b') { if(CmpInst *ci = dyn_cast<CmpInst>(I)) if(is_used_by_branch(ci)){ vector<const Type*> argTypes(1); argTypes[0] = Type::getInt32Ty(context); // enum for the options FunctionType* countFuncType = FunctionType::get( Type::getVoidTy(context), argTypes, 0 ); Constant* countFunc = m->getOrInsertFunction("doProfiling", countFuncType); // get the injection function vector<Value*> countArgs(1); const IntegerType* itype = IntegerType::get(context,32); Value* branchVal = ConstantInt::get(itype, BRANCH ); countArgs[0] = branchVal; //enum for branch CallInst::Create( countFunc, countArgs.begin(),countArgs.end(), "", I); } } else if(profileoption == 'd') { //see if the current instruction is a cmp instruction that leads to a conditional branch //add the instrumentation to the defs of this cmp instruction //--> Static time deduction since branch not known if executed or not CmpInst *ci = dyn_cast<CmpInst>(I); //errs() <<"reached here:\n"; if(!ci) continue; //traverse def-use chain //int is_used_by_branch = 0; if(!is_used_by_branch(I)) continue; //the defines of this instruction I --> would be injectFaultCalls. for (User::op_iterator i = I->op_begin(), e = I->op_end(); i != e; ++i) { Instruction *v = dyn_cast<Instruction>(*i); if(!v) continue; //errs() <<"reached here:"<< *v << "\n"; //do profiling for the def vector<const Type*> argTypes(1); argTypes[0] = Type::getInt32Ty(context); // enum for the options FunctionType* countFuncType = FunctionType::get( Type::getVoidTy(context), argTypes, 0 ); Constant* countFunc = m->getOrInsertFunction("doProfiling", countFuncType); // get the injection function vector<Value*> countArgs(1); const IntegerType* itype = IntegerType::get(context,32); Value* defVal = ConstantInt::get(itype, DEF ); countArgs[0] = defVal; //enum for branch Instruction *beforeInst; if(isa<PHINode>(v)) { BasicBlock *bb = v->getParent(); beforeInst = bb->getFirstNonPHI(); } else beforeInst = v; CallInst::Create( countFunc, countArgs.begin(),countArgs.end(), "", beforeInst); // insert the profiling call before the def:v } } else if(profileoption == 'a' ) { Instruction *beforeInst; //consider all instructions profiling vector<const Type*> argTypes(1); argTypes[0] = Type::getInt32Ty(context); // enum for the options FunctionType* countFuncType = FunctionType::get( Type::getVoidTy(context), argTypes, 0 ); Constant* countFunc = m->getOrInsertFunction("doProfiling", countFuncType); // get the injection function vector<Value*> countArgs(1); const IntegerType* itype = IntegerType::get(context,32); Value* allVal = ConstantInt::get(itype, ALL ); if(isa<PHINode>(I)) { BasicBlock *bb = I->getParent(); beforeInst = bb->getFirstNonPHI(); } else beforeInst = I; countArgs[0] = allVal; //enum for All inst CallInst::Create( countFunc, countArgs.begin(),countArgs.end(), "", beforeInst); // Insert the inject call before the instruction } //in fact, here we only use backwardslice ('s') else if(profileoption == 's') { const Type* returnType = I->getType(); if (returnType->isVoidTy() || !filter(I))//Here we can insert a new filter /////////////////////////////////////////////// { //errs()<<"filter not passed\n"; continue; } //for injection into all instructions except invoke instructions (these are same as unconditional branch instructions with exception handling mechanism) if((isa<InvokeInst>(I)) #ifdef EXCLUDE_CASTINST || (isa<CastInst>(I)) #endif ) // cast instruction added by Jiesheng continue; //errs()<<"filter passed\n"; Instruction *beforeInst; if(isa<PHINode>(I)) { BasicBlock *bb = I->getParent(); beforeInst = bb->getFirstNonPHI(); } else beforeInst = I; insert_worklist.push_back(beforeInst); } } while(!insert_worklist.empty()) { Instruction* beforeInst = insert_worklist.back(); insert_worklist.pop_back(); vector<const Type*> argTypes(1); argTypes[0] = Type::getInt32Ty(context); // enum for the options FunctionType* countFuncType = FunctionType::get( Type::getVoidTy(context), argTypes, 0 ); Constant* countFunc = m->getOrInsertFunction("doProfiling", countFuncType); vector<Value*> countArgs(1); const IntegerType* itype = IntegerType::get(context,32); Value* allVal = ConstantInt::get(itype, BACKWARD_SLICE ); countArgs[0] = allVal; //enum for All inst CallInst::Create( countFunc, countArgs.begin(),countArgs.end(), "", beforeInst); } return true; }
bool runOnFunction(Function &Func) override { if (Func.isDeclaration()) { return false; } vector<BranchInst *> BIs; for (inst_iterator I = inst_begin(Func); I != inst_end(Func); I++) { Instruction *Inst = &(*I); if (BranchInst *BI = dyn_cast<BranchInst>(Inst)) { BIs.push_back(BI); } } // Finish collecting branching conditions Value *zero = ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), 0); for (BranchInst *BI : BIs) { IRBuilder<> IRB(BI); vector<BasicBlock *> BBs; // We use the condition's evaluation result to generate the GEP // instruction False evaluates to 0 while true evaluates to 1. So here // we insert the false block first if (BI->isConditional()) { BBs.push_back(BI->getSuccessor(1)); } BBs.push_back(BI->getSuccessor(0)); ArrayType *AT = ArrayType::get( Type::getInt8PtrTy(Func.getParent()->getContext()), BBs.size()); vector<Constant *> BlockAddresses; for (unsigned i = 0; i < BBs.size(); i++) { BlockAddresses.push_back(BlockAddress::get(BBs[i])); } GlobalVariable *LoadFrom = NULL; if (BI->isConditional() || indexmap.find(BI->getSuccessor(0))==indexmap.end()) { // Create a new GV Constant *BlockAddressArray = ConstantArray::get(AT, ArrayRef<Constant *>(BlockAddresses)); LoadFrom = new GlobalVariable(*Func.getParent(), AT, false, GlobalValue::LinkageTypes::PrivateLinkage, BlockAddressArray); } else { LoadFrom = Func.getParent()->getGlobalVariable("IndirectBranchingGlobalTable",true); } Value *index = NULL; if (BI->isConditional()) { Value *condition = BI->getCondition(); index = IRB.CreateZExt( condition, Type::getInt32Ty(Func.getParent()->getContext())); } else { index = ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), indexmap[BI->getSuccessor(0)]); } Value *GEP = IRB.CreateGEP(LoadFrom, {zero, index}); LoadInst *LI = IRB.CreateLoad(GEP, "IndirectBranchingTargetAddress"); IndirectBrInst *indirBr = IndirectBrInst::Create(LI, BBs.size()); for (BasicBlock *BB : BBs) { indirBr->addDestination(BB); } ReplaceInstWithInst(BI, indirBr); } return true; }
bool ProfilingPass::doInitialization(Module &M) { LLVMContext& context = M.getContext(); Function* mainFunc = M.getFunction("main"); const string moduleName = M.getModuleIdentifier(); if (mainFunc!=NULL) { //BasicBlock* entryBlock = &mainFunc->front(); Constant* Init = ConstantArray::get(context,moduleName,true); // Convert it to an LLVM Type GlobalVariable* nameStr = new GlobalVariable(Init->getType(), true, GlobalValue::InternalLinkage, Init, "NameStr" ); M.getGlobalList().push_back( nameStr ); // Insert it into the list of globals for module std::vector<Constant*>IndicesC(2); IndicesC[0] = Constant::getNullValue(Type::getInt32Ty(context)); IndicesC[1] = ConstantInt::get(Type::getInt32Ty(context),0); Constant *getElemExpr = ConstantExpr::getGetElementPtr(nameStr, &IndicesC[0], IndicesC.size()); vector<Value*> initInjectArgs; initInjectArgs.push_back( getElemExpr ); FunctionType* initInjectionFuncType = FunctionType::get(Type::getVoidTy(context), vector<const Type*>(1, PointerType::get(Type::getInt8Ty(context),0)),0); //BasicBlock *exitBlock = &mainFunc->back(); Instruction *I; for (inst_iterator fi = inst_begin(mainFunc), fe = inst_end(mainFunc); fi!=fe; ++fi){ I = &*fi; if(isa<ReturnInst>(I)) break; } BasicBlock *retblock = I->getParent(); //*retpred = retblock->getSinglePredecessor(); Instruction *term = retblock->getTerminator(); Constant *endFunc = M.getOrInsertFunction("endProfiling", initInjectionFuncType); vector<Value*> countArgs(1); //const IntegerType* itype = IntegerType::get(context,32); //Value* branchVal = ConstantInt::get(itype, BRANCH ); CallInst::Create(endFunc, initInjectArgs.begin(), initInjectArgs.end(), "", term); } else { Constant* Init = ConstantArray::get(context,moduleName,true); // Convert it to an LLVM Type GlobalVariable* nameStr = new GlobalVariable(Init->getType(), true, GlobalValue::InternalLinkage, Init, "NameStr" ); M.getGlobalList().push_back( nameStr ); } //*********************************************************************************************************** //code for loading configure file should be here ifstream config ("llfi_configure.txt"); if (config.is_open()) { // we need to extract information from config file here Qining // this loop is used to know if the file is end while ( config.good() ) { string line; getline (config,line); if(line.empty()) continue; //if the line is empty, just skip. //Any block of configure is started with one specific function unsigned found = line.find("FUNCTION_NAME:"); if (found < line.length()) { //std::cout << "\nfound FUNCTION_NAME at " << found << '\n'; std::string func_name = line.substr (found + string("FUNCTION_NAME:").length(),line.length() - found - string("FUNCTION_NAME:").length()); //first, I need to trim it while(func_name[0] == ' ') { func_name.erase(0, 1); } while(func_name[func_name.length() - 1] == ' ') { func_name.erase(func_name.length() - 1, 0); } //so now I've got the name of the function if(func_name.empty()) continue; std::cout << "The func_name is " << func_name << "\n"; map_func_argu[func_name] = set<unsigned int>(); // create entry //map_func_fault_type[func_name] = set<unsigned int>(); //second, I need to load argument set and type set do { line.clear(); getline(config,line); // get the next line if(!config.good()) break; // if the new line is the end of file, our job is done. if(line.find("ARGUMENT:") < line.length()) { //insert argument id to argument set std::string arg_set = line.substr(line.find("ARGUMENT:")+string("ARGUMENT:").length(), line.length() - line.find("ARGUMENT:")-string("ARGUMENT:").length()); std::string arg; while(!arg_set.empty()) { while(arg_set[0] <= '9' && arg_set[0] >= '0') { arg.append(arg_set.substr(0,1)); if(!arg_set.empty()) arg_set.erase(0,1); } if(!arg.empty()) { unsigned int arg_num = atoi(arg.c_str()) - 1; map_func_argu[func_name].insert(arg_num); std::cout << "\tinclude arg: " << arg_num+1 << "\n"; } arg.clear(); if(!arg_set.empty()) arg_set.erase(0,1); } } }while(line.find("FUNC_DEF_END") != 0); } } // The file is end, we should have already finished our work, now close the file config.close(); } else errs()<<"Unable to open config file, use default config: all instructions, one bit flip\n"; //*********************************************************************************************************** return FunctionPass::doInitialization(M); }
Function * futamurize( const Function * orig_func, DenseMap<const Value*, Value*> &argmap, std::set<const unsigned char *> &constant_addresses_set ) { LLVMContext &context = getGlobalContext(); // Make a copy of the function, removing constant arguments Function * specialized_func = CloneFunction( orig_func, argmap ); specialized_func->setName( orig_func->getNameStr() + "_1" ); // add it to our module LLVM_Module->getFunctionList().push_back( specialized_func ); printf("\nspecialized_func = %p <%s>\n", specialized_func, specialized_func->getName().data()); //~ specialized_func->dump(); // Optimize it FunctionPassManager PM( LLVM_Module ); createStandardFunctionPasses( &PM, 3 ); PM.add(createScalarReplAggregatesPass()); // Break up aggregate allocas PM.add(createInstructionCombiningPass()); // Cleanup for scalarrepl. PM.add(createJumpThreadingPass()); // Thread jumps. PM.add(createCFGSimplificationPass()); // Merge & remove BBs PM.add(createInstructionCombiningPass()); // Combine silly seq's PM.add(createTailCallEliminationPass()); // Eliminate tail calls PM.add(createCFGSimplificationPass()); // Merge & remove BBs PM.add(createReassociatePass()); // Reassociate expressions PM.add(createLoopRotatePass()); // Rotate Loop PM.add(createLICMPass()); // Hoist loop invariants PM.add(createLoopUnswitchPass( false )); PM.add(createInstructionCombiningPass()); PM.add(createIndVarSimplifyPass()); // Canonicalize indvars PM.add(createLoopDeletionPass()); // Delete dead loops PM.add(createLoopUnroll2Pass()); // Unroll small loops PM.add(createInstructionCombiningPass()); // Clean up after the unroller PM.add(createGVNPass()); // Remove redundancies PM.add(createMemCpyOptPass()); // Remove memcpy / form memset PM.add(createSCCPPass()); // Constant prop with SCCP PM.add(createPromoteMemoryToRegisterPass()); PM.add(createConstantPropagationPass()); PM.add(createDeadStoreEliminationPass()); PM.add(createAggressiveDCEPass()); PM.add(new MemoryDependenceAnalysis()); //~ PM.add(createAAEvalPass()); const PassInfo * pinfo = Pass::lookupPassInfo( "print-alias-sets" ); if( !pinfo ) { printf( "print-alias-sets not found\n" ); exit(-1); } PM.add( pinfo->createPass() ); FunctionPassManager PM_Inline( LLVM_Module ); PM_Inline.add(createSingleFunctionInliningPass()); bool Changed = false; int iterations = 2; int inline_iterations = 6; do { Changed = false; // first do some optimizations PM.doInitialization(); PM.run( *specialized_func ); PM.doFinalization(); // Load from Constant Memory detection const TargetData *TD = LLVM_EE->getTargetData(); for (inst_iterator I = inst_begin(specialized_func), E = inst_end(specialized_func); I != E; ++I) { Instruction * inst = (Instruction *) &*I; // get all Load instructions LoadInst * load = dyn_cast<LoadInst>( inst ); if( !load ) continue; if( load->isVolatile() ) continue; if (load->use_empty()) continue; // Don't muck with dead instructions... // get the address loaded by load instruction Value *ptr_value = load->getPointerOperand(); // we're only interested in constant addresses ConstantExpr * ptr_constant_expr = dyn_cast<ConstantExpr>( ptr_value ); if( !ptr_constant_expr ) continue; ptr_constant_expr->dump(); // compute real address of constant pointer expression Constant * ptr_constant = ConstantFoldConstantExpression( ptr_constant_expr, TD ); if( !ptr_constant ) continue; ptr_constant->dump(); // convert to int constant ConstantInt *int_constant = dyn_cast<ConstantInt>( ConstantExpr::getPtrToInt( ptr_constant, Type::getInt64Ty( context ))); if( !int_constant ) continue; int_constant->dump(); // get data size int data_length = TD->getTypeAllocSize( load->getType() ); ptr_value->getType()->dump(); // get real address (at last !) const unsigned char * c_ptr = (const unsigned char *) int_constant->getLimitedValue(); printf( "%ld %d %d\n", c_ptr, constant_addresses_set.count( c_ptr ), data_length ); // check what's in this address int isconst = 1; for( int offset=0; offset<data_length; offset++ ) isconst &= constant_addresses_set.count( c_ptr + offset ); if( !isconst ) continue; printf( "It is constant.\n" ); // make a LLVM const with the data Constant *new_constant = NULL; switch( data_length ) { case 1: new_constant = ConstantInt::get( Type::getInt8Ty( context ), *(uint8_t*)c_ptr, false /* signed */ ); break; case 2: new_constant = ConstantInt::get( Type::getInt16Ty( context ), *(uint16_t*)c_ptr, false /* signed */ ); break; case 4: new_constant = ConstantInt::get( Type::getInt32Ty( context ), *(uint32_t*)c_ptr, false /* signed */ ); break; case 8: new_constant = ConstantInt::get( Type::getInt64Ty( context ), *(uint64_t*)c_ptr, false /* signed */ ); break; default: { StringRef const_data ( (const char *) c_ptr, data_length ); new_constant = ConstantArray::get( context, const_data, false /* dont add terminating null */ ); } } if( !new_constant ) continue; new_constant->dump(); //~ // get the type that is loaded const Type *Ty = load->getType(); // do we need a cast ? if( load->getType() != new_constant->getType() ) { new_constant = ConstantExpr::getBitCast( new_constant, Ty ); new_constant->dump(); } // zap the load and replace with constant address load->replaceAllUsesWith( new_constant ); printf( "\nREPLACED :...\n" ); load->dump(); new_constant->dump(); Changed = true; } if( Changed ) continue; // re-optimize and do another pass of constant load elimination // if we can't do anything else, do an inlining pass if( inline_iterations > 0 ) { inline_iterations --; PM_Inline.doInitialization(); Changed |= PM_Inline.run( *specialized_func ); PM_Inline.doFinalization(); //~ for( int i=0; i<3; i++ ) { PM.doInitialization(); Changed |= PM.run( *specialized_func ); PM.doFinalization(); } } if( iterations>0 && !Changed ) iterations--; } while( Changed || iterations>0 ); return specialized_func; }