diff options
Diffstat (limited to 'instrumentation')
20 files changed, 565 insertions, 378 deletions
diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 7855a987..c0677474 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -116,7 +116,7 @@ PCGUARD analysis. Several options are present to make llvm_mode faster or help it rearrange the code to make afl-fuzz path discovery easier. -If you need just to instrument specific parts of the code, you can the +If you need just to instrument specific parts of the code, you can create the instrument file list which C/C++ files to actually instrument. See [README.instrument_list.md](README.instrument_list.md) @@ -167,6 +167,10 @@ Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation all constant string compare parameters will be written to this file to be used with afl-fuzz' `-x` option. +Adding `AFL_LLVM_DICT2FILE_NO_MAIN=1` will skip parsing `main()` which often +does command line parsing which has string comparisons that are not helpful +for fuzzing. + ## 6) AFL++ Context Sensitive Branch Coverage ### What is this? @@ -275,4 +279,4 @@ then this can give a small performance boost. Please note that the default counter implementations are not thread safe! Support for thread safe counters in mode LLVM CLASSIC can be activated with -setting `AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file +setting `AFL_LLVM_THREADSAFE_INST=1`. diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md index a20175b1..df59cc2a 100644 --- a/instrumentation/README.lto.md +++ b/instrumentation/README.lto.md @@ -2,52 +2,53 @@ ## TL;DR: -This version requires a current llvm 11+ compiled from the GitHub master. +This version requires a LLVM 11 or newer. -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. +1. Use afl-clang-lto/afl-clang-lto++ because the resulting binaries run + slightly faster and give better coverage. -2. You can use it together with llvm_mode: laf-intel and the instrument file - listing features and can be combined with cmplog/Redqueen. +2. You can use it together with COMPCOV, COMPLOG and the instrument file + listing features. -3. It only works with llvm 11+. +3. It only works with LLVM 11 or newer. -4. AUTODICTIONARY feature (see below)! +4. AUTODICTIONARY feature (see below) -5. If any problems arise, be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`. Some - targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`. +5. If any problems arise, be sure to set `AR=llvm-ar RANLIB=llvm-ranlib AS=llvm-as`. + Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`. ## Introduction and problem description -A big issue with how AFL++ works is that the basic block IDs that are set during -compilation are random - and hence naturally the larger the number of -instrumented locations, the higher the number of edge collisions are in the map. -This can result in not discovering new paths and therefore degrade the +A big issue with how vanilla AFL worked was that the basic block IDs that are +set during compilation are random - and hence naturally the larger the number +of instrumented locations, the higher the number of edge collisions are in the +map. This can result in not discovering new paths and therefore degrade the efficiency of the fuzzing process. -*This issue is underestimated in the fuzzing community!* With a 2^16 = 64kb +*This issue is underestimated in the fuzzing community* With a 2^16 = 64kb standard map at already 256 instrumented blocks, there is on average one collision. On average, a target has 10.000 to 50.000 instrumented blocks, hence the real collisions are between 750-18.000! -To reach a solution that prevents any collisions took several approaches and -many dead ends until we got to this: +Note that PCGUARD (our own modified implementation and the SANCOV PCGUARD +implementation from libfuzzer) also provides collision free coverage. +It is a bit slower though and can a few targets with very early constructors. * We instrument at link time when we have all files pre-compiled. * To instrument at link time, we compile in LTO (link time optimization) mode. * Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the correct LTO options and runs our own afl-ld linker instead of the system linker. * The LLVM linker collects all LTO files to link and instruments them so that we - have non-colliding edge overage. + have non-colliding edge coverage. * We use a new (for afl) edge coverage - which is the same as in llvm -fsanitize=coverage edge coverage mode. :) The result: * 10-25% speed gain compared to llvm_mode -* guaranteed non-colliding edge coverage :-) +* guaranteed non-colliding edge coverage * The compile time, especially for binaries to an instrumented library, can be - much longer. + much (and sometimes much much) longer. Example build output from a libtiff build: @@ -59,70 +60,30 @@ 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 version 11 or 12 +### Installing llvm -llvm 11 or even 12 should be available in all current Linux repositories. If you -use an outdated Linux distribution, read the next section. - -### Installing llvm from the llvm repository (version 12+) - -Installing the llvm snapshot builds is easy and mostly painless: - -In the following line, change `NAME` for your Debian or Ubuntu release name -(e.g., buster, focal, eon, etc.): +The best way to install LLVM is to follow [https://apt.llvm.org/](https://apt.llvm.org/) +e.g. for LLVM 15: ``` -echo deb http://apt.llvm.org/NAME/ llvm-toolchain-NAME NAME >> /etc/apt/sources.list +wget https://apt.llvm.org/llvm.sh +chmod +x llvm.sh +sudo ./llvm.sh 15 all ``` -Then add the pgp key of llvm and install the packages: +LLVM 11 to 16 should be available in all current Linux repositories. -``` -wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - -apt-get update && apt-get upgrade -y -apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \ - libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \ - libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \ - liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \ - libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools -``` +## How to build afl-clang-lto + +That part is easy. +Just set `LLVM_CONFIG` to the llvm-config-VERSION and build AFL++, e.g. for +LLVM 15: -### Building llvm yourself (version 12+) - -Building llvm from GitHub takes quite some time and is not painless: - -```sh -sudo apt install binutils-dev # this is *essential*! -git clone --depth=1 https://github.com/llvm/llvm-project -cd llvm-project -mkdir build -cd build - -# Add -G Ninja if ninja-build installed -# "Building with ninja significantly improves your build time, especially with -# incremental builds, and improves your memory usage." -cmake \ - -DCLANG_INCLUDE_DOCS="OFF" \ - -DCMAKE_BUILD_TYPE=Release \ - -DLLVM_BINUTILS_INCDIR=/usr/include/ \ - -DLLVM_BUILD_LLVM_DYLIB="ON" \ - -DLLVM_ENABLE_BINDINGS="OFF" \ - -DLLVM_ENABLE_PROJECTS='clang;compiler-rt;libcxx;libcxxabi;libunwind;lld' \ - -DLLVM_ENABLE_WARNINGS="OFF" \ - -DLLVM_INCLUDE_BENCHMARKS="OFF" \ - -DLLVM_INCLUDE_DOCS="OFF" \ - -DLLVM_INCLUDE_EXAMPLES="OFF" \ - -DLLVM_INCLUDE_TESTS="OFF" \ - -DLLVM_LINK_LLVM_DYLIB="ON" \ - -DLLVM_TARGETS_TO_BUILD="host" \ - ../llvm/ -cmake --build . -j4 -export PATH="$(pwd)/bin:$PATH" -export LLVM_CONFIG="$(pwd)/bin/llvm-config" -export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" -cd /path/to/AFLplusplus/ +``` +cd ~/AFLplusplus +export LLVM_CONFIG=llvm-config-15 make sudo make install ``` @@ -135,10 +96,10 @@ Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -> [README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work. -Example: +Example (note that you might need to add the version, e.g. `llvm-ar-15`: ``` -CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure +CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as ./configure make ``` @@ -316,13 +277,13 @@ AS=llvm-as ... afl-clang-lto is still work in progress. Known issues: -* Anything that llvm 11+ cannot compile, afl-clang-lto cannot compile either - +* Anything that LLVM 11+ cannot compile, afl-clang-lto cannot compile either - obviously. * Anything that does not compile with LTO, afl-clang-lto cannot compile either - obviously. 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`, +LLVM 12 and LTO enabled (`CC=clang-12`, `CXX=clang++-12`, `CFLAGS=-flto=full`, and `CXXFLAGS=-flto=full`). If this succeeds, then there is an issue with afl-clang-lto. Please report at @@ -340,7 +301,7 @@ knows what this is doing. And the developer who implemented this didn't respond to emails.) In December then came the idea to implement this as a pass that is run via the -llvm "opt" program, which is performed via an own linker that afterwards calls +LLVM "opt" program, which is performed via an own linker that afterwards calls the real linker. This was first implemented in January and work ... kinda. The LTO time instrumentation worked, however, "how" the basic blocks were instrumented was a problem, as reducing duplicates turned out to be very, very @@ -352,13 +313,13 @@ dead-end too. The final idea to solve this came from domenukk who proposed to insert a block into an edge and then just use incremental counters ... and this worked! After some trials and errors to implement this vanhauser-thc found out that there is -actually an llvm function for this: SplitEdge() :-) +actually an LLVM function for this: SplitEdge() :-) -Still more problems came up though as this only works without bugs from llvm 9 +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 load +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 :) \ No newline at end of file +Happy end :) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 721bc487..e41f19b6 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -17,7 +17,9 @@ #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" +#if LLVM_VERSION_MAJOR < 17 + #include "llvm/ADT/Triple.h" +#endif #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/ValueTracking.h" @@ -111,6 +113,12 @@ static cl::opt<bool> ClPruneBlocks( cl::desc("Reduce the number of instrumented blocks"), cl::Hidden, cl::init(true)); +namespace llvm { + +void initializeModuleSanitizerCoverageLTOLegacyPassPass(PassRegistry &PB); + +} + namespace { SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) { @@ -230,6 +238,7 @@ class ModuleSanitizerCoverageLTO // const SpecialCaseList * Allowlist; // const SpecialCaseList * Blocklist; uint32_t autodictionary = 1; + uint32_t autodictionary_no_main = 0; uint32_t inst = 0; uint32_t afl_global_id = 0; uint32_t unhandled = 0; @@ -255,13 +264,13 @@ class ModuleSanitizerCoverageLTO }; -class ModuleSanitizerCoverageLegacyPass : public ModulePass { +class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass { public: static char ID; StringRef getPassName() const override { - return "sancov"; + return "sancov-lto"; } @@ -272,11 +281,11 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass { } - ModuleSanitizerCoverageLegacyPass( + ModuleSanitizerCoverageLTOLegacyPass( const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()) : ModulePass(ID), Options(Options) { - initializeModuleSanitizerCoverageLegacyPassPass( + initializeModuleSanitizerCoverageLTOLegacyPassPass( *PassRegistry::getPassRegistry()); } @@ -318,8 +327,11 @@ llvmGetPassPluginInfo() { #if LLVM_VERSION_MAJOR <= 13 using OptimizationLevel = typename PassBuilder::OptimizationLevel; #endif - // PB.registerFullLinkTimeOptimizationLastEPCallback( +#if LLVM_VERSION_MAJOR >= 15 + PB.registerFullLinkTimeOptimizationLastEPCallback( +#else PB.registerOptimizerLastEPCallback( +#endif [](ModulePassManager &MPM, OptimizationLevel OL) { MPM.addPass(ModuleSanitizerCoverageLTO()); @@ -402,7 +414,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( /* Show a banner */ setvbuf(stdout, NULL, _IONBF, 0); - if (getenv("AFL_DEBUG")) debug = 1; + if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; } if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { @@ -420,6 +433,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( if ((afl_global_id = atoi(ptr)) < 0) FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is negative\n", ptr); + if (afl_global_id < 4) { afl_global_id = 4; } + if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) { dFile.open(ptr, std::ofstream::out | std::ofstream::app); @@ -494,6 +509,13 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; } + if (autodictionary_no_main && + (!F.getName().compare("main") || !F.getName().compare("_main"))) { + + continue; + + } + for (auto &BB : F) { for (auto &IN : BB) { @@ -1750,30 +1772,22 @@ std::string ModuleSanitizerCoverageLTO::getSectionName( } -char ModuleSanitizerCoverageLegacyPass::ID = 0; +char ModuleSanitizerCoverageLTOLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov", +INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto", "Pass for instrumenting coverage on functions", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass) -INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov", +INITIALIZE_PASS_END(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto", "Pass for instrumenting coverage on functions", false, false) -ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( - const SanitizerCoverageOptions &Options, - const std::vector<std::string> &AllowlistFiles, - const std::vector<std::string> &BlocklistFiles) { - - return new ModuleSanitizerCoverageLegacyPass(Options); - -} - +#if LLVM_VERSION_MAJOR < 16 static void registerLTOPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { - auto p = new ModuleSanitizerCoverageLegacyPass(); + auto p = new ModuleSanitizerCoverageLTOLegacyPass(); PM.add(p); } @@ -1784,8 +1798,9 @@ static RegisterStandardPasses RegisterCompTransPass( static RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerLTOPass); -#if LLVM_VERSION_MAJOR >= 11 + #if LLVM_VERSION_MAJOR >= 11 static RegisterStandardPasses RegisterCompTransPassLTO( PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerLTOPass); + #endif #endif diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index e22c9ead..85b1ddd5 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -13,7 +13,9 @@ #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" +#if LLVM_VERSION_MAJOR < 17 + #include "llvm/ADT/Triple.h" +#endif #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/CFG.h" @@ -209,57 +211,6 @@ class ModuleSanitizerCoverageAFL }; -class ModuleSanitizerCoverageLegacyPass : public ModulePass { - - public: - ModuleSanitizerCoverageLegacyPass( - const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()) - : ModulePass(ID), Options(Options) { - - initializeModuleSanitizerCoverageLegacyPassPass( - *PassRegistry::getPassRegistry()); - - } - - bool runOnModule(Module &M) override { - - ModuleSanitizerCoverageAFL ModuleSancov(Options); - auto DTCallback = [this](Function &F) -> const DominatorTree * { - - return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); - - }; - - auto PDTCallback = [this](Function &F) -> const PostDominatorTree * { - - return &this->getAnalysis<PostDominatorTreeWrapperPass>(F) - .getPostDomTree(); - - }; - - return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback); - - } - - /*static*/ char ID; // Pass identification, replacement for typeid - StringRef getPassName() const override { - - return "ModuleSanitizerCoverage"; - - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - - AU.addRequired<DominatorTreeWrapperPass>(); - AU.addRequired<PostDominatorTreeWrapperPass>(); - - } - - private: - SanitizerCoverageOptions Options; - -}; - } // namespace #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ @@ -779,7 +730,11 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection( Array->setSection(getSectionName(Section)); #if (LLVM_VERSION_MAJOR >= 11) || \ (LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1) + #if LLVM_VERSION_MAJOR >= 16 + Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue())); + #else Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize())); + #endif #else Array->setAlignment(Align(4)); // cheating #endif @@ -850,7 +805,8 @@ void ModuleSanitizerCoverageAFL::CreateFunctionLocalArrays( bool ModuleSanitizerCoverageAFL::InjectCoverage( Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) { - uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0; + uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0; + static uint32_t first = 1; for (auto &BB : F) { @@ -876,9 +832,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; + if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) { - cnt_cov++; + cnt_cov++; + + } } @@ -917,7 +875,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } /* Create PCGUARD array */ - CreateFunctionLocalArrays(F, AllBlocks, cnt_cov + cnt_sel_inc); + CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc); + if (first) { first = 0; } selects += cnt_sel; uint32_t special = 0, local_selects = 0, skip_next = 0; @@ -1103,10 +1062,10 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr); /* - std::string errMsg; - raw_string_ostream os(errMsg); - result->print(os); - fprintf(stderr, "X: %s\n", os.str().c_str()); + std::string errMsg; + raw_string_ostream os(errMsg); + result->print(os); + fprintf(stderr, "X: %s\n", os.str().c_str()); */ while (1) { @@ -1526,26 +1485,3 @@ std::string ModuleSanitizerCoverageAFL::getSectionEnd( } -#if 0 - -char ModuleSanitizerCoverageLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov", - "Pass for instrumenting coverage on functions", false, - false) -INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) -INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass) -INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov", - "Pass for instrumenting coverage on functions", false, - false) -ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( - const SanitizerCoverageOptions &Options, - const std::vector<std::string> &AllowlistFiles, - const std::vector<std::string> &BlocklistFiles) { - - return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles, - BlocklistFiles); - -} - -#endif - diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1759898e..e0e40983 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -3,7 +3,7 @@ ------------------------------------------------ Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -97,18 +97,23 @@ u8 *__afl_dictionary; u8 *__afl_fuzz_ptr; static u32 __afl_fuzz_len_dummy; u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy; +int __afl_sharedmem_fuzzing __attribute__((weak)); u32 __afl_final_loc; u32 __afl_map_size = MAP_SIZE; u32 __afl_dictionary_len; u64 __afl_map_addr; +u32 __afl_first_final_loc; + +/* 1 if we are running in afl, and the forkserver was started, else 0 */ +u32 __afl_connected = 0; // for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: int __afl_selective_coverage __attribute__((weak)); int __afl_selective_coverage_start_off __attribute__((weak)); static int __afl_selective_coverage_temp = 1; -#if defined(__ANDROID__) || defined(__HAIKU__) +#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; PREV_LOC_T __afl_prev_caller[CTX_MAX_K]; u32 __afl_prev_ctx; @@ -118,8 +123,6 @@ __thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K]; __thread u32 __afl_prev_ctx; #endif -int __afl_sharedmem_fuzzing __attribute__((weak)); - struct cmp_map *__afl_cmp_map; struct cmp_map *__afl_cmp_map_backup; @@ -146,6 +149,7 @@ u32 __afl_already_initialized_shm; u32 __afl_already_initialized_forkserver; u32 __afl_already_initialized_first; u32 __afl_already_initialized_second; +u32 __afl_already_initialized_early; u32 __afl_already_initialized_init; /* Dummy pipe for area_is_valid() */ @@ -159,6 +163,7 @@ static void at_exit(int signal) { if (unlikely(child_pid > 0)) { kill(child_pid, SIGKILL); + waitpid(child_pid, NULL, 0); child_pid = -1; } @@ -319,13 +324,16 @@ static void __afl_map_shm(void) { } else { - if (!getenv("AFL_QUIET")) + if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) { + fprintf(stderr, "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u " "to be able to run this instrumented program if this " "crashes!\n", __afl_final_loc); + } + } } @@ -343,29 +351,51 @@ static void __afl_map_shm(void) { } - if (!id_str && __afl_area_ptr_dummy == __afl_area_initial) { + if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) || + fcntl(FORKSRV_FD, F_GETFD) == -1 || + fcntl(FORKSRV_FD + 1, F_GETFD) == -1)) { + + if (__afl_debug) { + + fprintf(stderr, + "DEBUG: running not inside afl-fuzz, disabling shared memory " + "testcases\n"); + + } + + __afl_sharedmem_fuzzing = 0; + + } + + if (!id_str) { u32 val = 0; u8 *ptr; - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) val = atoi(ptr); + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); } if (val > MAP_INITIAL_SIZE) { __afl_map_size = val; - __afl_area_ptr_dummy = malloc(__afl_map_size); - if (!__afl_area_ptr_dummy) { - fprintf(stderr, - "Error: AFL++ could not aquire %u bytes of memory, exiting!\n", - __afl_map_size); - exit(-1); + } else { + + if (__afl_first_final_loc > MAP_INITIAL_SIZE) { + + // done in second stage constructor + __afl_map_size = __afl_first_final_loc; + + } else { + + __afl_map_size = MAP_INITIAL_SIZE; } - } else { + } - __afl_map_size = MAP_INITIAL_SIZE; + if (__afl_map_size > MAP_INITIAL_SIZE && __afl_final_loc < __afl_map_size) { + + __afl_final_loc = __afl_map_size; } @@ -516,7 +546,9 @@ static void __afl_map_shm(void) { } - } else if (__afl_final_loc > __afl_map_size) { + } else if (__afl_final_loc > MAP_INITIAL_SIZE && + + __afl_final_loc > __afl_first_final_loc) { if (__afl_area_initial != __afl_area_ptr_dummy) { @@ -531,13 +563,13 @@ static void __afl_map_shm(void) { if (!__afl_area_ptr_dummy) { fprintf(stderr, - "Error: AFL++ could not aquire %u bytes of memory, exiting!\n", + "Error: AFL++ could not acquire %u bytes of memory, exiting!\n", __afl_final_loc); exit(-1); } - } + } // else: nothing to be done __afl_area_ptr_backup = __afl_area_ptr; @@ -745,10 +777,10 @@ static void __afl_start_snapshots(void) { assume we're not running in forkserver mode and just execute program. */ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG); - if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ; + if (__afl_sharedmem_fuzzing) { status |= FS_OPT_SHDMEM_FUZZ; } if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT; + if (__afl_dictionary_len && __afl_dictionary) { status |= FS_OPT_AUTODICT; } memcpy(tmp, &status, 4); if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } @@ -1009,7 +1041,7 @@ static void __afl_start_forkserver(void) { } - if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; } + if (__afl_sharedmem_fuzzing) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; } if (status_for_fsrv) { status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG); @@ -1023,6 +1055,8 @@ static void __afl_start_forkserver(void) { if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } + __afl_connected = 1; + if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); @@ -1233,13 +1267,9 @@ int __afl_persistent_loop(unsigned int max_cnt) { iteration, it's our job to erase any trace of whatever happened before the loop. */ - if (is_persistent) { - - memset(__afl_area_ptr, 0, __afl_map_size); - __afl_area_ptr[0] = 1; - memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); - - } + memset(__afl_area_ptr, 0, __afl_map_size); + __afl_area_ptr[0] = 1; + memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); cycle_cnt = max_cnt; first_pass = 0; @@ -1247,34 +1277,28 @@ int __afl_persistent_loop(unsigned int max_cnt) { return 1; - } - - if (is_persistent) { + } else if (--cycle_cnt) { - if (--cycle_cnt) { + raise(SIGSTOP); - raise(SIGSTOP); - - __afl_area_ptr[0] = 1; - memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); - __afl_selective_coverage_temp = 1; + __afl_area_ptr[0] = 1; + memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); + __afl_selective_coverage_temp = 1; - return 1; + return 1; - } else { + } else { - /* When exiting __AFL_LOOP(), make sure that the subsequent code that - follows the loop is not traced. We do that by pivoting back to the - dummy output region. */ + /* When exiting __AFL_LOOP(), make sure that the subsequent code that + follows the loop is not traced. We do that by pivoting back to the + dummy output region. */ - __afl_area_ptr = __afl_area_ptr_dummy; + __afl_area_ptr = __afl_area_ptr_dummy; - } + return 0; } - return 0; - } /* This one can be called from user code when deferred forkserver mode @@ -1350,6 +1374,9 @@ __attribute__((constructor(EARLY_FS_PRIO))) void __early_forkserver(void) { __attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) { + if (__afl_already_initialized_early) return; + __afl_already_initialized_early = 1; + is_persistent = !!getenv(PERSIST_ENV_VAR); if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; @@ -1375,21 +1402,24 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; - if (__afl_final_loc) { + if (__afl_final_loc > MAP_INITIAL_SIZE) { + + __afl_first_final_loc = __afl_final_loc + 1; if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) free(__afl_area_ptr); if (__afl_map_addr) - ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_final_loc, + ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_first_final_loc, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0); else - ptr = (u8 *)malloc(__afl_final_loc); + ptr = (u8 *)malloc(__afl_first_final_loc); if (ptr && (ssize_t)ptr != -1) { __afl_area_ptr = ptr; + __afl_area_ptr_dummy = __afl_area_ptr; __afl_area_ptr_backup = __afl_area_ptr; } @@ -1407,14 +1437,18 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { __afl_already_initialized_first = 1; if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; - u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE); - if (ptr && (ssize_t)ptr != -1) { + /* + u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE); + + if (ptr && (ssize_t)ptr != -1) { - __afl_area_ptr = ptr; - __afl_area_ptr_backup = __afl_area_ptr; + __afl_area_ptr = ptr; + __afl_area_ptr_backup = __afl_area_ptr; - } + } + + */ } // ptr memleak report is a false positive @@ -1484,6 +1518,14 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { _is_sancov = 1; + if (!getenv("AFL_DUMP_MAP_SIZE")) { + + __afl_auto_first(); + __afl_auto_second(); + __afl_auto_early(); + + } + if (__afl_debug) { fprintf(stderr, @@ -1494,7 +1536,21 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { } - if (start == stop || *start) return; + if (start == stop || *start) { return; } + + x = getenv("AFL_INST_RATIO"); + if (x) { + + inst_ratio = (u32)atoi(x); + + if (!inst_ratio || inst_ratio > 100) { + + fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); + abort(); + + } + + } // If a dlopen of an instrumented library happens after the forkserver then // we have a problem as we cannot increase the coverage map anymore. @@ -1507,85 +1563,55 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { "[-] FATAL: forkserver is already up, but an instrumented dlopen() " "library loaded afterwards. You must AFL_PRELOAD such libraries to " "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n" - "To ignore this set AFL_IGNORE_PROBLEMS=1.\n"); + "To ignore this set AFL_IGNORE_PROBLEMS=1 but this will be bad for " + "coverage.\n"); abort(); } else { - static u32 offset = 4; + static u32 offset = 5; while (start < stop) { - *(start++) = offset; - if (unlikely(++offset >= __afl_final_loc)) { offset = 4; } - - } - - } - - } - - x = getenv("AFL_INST_RATIO"); - if (x) { inst_ratio = (u32)atoi(x); } - - if (!inst_ratio || inst_ratio > 100) { - - fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); - abort(); - - } - - /* instrumented code is loaded *after* our forkserver is up. this is a - problem. We cannot prevent collisions then :( */ - /* - if (__afl_already_initialized_forkserver && - __afl_final_loc + 1 + stop - start > __afl_map_size) { - - if (__afl_debug) { - - fprintf(stderr, "Warning: new instrumented code after the forkserver!\n"); - - } - - __afl_final_loc = 2; + if (likely(inst_ratio == 100) || R(100) < inst_ratio) { - if (1 + stop - start > __afl_map_size) { + *(start++) = offset; - *(start++) = ++__afl_final_loc; + } else { - while (start < stop) { + *(start++) = 0; // write to map[0] - if (R(100) < inst_ratio) - *start = ++__afl_final_loc % __afl_map_size; - else - *start = 4; + } - start++; + if (unlikely(++offset >= __afl_final_loc)) { offset = 5; } } - return; - } - } + return; // we are done for this special case - */ + } /* Make sure that the first element in the range is always set - we use that to avoid duplicate calls (which can happen as an artifact of the underlying implementation in LLVM). */ + if (__afl_final_loc < 5) __afl_final_loc = 5; // we skip the first 5 entries + *(start++) = ++__afl_final_loc; while (start < stop) { - if (R(100) < inst_ratio) - *start = ++__afl_final_loc; - else - *start = 4; + if (likely(inst_ratio == 100) || R(100) < inst_ratio) { + + *(start++) = ++__afl_final_loc; + + } else { - start++; + *(start++) = 0; // write to map[0] + + } } @@ -1597,17 +1623,23 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { } - if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) { + if (__afl_already_initialized_shm) { - if (__afl_debug) { + if (__afl_final_loc > __afl_map_size) { + + if (__afl_debug) { + + fprintf(stderr, "Reinit shm necessary (+%u)\n", + __afl_final_loc - __afl_map_size); + + } - fprintf(stderr, "Reinit shm necessary (+%u)\n", - __afl_final_loc - __afl_map_size); + __afl_unmap_shm(); + __afl_map_shm(); } - __afl_unmap_shm(); - __afl_map_shm(); + __afl_map_size = __afl_final_loc + 1; } diff --git a/instrumentation/afl-gcc-cmplog-pass.so.cc b/instrumentation/afl-gcc-cmplog-pass.so.cc index 5e5792c3..b4e6fda9 100644 --- a/instrumentation/afl-gcc-cmplog-pass.so.cc +++ b/instrumentation/afl-gcc-cmplog-pass.so.cc @@ -3,7 +3,7 @@ Copyright 2014-2019 Free Software Foundation, Inc Copyright 2015, 2016 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Copyright 2019-2022 AdaCore + Copyright 2019-2023 AdaCore Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ LLVM CmpLog pass by Andrea Fioraldi <andreafioraldi@gmail.com>, and @@ -243,9 +243,9 @@ struct afl_cmplog_pass : afl_base_pass { tree t = build_nonstandard_integer_type(sz, 1); - tree s = make_ssa_name(t); - gimple *g = gimple_build_assign(s, VIEW_CONVERT_EXPR, - build1(VIEW_CONVERT_EXPR, t, lhs)); + tree s = make_ssa_name(t); + gimple g = gimple_build_assign(s, VIEW_CONVERT_EXPR, + build1(VIEW_CONVERT_EXPR, t, lhs)); lhs = s; gsi_insert_before(&gsi, g, GSI_SAME_STMT); @@ -263,8 +263,8 @@ struct afl_cmplog_pass : afl_base_pass { lhs = fold_convert_loc(UNKNOWN_LOCATION, t, lhs); if (!is_gimple_val(lhs)) { - tree s = make_ssa_name(t); - gimple *g = gimple_build_assign(s, lhs); + tree s = make_ssa_name(t); + gimple g = gimple_build_assign(s, lhs); lhs = s; gsi_insert_before(&gsi, g, GSI_SAME_STMT); @@ -273,16 +273,16 @@ struct afl_cmplog_pass : afl_base_pass { rhs = fold_convert_loc(UNKNOWN_LOCATION, t, rhs); if (!is_gimple_val(rhs)) { - tree s = make_ssa_name(t); - gimple *g = gimple_build_assign(s, rhs); + tree s = make_ssa_name(t); + gimple g = gimple_build_assign(s, rhs); rhs = s; gsi_insert_before(&gsi, g, GSI_SAME_STMT); } /* Insert the call. */ - tree att = build_int_cst(t8u, attr); - gimple *call; + tree att = build_int_cst(t8u, attr); + gimple call; if (pass_n) call = gimple_build_call(fn, 4, lhs, rhs, att, build_int_cst(t8u, sz / 8 - 1)); @@ -305,7 +305,7 @@ struct afl_cmplog_pass : afl_base_pass { gimple_stmt_iterator gsi = gsi_last_bb(bb); if (gsi_end_p(gsi)) continue; - gimple *stmt = gsi_stmt(gsi); + gimple stmt = gsi_stmt(gsi); if (gimple_code(stmt) == GIMPLE_COND) { diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc index e9e2fe0d..dbb408b0 100644 --- a/instrumentation/afl-gcc-cmptrs-pass.so.cc +++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc @@ -3,7 +3,7 @@ Copyright 2014-2019 Free Software Foundation, Inc Copyright 2015, 2016 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Copyright 2019-2022 AdaCore + Copyright 2019-2023 AdaCore Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ LLVM CmpLog Routines pass by Andrea Fioraldi @@ -241,7 +241,7 @@ struct afl_cmptrs_pass : afl_base_pass { for (gimple_stmt_iterator gsi = gsi_after_labels(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { - gimple *stmt = gsi_stmt(gsi); + gimple stmt = gsi_stmt(gsi); /* We're only interested in GIMPLE_CALLs. */ if (gimple_code(stmt) != GIMPLE_CALL) continue; @@ -291,8 +291,8 @@ struct afl_cmptrs_pass : afl_base_pass { tree c = fold_convert_loc(UNKNOWN_LOCATION, tp8u, arg[i]); if (!is_gimple_val(c)) { - tree s = make_ssa_name(tp8u); - gimple *g = gimple_build_assign(s, c); + tree s = make_ssa_name(tp8u); + gimple g = gimple_build_assign(s, c); c = s; gsi_insert_before(&gsi, g, GSI_SAME_STMT); @@ -302,7 +302,7 @@ struct afl_cmptrs_pass : afl_base_pass { } - gimple *call = gimple_build_call(fn, 2, arg[0], arg[1]); + gimple call = gimple_build_call(fn, 2, arg[0], arg[1]); gsi_insert_before(&gsi, call, GSI_SAME_STMT); } diff --git a/instrumentation/afl-gcc-common.h b/instrumentation/afl-gcc-common.h index 2b71bd22..1d5eb466 100644 --- a/instrumentation/afl-gcc-common.h +++ b/instrumentation/afl-gcc-common.h @@ -2,7 +2,7 @@ Copyright 2014-2019 Free Software Foundation, Inc Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AdaCore + Copyright 2019-2023 AdaCore Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++ GCC plugin. @@ -498,3 +498,11 @@ struct afl_base_pass : gimple_opt_pass { } // namespace +// compatibility for older gcc versions +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \ + 60200 /* >= version 6.2.0 */ + #define gimple gimple * +#else + #define gimple gimple +#endif + diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index 052b3159..4d7fd0ef 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -2,7 +2,7 @@ Copyright 2014-2019 Free Software Foundation, Inc Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AdaCore + Copyright 2019-2023 AdaCore Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL LLVM pass by Laszlo Szekeres <lszekeres@google.com> and Michal @@ -125,7 +125,10 @@ */ #include "afl-gcc-common.h" -#include "memmodel.h" +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \ + 60200 /* >= version 6.2.0 */ + #include "memmodel.h" +#endif /* This plugin, being under the same license as GCC, satisfies the "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 5fcf27fb..5d82aa25 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -12,6 +12,7 @@ #include <list> #include <string> #include <fstream> +#include <cmath> #include <llvm/Support/raw_ostream.h> @@ -288,6 +289,7 @@ void scanForDangerousFunctions(llvm::Module *M) { StringRef ifunc_name = IF.getName(); Constant *r = IF.getResolver(); + if (r->getNumOperands() == 0) { continue; } StringRef r_name = cast<Function>(r->getOperand(0))->getName(); if (!be_quiet) fprintf(stderr, diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h index dee5f9fc..16a13da5 100644 --- a/instrumentation/afl-llvm-common.h +++ b/instrumentation/afl-llvm-common.h @@ -8,6 +8,7 @@ #include <list> #include <string> #include <fstream> +#include <optional> #include <sys/time.h> #include "llvm/Config/llvm-config.h" @@ -35,6 +36,12 @@ typedef long double max_align_t; #if LLVM_VERSION_MAJOR >= 11 #define MNAME M.getSourceFileName() #define FMNAME F.getParent()->getSourceFileName() + #if LLVM_VERSION_MAJOR >= 16 +// None becomes deprecated +// the standard std::nullopt_t is recommended instead +// from C++17 and onwards. +constexpr std::nullopt_t None = std::nullopt; + #endif #else #define MNAME std::string("") #define FMNAME std::string("") diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index fd8baea2..97f1d47f 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -4,7 +4,7 @@ Written by Marc Heuse <mh@mh-sec.de> - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -182,7 +182,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { DenseMap<Value *, std::string *> valueMap; char *ptr; - int found = 0; + int found = 0, handle_main = 1; /* Show a banner */ setvbuf(stdout, NULL, _IONBF, 0); @@ -192,10 +192,14 @@ bool AFLdict2filePass::runOnModule(Module &M) { SAYF(cCYA "afl-llvm-dict2file" VERSION cRST " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n"); - } else + } else { be_quiet = 1; + } + + if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { handle_main = 0; } + scanForDangerousFunctions(&M); ptr = getenv("AFL_LLVM_DICT2FILE"); @@ -210,7 +214,14 @@ bool AFLdict2filePass::runOnModule(Module &M) { for (auto &F : M) { - if (isIgnoreFunction(&F)) continue; + if (!handle_main && + (!F.getName().compare("main") || !F.getName().compare("_main"))) { + + continue; + + } + + if (isIgnoreFunction(&F)) { continue; } if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; } /* Some implementation notes. diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index 32b1798a..db5bd55e 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -9,7 +9,7 @@ from afl-as.c are Michal's fault. Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index df1ccc4f..c59324fd 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -12,7 +12,7 @@ NGRAM previous location coverage comes from Adrian Herrera. Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -413,7 +413,7 @@ bool AFLCoverage::runOnModule(Module &M) { GlobalVariable *AFLContext = NULL; if (ctx_str || caller_str) -#if defined(__ANDROID__) || defined(__HAIKU__) +#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); #else @@ -424,7 +424,7 @@ bool AFLCoverage::runOnModule(Module &M) { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ngram_size) - #if defined(__ANDROID__) || defined(__HAIKU__) + #if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) AFLPrevLoc = new GlobalVariable( M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_loc"); @@ -437,7 +437,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif else #endif -#if defined(__ANDROID__) || defined(__HAIKU__) +#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); #else @@ -448,7 +448,7 @@ bool AFLCoverage::runOnModule(Module &M) { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ctx_k) - #if defined(__ANDROID__) || defined(__HAIKU__) + #if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) AFLPrevCaller = new GlobalVariable( M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_caller"); @@ -461,7 +461,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif else #endif -#if defined(__ANDROID__) || defined(__HAIKU__) +#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS) AFLPrevCaller = new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_caller"); diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 084ad8c9..bca1f927 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -5,7 +5,7 @@ Written by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc index 9733f86e..0498156d 100644 --- a/instrumentation/cmplog-routines-pass.cc +++ b/instrumentation/cmplog-routines-pass.cc @@ -5,7 +5,7 @@ Written by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/cmplog-switches-pass.cc b/instrumentation/cmplog-switches-pass.cc index 563a4481..cd0ae76d 100644 --- a/instrumentation/cmplog-switches-pass.cc +++ b/instrumentation/cmplog-switches-pass.cc @@ -5,7 +5,7 @@ Written by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 39bff510..efc99d20 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -708,7 +708,11 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, /* since the call is the first instruction of the bb it is safe to * replace it with a phi instruction */ BasicBlock::iterator ii(callInst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(callInst->getParent(), ii, PN); +#else ReplaceInstWithInst(callInst->getParent()->getInstList(), ii, PN); +#endif } diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 95eca0cb..8a07610c 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -322,8 +322,12 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { * 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); +#if LLVM_MAJOR >= 16 + fcmp_np->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); +#else bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), fcmp_np); +#endif /* create a new basic block which holds the new EQ fcmp */ Instruction *fcmp_eq; @@ -331,7 +335,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1); +#if LLVM_MAJOR >= 16 + fcmp_eq->insertInto(middle_bb, middle_bb->end()); +#else middle_bb->getInstList().push_back(fcmp_eq); +#endif /* add an unconditional branch to the end of middle_bb with destination * end_bb */ BranchInst::Create(end_bb, middle_bb); @@ -352,7 +360,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); /* replace the old FcmpInst with our new and shiny PHI inst */ BasicBlock::iterator ii(FcmpInst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(FcmpInst->getParent(), ii, PN); +#else ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); +#endif } @@ -409,7 +421,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst, /* 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 */ CmpInst *icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); +#if LLVM_MAJOR >= 16 + icmp_np->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); +#else bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), icmp_np); +#endif /* create a new basic block which holds the new EQ icmp */ CmpInst *icmp_eq; @@ -417,7 +433,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst, BasicBlock *middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); +#if LLVM_MAJOR >= 16 + icmp_eq->insertInto(middle_bb, middle_bb->end()); +#else middle_bb->getInstList().push_back(icmp_eq); +#endif /* add an unconditional branch to the end of middle_bb with destination * end_bb */ BranchInst::Create(end_bb, middle_bb); @@ -438,7 +458,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst, PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); /* replace the old IcmpInst with our new and shiny PHI inst */ BasicBlock::iterator ii(IcmpInst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(IcmpInst->getParent(), ii, PN); +#else ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); +#endif worklist.push_back(icmp_np); worklist.push_back(icmp_eq); @@ -518,7 +542,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, } +#if LLVM_MAJOR >= 16 + icmp_inv_sig_cmp->insertInto(sign_bb, sign_bb->end()); +#else sign_bb->getInstList().push_back(icmp_inv_sig_cmp); +#endif BranchInst::Create(end_bb, sign_bb); /* create a new bb which is executed if signedness is equal */ @@ -528,7 +556,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, /* we can do a normal unsigned compare now */ icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); +#if LLVM_MAJOR >= 16 + icmp_usign_cmp->insertInto(middle_bb, middle_bb->end()); +#else middle_bb->getInstList().push_back(icmp_usign_cmp); +#endif BranchInst::Create(end_bb, middle_bb); auto term = bb->getTerminator(); @@ -543,7 +575,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, PN->addIncoming(icmp_inv_sig_cmp, sign_bb); BasicBlock::iterator ii(IcmpInst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(IcmpInst->getParent(), ii, PN); +#else ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); +#endif // save for later worklist.push_back(icmp_usign_cmp); @@ -717,7 +753,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, } +#if LLVM_MAJOR >= 16 + icmp_inv_cmp->insertInto(inv_cmp_bb, inv_cmp_bb->end()); +#else inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); +#endif worklist.push_back(icmp_inv_cmp); auto term = bb->getTerminator(); @@ -728,12 +768,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, BasicBlock *cmp_low_bb = BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); op0_low = new TruncInst(op0, NewIntType); - cmp_low_bb->getInstList().push_back(op0_low); op1_low = new TruncInst(op1, NewIntType); - cmp_low_bb->getInstList().push_back(op1_low); - icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low); + +#if LLVM_MAJOR >= 16 + op0_low->insertInto(cmp_low_bb, cmp_low_bb->end()); + op1_low->insertInto(cmp_low_bb, cmp_low_bb->end()); + icmp_low->insertInto(cmp_low_bb, cmp_low_bb->end()); +#else + cmp_low_bb->getInstList().push_back(op0_low); + cmp_low_bb->getInstList().push_back(op1_low); cmp_low_bb->getInstList().push_back(icmp_low); +#endif BranchInst::Create(end_bb, cmp_low_bb); BranchInst::Create(end_bb, cmp_low_bb, icmp_inv_cmp, inv_cmp_bb); @@ -754,7 +800,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, } BasicBlock::iterator ii(cmp_inst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(cmp_inst->getParent(), ii, PN); +#else ReplaceInstWithInst(cmp_inst->getParent()->getInstList(), ii, PN); +#endif // We split the comparison into low and high. If this isn't our target // bitwidth we recursively split the low and high parts again until we have @@ -999,13 +1049,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *bpre_op0, *bpre_op1; bpre_op0 = CastInst::Create(Instruction::BitCast, op0, IntegerType::get(C, op_size)); +#if LLVM_MAJOR >= 16 + bpre_op0->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); +#else bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), bpre_op0); +#endif bpre_op1 = CastInst::Create(Instruction::BitCast, op1, IntegerType::get(C, op_size)); +#if LLVM_MAJOR >= 16 + bpre_op1->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); +#else bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), bpre_op1); +#endif /* Check if any operand is NaN. * If so, all comparisons except unequal (which yields true) yield false */ @@ -1025,34 +1083,42 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *nan_op0, *nan_op1; nan_op0 = BinaryOperator::Create(Instruction::Shl, bpre_op0, ConstantInt::get(bpre_op0->getType(), 1)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - nan_op0); - + /* Check op1 for NaN */ + /* Shift right 1 Bit, ignore sign bit */ + nan_op1 = BinaryOperator::Create(Instruction::Shl, bpre_op1, + ConstantInt::get(bpre_op1->getType(), 1)); /* compare to NaN interval */ Instruction *is_op0_nan = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op0, ConstantInt::get(intType, NaN_lowend)); + /* compare to NaN interval */ + Instruction *is_op1_nan = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op1, + ConstantInt::get(intType, NaN_lowend)); + /* combine checks */ + Instruction *is_nan = + BinaryOperator::Create(Instruction::Or, is_op0_nan, is_op1_nan); +#if LLVM_MAJOR >= 16 + nan_op0->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); + is_op0_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); + nan_op1->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); + is_op1_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); + is_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator())); +#else + bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), + nan_op0); + bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), is_op0_nan); - /* Check op1 for NaN */ - /* Shift right 1 Bit, ignore sign bit */ - nan_op1 = BinaryOperator::Create(Instruction::Shl, bpre_op1, - ConstantInt::get(bpre_op1->getType(), 1)); bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), nan_op1); - /* compare to NaN interval */ - Instruction *is_op1_nan = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op1, - ConstantInt::get(intType, NaN_lowend)); bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), is_op1_nan); - /* combine checks */ - Instruction *is_nan = - BinaryOperator::Create(Instruction::Or, is_op0_nan, is_op1_nan); bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), is_nan); +#endif /* the result of the comparison, when at least one op is NaN is true only for the "NOT EQUAL" predicates. */ @@ -1079,23 +1145,34 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { isMzero_op0 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op0, ConstantInt::get(intType, MinusZero)); + isMzero_op1 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op1, + ConstantInt::get(intType, MinusZero)); + b_op0 = SelectInst::Create(isMzero_op0, ConstantInt::get(intType, PlusZero), + bpre_op0); + b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero), + bpre_op1); +#if LLVM_MAJOR >= 16 + isMzero_op0->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + isMzero_op1->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + b_op0->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + b_op1->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); +#else nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op0); - isMzero_op1 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op1, - ConstantInt::get(intType, MinusZero)); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op1); - b_op0 = SelectInst::Create(isMzero_op0, ConstantInt::get(intType, PlusZero), - bpre_op0); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), b_op0); - b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero), - bpre_op1); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), b_op1); +#endif /* isolate signs of value of floating point type */ @@ -1106,26 +1183,35 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { s_s0 = BinaryOperator::Create(Instruction::LShr, b_op0, ConstantInt::get(b_op0->getType(), op_size - 1)); + s_s1 = + BinaryOperator::Create(Instruction::LShr, b_op1, + ConstantInt::get(b_op1->getType(), op_size - 1)); + t_s0 = new TruncInst(s_s0, Int1Ty); + t_s1 = new TruncInst(s_s1, Int1Ty); + /* compare of the sign bits */ + icmp_sign_bit = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_s0, t_s1); +#if LLVM_MAJOR >= 16 + s_s0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + t_s0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + s_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + t_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + icmp_sign_bit->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); +#else nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), s_s0); - t_s0 = new TruncInst(s_s0, Int1Ty); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), t_s0); - s_s1 = - BinaryOperator::Create(Instruction::LShr, b_op1, - ConstantInt::get(b_op1->getType(), op_size - 1)); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), s_s1); - t_s1 = new TruncInst(s_s1, Int1Ty); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), t_s1); - /* compare of the sign bits */ - icmp_sign_bit = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_s0, t_s1); nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), icmp_sign_bit); +#endif /* create a new basic block which is executed if the signedness bits are * equal */ @@ -1157,17 +1243,31 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { s_e1 = BinaryOperator::Create( Instruction::LShr, b_op1, ConstantInt::get(b_op1->getType(), shiftR_exponent)); +#if LLVM_MAJOR >= 16 + s_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + s_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); +#else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), s_e0); signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), s_e1); +#endif t_e0 = new TruncInst(s_e0, IntExponentTy); t_e1 = new TruncInst(s_e1, IntExponentTy); +#if LLVM_MAJOR >= 16 + t_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + t_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); +#else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), t_e0); signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), t_e1); +#endif if (sizeInBits - precision < exTySizeBytes * 8) { @@ -1177,10 +1277,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { m_e1 = BinaryOperator::Create( Instruction::And, t_e1, ConstantInt::get(t_e1->getType(), mask_exponent)); +#if LLVM_MAJOR >= 16 + m_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + m_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); +#else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), m_e0); signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), m_e1); +#endif } else { @@ -1214,9 +1321,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *icmp_exponent; icmp_exponents_equal = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); +#if LLVM_MAJOR >= 16 + icmp_exponents_equal->insertInto( + signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); +#else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponents_equal); +#endif // shortcut for unequal exponents signequal2_bb = signequal_bb->splitBasicBlock( @@ -1230,9 +1342,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1); +#if LLVM_MAJOR >= 16 + icmp_exponent->insertInto( + signequal2_bb, + BasicBlock::iterator(signequal2_bb->getTerminator())); +#else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), icmp_exponent); +#endif icmp_exponent_result = BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0); break; @@ -1240,9 +1358,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_ULT: icmp_exponents_equal = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); +#if LLVM_MAJOR >= 16 + icmp_exponents_equal->insertInto( + signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); +#else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponents_equal); +#endif // shortcut for unequal exponents signequal2_bb = signequal_bb->splitBasicBlock( @@ -1256,9 +1379,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1); +#if LLVM_MAJOR >= 16 + icmp_exponent->insertInto( + signequal2_bb, + BasicBlock::iterator(signequal2_bb->getTerminator())); +#else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), icmp_exponent); +#endif icmp_exponent_result = BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0); break; @@ -1267,9 +1396,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } +#if LLVM_MAJOR >= 16 + icmp_exponent_result->insertInto( + signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator())); +#else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), icmp_exponent_result); +#endif { @@ -1319,19 +1453,33 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { m_f1 = BinaryOperator::Create( Instruction::And, b_op1, ConstantInt::get(b_op1->getType(), mask_fraction)); +#if LLVM_MAJOR >= 16 + m_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + m_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); +#else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), m_f0); middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), m_f1); +#endif if (needTrunc) { t_f0 = new TruncInst(m_f0, IntFractionTy); t_f1 = new TruncInst(m_f1, IntFractionTy); +#if LLVM_MAJOR >= 16 + t_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + t_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); +#else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f0); middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f1); +#endif } else { @@ -1346,10 +1494,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { t_f0 = new TruncInst(b_op0, IntFractionTy); t_f1 = new TruncInst(b_op1, IntFractionTy); +#if LLVM_MAJOR >= 16 + t_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + t_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); +#else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f0); middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f1); +#endif } else { @@ -1370,18 +1525,28 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_OEQ: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1); +#if LLVM_MAJOR >= 16 + icmp_fraction_result->insertInto( + middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); +#else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), icmp_fraction_result); +#endif break; case CmpInst::FCMP_UNE: case CmpInst::FCMP_ONE: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1); +#if LLVM_MAJOR >= 16 + icmp_fraction_result->insertInto( + middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); +#else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), icmp_fraction_result); +#endif break; case CmpInst::FCMP_OGT: @@ -1402,21 +1567,31 @@ 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)); - positive_bb->getInstList().push_back( - icmp_fraction_result2 = CmpInst::Create( - Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); + icmp_fraction_result = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); + icmp_fraction_result2 = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); +#if LLVM_MAJOR >= 16 + icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); + icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); +#else + negative_bb->getInstList().push_back(icmp_fraction_result); + positive_bb->getInstList().push_back(icmp_fraction_result2); +#endif } 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)); + icmp_fraction_result = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); + icmp_fraction_result2 = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); +#if LLVM_MAJOR >= 16 + icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); + icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); +#else + negative_bb->getInstList().push_back(icmp_fraction_result); + positive_bb->getInstList().push_back(icmp_fraction_result2); +#endif } @@ -1430,8 +1605,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { PN2 = PHINode::Create(Int1Ty, 2, ""); PN2->addIncoming(icmp_fraction_result, negative_bb); PN2->addIncoming(icmp_fraction_result2, positive_bb); +#if LLVM_MAJOR >= 16 + PN2->insertInto(middle2_bb, + BasicBlock::iterator(middle2_bb->getTerminator())); +#else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), PN2); +#endif } break; @@ -1494,7 +1674,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } BasicBlock::iterator ii(FcmpInst); +#if LLVM_MAJOR >= 16 + ReplaceInstWithInst(FcmpInst->getParent(), ii, PN); +#else ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); +#endif ++count; } diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index 79ba12d2..dcd89652 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -225,12 +225,20 @@ BasicBlock *SplitSwitchesTransform::switchConvert( BasicBlock *NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F); Shift = BinaryOperator::Create(Instruction::LShr, Val, ConstantInt::get(ValType, smallestIndex * 8)); +#if LLVM_VERSION_MAJOR >= 16 + Shift->insertInto(NewNode, NewNode->end()); +#else NewNode->getInstList().push_back(Shift); +#endif if (ValTypeBitWidth > 8) { Trunc = new TruncInst(Shift, ByteType); +#if LLVM_VERSION_MAJOR >= 16 + Trunc->insertInto(NewNode, NewNode->end()); +#else NewNode->getInstList().push_back(Trunc); +#endif } else { @@ -253,7 +261,11 @@ BasicBlock *SplitSwitchesTransform::switchConvert( ICmpInst *Comp = new ICmpInst(ICmpInst::ICMP_EQ, Trunc, ConstantInt::get(ByteType, byte), "byteMatch"); +#if LLVM_VERSION_MAJOR >= 16 + Comp->insertInto(NewNode, NewNode->end()); +#else NewNode->getInstList().push_back(Comp); +#endif bytesChecked[smallestIndex] = true; bool allBytesAreChecked = true; @@ -355,7 +367,11 @@ BasicBlock *SplitSwitchesTransform::switchConvert( ICmpInst *Comp = new ICmpInst(ICmpInst::ICMP_ULT, Trunc, ConstantInt::get(ByteType, pivot), "byteMatch"); +#if LLVM_VERSION_MAJOR >= 16 + Comp->insertInto(NewNode, NewNode->end()); +#else NewNode->getInstList().push_back(Comp); +#endif BranchInst::Create(LBB, RBB, Comp, NewNode); } @@ -452,7 +468,11 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { BranchInst::Create(SwitchBlock, OrigBlock); /* We are now done with the switch instruction, delete it. */ +#if LLVM_VERSION_MAJOR >= 16 + SI->eraseFromParent(); +#else CurBlock->getInstList().erase(SI); +#endif /* we have to update the phi nodes! */ for (BasicBlock::iterator I = Default->begin(); I != Default->end(); ++I) { |