diff options
Diffstat (limited to 'llvm_mode')
-rw-r--r-- | llvm_mode/GNUmakefile | 11 | ||||
-rw-r--r-- | llvm_mode/README.lto.md | 54 | ||||
-rw-r--r-- | llvm_mode/README.md | 4 | ||||
-rw-r--r-- | llvm_mode/afl-clang-fast.c | 42 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-lto-instrim.so.cc | 6 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-lto-instrumentation.so.cc | 6 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-rt.o.c | 10 | ||||
-rw-r--r-- | llvm_mode/compare-transform-pass.so.cc | 4 | ||||
-rw-r--r-- | llvm_mode/split-compares-pass.so.cc | 391 |
9 files changed, 359 insertions, 169 deletions
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index b5d026ef..443322d7 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -32,15 +32,16 @@ ifeq "$(shell uname)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" - $(error llvm_mode needs a complete llvm installation (versions 3.4 up to 11) -> e.g. "pkg_add llvm-7.0.1p9") + $(error llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") endif else LLVM_CONFIG ?= llvm-config endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[3-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) +LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//') LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null) LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) @@ -53,7 +54,7 @@ ifeq "$(LLVMVER)" "" endif ifeq "$(LLVM_UNSUPPORTED)" "1" - $(warning llvm_mode only supports llvm versions 3.4 up to 11) + $(warning llvm_mode only supports llvm versions 3.4 up to 12) endif ifeq "$(LLVM_MAJOR)" "9" @@ -65,8 +66,8 @@ ifeq "$(LLVM_NEW_API)" "1" LLVM_STDCXX = c++14 endif -ifeq "$(LLVM_MAJOR)" "11" - $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation) +ifeq "$(LLVM_HAVE_LTO)" "1" + $(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation) LLVM_LTO = 1 #TEST_MMAP = 1 endif diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 4641fa89..d54d4ee0 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -2,7 +2,7 @@ ## TLDR; -This version requires a current llvm 11 compiled from the github master. +This version requires a current llvm 11+ compiled from the github master. 1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better coverage than anything else that is out there in the AFL world @@ -10,7 +10,7 @@ This version requires a current llvm 11 compiled from the github master. 2. You can use it together with llvm_mode: laf-intel and the instrument file listing features and can be combined with cmplog/Redqueen -3. It only works with llvm 11 (current github master state) +3. It only works with llvm 11+ 4. AUTODICTIONARY feature! see below @@ -61,9 +61,9 @@ AUTODICTIONARY: 11 strings found [+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). ``` -## Getting llvm 11 +## Getting llvm 11+ -### Installing llvm 11 from the llvm repository +### Installing llvm from the llvm repository (version 11) Installing the llvm snapshot builds is easy and mostly painless: @@ -83,7 +83,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \ libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools ``` -### Building llvm 11 yourself +### Building llvm yourself (version 12) Building llvm from github takes quite some long time and is not painless: ``` @@ -125,10 +125,9 @@ NOTE: some targets also need to set the linker, try both `afl-clang-lto` and ## AUTODICTIONARY feature -Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the -target binary based on string compare and memory compare functions. -afl-fuzz will automatically get these transmitted when starting to fuzz. -This improves coverage on a lot of targets. +While compiling, automatically a dictionary based on string comparisons is +generated put into the target binary. This dictionary is transfered to afl-fuzz +on start. This improves coverage statistically by 5-10% :) ## Fixed memory map @@ -147,6 +146,8 @@ Some targets are difficult because the configure script does unusual stuff that is unexpected for afl. See the next chapter `Potential issues` how to solve these. +### Example: ffmpeg + An example of a hard to solve target is ffmpeg. Here is how to successfully instrument it: @@ -186,6 +187,31 @@ instrument it: 4. Then type make, wait for a long time and you are done :) +### Example: WebKit jsc + +Building jsc is difficult as the build script has bugs. + +1. checkout Webkit: +``` +svn checkout https://svn.webkit.org/repository/webkit/trunk WebKit +cd WebKit +``` + +2. Fix the build environment: +``` +mkdir -p WebKitBuild/Release +cd WebKitBuild/Release +ln -s ../../../../../usr/bin/llvm-ar-12 llvm-ar-12 +ln -s ../../../../../usr/bin/llvm-ranlib-12 llvm-ranlib-12 +cd ../.. +``` + +3. Build :) + +``` +Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-12' -DCMAKE_RANLIB='llvm-ranlib-12' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON" +``` + ## Potential issues ### compiling libraries fails @@ -220,17 +246,17 @@ AS=llvm-as ... afl-clang-lto is still work in progress. Known issues: - * Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously + * Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously * Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously -Hence if building a target with afl-clang-lto fails try to build it with llvm11 -and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and +Hence if building a target with afl-clang-lto fails try to build it with llvm12 +and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and `CXXFLAGS=-flto=full`). If this succeeeds then there is an issue with afl-clang-lto. Please report at [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226) -Even some targets where clang-11 fails can be build if the fail is just in +Even some targets where clang-12 fails can be build if the fail is just in `./configure`, see `Solving difficult targets` above. ### Target crashes immediately @@ -270,7 +296,7 @@ Still more problems came up though as this only works without bugs from llvm 9 onwards, and with high optimization the link optimization ruins the instrumented control flow graph. -This is all now fixed with llvm 11. The llvm's own linker is now able to +This is all now fixed with llvm 11+. The llvm's own linker is now able to load passes and this bypasses all problems we had. Happy end :) diff --git a/llvm_mode/README.md b/llvm_mode/README.md index e2e22751..22088dfd 100644 --- a/llvm_mode/README.md +++ b/llvm_mode/README.md @@ -6,7 +6,7 @@ ## 1) Introduction -! llvm_mode works with llvm versions 3.4 up to 11 ! +! llvm_mode works with llvm versions 3.4 up to 12 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude @@ -183,4 +183,4 @@ AFL_LLVM_INSTRUMENT=PCGUARD make ``` Note that this us currently the default, as it is the best mode. -If you have llvm 11 and compiled afl-clang-lto - this is the only better mode. +If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode. diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index f1b03682..4d01e740 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -311,12 +311,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD); cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; - if (instrument_mode == INSTRUMENT_CFG) - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path); - else - cc_params[cc_par_cnt++] = alloc_printf( - "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path); + /* + The current LTO instrim mode is not good, so we disable it + if (instrument_mode == INSTRUMENT_CFG) + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", + obj_path); else + */ + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path); cc_params[cc_par_cnt++] = lto_flag; } else { @@ -379,6 +382,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined")) continue; + if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; + cc_params[cc_par_cnt++] = cur; } @@ -660,7 +665,7 @@ int main(int argc, char **argv, char **envp) { } if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || - strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) { + strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) instrument_mode = INSTRUMENT_PCGUARD; @@ -763,9 +768,19 @@ int main(int argc, char **argv, char **envp) { #if LLVM_VERSION_MAJOR <= 6 instrument_mode = INSTRUMENT_AFL; #else - if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) + if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) { + instrument_mode = INSTRUMENT_AFL; - else + WARNF( + "switching to classic instrumentation because " + "AFL_LLVM_INSTRUMENT_FILE does not work with PCGUARD. Use " + "-fsanitize-coverage-allowlist=allowlist.txt if you want to use " + "PCGUARD. See " + "https://clang.llvm.org/docs/" + "SanitizerCoverage.html#partially-disabling-instrumentation"); + + } else + instrument_mode = INSTRUMENT_PCGUARD; #endif @@ -813,9 +828,12 @@ int main(int argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD && (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST"))) - WARNF( + FATAL( "Instrumentation type PCGUARD does not support " - "AFL_LLVM_INSTRUMENT_FILE!"); + "AFL_LLVM_INSTRUMENT_FILE! Use " + "-fsanitize-coverage-allowlist=allowlist.txt instead, see " + "https://clang.llvm.org/docs/" + "SanitizerCoverage.html#partially-disabling-instrumentation"); if (argc < 2 || strcmp(argv[1], "-h") == 0) { @@ -939,7 +957,7 @@ int main(int argc, char **argv, char **envp) { u32 map_size = atoi(ptr2); if (map_size != MAP_SIZE) - FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast"); + WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast"); } diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc index ca2b5886..880963ac 100644 --- a/llvm_mode/afl-llvm-lto-instrim.so.cc +++ b/llvm_mode/afl-llvm-lto-instrim.so.cc @@ -73,7 +73,7 @@ struct InsTrimLTO : public ModulePass { protected: uint32_t function_minimum_size = 1; char * skip_nozero = NULL; - int afl_global_id = 1, debug = 0, autodictionary = 0; + int afl_global_id = 1, debug = 0, autodictionary = 1; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0; uint64_t map_addr = 0x10000; @@ -127,10 +127,6 @@ struct InsTrimLTO : public ModulePass { /* Process environment variables */ - if (getenv("AFL_LLVM_AUTODICTIONARY") || - getenv("AFL_LLVM_LTO_AUTODICTIONARY")) - autodictionary = 1; - if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) { diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index af2db3ff..3c1d3565 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -86,7 +86,7 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - int afl_global_id = 1, debug = 0, autodictionary = 0; + int afl_global_id = 1, debug = 0, autodictionary = 1; uint32_t function_minimum_size = 1; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; uint64_t map_addr = 0x10000; @@ -120,10 +120,6 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; - if (getenv("AFL_LLVM_AUTODICTIONARY") || - getenv("AFL_LLVM_LTO_AUTODICTIONARY")) - autodictionary = 1; - if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index f81d13ee..a509a9f0 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -53,7 +53,11 @@ #define CONST_PRIO 5 #ifndef MAP_FIXED_NOREPLACE - #define MAP_FIXED_NOREPLACE MAP_FIXED + #ifdef MAP_EXCL + #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED + #else + #define MAP_FIXED_NOREPLACE MAP_FIXED + #endif #endif #include <sys/mman.h> @@ -510,6 +514,8 @@ static void __afl_start_snapshots(void) { if (!child_pid) { + (void)nice(-20); + signal(SIGCHLD, old_sigchld_handler); close(FORKSRV_FD); @@ -713,6 +719,8 @@ static void __afl_start_forkserver(void) { if (!child_pid) { + (void)nice(-20); + signal(SIGCHLD, old_sigchld_handler); close(FORKSRV_FD); diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 2d1ab1cc..2f165ea6 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -474,8 +474,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (cur_lenchk_bb) { IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt())); - Value * icmp = cur_lenchk_IRB.CreateICmpEQ(sizedValue, - ConstantInt::get(Int64Ty, i)); + Value * icmp = cur_lenchk_IRB.CreateICmpEQ( + sizedValue, ConstantInt::get(sizedValue->getType(), i)); cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb); cur_lenchk_bb->getTerminator()->eraseFromParent(); diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc index 651fa5b4..55128ca2 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/llvm_mode/split-compares-pass.so.cc @@ -80,6 +80,7 @@ class SplitComparesTransform : public ModulePass { size_t splitIntCompares(Module &M, unsigned bitw); size_t splitFPCompares(Module &M); bool simplifyCompares(Module &M); + bool simplifyFPCompares(Module &M); bool simplifyIntSignedness(Module &M); size_t nextPowerOfTwo(size_t in); @@ -89,12 +90,11 @@ class SplitComparesTransform : public ModulePass { char SplitComparesTransform::ID = 0; -/* This function splits ICMP instructions with xGE or xLE predicates into two - * ICMP instructions with predicate xGT or xLT and EQ */ -bool SplitComparesTransform::simplifyCompares(Module &M) { +/* 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 *> icomps; std::vector<Instruction *> fcomps; IntegerType * Int1Ty = IntegerType::getInt1Ty(C); @@ -112,24 +112,6 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { - if (selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) { - - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); - - IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); - IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); - - /* this is probably not needed but we do it anyway */ - if (!intTyOp0 || !intTyOp1) { continue; } - - icomps.push_back(selectcmpInst); - - } - if (enableFPSplit && (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || @@ -159,105 +141,159 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { } - if (!icomps.size() && !fcomps.size()) { return false; } + if (!fcomps.size()) { return false; } - for (auto &IcmpInst : icomps) { + /* transform for floating point */ + for (auto &FcmpInst : fcomps) { - BasicBlock *bb = IcmpInst->getParent(); + BasicBlock *bb = FcmpInst->getParent(); - auto op0 = IcmpInst->getOperand(0); - auto op1 = IcmpInst->getOperand(1); + auto op0 = FcmpInst->getOperand(0); + auto op1 = FcmpInst->getOperand(1); /* find out what the new predicate is going to be */ - auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate(); + auto pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate(); CmpInst::Predicate new_pred; switch (pred) { - case CmpInst::ICMP_UGE: - new_pred = CmpInst::ICMP_UGT; + case CmpInst::FCMP_UGE: + new_pred = CmpInst::FCMP_UGT; break; - case CmpInst::ICMP_SGE: - new_pred = CmpInst::ICMP_SGT; + case CmpInst::FCMP_OGE: + new_pred = CmpInst::FCMP_OGT; break; - case CmpInst::ICMP_ULE: - new_pred = CmpInst::ICMP_ULT; + case CmpInst::FCMP_ULE: + new_pred = CmpInst::FCMP_ULT; break; - case CmpInst::ICMP_SLE: - new_pred = CmpInst::ICMP_SLT; + case CmpInst::FCMP_OLE: + new_pred = CmpInst::FCMP_OLT; break; default: // keep the compiler happy continue; } - /* split before the icmp instruction */ - BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); + /* split before the fcmp instruction */ + BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst)); /* the old bb now contains a unconditional jump to the new one (end_bb) * we need to delete it later */ - /* create the ICMP instruction with new_pred and add it to the old basic - * block bb it is now at the position where the old IcmpInst was */ - Instruction *icmp_np; - icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); + /* create the FCMP instruction with new_pred and add it to the old basic + * block bb it is now at the position where the old FcmpInst was */ + Instruction *fcmp_np; + fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1); bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - icmp_np); + fcmp_np); - /* create a new basic block which holds the new EQ icmp */ - Instruction *icmp_eq; + /* create a new basic block which holds the new EQ fcmp */ + Instruction *fcmp_eq; /* insert middle_bb before end_bb */ BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); - middle_bb->getInstList().push_back(icmp_eq); + fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1); + middle_bb->getInstList().push_back(fcmp_eq); /* add an unconditional branch to the end of middle_bb with destination * end_bb */ BranchInst::Create(end_bb, middle_bb); /* replace the uncond branch with a conditional one, which depends on the - * new_pred icmp. True goes to end, false to the middle (injected) bb */ + * new_pred fcmp. True goes to end, false to the middle (injected) bb */ auto term = bb->getTerminator(); - BranchInst::Create(end_bb, middle_bb, icmp_np, bb); + BranchInst::Create(end_bb, middle_bb, fcmp_np, bb); term->eraseFromParent(); - /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI + /* replace the old FcmpInst (which is the first inst in end_bb) with a PHI * inst to wire up the loose ends */ PHINode *PN = PHINode::Create(Int1Ty, 2, ""); - /* the first result depends on the outcome of icmp_eq */ - PN->addIncoming(icmp_eq, middle_bb); - /* if the source was the original bb we know that the icmp_np yielded true + /* the first result depends on the outcome of fcmp_eq */ + PN->addIncoming(fcmp_eq, middle_bb); + /* if the source was the original bb we know that the fcmp_np yielded true * hence we can hardcode this value */ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); - /* replace the old IcmpInst with our new and shiny PHI inst */ - BasicBlock::iterator ii(IcmpInst); - ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + /* replace the old FcmpInst with our new and shiny PHI inst */ + BasicBlock::iterator ii(FcmpInst); + ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); } - /* now for floating point */ - for (auto &FcmpInst : fcomps) { + return true; - BasicBlock *bb = FcmpInst->getParent(); +} - auto op0 = FcmpInst->getOperand(0); - auto op1 = FcmpInst->getOperand(1); +/* This function splits ICMP instructions with xGE or xLE predicates into two + * ICMP instructions with predicate xGT or xLT and EQ */ +bool SplitComparesTransform::simplifyCompares(Module &M) { + + LLVMContext & C = M.getContext(); + std::vector<Instruction *> icomps; + IntegerType * Int1Ty = IntegerType::getInt1Ty(C); + + /* 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 (selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || + selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || + selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || + selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) { + + auto op0 = selectcmpInst->getOperand(0); + auto op1 = selectcmpInst->getOperand(1); + + IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); + IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); + + /* this is probably not needed but we do it anyway */ + if (!intTyOp0 || !intTyOp1) { continue; } + + icomps.push_back(selectcmpInst); + + } + + } + + } + + } + + } + + if (!icomps.size()) { return false; } + + for (auto &IcmpInst : icomps) { + + BasicBlock *bb = IcmpInst->getParent(); + + auto op0 = IcmpInst->getOperand(0); + auto op1 = IcmpInst->getOperand(1); /* find out what the new predicate is going to be */ - auto pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate(); + auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate(); CmpInst::Predicate new_pred; switch (pred) { - case CmpInst::FCMP_UGE: - new_pred = CmpInst::FCMP_UGT; + case CmpInst::ICMP_UGE: + new_pred = CmpInst::ICMP_UGT; break; - case CmpInst::FCMP_OGE: - new_pred = CmpInst::FCMP_OGT; + case CmpInst::ICMP_SGE: + new_pred = CmpInst::ICMP_SGT; break; - case CmpInst::FCMP_ULE: - new_pred = CmpInst::FCMP_ULT; + case CmpInst::ICMP_ULE: + new_pred = CmpInst::ICMP_ULT; break; - case CmpInst::FCMP_OLE: - new_pred = CmpInst::FCMP_OLT; + case CmpInst::ICMP_SLE: + new_pred = CmpInst::ICMP_SLT; break; default: // keep the compiler happy continue; @@ -265,25 +301,25 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { } /* split before the icmp instruction */ - BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst)); + BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); /* the old bb now contains a unconditional jump to the new one (end_bb) * we need to delete it later */ /* create the ICMP instruction with new_pred and add it to the old basic * block bb it is now at the position where the old IcmpInst was */ - Instruction *fcmp_np; - fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1); + Instruction *icmp_np; + icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - fcmp_np); + icmp_np); - /* create a new basic block which holds the new EQ fcmp */ - Instruction *fcmp_eq; + /* create a new basic block which holds the new EQ icmp */ + Instruction *icmp_eq; /* insert middle_bb before end_bb */ BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1); - middle_bb->getInstList().push_back(fcmp_eq); + icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); + middle_bb->getInstList().push_back(icmp_eq); /* add an unconditional branch to the end of middle_bb with destination * end_bb */ BranchInst::Create(end_bb, middle_bb); @@ -291,20 +327,20 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { /* replace the uncond branch with a conditional one, which depends on the * new_pred icmp. True goes to end, false to the middle (injected) bb */ auto term = bb->getTerminator(); - BranchInst::Create(end_bb, middle_bb, fcmp_np, bb); + BranchInst::Create(end_bb, middle_bb, icmp_np, bb); term->eraseFromParent(); /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI * inst to wire up the loose ends */ PHINode *PN = PHINode::Create(Int1Ty, 2, ""); /* the first result depends on the outcome of icmp_eq */ - PN->addIncoming(fcmp_eq, middle_bb); + PN->addIncoming(icmp_eq, middle_bb); /* if the source was the original bb we know that the icmp_np yielded true * hence we can hardcode this value */ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); /* replace the old IcmpInst with our new and shiny PHI inst */ - BasicBlock::iterator ii(FcmpInst); - ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); + BasicBlock::iterator ii(IcmpInst); + ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); } @@ -640,7 +676,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BranchInst::Create(end_bb, signequal_bb); - /* create a new bb which is executed if exponents are equal */ + /* create a new bb which is executed if exponents are satisfying the compare + */ BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); @@ -695,7 +732,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } /* compare the exponents of the operands */ + Instruction *icmp_exponents_equal; Instruction *icmp_exponent_result; + BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { case CmpInst::FCMP_OEQ: @@ -707,22 +746,60 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, m_e0, m_e1); break; + /* compare the exponents of the operands (signs are equal) + * if exponents are equal -> proceed to mantissa comparison + * else get result depending on sign + */ case CmpInst::FCMP_OGT: case CmpInst::FCMP_UGT: Instruction *icmp_exponent; + icmp_exponents_equal = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); + signequal_bb->getInstList().insert( + BasicBlock::iterator(signequal_bb->getTerminator()), + icmp_exponents_equal); + + // shortcut for unequal exponents + signequal2_bb = signequal_bb->splitBasicBlock( + BasicBlock::iterator(signequal_bb->getTerminator())); + + /* if the exponents are equal goto middle_bb else to signequal2_bb */ + term = signequal_bb->getTerminator(); + BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal, + signequal_bb); + term->eraseFromParent(); + icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1); - signequal_bb->getInstList().insert( - BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent); + signequal2_bb->getInstList().insert( + BasicBlock::iterator(signequal2_bb->getTerminator()), + icmp_exponent); icmp_exponent_result = BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0); break; case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: + icmp_exponents_equal = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); + signequal_bb->getInstList().insert( + BasicBlock::iterator(signequal_bb->getTerminator()), + icmp_exponents_equal); + + // shortcut for unequal exponents + signequal2_bb = signequal_bb->splitBasicBlock( + BasicBlock::iterator(signequal_bb->getTerminator())); + + /* if the exponents are equal goto middle_bb else to signequal2_bb */ + term = signequal_bb->getTerminator(); + BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal, + signequal_bb); + term->eraseFromParent(); + icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1); - signequal_bb->getInstList().insert( - BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent); + signequal2_bb->getInstList().insert( + BasicBlock::iterator(signequal2_bb->getTerminator()), + icmp_exponent); icmp_exponent_result = BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0); break; @@ -731,15 +808,40 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } - signequal_bb->getInstList().insert( - BasicBlock::iterator(signequal_bb->getTerminator()), + signequal2_bb->getInstList().insert( + BasicBlock::iterator(signequal2_bb->getTerminator()), icmp_exponent_result); { - auto term = signequal_bb->getTerminator(); - /* if the exponents are different do a fraction cmp */ - BranchInst::Create(middle_bb, end_bb, icmp_exponent_result, signequal_bb); + term = signequal2_bb->getTerminator(); + + switch (FcmpInst->getPredicate()) { + + case CmpInst::FCMP_OEQ: + /* if the exponents are satifying the compare do a fraction cmp in + * middle_bb */ + BranchInst::Create(middle_bb, end_bb, icmp_exponent_result, + signequal2_bb); + break; + case CmpInst::FCMP_ONE: + case CmpInst::FCMP_UNE: + /* if the exponents are satifying the compare do a fraction cmp in + * middle_bb */ + BranchInst::Create(end_bb, middle_bb, icmp_exponent_result, + signequal2_bb); + break; + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_UGT: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_ULT: + BranchInst::Create(end_bb, signequal2_bb); + break; + default: + continue; + + } + term->eraseFromParent(); } @@ -800,44 +902,82 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* compare the fractions of the operands */ Instruction *icmp_fraction_result; + Instruction *icmp_fraction_result2; + BasicBlock * middle2_bb = middle_bb; + PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { case CmpInst::FCMP_OEQ: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1); + middle2_bb->getInstList().insert( + BasicBlock::iterator(middle2_bb->getTerminator()), + icmp_fraction_result); + break; case CmpInst::FCMP_UNE: case CmpInst::FCMP_ONE: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1); + middle2_bb->getInstList().insert( + BasicBlock::iterator(middle2_bb->getTerminator()), + icmp_fraction_result); + break; case CmpInst::FCMP_OGT: case CmpInst::FCMP_UGT: - Instruction *icmp_fraction; - icmp_fraction = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); - middle_bb->getInstList().insert( - BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction); - icmp_fraction_result = - BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0); - break; case CmpInst::FCMP_OLT: - case CmpInst::FCMP_ULT: - icmp_fraction = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); - middle_bb->getInstList().insert( - BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction); - icmp_fraction_result = - BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0); - break; + case CmpInst::FCMP_ULT: { + + middle2_bb = middle_bb->splitBasicBlock( + BasicBlock::iterator(middle_bb->getTerminator())); + + BasicBlock *negative_bb = BasicBlock::Create( + C, "negative_value", middle2_bb->getParent(), middle2_bb); + BasicBlock *positive_bb = BasicBlock::Create( + C, "positive_value", negative_bb->getParent(), negative_bb); + + 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)); + positive_bb->getInstList().push_back( + icmp_fraction_result2 = CmpInst::Create( + 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); + BranchInst::Create(middle2_bb, positive_bb); + + term = middle_bb->getTerminator(); + BranchInst::Create(negative_bb, positive_bb, t_s0, middle_bb); + term->eraseFromParent(); + + PN2 = PHINode::Create(Int1Ty, 2, ""); + PN2->addIncoming(icmp_fraction_result, negative_bb); + PN2->addIncoming(icmp_fraction_result2, positive_bb); + middle2_bb->getInstList().insert( + BasicBlock::iterator(middle2_bb->getTerminator()), PN2); + + } break; + default: continue; } - middle_bb->getInstList().insert( - BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction_result); - PHINode *PN = PHINode::Create(Int1Ty, 3, ""); switch (FcmpInst->getPredicate()) { @@ -849,7 +989,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* unequal exponents cannot be equal values, too */ PN->addIncoming(ConstantInt::get(Int1Ty, 0), signequal_bb); /* fractions comparison */ - PN->addIncoming(icmp_fraction_result, middle_bb); + PN->addIncoming(icmp_fraction_result, middle2_bb); break; case CmpInst::FCMP_ONE: case CmpInst::FCMP_UNE: @@ -857,25 +997,25 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* goto true branch */ PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); /* unequal exponents are unequal values, too */ - PN->addIncoming(ConstantInt::get(Int1Ty, 1), signequal_bb); + PN->addIncoming(icmp_exponent_result, signequal_bb); /* fractions comparison */ - PN->addIncoming(icmp_fraction_result, middle_bb); + PN->addIncoming(icmp_fraction_result, middle2_bb); break; case CmpInst::FCMP_OGT: case CmpInst::FCMP_UGT: /* if op1 is negative goto true branch, else go on comparing */ PN->addIncoming(t_s1, bb); - PN->addIncoming(icmp_exponent_result, signequal_bb); - PN->addIncoming(icmp_fraction_result, middle_bb); + PN->addIncoming(icmp_exponent_result, signequal2_bb); + PN->addIncoming(PN2, middle2_bb); break; case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: /* if op0 is negative goto true branch, else go on comparing */ PN->addIncoming(t_s0, bb); - PN->addIncoming(icmp_exponent_result, signequal_bb); - PN->addIncoming(icmp_fraction_result, middle_bb); + PN->addIncoming(icmp_exponent_result, signequal2_bb); + PN->addIncoming(PN2, middle2_bb); break; default: continue; @@ -1115,24 +1255,29 @@ bool SplitComparesTransform::runOnModule(Module &M) { enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL; - simplifyCompares(M); - - simplifyIntSignedness(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\n"; - if (enableFPSplit) + if (enableFPSplit) { + errs() << "Split-floatingpoint-compare-pass: " << splitFPCompares(M) << " FP comparisons splitted\n"; + } + } else be_quiet = 1; + if (enableFPSplit) simplifyFPCompares(M); + + simplifyCompares(M); + + simplifyIntSignedness(M); + switch (bitw) { case 64: |