about summary refs log tree commit diff
path: root/instrumentation
diff options
context:
space:
mode:
Diffstat (limited to 'instrumentation')
-rw-r--r--instrumentation/README.llvm.md8
-rw-r--r--instrumentation/README.lto.md129
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc57
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc102
-rw-r--r--instrumentation/afl-compiler-rt.o.c256
-rw-r--r--instrumentation/afl-gcc-cmplog-pass.so.cc22
-rw-r--r--instrumentation/afl-gcc-cmptrs-pass.so.cc10
-rw-r--r--instrumentation/afl-gcc-common.h10
-rw-r--r--instrumentation/afl-gcc-pass.so.cc7
-rw-r--r--instrumentation/afl-llvm-common.cc2
-rw-r--r--instrumentation/afl-llvm-common.h7
-rw-r--r--instrumentation/afl-llvm-dict2file.so.cc19
-rw-r--r--instrumentation/afl-llvm-lto-instrumentlist.so.cc2
-rw-r--r--instrumentation/afl-llvm-pass.so.cc12
-rw-r--r--instrumentation/cmplog-instructions-pass.cc2
-rw-r--r--instrumentation/cmplog-routines-pass.cc2
-rw-r--r--instrumentation/cmplog-switches-pass.cc2
-rw-r--r--instrumentation/compare-transform-pass.so.cc4
-rw-r--r--instrumentation/split-compares-pass.so.cc270
-rw-r--r--instrumentation/split-switches-pass.so.cc20
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) {