diff options
-rw-r--r-- | docs/Changelog.md | 4 | ||||
-rw-r--r-- | docs/FAQ.md | 21 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc | 184 |
3 files changed, 206 insertions, 3 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md index 97903c2a..0e2ce27d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,11 +17,13 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - afl-cc + - Update to COMPCOV/laf-intel that speeds up the instrumentation process + a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix for llvm 13 - support partial linking - We do support llvm versions from 3.8 again - afl_analyze - fix timeout handling and support forkserver - - Fix for llvm 13 - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance diff --git a/docs/FAQ.md b/docs/FAQ.md index 714d50eb..ab0abe6c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -3,6 +3,7 @@ ## Contents * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) + * [I got a weird compile error from clang](#i-got-a-weird-compile-error-from-clang) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) @@ -35,6 +36,26 @@ flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) +## I got a weird compile error from clang + +If you see this kind of error when trying to instrument a target with afl-cc/ +afl-clang-fast/afl-clang-lto: +``` +/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv +clang-13: error: unable to execute command: No such file or directory +clang-13: error: clang frontend command failed due to signal (use -v to see invocation) +clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad) +Target: x86_64-unknown-linux-gnu +Thread model: posix +InstalledDir: /prg/tmp/llvm-project/build/bin +clang-13: note: diagnostic msg: +******************** +``` +Then this means that your OS updated the clang installation from an upgrade +package and because of that the afl++ llvm plugins do not match anymore. + +Solution: `git pull ; make clean install` of afl++ + ## How to improve the fuzzing speed? 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 6eb9050c..10f86a66 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -54,20 +54,25 @@ using namespace llvm; namespace { class SplitComparesTransform : public ModulePass { + public: static char ID; SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { + initInstrumentList(); + } bool runOnModule(Module &M) override; #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { + #else const char *getPassName() const override { #endif return "AFL_SplitComparesTransform"; + } private: @@ -98,30 +103,47 @@ class SplitComparesTransform : public ModulePass { /// print an error to llvm's errs stream, but only if not ordered to be quiet void reportError(const StringRef msg, Instruction *I, Module &M) { + if (!be_quiet) { + errs() << "[AFL++ SplitComparesTransform] ERROR: " << msg << "\n"; if (debug) { + if (I) { + errs() << "Instruction = " << *I << "\n"; if (auto BB = I->getParent()) { + if (auto F = BB->getParent()) { + if (F->hasName()) { + errs() << "|-> in function " << F->getName() << " "; + } + } + } + } + auto n = M.getName(); if (n.size() > 0) { errs() << "in module " << n << "\n"; } + } + } + } bool isSupportedBitWidth(unsigned bitw) { + // IDK whether the icmp code works on other bitwidths. I guess not? So we // try to avoid dealing with other weird icmp's that llvm might use (looking // at you `icmp i0`). switch (bitw) { + case 8: case 16: case 32: @@ -131,8 +153,11 @@ class SplitComparesTransform : public ModulePass { return true; default: return false; + } + } + }; } // namespace @@ -142,6 +167,7 @@ char SplitComparesTransform::ID = 0; /// This function splits FCMP instructions with xGE or xLE predicates into two /// FCMP instructions with predicate xGT or xLT and EQ bool SplitComparesTransform::simplifyFPCompares(Module &M) { + LLVMContext & C = M.getContext(); std::vector<Instruction *> fcomps; IntegerType * Int1Ty = IntegerType::getInt1Ty(C); @@ -149,18 +175,23 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* iterate over all functions, bbs and instruction and add * all integer comparisons with >= and <= predicates to the icomps vector */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { + if (enableFPSplit && (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -173,16 +204,22 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return false; } /* transform for floating point */ for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -195,6 +232,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::FCMP_UGE: new_pred = CmpInst::FCMP_UGT; break; @@ -209,6 +247,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { break; default: // keep the compiler happy continue; + } /* split before the fcmp instruction */ @@ -252,9 +291,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* replace the old FcmpInst with our new and shiny PHI inst */ BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); + } return true; + } /// This function splits ICMP instructions with xGE or xLE predicates into two @@ -262,6 +303,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, Module & M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -278,6 +320,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::ICMP_UGE: new_pred = CmpInst::ICMP_UGT; break; @@ -292,6 +335,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, break; default: // keep the compiler happy return false; + } /* split before the icmp instruction */ @@ -338,6 +382,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, worklist.push_back(icmp_eq); return true; + } /// Simplify a signed comparison operator by splitting it into a unsigned and @@ -345,6 +390,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, /// the worklist passed as a reference. bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -365,10 +411,13 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Predicate new_pred; if (pred == CmpInst::ICMP_SGT) { + new_pred = CmpInst::ICMP_UGT; } else { + new_pred = CmpInst::ICMP_ULT; + } BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); @@ -391,6 +440,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, BasicBlock *sign_bb = BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_SGT) { + /* if we check for > and the op0 positive and op1 negative then the final * result is true. if op0 negative and op1 pos, the cmp must result * in false @@ -399,9 +449,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); } else { + /* just the inverse of the above statement */ icmp_inv_sig_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); + } sign_bb->getInstList().push_back(icmp_inv_sig_cmp); @@ -439,12 +491,15 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, // worklist.push_back(icmp_inv_sig_cmp); return true; + } bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, CmpWorklist &worklist) { + auto pred = cmp_inst->getPredicate(); switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: case CmpInst::ICMP_UGT: @@ -453,6 +508,7 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, default: // unsupported predicate! return false; + } auto op0 = cmp_inst->getOperand(0); @@ -461,14 +517,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // get bitwidth by checking the bitwidth of the first operator IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); if (!intTyOp0) { + // not an integer type return false; + } unsigned bitw = intTyOp0->getBitWidth(); if (bitw == target_bitwidth) { + // already the target bitwidth so we have to do nothing here. return true; + } LLVMContext &C = M.getContext(); @@ -497,15 +557,17 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, /* now we have to destinguish between == != and > < */ switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: { + /* transformation for == and != icmps */ /* create a compare for the lower half of the original operands */ BasicBlock *cmp_low_bb = BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); - Value *op0_low, *op1_low; + Value * op0_low, *op1_low; IRBuilder<> Builder(cmp_low_bb); op0_low = Builder.CreateTrunc(op0, NewIntType); @@ -519,11 +581,16 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, auto term = bb->getTerminator(); BranchInst *br = nullptr; if (pred == CmpInst::ICMP_EQ) { + br = BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb); + } else { + /* CmpInst::ICMP_NE */ br = BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb); + } + term->eraseFromParent(); /* create the PHI and connect the edges accordingly */ @@ -531,32 +598,43 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(icmp_low, cmp_low_bb); Value *val = nullptr; if (pred == CmpInst::ICMP_EQ) { + val = ConstantInt::get(Int1Ty, 0); + } else { + /* CmpInst::ICMP_NE */ val = ConstantInt::get(Int1Ty, 1); + } + PN->addIncoming(val, icmp_high->getParent()); break; + } + case CmpInst::ICMP_UGT: case CmpInst::ICMP_ULT: { + /* transformations for < and > */ /* create a basic block which checks for the inverse predicate. * if this is true we can go to the end if not we have to go to the * bb which checks the lower half of the operands */ Instruction *op0_low, *op1_low; - CmpInst *icmp_inv_cmp = nullptr; + CmpInst * icmp_inv_cmp = nullptr; BasicBlock * inv_cmp_bb = BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_UGT) { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, op0_high, op1_high); } else { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, op0_high, op1_high); + } inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); @@ -585,9 +663,12 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb); break; + } + default: return false; + } BasicBlock::iterator ii(cmp_inst); @@ -597,14 +678,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // bitwidth we recursivly split the low and high parts again until we have // target bitwidth. if ((bitw / 2) > target_bitwidth) { + worklist.push_back(icmp_high); worklist.push_back(icmp_low); + } return true; + } bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { + CmpWorklist worklist; auto op0 = I->getOperand(0); @@ -625,23 +710,35 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { I->getPredicate() == CmpInst::ICMP_SGE || I->getPredicate() == CmpInst::ICMP_ULE || I->getPredicate() == CmpInst::ICMP_SLE) { + if (!simplifyOrEqualsCompare(I, M, worklist)) { + reportError( "Failed to simplify inequality or equals comparison " "(UGE,SGE,ULE,SLE)", I, M); + } + } else if (I->getPredicate() == CmpInst::ICMP_SGT || + I->getPredicate() == CmpInst::ICMP_SLT) { + if (!simplifySignedCompare(I, M, worklist)) { + reportError("Failed to simplify signed comparison (SGT,SLT)", I, M); + } + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("simpliyfing compare lead to broken function", nullptr, M); + } + #endif // the simplification methods replace the original CmpInst and push the @@ -650,27 +747,38 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { if (worklist.size() == 0) { worklist.push_back(I); } while (!worklist.empty()) { + CmpInst *cmp = worklist.pop_back_val(); // we split the simplified compares into comparisons with smaller bitwidths // if they are larger than our target_bitwidth. if (bitw > target_bitwidth) { + if (!splitCompare(cmp, M, worklist)) { + reportError("Failed to split comparison", cmp, M); + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("splitting compare lead to broken function", nullptr, M); + } + #endif + } + } count++; return true; + } size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { + --in; in |= in >> 1; in |= in >> 2; @@ -678,10 +786,12 @@ size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { // in |= in >> 8; // in |= in >> 16; return in + 1; + } /* splits fcmps into two nested fcmps with sign compare and the rest */ size_t SplitComparesTransform::splitFPCompares(Module &M) { + size_t count = 0; LLVMContext &C = M.getContext(); @@ -693,9 +803,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* define unions with floating point and (sign, exponent, mantissa) triples */ if (dl.isLittleEndian()) { + } else if (dl.isBigEndian()) { + } else { + return count; + } #endif @@ -705,13 +819,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* get all EQ, NE, GT, and LT fcmps. if the other two * functions were executed only these four predicates should exist */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { + if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_ONE || @@ -720,6 +838,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || selectcmpInst->getPredicate() == CmpInst::FCMP_OLT) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -731,10 +850,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return count; } @@ -742,6 +866,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { IntegerType *Int1Ty = IntegerType::getInt1Ty(C); for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -866,6 +991,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), t_e1); if (sizeInBits - precision < exTySizeBytes * 8) { + m_e0 = BinaryOperator::Create( Instruction::And, t_e0, ConstantInt::get(t_e0->getType(), mask_exponent)); @@ -878,8 +1004,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), m_e1); } else { + m_e0 = t_e0; m_e1 = t_e1; + } /* compare the exponents of the operands */ @@ -887,6 +1015,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *icmp_exponent_result; BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_exponent_result = @@ -956,6 +1085,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } signequal2_bb->getInstList().insert( @@ -963,9 +1093,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent_result); { + term = signequal2_bb->getTerminator(); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* if the exponents are satifying the compare do a fraction cmp in @@ -988,9 +1120,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } term->eraseFromParent(); + } /* isolate the mantissa aka fraction */ @@ -998,6 +1132,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { bool needTrunc = IntFractionTy->getPrimitiveSizeInBits() < op_size; if (precision - 1 < frTySizeBytes * 8) { + Instruction *m_f0, *m_f1; m_f0 = BinaryOperator::Create( Instruction::And, b_op0, @@ -1011,6 +1146,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), m_f1); if (needTrunc) { + t_f0 = new TruncInst(m_f0, IntFractionTy); t_f1 = new TruncInst(m_f1, IntFractionTy); middle_bb->getInstList().insert( @@ -1019,12 +1155,16 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = m_f0; t_f1 = m_f1; + } } else { + if (needTrunc) { + t_f0 = new TruncInst(b_op0, IntFractionTy); t_f1 = new TruncInst(b_op1, IntFractionTy); middle_bb->getInstList().insert( @@ -1033,9 +1173,12 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = b_op0; t_f1 = b_op1; + } + } /* compare the fractions of the operands */ @@ -1043,6 +1186,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock * middle2_bb = middle_bb; PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_fraction_result = @@ -1065,6 +1209,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_UGT: case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: { + Instruction *icmp_fraction_result2; middle2_bb = middle_bb->splitBasicBlock( @@ -1077,6 +1222,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT || FcmpInst->getPredicate() == CmpInst::FCMP_UGT) { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); @@ -1085,12 +1231,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); } else { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); positive_bb->getInstList().push_back( icmp_fraction_result2 = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); + } BranchInst::Create(middle2_bb, negative_bb); @@ -1110,11 +1258,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { default: continue; + } PHINode *PN = PHINode::Create(Int1Ty, 3, ""); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ @@ -1153,17 +1303,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); ++count; + } return count; + } bool SplitComparesTransform::runOnModule(Module &M) { + char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { target_bitwidth = atoi(bitw_env); } @@ -1172,6 +1326,7 @@ bool SplitComparesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) { + errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " "heiko@hexco.de (splitting icmp to " << target_bitwidth << " bit)\n"; @@ -1179,10 +1334,13 @@ bool SplitComparesTransform::runOnModule(Module &M) { if (getenv("AFL_DEBUG") != NULL && !debug) { debug = 1; } } else { + be_quiet = 1; + } if (enableFPSplit) { + count = splitFPCompares(M); /* @@ -1195,55 +1353,76 @@ bool SplitComparesTransform::runOnModule(Module &M) { */ simplifyFPCompares(M); + } std::vector<CmpInst *> worklist; /* iterate over all functions, bbs and instruction search for all integer * compare instructions. Save them into the worklist for later. */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + if (auto CI = dyn_cast<CmpInst>(&IN)) { + auto op0 = CI->getOperand(0); auto op1 = CI->getOperand(1); if (!op0 || !op1) { return false; } auto iTy1 = dyn_cast<IntegerType>(op0->getType()); if (iTy1 && isa<IntegerType>(op1->getType())) { + unsigned bitw = iTy1->getBitWidth(); if (isSupportedBitWidth(bitw)) { worklist.push_back(CI); } + } + } + } + } + } // now that we have a list of all integer comparisons we can start replacing // them with the splitted alternatives. for (auto CI : worklist) { + simplifyAndSplit(CI, M); + } bool brokenDebug = false; if (verifyModule(M, &errs(), &brokenDebug)) { + reportError( "Module Verifier failed! Consider reporting a bug with the AFL++ " "project.", nullptr, M); + } if (brokenDebug) { + reportError("Module Verifier reported broken Debug Infos - Stripping!", nullptr, M); StripDebugInfo(M); + } + return true; + } static void registerSplitComparesPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(new SplitComparesTransform()); + } static RegisterStandardPasses RegisterSplitComparesPass( @@ -1262,3 +1441,4 @@ static RegisterPass<SplitComparesTransform> X("splitcompares", "AFL++ split compares", true /* Only looks at CFG */, true /* Analysis Pass */); + |