about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--TODO.md7
-rw-r--r--docs/Changelog.md11
-rw-r--r--docs/env_variables.md10
-rw-r--r--include/afl-fuzz.h2
-rw-r--r--llvm_mode/GNUmakefile15
-rw-r--r--llvm_mode/LLVMInsTrim.so.cc4
-rw-r--r--llvm_mode/README.instrim.md9
-rw-r--r--llvm_mode/SanitizerCoverageLTO.so.cc1505
-rw-r--r--llvm_mode/afl-clang-fast.c42
-rw-r--r--llvm_mode/afl-llvm-lto-instrim.so.cc951
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc56
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc4
-rw-r--r--src/afl-fuzz-extras.c2
-rw-r--r--src/afl-fuzz-stats.c17
14 files changed, 1591 insertions, 1044 deletions
diff --git a/TODO.md b/TODO.md
index e74fa1d5..65d59271 100644
--- a/TODO.md
+++ b/TODO.md
@@ -13,13 +13,10 @@ afl-fuzz:
  - add __sanitizer_cov_trace_cmp* support via shmem
 
 llvm_mode:
- - LTO - imitate sancov
  - add __sanitizer_cov_trace_cmp* support
 
 gcc_plugin:
  - (wait for submission then decide)
- - laf-intel
- - better instrumentation (seems to be better with gcc-9+)
 
 qemu_mode:
  - update to 5.x (if the performance bug is gone)
@@ -36,9 +33,9 @@ qemu_mode:
  - LTO/sancov: write current edge to prev_loc and use that information when
    using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow
    up edge numbers that both following cmp paths have been found and then
-   disable working on this edge id
+   disable working on this edge id -> cmplog_intelligence branch
 
  - new tancov: use some lightweight taint analysis to see which parts of a
    new queue entry is accessed and only fuzz these bytes - or better, only
    fuzz those bytes that are newly in coverage compared to the queue entry
-   the new one is based on
+   the new one is based on -> taint branch, not useful :-(
diff --git a/docs/Changelog.md b/docs/Changelog.md
index efb5ed0b..8bbb4e19 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -10,8 +10,15 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
 
 
 ### Version ++2.67d (develop)
-  - Further llvm 12 support (fast moving target like afl++ :-) )
-  - Fix for auto dictionary not to throw out a -x dictionary
+  - afl-fuzz:
+    - Fix for auto dictionary entries found during fuzzing to not throw out
+      a -x dictionary
+    - added total execs done to plot file
+  - llvm_mode:
+    - Ported SanCov to LTO, and made it the default for LTO. better
+      instrumentation locations
+    - Further llvm 12 support (fast moving target like afl++ :-) )
+    - deprecated LLVM SKIPSINGLEBLOCK env environment
 
 
 ### Version ++2.67c (release)
diff --git a/docs/env_variables.md b/docs/env_variables.md
index f0ae0b6c..94c34400 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -83,17 +83,12 @@ tools make fairly broad use of environmental variables:
 The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset
 of the settings discussed in section #1, with the exception of:
 
-    - Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting
-      functions with a single basic block. This is useful for most C and
-      some C++ targets. This works for all instrumentation modes.
-
   - AFL_AS, since this toolchain does not directly invoke GNU as.
 
   - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are
     created.
 
-  - AFL_INST_RATIO, as we switched for instrim instrumentation which
-    is more effective but makes not much sense together with this option.
+  - AFL_INST_RATIO, as we by default collision free instrumentation is used.
 
 Then there are a few specific features that are only available in llvm_mode:
 
@@ -121,7 +116,8 @@ Then there are a few specific features that are only available in llvm_mode:
     built if LLVM 11 or newer is used.
 
    - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
-     (not recommended!)
+     (not recommended for afl-clang-fast, default for afl-clang-lto as there
+      it is a different and better kind of instrumentation.)
 
     None of the following options are necessary to be used and are rather for
     manual use (which only ever the author of this LTO implementation will use).
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index c04ba396..1deeddd3 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -624,7 +624,7 @@ typedef struct afl_state {
 
   /* plot file saves from last run */
   u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md;
-  u64 plot_prev_qc, plot_prev_uc, plot_prev_uh;
+  u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed;
 
   u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
   double stats_avg_exec;
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index fb4e8537..702c2c08 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -274,7 +274,7 @@ ifeq "$(TEST_MMAP)" "1"
         LDFLAGS += -Wno-deprecated-declarations
 endif
 
-  PROGS      = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
+PROGS      = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so ../SanitizerCoverageLTO.so
 
 # If prerequisites are not given, warn, do not build anything, and exit with code 0
 ifeq "$(LLVMVER)" ""
@@ -363,6 +363,11 @@ ifeq "$(LLVM_LTO)" "1"
 	$(CC) $(CFLAGS) $< -o $@
 endif
 
+../SanitizerCoverageLTO.so: SanitizerCoverageLTO.so.cc
+ifeq "$(LLVM_LTO)" "1"
+	$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
+endif
+
 ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
 ifeq "$(LLVM_LTO)" "1"
 	$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
@@ -371,11 +376,6 @@ ifeq "$(LLVM_LTO)" "1"
 	@$(CLANG_BIN) $(CFLAGS_SAFE) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
 endif
 
-../afl-llvm-lto-instrim.so: afl-llvm-lto-instrim.so.cc afl-llvm-common.o
-ifeq "$(LLVM_LTO)" "1"
-	$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
-endif
-
 # laf
 ../split-switches-pass.so:	split-switches-pass.so.cc afl-llvm-common.o | test_deps
 	$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
@@ -424,7 +424,7 @@ all_done: test_build
 install: all
 	install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
 	if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
-	if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
+	if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../afl-ld-lto ]; then set -e; install -m 755 ../afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
 	if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
@@ -432,6 +432,7 @@ install: all
 	if [ -f ../split-compares-pass.so ]; then set -e; install -m 755 ../split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../split-switches-pass.so ]; then set -e; install -m 755 ../split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../cmplog-instructions-pass.so ]; then set -e; install -m 755 ../cmplog-*-pass.so $${DESTDIR}$(HELPER_PATH); fi
+	if [ -f ../SanitizerCoverageLTO.so ]; then set -e; install -m 755 ../SanitizerCoverageLTO.so $${DESTDIR}$(HELPER_PATH); fi
 	set -e; install -m 644 ../dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
 	set -e; if [ -f ../afl-clang-fast ] ; then ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
 	install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/
diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc
index 6b2aaf23..775e9591 100644
--- a/llvm_mode/LLVMInsTrim.so.cc
+++ b/llvm_mode/LLVMInsTrim.so.cc
@@ -132,10 +132,6 @@ struct InsTrim : public ModulePass {
 
     }
 
-    if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
-        getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
-      function_minimum_size = 2;
-
     unsigned int PrevLocSize = 0;
     char *       ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
     if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
diff --git a/llvm_mode/README.instrim.md b/llvm_mode/README.instrim.md
index 53a518a9..7758091b 100644
--- a/llvm_mode/README.instrim.md
+++ b/llvm_mode/README.instrim.md
@@ -19,15 +19,6 @@ see how often the loop has been rerun.
 This again is a tradeoff for speed for less path information.
 To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
 
-There is an additional optimization option that skips single block
-functions. In 95% of the C targets and (guess) 50% of the C++ targets
-it is good to enable this, as otherwise pointless instrumentation occurs.
-The corner case where we want this instrumentation is when vtable/call table
-is used and the index to that vtable/call table is not set in specific
-basic blocks.
-To enable skipping these (most of the time) unnecessary instrumentations set
-`AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1`
-
 ## Background
 
 The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]
diff --git a/llvm_mode/SanitizerCoverageLTO.so.cc b/llvm_mode/SanitizerCoverageLTO.so.cc
new file mode 100644
index 00000000..1d659096
--- /dev/null
+++ b/llvm_mode/SanitizerCoverageLTO.so.cc
@@ -0,0 +1,1505 @@
+/* SanitizeCoverage.cpp ported to afl++ LTO :-) */
+
+#define AFL_LLVM_PASS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <list>
+#include <string>
+#include <fstream>
+#include <set>
+
+#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/EHPersonalities.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+#include "config.h"
+#include "debug.h"
+#include "afl-llvm-common.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sancov"
+
+static const char *const SanCovTracePCIndirName =
+    "__sanitizer_cov_trace_pc_indir";
+static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc";
+// static const char *const SanCovTracePCGuardName =
+//    "__sanitizer_cov_trace_pc_guard";
+static const char *const SanCovGuardsSectionName = "sancov_guards";
+static const char *const SanCovCountersSectionName = "sancov_cntrs";
+static const char *const SanCovBoolFlagSectionName = "sancov_bools";
+static const char *const SanCovPCsSectionName = "sancov_pcs";
+
+static cl::opt<int> ClCoverageLevel(
+    "lto-coverage-level",
+    cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
+             "3: all blocks and critical edges"),
+    cl::Hidden, cl::init(3));
+
+static cl::opt<bool> ClTracePC("lto-coverage-trace-pc",
+                               cl::desc("Experimental pc tracing"), cl::Hidden,
+                               cl::init(false));
+
+static cl::opt<bool> ClTracePCGuard("lto-coverage-trace-pc-guard",
+                                    cl::desc("pc tracing with a guard"),
+                                    cl::Hidden, cl::init(false));
+
+// If true, we create a global variable that contains PCs of all instrumented
+// BBs, put this global into a named section, and pass this section's bounds
+// to __sanitizer_cov_pcs_init.
+// This way the coverage instrumentation does not need to acquire the PCs
+// at run-time. Works with trace-pc-guard, inline-8bit-counters, and
+// inline-bool-flag.
+static cl::opt<bool> ClCreatePCTable("lto-coverage-pc-table",
+                                     cl::desc("create a static PC table"),
+                                     cl::Hidden, cl::init(false));
+
+static cl::opt<bool> ClInline8bitCounters(
+    "lto-coverage-inline-8bit-counters",
+    cl::desc("increments 8-bit counter for every edge"), cl::Hidden,
+    cl::init(false));
+
+static cl::opt<bool> ClInlineBoolFlag(
+    "lto-coverage-inline-bool-flag",
+    cl::desc("sets a boolean flag for every edge"), cl::Hidden,
+    cl::init(false));
+
+static cl::opt<bool> ClPruneBlocks(
+    "lto-coverage-prune-blocks",
+    cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
+    cl::init(true));
+
+namespace {
+
+SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
+
+  SanitizerCoverageOptions Res;
+  switch (LegacyCoverageLevel) {
+
+    case 0:
+      Res.CoverageType = SanitizerCoverageOptions::SCK_None;
+      break;
+    case 1:
+      Res.CoverageType = SanitizerCoverageOptions::SCK_Function;
+      break;
+    case 2:
+      Res.CoverageType = SanitizerCoverageOptions::SCK_BB;
+      break;
+    case 3:
+      Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
+      break;
+    case 4:
+      Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
+      Res.IndirectCalls = true;
+      break;
+
+  }
+
+  return Res;
+
+}
+
+SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
+
+  // Sets CoverageType and IndirectCalls.
+  SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
+  Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType);
+  Options.IndirectCalls |= CLOpts.IndirectCalls;
+  Options.TracePC |= ClTracePC;
+  Options.TracePCGuard |= ClTracePCGuard;
+  Options.Inline8bitCounters |= ClInline8bitCounters;
+  Options.InlineBoolFlag |= ClInlineBoolFlag;
+  Options.PCTable |= ClCreatePCTable;
+  Options.NoPrune |= !ClPruneBlocks;
+  if (!Options.TracePCGuard && !Options.TracePC &&
+      !Options.Inline8bitCounters && !Options.InlineBoolFlag)
+    Options.TracePCGuard = true;  // TracePCGuard is default.
+  return Options;
+
+}
+
+using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
+using PostDomTreeCallback =
+    function_ref<const PostDominatorTree *(Function &F)>;
+
+class ModuleSanitizerCoverage {
+
+ public:
+  ModuleSanitizerCoverage(
+      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+      : Options(OverrideFromCL(Options)) {
+
+    /* ,
+    const SpecialCaseList *         Allowlist = nullptr,
+    const SpecialCaseList *         Blocklist = nullptr)
+      ,
+      Allowlist(Allowlist),
+      Blocklist(Blocklist) {
+
+    */
+
+  }
+
+  bool instrumentModule(Module &M, DomTreeCallback DTCallback,
+                        PostDomTreeCallback PDTCallback);
+
+ private:
+  void            instrumentFunction(Function &F, DomTreeCallback DTCallback,
+                                     PostDomTreeCallback PDTCallback);
+  void            InjectCoverageForIndirectCalls(Function &              F,
+                                                 ArrayRef<Instruction *> IndirCalls);
+  bool            InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
+                                 bool IsLeafFunc = true);
+  GlobalVariable *CreateFunctionLocalArrayInSection(size_t    NumElements,
+                                                    Function &F, Type *Ty,
+                                                    const char *Section);
+  GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
+  void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks);
+  void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
+                             bool IsLeafFunc = true);
+  std::pair<Value *, Value *> CreateSecStartEnd(Module &M, const char *Section,
+                                                Type *Ty);
+
+  void SetNoSanitizeMetadata(Instruction *I) {
+
+    I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
+                   MDNode::get(*C, None));
+
+  }
+
+  std::string    getSectionName(const std::string &Section) const;
+  std::string    getSectionStart(const std::string &Section) const;
+  std::string    getSectionEnd(const std::string &Section) const;
+  FunctionCallee SanCovTracePCIndir;
+  FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/;
+  Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
+      *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
+  Module *          CurModule;
+  std::string       CurModuleUniqueId;
+  Triple            TargetTriple;
+  LLVMContext *     C;
+  const DataLayout *DL;
+
+  GlobalVariable *FunctionGuardArray;        // for trace-pc-guard.
+  GlobalVariable *Function8bitCounterArray;  // for inline-8bit-counters.
+  GlobalVariable *FunctionBoolArray;         // for inline-bool-flag.
+  GlobalVariable *FunctionPCsArray;          // for pc-table.
+  SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;
+  SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
+
+  SanitizerCoverageOptions Options;
+
+  // afl++ START
+  // const SpecialCaseList *          Allowlist;
+  // const SpecialCaseList *          Blocklist;
+  uint32_t                         autodictionary = 1;
+  uint32_t                         inst = 0;
+  uint32_t                         afl_global_id = 0;
+  uint64_t                         map_addr = 0;
+  char *                           skip_nozero = NULL;
+  std::vector<BasicBlock *>        BlockList;
+  DenseMap<Value *, std::string *> valueMap;
+  std::vector<std::string>         dictionary;
+  IntegerType *                    Int8Tyi = NULL;
+  IntegerType *                    Int32Tyi = NULL;
+  IntegerType *                    Int64Tyi = NULL;
+  ConstantInt *                    Zero = NULL;
+  ConstantInt *                    One = NULL;
+  LLVMContext *                    Ct = NULL;
+  Module *                         Mo = NULL;
+  GlobalVariable *                 AFLMapPtr = NULL;
+  Value *                          MapPtrFixed = NULL;
+  FILE *                           documentFile = NULL;
+  // afl++ END
+
+};
+
+class ModuleSanitizerCoverageLegacyPass : public ModulePass {
+
+ public:
+  static char ID;
+  StringRef   getPassName() const override {
+
+    return "sancov";
+
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+
+    AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<PostDominatorTreeWrapperPass>();
+
+  }
+
+  ModuleSanitizerCoverageLegacyPass(
+      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+      : ModulePass(ID), Options(Options) {
+
+    /* ,
+          const std::vector<std::string> &AllowlistFiles =
+              std::vector<std::string>(),
+          const std::vector<std::string> &BlocklistFiles =
+              std::vector<std::string>())
+        if (AllowlistFiles.size() > 0)
+          Allowlist = SpecialCaseList::createOrDie(AllowlistFiles,
+                                                   *vfs::getRealFileSystem());
+        if (BlocklistFiles.size() > 0)
+          Blocklist = SpecialCaseList::createOrDie(BlocklistFiles,
+                                                   *vfs::getRealFileSystem());
+    */
+    initializeModuleSanitizerCoverageLegacyPassPass(
+        *PassRegistry::getPassRegistry());
+
+  }
+
+  bool runOnModule(Module &M) override {
+
+    ModuleSanitizerCoverage ModuleSancov(Options);
+    // , Allowlist.get(), Blocklist.get());
+    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);
+
+  }
+
+ private:
+  SanitizerCoverageOptions Options;
+
+  // std::unique_ptr<SpecialCaseList> Allowlist;
+  // std::unique_ptr<SpecialCaseList> Blocklist;
+
+};
+
+}  // namespace
+
+PreservedAnalyses ModuleSanitizerCoveragePass::run(Module &               M,
+                                                   ModuleAnalysisManager &MAM) {
+
+  ModuleSanitizerCoverage ModuleSancov(Options);
+  // Allowlist.get(), Blocklist.get());
+  auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+  auto  DTCallback = [&FAM](Function &F) -> const DominatorTree * {
+
+    return &FAM.getResult<DominatorTreeAnalysis>(F);
+
+  };
+
+  auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
+
+    return &FAM.getResult<PostDominatorTreeAnalysis>(F);
+
+  };
+
+  if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
+    return PreservedAnalyses::none();
+
+  return PreservedAnalyses::all();
+
+}
+
+std::pair<Value *, Value *> ModuleSanitizerCoverage::CreateSecStartEnd(
+    Module &M, const char *Section, Type *Ty) {
+
+  GlobalVariable *SecStart =
+      new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, nullptr,
+                         getSectionStart(Section));
+  SecStart->setVisibility(GlobalValue::HiddenVisibility);
+  GlobalVariable *SecEnd =
+      new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, nullptr,
+                         getSectionEnd(Section));
+  SecEnd->setVisibility(GlobalValue::HiddenVisibility);
+  IRBuilder<> IRB(M.getContext());
+  Value *     SecEndPtr = IRB.CreatePointerCast(SecEnd, Ty);
+  if (!TargetTriple.isOSBinFormatCOFF())
+    return std::make_pair(IRB.CreatePointerCast(SecStart, Ty), SecEndPtr);
+
+  // Account for the fact that on windows-msvc __start_* symbols actually
+  // point to a uint64_t before the start of the array.
+  auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
+  auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
+                           ConstantInt::get(IntptrTy, sizeof(uint64_t)));
+  return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEndPtr);
+
+}
+
+bool ModuleSanitizerCoverage::instrumentModule(
+    Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+  if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
+  /*
+    if (Allowlist &&
+        !Allowlist->inSection("coverage", "src", M.getSourceFileName()))
+      return false;
+    if (Blocklist &&
+        Blocklist->inSection("coverage", "src", M.getSourceFileName()))
+      return false;
+  */
+  BlockList.clear();
+  valueMap.clear();
+  dictionary.clear();
+  C = &(M.getContext());
+  DL = &M.getDataLayout();
+  CurModule = &M;
+  CurModuleUniqueId = getUniqueModuleId(CurModule);
+  TargetTriple = Triple(M.getTargetTriple());
+  FunctionGuardArray = nullptr;
+  Function8bitCounterArray = nullptr;
+  FunctionBoolArray = nullptr;
+  FunctionPCsArray = nullptr;
+  IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
+  IntptrPtrTy = PointerType::getUnqual(IntptrTy);
+  Type *      VoidTy = Type::getVoidTy(*C);
+  IRBuilder<> IRB(*C);
+  Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
+  Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
+  Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty());
+  Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty());
+  Int64Ty = IRB.getInt64Ty();
+  Int32Ty = IRB.getInt32Ty();
+  Int16Ty = IRB.getInt16Ty();
+  Int8Ty = IRB.getInt8Ty();
+  Int1Ty = IRB.getInt1Ty();
+
+  /* afl++ START */
+  char *       ptr;
+  LLVMContext &Ctx = M.getContext();
+  Ct = &Ctx;
+  Int8Tyi = IntegerType::getInt8Ty(Ctx);
+  Int32Tyi = IntegerType::getInt32Ty(Ctx);
+  Int64Tyi = IntegerType::getInt64Ty(Ctx);
+
+  /* Show a banner */
+  setvbuf(stdout, NULL, _IONBF, 0);
+  if (getenv("AFL_DEBUG")) debug = 1;
+
+  if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
+
+    SAYF(cCYA "afl-llvm-lto" VERSION cRST
+              " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+  } else
+
+    be_quiet = 1;
+
+  skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+
+  if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
+    if ((afl_global_id = atoi(ptr)) < 0)
+      FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is negative\n", ptr);
+
+  if (getenv("AFL_LLVM_CMPLOG")) autodictionary = 0;
+
+  if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
+
+    if ((documentFile = fopen(ptr, "a")) == NULL)
+      WARNF("Cannot access document file %s", ptr);
+
+  }
+
+  // we make this the default as the fixed map has problems with
+  // defered forkserver, early constructors, ifuncs and maybe more
+  /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
+  map_addr = 0;
+
+  if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
+
+    uint64_t val;
+    if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
+
+      map_addr = 0;
+
+    } else if (getenv("AFL_LLVM_MAP_DYNAMIC")) {
+
+      FATAL(
+          "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
+
+    } else if (strncmp(ptr, "0x", 2) != 0) {
+
+      map_addr = 0x10000;  // the default
+
+    } else {
+
+      val = strtoull(ptr, NULL, 16);
+      if (val < 0x100 || val > 0xffffffff00000000) {
+
+        FATAL(
+            "AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
+            "0xffffffff00000000");
+
+      }
+
+      map_addr = val;
+
+    }
+
+  }
+
+  /* Get/set the globals for the SHM region. */
+
+  if (!map_addr) {
+
+    AFLMapPtr =
+        new GlobalVariable(M, PointerType::get(Int8Tyi, 0), false,
+                           GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
+
+  } else {
+
+    ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
+    MapPtrFixed =
+        ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Tyi));
+
+  }
+
+  Zero = ConstantInt::get(Int8Tyi, 0);
+  One = ConstantInt::get(Int8Tyi, 1);
+
+  scanForDangerousFunctions(&M);
+  Mo = &M;
+
+  if (autodictionary) {
+
+    for (auto &F : M) {
+
+      for (auto &BB : F) {
+
+        for (auto &IN : BB) {
+
+          CallInst *callInst = nullptr;
+
+          if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+            bool   isStrcmp = true;
+            bool   isMemcmp = true;
+            bool   isStrncmp = true;
+            bool   isStrcasecmp = true;
+            bool   isStrncasecmp = true;
+            bool   isIntMemcpy = true;
+            bool   addedNull = false;
+            size_t optLen = 0;
+
+            Function *Callee = callInst->getCalledFunction();
+            if (!Callee) continue;
+            if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+            std::string FuncName = Callee->getName().str();
+            isStrcmp &= !FuncName.compare("strcmp");
+            isMemcmp &= !FuncName.compare("memcmp");
+            isStrncmp &= !FuncName.compare("strncmp");
+            isStrcasecmp &= !FuncName.compare("strcasecmp");
+            isStrncasecmp &= !FuncName.compare("strncasecmp");
+            isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
+
+            /* we do something different here, putting this BB and the
+               successors in a block map */
+            if (!FuncName.compare("__afl_persistent_loop")) {
+
+              BlockList.push_back(&BB);
+              for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB);
+                   SI != SE; ++SI) {
+
+                BasicBlock *succ = *SI;
+                BlockList.push_back(succ);
+
+              }
+
+            }
+
+            if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+                !isStrncasecmp && !isIntMemcpy)
+              continue;
+
+            /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+             * prototype */
+            FunctionType *FT = Callee->getFunctionType();
+
+            isStrcmp &= FT->getNumParams() == 2 &&
+                        FT->getReturnType()->isIntegerTy(32) &&
+                        FT->getParamType(0) == FT->getParamType(1) &&
+                        FT->getParamType(0) ==
+                            IntegerType::getInt8PtrTy(M.getContext());
+            isStrcasecmp &= FT->getNumParams() == 2 &&
+                            FT->getReturnType()->isIntegerTy(32) &&
+                            FT->getParamType(0) == FT->getParamType(1) &&
+                            FT->getParamType(0) ==
+                                IntegerType::getInt8PtrTy(M.getContext());
+            isMemcmp &= FT->getNumParams() == 3 &&
+                        FT->getReturnType()->isIntegerTy(32) &&
+                        FT->getParamType(0)->isPointerTy() &&
+                        FT->getParamType(1)->isPointerTy() &&
+                        FT->getParamType(2)->isIntegerTy();
+            isStrncmp &= FT->getNumParams() == 3 &&
+                         FT->getReturnType()->isIntegerTy(32) &&
+                         FT->getParamType(0) == FT->getParamType(1) &&
+                         FT->getParamType(0) ==
+                             IntegerType::getInt8PtrTy(M.getContext()) &&
+                         FT->getParamType(2)->isIntegerTy();
+            isStrncasecmp &= FT->getNumParams() == 3 &&
+                             FT->getReturnType()->isIntegerTy(32) &&
+                             FT->getParamType(0) == FT->getParamType(1) &&
+                             FT->getParamType(0) ==
+                                 IntegerType::getInt8PtrTy(M.getContext()) &&
+                             FT->getParamType(2)->isIntegerTy();
+
+            if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+                !isStrncasecmp && !isIntMemcpy)
+              continue;
+
+            /* is a str{n,}{case,}cmp/memcmp, check if we have
+             * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+             * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+             * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+            Value *Str1P = callInst->getArgOperand(0),
+                  *Str2P = callInst->getArgOperand(1);
+            std::string Str1, Str2;
+            StringRef   TmpStr;
+            bool        HasStr1 = getConstantStringInfo(Str1P, TmpStr);
+            if (TmpStr.empty())
+              HasStr1 = false;
+            else
+              Str1 = TmpStr.str();
+            bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
+            if (TmpStr.empty())
+              HasStr2 = false;
+            else
+              Str2 = TmpStr.str();
+
+            if (debug)
+              fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
+                      FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
+                      Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
+                      Str2P->getName().str().c_str(), Str2.c_str(),
+                      HasStr2 == true ? "true" : "false");
+
+            // we handle the 2nd parameter first because of llvm memcpy
+            if (!HasStr2) {
+
+              auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+                if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                  if (Var->hasInitializer()) {
+
+                    if (auto *Array = dyn_cast<ConstantDataArray>(
+                            Var->getInitializer())) {
+
+                      HasStr2 = true;
+                      Str2 = Array->getAsString().str();
+
+                    }
+
+                  }
+
+                }
+
+              }
+
+            }
+
+            // for the internal memcpy routine we only care for the second
+            // parameter and are not reporting anything.
+            if (isIntMemcpy == true) {
+
+              if (HasStr2 == true) {
+
+                Value *      op2 = callInst->getArgOperand(2);
+                ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+                if (ilen) {
+
+                  uint64_t literalLength = Str2.size();
+                  uint64_t optLength = ilen->getZExtValue();
+                  if (literalLength + 1 == optLength) {
+
+                    Str2.append("\0", 1);  // add null byte
+                    addedNull = true;
+
+                  }
+
+                }
+
+                valueMap[Str1P] = new std::string(Str2);
+
+                if (debug)
+                  fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
+                continue;
+
+              }
+
+              continue;
+
+            }
+
+            // Neither a literal nor a global variable?
+            // maybe it is a local variable that we saved
+            if (!HasStr2) {
+
+              std::string *strng = valueMap[Str2P];
+              if (strng && !strng->empty()) {
+
+                Str2 = *strng;
+                HasStr2 = true;
+                if (debug)
+                  fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
+                          Str2P);
+
+              }
+
+            }
+
+            if (!HasStr1) {
+
+              auto Ptr = dyn_cast<ConstantExpr>(Str1P);
+
+              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+                if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                  if (Var->hasInitializer()) {
+
+                    if (auto *Array = dyn_cast<ConstantDataArray>(
+                            Var->getInitializer())) {
+
+                      HasStr1 = true;
+                      Str1 = Array->getAsString().str();
+
+                    }
+
+                  }
+
+                }
+
+              }
+
+            }
+
+            // Neither a literal nor a global variable?
+            // maybe it is a local variable that we saved
+            if (!HasStr1) {
+
+              std::string *strng = valueMap[Str1P];
+              if (strng && !strng->empty()) {
+
+                Str1 = *strng;
+                HasStr1 = true;
+                if (debug)
+                  fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
+                          Str1P);
+
+              }
+
+            }
+
+            /* handle cases of one string is const, one string is variable */
+            if (!(HasStr1 ^ HasStr2)) continue;
+
+            std::string thestring;
+
+            if (HasStr1)
+              thestring = Str1;
+            else
+              thestring = Str2;
+
+            optLen = thestring.length();
+
+            if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+              Value *      op2 = callInst->getArgOperand(2);
+              ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+              if (ilen) {
+
+                uint64_t literalLength = optLen;
+                optLen = ilen->getZExtValue();
+                if (literalLength + 1 == optLen) {  // add null byte
+                  thestring.append("\0", 1);
+                  addedNull = true;
+
+                }
+
+              }
+
+            }
+
+            // add null byte if this is a string compare function and a null
+            // was not already added
+            if (!isMemcmp) {
+
+              if (addedNull == false) {
+
+                thestring.append("\0", 1);  // add null byte
+                optLen++;
+
+              }
+
+              // ensure we do not have garbage
+              size_t offset = thestring.find('\0', 0);
+              if (offset + 1 < optLen) optLen = offset + 1;
+              thestring = thestring.substr(0, optLen);
+
+            }
+
+            if (!be_quiet) {
+
+              std::string outstring;
+              fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
+                      thestring.length());
+              for (uint8_t i = 0; i < thestring.length(); i++) {
+
+                uint8_t c = thestring[i];
+                if (c <= 32 || c >= 127)
+                  fprintf(stderr, "\\x%02x", c);
+                else
+                  fprintf(stderr, "%c", c);
+
+              }
+
+              fprintf(stderr, "\"\n");
+
+            }
+
+            // we take the longer string, even if the compare was to a
+            // shorter part. Note that depending on the optimizer of the
+            // compiler this can be wrong, but it is more likely that this
+            // is helping the fuzzer
+            if (optLen != thestring.length()) optLen = thestring.length();
+            if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
+            if (optLen < MIN_AUTO_EXTRA)  // too short? skip
+              continue;
+
+            dictionary.push_back(thestring.substr(0, optLen));
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+  // afl++ END
+
+  SanCovTracePCIndir =
+      M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
+  // Make sure smaller parameters are zero-extended to i64 as required by the
+  // x86_64 ABI.
+  AttributeList SanCovTraceCmpZeroExtAL;
+  if (TargetTriple.getArch() == Triple::x86_64) {
+
+    SanCovTraceCmpZeroExtAL =
+        SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt);
+    SanCovTraceCmpZeroExtAL =
+        SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt);
+
+  }
+
+  SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
+
+  // SanCovTracePCGuard =
+  //    M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
+
+  for (auto &F : M)
+    instrumentFunction(F, DTCallback, PDTCallback);
+
+  // afl++ START
+  if (documentFile) {
+
+    fclose(documentFile);
+    documentFile = NULL;
+
+  }
+
+  if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
+
+    // yes we could create our own function, insert it into ctors ...
+    // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
+
+    Function *f = M.getFunction("__afl_auto_init_globals");
+
+    if (!f) {
+
+      fprintf(stderr,
+              "Error: init function could not be found (this should not "
+              "happen)\n");
+      exit(-1);
+
+    }
+
+    BasicBlock *bb = &f->getEntryBlock();
+    if (!bb) {
+
+      fprintf(stderr,
+              "Error: init function does not have an EntryBlock (this should "
+              "not happen)\n");
+      exit(-1);
+
+    }
+
+    BasicBlock::iterator IP = bb->getFirstInsertionPt();
+    IRBuilder<>          IRB(&(*IP));
+
+    if (map_addr) {
+
+      GlobalVariable *AFLMapAddrFixed = new GlobalVariable(
+          M, Int64Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr");
+      ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
+      StoreInst *  StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
+      StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"),
+                                MDNode::get(Ctx, None));
+
+    }
+
+    if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
+
+      uint32_t write_loc = afl_global_id;
+
+      if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
+
+      GlobalVariable *AFLFinalLoc =
+          new GlobalVariable(M, Int32Tyi, true, GlobalValue::ExternalLinkage, 0,
+                             "__afl_final_loc");
+      ConstantInt *const_loc = ConstantInt::get(Int32Tyi, write_loc);
+      StoreInst *  StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+      StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
+                                 MDNode::get(Ctx, None));
+
+    }
+
+    if (dictionary.size()) {
+
+      size_t memlen = 0, count = 0, offset = 0;
+      char * ptr;
+
+      for (auto token : dictionary) {
+
+        memlen += token.length();
+        count++;
+
+      }
+
+      if (!be_quiet)
+        printf("AUTODICTIONARY: %lu string%s found\n", count,
+               count == 1 ? "" : "s");
+
+      if (count) {
+
+        if ((ptr = (char *)malloc(memlen + count)) == NULL) {
+
+          fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
+                  memlen + count);
+          exit(-1);
+
+        }
+
+        count = 0;
+
+        for (auto token : dictionary) {
+
+          if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
+
+            ptr[offset++] = (uint8_t)token.length();
+            memcpy(ptr + offset, token.c_str(), token.length());
+            offset += token.length();
+            count++;
+
+          }
+
+        }
+
+        GlobalVariable *AFLDictionaryLen =
+            new GlobalVariable(M, Int32Tyi, false, GlobalValue::ExternalLinkage,
+                               0, "__afl_dictionary_len");
+        ConstantInt *const_len = ConstantInt::get(Int32Tyi, offset);
+        StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
+        StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
+                                  MDNode::get(Ctx, None));
+
+        ArrayType *ArrayTy = ArrayType::get(IntegerType::get(Ctx, 8), offset);
+        GlobalVariable *AFLInternalDictionary = new GlobalVariable(
+            M, ArrayTy, true, GlobalValue::ExternalLinkage,
+            ConstantDataArray::get(Ctx,
+                                   *(new ArrayRef<char>((char *)ptr, offset))),
+            "__afl_internal_dictionary");
+        AFLInternalDictionary->setInitializer(ConstantDataArray::get(
+            Ctx, *(new ArrayRef<char>((char *)ptr, offset))));
+        AFLInternalDictionary->setConstant(true);
+
+        GlobalVariable *AFLDictionary = new GlobalVariable(
+            M, PointerType::get(Int8Tyi, 0), false,
+            GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
+
+        Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
+        Value *AFLDictPtr =
+            IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Tyi, 0));
+        StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
+        StoreDict->setMetadata(M.getMDKindID("nosanitize"),
+                               MDNode::get(Ctx, None));
+
+      }
+
+    }
+
+  }
+
+  /* Say something nice. */
+
+  if (!be_quiet) {
+
+    if (!inst)
+      WARNF("No instrumentation targets found.");
+    else {
+
+      char modeline[100];
+      snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
+               getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
+               getenv("AFL_USE_ASAN") ? ", ASAN" : "",
+               getenv("AFL_USE_MSAN") ? ", MSAN" : "",
+               getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
+               getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
+      OKF("Instrumented %u locations with no collisions (on average %llu "
+          "collisions would be in afl-gcc/afl-clang-fast) (%s mode).",
+          inst, calculateCollisions(inst), modeline);
+
+    }
+
+  }
+
+  // afl++ END
+
+  // We don't reference these arrays directly in any of our runtime functions,
+  // so we need to prevent them from being dead stripped.
+  if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
+  appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
+  return true;
+
+}
+
+// True if block has successors and it dominates all of them.
+static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
+
+  if (succ_begin(BB) == succ_end(BB)) return false;
+
+  for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
+
+    if (!DT->dominates(BB, SUCC)) return false;
+
+  }
+
+  return true;
+
+}
+
+// True if block has predecessors and it postdominates all of them.
+static bool isFullPostDominator(const BasicBlock *       BB,
+                                const PostDominatorTree *PDT) {
+
+  if (pred_begin(BB) == pred_end(BB)) return false;
+
+  for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
+
+    if (!PDT->dominates(BB, PRED)) return false;
+
+  }
+
+  return true;
+
+}
+
+static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
+                                  const DominatorTree *           DT,
+                                  const PostDominatorTree *       PDT,
+                                  const SanitizerCoverageOptions &Options) {
+
+  // Don't insert coverage for blocks containing nothing but unreachable: we
+  // will never call __sanitizer_cov() for them, so counting them in
+  // NumberOfInstrumentedBlocks() might complicate calculation of code coverage
+  // percentage. Also, unreachable instructions frequently have no debug
+  // locations.
+  if (isa<UnreachableInst>(BB->getFirstNonPHIOrDbgOrLifetime())) return false;
+
+  // Don't insert coverage into blocks without a valid insertion point
+  // (catchswitch blocks).
+  if (BB->getFirstInsertionPt() == BB->end()) return false;
+
+  // afl++ START
+  if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
+    return false;
+  // afl++ END
+
+  if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
+
+  if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
+      &F.getEntryBlock() != BB)
+    return false;
+
+  // Do not instrument full dominators, or full post-dominators with multiple
+  // predecessors.
+  return !isFullDominator(BB, DT) &&
+         !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor());
+
+}
+
+void ModuleSanitizerCoverage::instrumentFunction(
+    Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
+
+  if (F.empty()) return;
+  if (F.getName().find(".module_ctor") != std::string::npos)
+    return;  // Should not instrument sanitizer init functions.
+  if (F.getName().startswith("__sanitizer_"))
+    return;  // Don't instrument __sanitizer_* callbacks.
+  // Don't touch available_externally functions, their actual body is elewhere.
+  if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return;
+  // Don't instrument MSVC CRT configuration helpers. They may run before normal
+  // initialization.
+  if (F.getName() == "__local_stdio_printf_options" ||
+      F.getName() == "__local_stdio_scanf_options")
+    return;
+  if (isa<UnreachableInst>(F.getEntryBlock().getTerminator())) return;
+  // Don't instrument functions using SEH for now. Splitting basic blocks like
+  // we do for coverage breaks WinEHPrepare.
+  // FIXME: Remove this when SEH no longer uses landingpad pattern matching.
+  if (F.hasPersonalityFn() &&
+      isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
+    return;
+  // if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName()))
+  //  return;
+  // if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
+  // return;
+
+  // afl++ START
+  if (!F.size()) return;
+  if (isIgnoreFunction(&F)) return;
+  // afl++ END
+
+  if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
+    SplitAllCriticalEdges(
+        F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
+  SmallVector<Instruction *, 8> IndirCalls;
+  SmallVector<BasicBlock *, 16> BlocksToInstrument;
+
+  const DominatorTree *    DT = DTCallback(F);
+  const PostDominatorTree *PDT = PDTCallback(F);
+  bool                     IsLeafFunc = true;
+
+  for (auto &BB : F) {
+
+    if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
+      BlocksToInstrument.push_back(&BB);
+    for (auto &Inst : BB) {
+
+      if (Options.IndirectCalls) {
+
+        CallBase *CB = dyn_cast<CallBase>(&Inst);
+        if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
+
+      }
+
+    }
+
+  }
+
+  InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
+  InjectCoverageForIndirectCalls(F, IndirCalls);
+
+}
+
+GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection(
+    size_t NumElements, Function &F, Type *Ty, const char *Section) {
+
+  ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
+  auto       Array = new GlobalVariable(
+      *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
+      Constant::getNullValue(ArrayTy), "__sancov_gen_");
+
+  if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
+    if (auto Comdat =
+            GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
+      Array->setComdat(Comdat);
+  Array->setSection(getSectionName(Section));
+  Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
+  GlobalsToAppendToUsed.push_back(Array);
+  GlobalsToAppendToCompilerUsed.push_back(Array);
+  MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
+  Array->addMetadata(LLVMContext::MD_associated, *MD);
+
+  return Array;
+
+}
+
+GlobalVariable *ModuleSanitizerCoverage::CreatePCArray(
+    Function &F, ArrayRef<BasicBlock *> AllBlocks) {
+
+  size_t N = AllBlocks.size();
+  assert(N);
+  SmallVector<Constant *, 32> PCs;
+  IRBuilder<>                 IRB(&*F.getEntryBlock().getFirstInsertionPt());
+  for (size_t i = 0; i < N; i++) {
+
+    if (&F.getEntryBlock() == AllBlocks[i]) {
+
+      PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
+      PCs.push_back((Constant *)IRB.CreateIntToPtr(
+          ConstantInt::get(IntptrTy, 1), IntptrPtrTy));
+
+    } else {
+
+      PCs.push_back((Constant *)IRB.CreatePointerCast(
+          BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
+      PCs.push_back((Constant *)IRB.CreateIntToPtr(
+          ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
+
+    }
+
+  }
+
+  auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy,
+                                                    SanCovPCsSectionName);
+  PCArray->setInitializer(
+      ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs));
+  PCArray->setConstant(true);
+
+  return PCArray;
+
+}
+
+void ModuleSanitizerCoverage::CreateFunctionLocalArrays(
+    Function &F, ArrayRef<BasicBlock *> AllBlocks) {
+
+  if (Options.TracePCGuard)
+    FunctionGuardArray = CreateFunctionLocalArrayInSection(
+        AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName);
+  if (Options.Inline8bitCounters)
+    Function8bitCounterArray = CreateFunctionLocalArrayInSection(
+        AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
+  if (Options.InlineBoolFlag)
+    FunctionBoolArray = CreateFunctionLocalArrayInSection(
+        AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
+  if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
+
+}
+
+bool ModuleSanitizerCoverage::InjectCoverage(Function &             F,
+                                             ArrayRef<BasicBlock *> AllBlocks,
+                                             bool IsLeafFunc) {
+
+  if (AllBlocks.empty()) return false;
+  CreateFunctionLocalArrays(F, AllBlocks);
+  for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
+
+    // afl++ START
+    if (BlockList.size()) {
+
+      int skip = 0;
+      for (uint32_t k = 0; k < BlockList.size(); k++) {
+
+        if (AllBlocks[i] == BlockList[k]) {
+
+          if (debug)
+            fprintf(stderr,
+                    "DEBUG: Function %s skipping BB with/after __afl_loop\n",
+                    F.getName().str().c_str());
+          skip = 1;
+
+        }
+
+      }
+
+      if (skip) continue;
+
+    }
+
+    // afl++ END
+
+    InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
+
+  }
+
+  return true;
+
+}
+
+// On every indirect call we call a run-time function
+// __sanitizer_cov_indir_call* with two parameters:
+//   - callee address,
+//   - global cache array that contains CacheSize pointers (zero-initialized).
+//     The cache is used to speed up recording the caller-callee pairs.
+// The address of the caller is passed implicitly via caller PC.
+// CacheSize is encoded in the name of the run-time function.
+void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls(
+    Function &F, ArrayRef<Instruction *> IndirCalls) {
+
+  if (IndirCalls.empty()) return;
+  assert(Options.TracePC || Options.TracePCGuard ||
+         Options.Inline8bitCounters || Options.InlineBoolFlag);
+  for (auto I : IndirCalls) {
+
+    IRBuilder<> IRB(I);
+    CallBase &  CB = cast<CallBase>(*I);
+    Value *     Callee = CB.getCalledOperand();
+    if (isa<InlineAsm>(Callee)) continue;
+    IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
+
+  }
+
+}
+
+void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
+                                                    size_t Idx,
+                                                    bool   IsLeafFunc) {
+
+  BasicBlock::iterator IP = BB.getFirstInsertionPt();
+  bool                 IsEntryBB = &BB == &F.getEntryBlock();
+  DebugLoc             EntryLoc;
+  if (IsEntryBB) {
+
+    if (auto SP = F.getSubprogram())
+      EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP);
+    // Keep static allocas and llvm.localescape calls in the entry block.  Even
+    // if we aren't splitting the block, it's nice for allocas to be before
+    // calls.
+    IP = PrepareToSplitEntryBlock(BB, IP);
+
+  } else {
+
+    EntryLoc = IP->getDebugLoc();
+
+  }
+
+  IRBuilder<> IRB(&*IP);
+  IRB.SetCurrentDebugLocation(EntryLoc);
+  if (Options.TracePC) {
+
+    IRB.CreateCall(SanCovTracePC)
+#if LLVM_VERSION_MAJOR < 12
+        ->cannotMerge();  // gets the PC using GET_CALLER_PC.
+#else
+        ->setCannotMerge();  // gets the PC using GET_CALLER_PC.
+#endif
+
+  }
+
+  if (Options.TracePCGuard) {
+
+    // afl++ START
+    ++afl_global_id;
+
+    if (documentFile) {
+
+      unsigned long long int moduleID =
+          (((unsigned long long int)(rand() & 0xffffffff)) << 32) | getpid();
+      fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n", moduleID,
+              F.getName().str().c_str(), afl_global_id);
+
+    }
+
+    /* Set the ID of the inserted basic block */
+
+    ConstantInt *CurLoc = ConstantInt::get(Int32Tyi, afl_global_id);
+
+    /* Load SHM pointer */
+
+    Value *MapPtrIdx;
+
+    if (map_addr) {
+
+      MapPtrIdx = IRB.CreateGEP(MapPtrFixed, CurLoc);
+
+    } else {
+
+      LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
+      MapPtr->setMetadata(Mo->getMDKindID("nosanitize"),
+                          MDNode::get(*Ct, None));
+      MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
+
+    }
+
+    /* Update bitmap */
+
+    LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+    Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None));
+
+    Value *Incr = IRB.CreateAdd(Counter, One);
+
+    if (skip_nozero == NULL) {
+
+      auto cf = IRB.CreateICmpEQ(Incr, Zero);
+      auto carry = IRB.CreateZExt(cf, Int8Tyi);
+      Incr = IRB.CreateAdd(Incr, carry);
+
+    }
+
+    IRB.CreateStore(Incr, MapPtrIdx)
+        ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None));
+
+    // done :)
+
+    inst++;
+    // afl++ END
+
+    /*
+    XXXXXXXXXXXXXXXXXXX
+
+        auto GuardPtr = IRB.CreateIntToPtr(
+            IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+                          ConstantInt::get(IntptrTy, Idx * 4)),
+            Int32PtrTy);
+
+        IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
+    */
+
+  }
+
+  if (Options.Inline8bitCounters) {
+
+    auto CounterPtr = IRB.CreateGEP(
+        Function8bitCounterArray->getValueType(), Function8bitCounterArray,
+        {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+    auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
+    auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
+    auto Store = IRB.CreateStore(Inc, CounterPtr);
+    SetNoSanitizeMetadata(Load);
+    SetNoSanitizeMetadata(Store);
+
+  }
+
+  if (Options.InlineBoolFlag) {
+
+    auto FlagPtr = IRB.CreateGEP(
+        FunctionBoolArray->getValueType(), FunctionBoolArray,
+        {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
+    auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
+    auto ThenTerm =
+        SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
+    IRBuilder<> ThenIRB(ThenTerm);
+    auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
+    SetNoSanitizeMetadata(Load);
+    SetNoSanitizeMetadata(Store);
+
+  }
+
+}
+
+std::string ModuleSanitizerCoverage::getSectionName(
+    const std::string &Section) const {
+
+  if (TargetTriple.isOSBinFormatCOFF()) {
+
+    if (Section == SanCovCountersSectionName) return ".SCOV$CM";
+    if (Section == SanCovBoolFlagSectionName) return ".SCOV$BM";
+    if (Section == SanCovPCsSectionName) return ".SCOVP$M";
+    return ".SCOV$GM";  // For SanCovGuardsSectionName.
+
+  }
+
+  if (TargetTriple.isOSBinFormatMachO()) return "__DATA,__" + Section;
+  return "__" + Section;
+
+}
+
+std::string ModuleSanitizerCoverage::getSectionStart(
+    const std::string &Section) const {
+
+  if (TargetTriple.isOSBinFormatMachO())
+    return "\1section$start$__DATA$__" + Section;
+  return "__start___" + Section;
+
+}
+
+std::string ModuleSanitizerCoverage::getSectionEnd(
+    const std::string &Section) const {
+
+  if (TargetTriple.isOSBinFormatMachO())
+    return "\1section$end$__DATA$__" + Section;
+  return "__stop___" + Section;
+
+}
+
+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);
+
+}
+
+static void registerLTOPass(const PassManagerBuilder &,
+                            legacy::PassManagerBase &PM) {
+
+  auto p = new ModuleSanitizerCoverageLegacyPass();
+  PM.add(p);
+
+}
+
+static RegisterStandardPasses RegisterCompTransPass(
+    PassManagerBuilder::EP_OptimizerLast, registerLTOPass);
+
+static RegisterStandardPasses RegisterCompTransPass0(
+    PassManagerBuilder::EP_EnabledOnOptLevel0, registerLTOPass);
+
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCompTransPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerLTOPass);
+#endif
+
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 72b81922..d1fa548c 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -347,11 +347,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   if (lto_mode) {
 
-    if (cmplog_mode)
-      unsetenv("AFL_LLVM_LTO_AUTODICTIONARY");
-    else
-      setenv("AFL_LLVM_LTO_AUTODICTIONARY", "1", 1);
-
 #if defined(AFL_CLANG_LDPATH) && LLVM_VERSION_MAJOR >= 12
     u8 *ld_ptr = strrchr(AFL_REAL_LD, '/');
     if (!ld_ptr) ld_ptr = "ld.lld";
@@ -363,16 +358,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
 
-    /*
-        The current LTO instrim mode is not good, so we disable it
-        if (instrument_mode == INSTRUMENT_CFG)
-          cc_params[cc_par_cnt++] =
-              alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so",
-       obj_path); else
-    */
+    if (instrument_mode == INSTRUMENT_CFG)
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
+    else
 
-    cc_params[cc_par_cnt++] = alloc_printf(
-        "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
+      cc_params[cc_par_cnt++] = alloc_printf(
+          "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
     cc_params[cc_par_cnt++] = lto_flag;
 
   } else {
@@ -756,7 +748,13 @@ int main(int argc, char **argv, char **envp) {
       if (strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
           strncasecmp(ptr, "classic", strlen("classic")) == 0) {
 
-        if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
+        if (instrument_mode == INSTRUMENT_LTO) {
+
+          instrument_mode = INSTRUMENT_CLASSIC;
+          lto_mode = 1;
+
+        } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
+
           instrument_mode = INSTRUMENT_AFL;
         else
           FATAL("main instrumentation mode already set with %s",
@@ -848,11 +846,18 @@ int main(int argc, char **argv, char **envp) {
       callname = "afl-clang-lto";
       if (!instrument_mode) {
 
-        instrument_mode = INSTRUMENT_LTO;
+        instrument_mode = INSTRUMENT_CFG;
         ptr = instrument_mode_string[instrument_mode];
 
       }
 
+    } else if (instrument_mode == INSTRUMENT_LTO ||
+
+               instrument_mode == INSTRUMENT_CLASSIC) {
+
+      lto_mode = 1;
+      callname = "afl-clang-lto";
+
     } else {
 
       if (!be_quiet)
@@ -992,9 +997,8 @@ int main(int argc, char **argv, char **envp) {
         "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
         "function calls\n"
         "AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
-        "AFL_LLVM_INSTRUMENT_FILE: enable the instrument file listing "
-        "(selective "
-        "instrumentation)\n"
+        "AFL_LLVM_INSTRUMENT_ALLOW/AFL_LLVM_INSTRUMENT_DENY: enable instrument"
+        "allow/deny listing (selective instrumentation)\n"
         "AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
         "AFL_PATH: path to instrumenting pass and runtime "
         "(afl-llvm-rt.*o)\n"
diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc
deleted file mode 100644
index 98e9ff9a..00000000
--- a/llvm_mode/afl-llvm-lto-instrim.so.cc
+++ /dev/null
@@ -1,951 +0,0 @@
-/*
-   american fuzzy lop++ - LLVM-mode instrumentation pass
-   ---------------------------------------------------
-
-   Copyright 2019-2020 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.
-   You may obtain a copy of the License at:
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-   This library is plugged into LLVM when invoking clang through afl-clang-fast
-   or afl-clang-lto with AFL_LLVM_INSTRUMENT=CFG or =INSTRIM
-
- */
-
-#define AFL_LLVM_PASS
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-
-#include <unordered_set>
-#include <list>
-#include <string>
-#include <fstream>
-#include <set>
-
-#include "llvm/Config/llvm-config.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Analysis/MemorySSAUpdater.h"
-#include "llvm/Analysis/ValueTracking.h"
-
-#include "MarkNodes.h"
-#include "afl-llvm-common.h"
-
-#include "config.h"
-#include "debug.h"
-
-using namespace llvm;
-
-static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
-                                cl::init(false));
-static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
-                                 cl::init(false));
-
-namespace {
-
-struct InsTrimLTO : public ModulePass {
-
- protected:
-  uint32_t function_minimum_size = 1;
-  char *   skip_nozero = NULL;
-  int      afl_global_id = 1, autodictionary = 1;
-  uint32_t inst_blocks = 0, inst_funcs = 0;
-  uint64_t map_addr = 0x10000;
-
- public:
-  static char ID;
-
-  InsTrimLTO() : ModulePass(ID) {
-
-    char *ptr;
-
-    if (getenv("AFL_DEBUG")) debug = 1;
-    if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
-      if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE)
-        FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
-              ptr, MAP_SIZE - 1);
-
-    skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
-
-  }
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-
-    ModulePass::getAnalysisUsage(AU);
-    AU.addRequired<DominatorTreeWrapperPass>();
-    AU.addRequired<LoopInfoWrapperPass>();
-
-  }
-
-  StringRef getPassName() const override {
-
-    return "InstTrim LTO Instrumentation";
-
-  }
-
-  bool runOnModule(Module &M) override {
-
-    char     be_quiet = 0;
-    char *   ptr;
-    uint32_t locations = 0, functions = 0;
-
-    setvbuf(stdout, NULL, _IONBF, 0);
-
-    if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
-
-      SAYF(cCYA "InsTrimLTO" VERSION cRST
-                " by csienslab and Marc \"vanHauser\" Heuse\n");
-
-    } else
-
-      be_quiet = 1;
-
-    /* Process environment variables */
-
-    if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
-
-    if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
-
-      uint64_t val;
-      if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
-
-        map_addr = 0;
-
-      } else if (map_addr == 0) {
-
-        FATAL(
-            "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used "
-            "together");
-
-      } else if (strncmp(ptr, "0x", 2) != 0) {
-
-        map_addr = 0x10000;  // the default
-
-      } else {
-
-        val = strtoull(ptr, NULL, 16);
-        if (val < 0x100 || val > 0xffffffff00000000) {
-
-          FATAL(
-              "AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
-              "0xffffffff00000000");
-
-        }
-
-        map_addr = val;
-
-      }
-
-    }
-
-    if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); }
-
-    if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
-        getenv("LOOPHEAD") != NULL) {
-
-      LoopHeadOpt = true;
-
-    }
-
-    if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
-        getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
-      function_minimum_size = 2;
-
-    // this is our default
-    MarkSetOpt = true;
-
-    /* Initialize LLVM instrumentation */
-
-    LLVMContext &                    C = M.getContext();
-    std::vector<std::string>         dictionary;
-    std::vector<CallInst *>          calls;
-    DenseMap<Value *, std::string *> valueMap;
-
-    IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
-    IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
-    IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
-
-    ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
-    ConstantInt *One = ConstantInt::get(Int8Ty, 1);
-
-    /* Get/set globals for the SHM region. */
-
-    GlobalVariable *AFLMapPtr = NULL;
-    Value *         MapPtrFixed = NULL;
-
-    if (!map_addr) {
-
-      AFLMapPtr =
-          new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
-                             GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
-
-    } else {
-
-      ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
-      MapPtrFixed =
-          ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Ty));
-
-    }
-
-    if (autodictionary) {
-
-      /*  Some implementation notes.
-       *
-       *  We try to handle 3 cases:
-       *  - memcmp("foo", arg, 3) <- literal string
-       *  - static char globalvar[] = "foo";
-       *    memcmp(globalvar, arg, 3) <- global variable
-       *  - char localvar[] = "foo";
-       *    memcmp(locallvar, arg, 3) <- local variable
-       *
-       *  The local variable case is the hardest. We can only detect that
-       *  case if there is no reassignment or change in the variable.
-       *  And it might not work across llvm version.
-       *  What we do is hooking the initializer function for local variables
-       *  (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
-       *  variable. And if that variable is then used in a compare function
-       *  we use that noted string.
-       *  This seems not to work for tokens that have a size <= 4 :-(
-       *
-       *  - if the compared length is smaller than the string length we
-       *    save the full string. This is likely better for fuzzing but
-       *    might be wrong in a few cases depending on optimizers
-       *
-       *  - not using StringRef because there is a bug in the llvm 11
-       *    checkout I am using which sometimes points to wrong strings
-       *
-       *  Over and out. Took me a full day. damn. mh/vh
-       */
-
-      for (Function &F : M) {
-
-        for (auto &BB : F) {
-
-          for (auto &IN : BB) {
-
-            CallInst *callInst = nullptr;
-
-            if ((callInst = dyn_cast<CallInst>(&IN))) {
-
-              bool    isStrcmp = true;
-              bool    isMemcmp = true;
-              bool    isStrncmp = true;
-              bool    isStrcasecmp = true;
-              bool    isStrncasecmp = true;
-              bool    isIntMemcpy = true;
-              bool    addedNull = false;
-              uint8_t optLen = 0;
-
-              Function *Callee = callInst->getCalledFunction();
-              if (!Callee) continue;
-              if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
-              std::string FuncName = Callee->getName().str();
-              isStrcmp &= !FuncName.compare("strcmp");
-              isMemcmp &= !FuncName.compare("memcmp");
-              isStrncmp &= !FuncName.compare("strncmp");
-              isStrcasecmp &= !FuncName.compare("strcasecmp");
-              isStrncasecmp &= !FuncName.compare("strncasecmp");
-              isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
-
-              if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
-                  !isStrncasecmp && !isIntMemcpy)
-                continue;
-
-              /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp
-               * function prototype */
-              FunctionType *FT = Callee->getFunctionType();
-
-              isStrcmp &= FT->getNumParams() == 2 &&
-                          FT->getReturnType()->isIntegerTy(32) &&
-                          FT->getParamType(0) == FT->getParamType(1) &&
-                          FT->getParamType(0) ==
-                              IntegerType::getInt8PtrTy(M.getContext());
-              isStrcasecmp &= FT->getNumParams() == 2 &&
-                              FT->getReturnType()->isIntegerTy(32) &&
-                              FT->getParamType(0) == FT->getParamType(1) &&
-                              FT->getParamType(0) ==
-                                  IntegerType::getInt8PtrTy(M.getContext());
-              isMemcmp &= FT->getNumParams() == 3 &&
-                          FT->getReturnType()->isIntegerTy(32) &&
-                          FT->getParamType(0)->isPointerTy() &&
-                          FT->getParamType(1)->isPointerTy() &&
-                          FT->getParamType(2)->isIntegerTy();
-              isStrncmp &= FT->getNumParams() == 3 &&
-                           FT->getReturnType()->isIntegerTy(32) &&
-                           FT->getParamType(0) == FT->getParamType(1) &&
-                           FT->getParamType(0) ==
-                               IntegerType::getInt8PtrTy(M.getContext()) &&
-                           FT->getParamType(2)->isIntegerTy();
-              isStrncasecmp &= FT->getNumParams() == 3 &&
-                               FT->getReturnType()->isIntegerTy(32) &&
-                               FT->getParamType(0) == FT->getParamType(1) &&
-                               FT->getParamType(0) ==
-                                   IntegerType::getInt8PtrTy(M.getContext()) &&
-                               FT->getParamType(2)->isIntegerTy();
-
-              if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
-                  !isStrncasecmp && !isIntMemcpy)
-                continue;
-
-              /* is a str{n,}{case,}cmp/memcmp, check if we have
-               * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
-               * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x,
-               * ..) memcmp(x, "const", ..) or memcmp("const", x, ..) */
-              Value *Str1P = callInst->getArgOperand(0),
-                    *Str2P = callInst->getArgOperand(1);
-              std::string Str1, Str2;
-              StringRef   TmpStr;
-              bool        HasStr1 = getConstantStringInfo(Str1P, TmpStr);
-              if (TmpStr.empty())
-                HasStr1 = false;
-              else
-                Str1 = TmpStr.str();
-              bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
-              if (TmpStr.empty())
-                HasStr2 = false;
-              else
-                Str2 = TmpStr.str();
-
-              if (debug)
-                fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
-                        FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
-                        Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
-                        Str2P->getName().str().c_str(), Str2.c_str(),
-                        HasStr2 == true ? "true" : "false");
-
-              // we handle the 2nd parameter first because of llvm memcpy
-              if (!HasStr2) {
-
-                auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
-                if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
-
-                  if (auto *Var =
-                          dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
-
-                    if (Var->hasInitializer()) {
-
-                      if (auto *Array = dyn_cast<ConstantDataArray>(
-                              Var->getInitializer())) {
-
-                        HasStr2 = true;
-                        Str2 = Array->getAsString().str();
-
-                      }
-
-                    }
-
-                  }
-
-                }
-
-              }
-
-              // for the internal memcpy routine we only care for the second
-              // parameter and are not reporting anything.
-              if (isIntMemcpy == true) {
-
-                if (HasStr2 == true) {
-
-                  Value *      op2 = callInst->getArgOperand(2);
-                  ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
-                  if (ilen) {
-
-                    uint64_t literalLength = Str2.size();
-                    uint64_t optLength = ilen->getZExtValue();
-                    if (literalLength + 1 == optLength) {
-
-                      Str2.append("\0", 1);  // add null byte
-                      addedNull = true;
-
-                    }
-
-                  }
-
-                  valueMap[Str1P] = new std::string(Str2);
-
-                  if (debug)
-                    fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
-                  continue;
-
-                }
-
-                continue;
-
-              }
-
-              // Neither a literal nor a global variable?
-              // maybe it is a local variable that we saved
-              if (!HasStr2) {
-
-                std::string *strng = valueMap[Str2P];
-                if (strng && !strng->empty()) {
-
-                  Str2 = *strng;
-                  HasStr2 = true;
-                  if (debug)
-                    fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
-                            Str2P);
-
-                }
-
-              }
-
-              if (!HasStr1) {
-
-                auto Ptr = dyn_cast<ConstantExpr>(Str1P);
-
-                if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
-
-                  if (auto *Var =
-                          dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
-
-                    if (Var->hasInitializer()) {
-
-                      if (auto *Array = dyn_cast<ConstantDataArray>(
-                              Var->getInitializer())) {
-
-                        HasStr1 = true;
-                        Str1 = Array->getAsString().str();
-
-                      }
-
-                    }
-
-                  }
-
-                }
-
-              }
-
-              // Neither a literal nor a global variable?
-              // maybe it is a local variable that we saved
-              if (!HasStr1) {
-
-                std::string *strng = valueMap[Str1P];
-                if (strng && !strng->empty()) {
-
-                  Str1 = *strng;
-                  HasStr1 = true;
-                  if (debug)
-                    fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
-                            Str1P);
-
-                }
-
-              }
-
-              /* handle cases of one string is const, one string is variable */
-              if (!(HasStr1 ^ HasStr2)) continue;
-
-              std::string thestring;
-
-              if (HasStr1)
-                thestring = Str1;
-              else
-                thestring = Str2;
-
-              optLen = thestring.length();
-
-              if (isMemcmp || isStrncmp || isStrncasecmp) {
-
-                Value *      op2 = callInst->getArgOperand(2);
-                ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
-                if (ilen) {
-
-                  uint64_t literalLength = optLen;
-                  optLen = ilen->getZExtValue();
-                  if (literalLength + 1 == optLen) {  // add null byte
-                    thestring.append("\0", 1);
-                    addedNull = true;
-
-                  }
-
-                }
-
-              }
-
-              // add null byte if this is a string compare function and a null
-              // was not already added
-              if (addedNull == false && !isMemcmp) {
-
-                thestring.append("\0", 1);  // add null byte
-                optLen++;
-
-              }
-
-              if (!be_quiet) {
-
-                std::string outstring;
-                fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
-                        (unsigned int)thestring.length());
-                for (uint8_t i = 0; i < thestring.length(); i++) {
-
-                  uint8_t c = thestring[i];
-                  if (c <= 32 || c >= 127)
-                    fprintf(stderr, "\\x%02x", c);
-                  else
-                    fprintf(stderr, "%c", c);
-
-                }
-
-                fprintf(stderr, "\"\n");
-
-              }
-
-              // we take the longer string, even if the compare was to a
-              // shorter part. Note that depending on the optimizer of the
-              // compiler this can be wrong, but it is more likely that this
-              // is helping the fuzzer
-              if (optLen != thestring.length()) optLen = thestring.length();
-              if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
-              if (optLen < MIN_AUTO_EXTRA)  // too short? skip
-                continue;
-
-              dictionary.push_back(thestring.substr(0, optLen));
-
-            }
-
-          }
-
-        }
-
-      }
-
-    }
-
-    /* InsTrim instrumentation starts here */
-
-    u64 total_rs = 0;
-    u64 total_hs = 0;
-
-    for (Function &F : M) {
-
-      if (debug) {
-
-        uint32_t bb_cnt = 0;
-
-        for (auto &BB : F)
-          if (BB.size() > 0) ++bb_cnt;
-        SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n",
-             F.getName().str().c_str(), F.size(), bb_cnt);
-
-      }
-
-      // if the function below our minimum size skip it (1 or 2)
-      if (F.size() < function_minimum_size) continue;
-      if (isIgnoreFunction(&F)) continue;
-
-      functions++;
-
-      // the instrument file list check
-      AttributeList Attrs = F.getAttributes();
-      if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {
-
-        if (debug)
-          fprintf(stderr,
-                  "DEBUG: Function %s is not the instrument file listed\n",
-                  F.getName().str().c_str());
-        continue;
-
-      }
-
-      std::unordered_set<BasicBlock *> MS;
-      if (!MarkSetOpt) {
-
-        for (auto &BB : F) {
-
-          MS.insert(&BB);
-
-        }
-
-        total_rs += F.size();
-
-      } else {
-
-        auto Result = markNodes(&F);
-        auto RS = Result.first;
-        auto HS = Result.second;
-
-        MS.insert(RS.begin(), RS.end());
-        if (!LoopHeadOpt) {
-
-          MS.insert(HS.begin(), HS.end());
-          total_rs += MS.size();
-
-        } else {
-
-          DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
-          DominatorTreeWrapperPass *                      DTWP =
-              &getAnalysis<DominatorTreeWrapperPass>(F);
-          auto DT = &DTWP->getDomTree();
-
-          total_rs += RS.size();
-          total_hs += HS.size();
-
-          for (BasicBlock *BB : HS) {
-
-            bool Inserted = false;
-            for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {
-
-              auto Edge = BasicBlockEdge(*BI, BB);
-              if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
-
-                EdgeSet.insert({*BI, BB});
-                Inserted = true;
-                break;
-
-              }
-
-            }
-
-            if (!Inserted) {
-
-              MS.insert(BB);
-              total_rs += 1;
-              total_hs -= 1;
-
-            }
-
-          }
-
-          for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
-
-            auto PredBB = I->first;
-            auto SuccBB = I->second;
-            auto NewBB = SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT,
-                                                nullptr, nullptr, false);
-            MS.insert(NewBB);
-
-          }
-
-        }
-
-      }
-
-      for (BasicBlock &BB : F) {
-
-        auto        PI = pred_begin(&BB);
-        auto        PE = pred_end(&BB);
-        IRBuilder<> IRB(&*BB.getFirstInsertionPt());
-        Value *     L = NULL;
-
-        if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
-
-        if (PI == PE) {
-
-          L = ConstantInt::get(Int32Ty, afl_global_id++);
-          locations++;
-
-        } else {
-
-          auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
-          DenseMap<BasicBlock *, unsigned> PredMap;
-          for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
-
-            BasicBlock *PBB = *PI;
-            auto        It = PredMap.insert({PBB, afl_global_id++});
-            unsigned    Label = It.first->second;
-            PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
-            locations++;
-
-          }
-
-          L = PN;
-
-        }
-
-        /* Load SHM pointer */
-        Value *MapPtrIdx;
-
-        if (map_addr) {
-
-          MapPtrIdx = IRB.CreateGEP(MapPtrFixed, L);
-
-        } else {
-
-          LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
-          MapPtr->setMetadata(M.getMDKindID("nosanitize"),
-                              MDNode::get(C, None));
-          MapPtrIdx = IRB.CreateGEP(MapPtr, L);
-
-        }
-
-        /* Update bitmap */
-        LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
-        Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-
-        Value *Incr = IRB.CreateAdd(Counter, One);
-
-        if (skip_nozero == NULL) {
-
-          auto cf = IRB.CreateICmpEQ(Incr, Zero);
-          auto carry = IRB.CreateZExt(cf, Int8Ty);
-          Incr = IRB.CreateAdd(Incr, carry);
-
-        }
-
-        IRB.CreateStore(Incr, MapPtrIdx)
-            ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-
-        // done :)
-
-        inst_blocks++;
-
-      }
-
-    }
-
-    // save highest location ID to global variable
-    // do this after each function to fail faster
-    if (!be_quiet && afl_global_id > MAP_SIZE &&
-        afl_global_id > FS_OPT_MAX_MAPSIZE) {
-
-      uint32_t pow2map = 1, map = afl_global_id;
-      while ((map = map >> 1))
-        pow2map++;
-      WARNF(
-          "We have %u blocks to instrument but the map size is only %u. Either "
-          "edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
-          "afl-fuzz and llvm_mode and then make this target - or set "
-          "AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
-          "target.",
-          afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id);
-
-    }
-
-    if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
-
-      // yes we could create our own function, insert it into ctors ...
-      // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
-
-      Function *f = M.getFunction("__afl_auto_init_globals");
-
-      if (!f) {
-
-        fprintf(stderr,
-                "Error: init function could not be found (this should not "
-                "happen)\n");
-        exit(-1);
-
-      }
-
-      BasicBlock *bb = &f->getEntryBlock();
-      if (!bb) {
-
-        fprintf(stderr,
-                "Error: init function does not have an EntryBlock (this should "
-                "not happen)\n");
-        exit(-1);
-
-      }
-
-      BasicBlock::iterator IP = bb->getFirstInsertionPt();
-      IRBuilder<>          IRB(&(*IP));
-
-      if (map_addr) {
-
-        GlobalVariable *AFLMapAddrFixed =
-            new GlobalVariable(M, Int64Ty, true, GlobalValue::ExternalLinkage,
-                               0, "__afl_map_addr");
-        ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
-        StoreInst *  StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
-        StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"),
-                                  MDNode::get(C, None));
-
-      }
-
-      if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
-
-        uint32_t write_loc = afl_global_id;
-
-        if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
-
-        GlobalVariable *AFLFinalLoc =
-            new GlobalVariable(M, Int32Ty, true, GlobalValue::ExternalLinkage,
-                               0, "__afl_final_loc");
-        ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
-        StoreInst *  StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
-        StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
-                                   MDNode::get(C, None));
-
-      }
-
-      if (dictionary.size()) {
-
-        size_t memlen = 0, count = 0, offset = 0;
-        char * ptr;
-
-        for (auto token : dictionary) {
-
-          memlen += token.length();
-          count++;
-
-        }
-
-        if (!be_quiet)
-          printf("AUTODICTIONARY: %lu string%s found\n", count,
-                 count == 1 ? "" : "s");
-
-        if (count) {
-
-          if ((ptr = (char *)malloc(memlen + count)) == NULL) {
-
-            fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
-                    memlen + count);
-            exit(-1);
-
-          }
-
-          count = 0;
-
-          for (auto token : dictionary) {
-
-            if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
-
-              ptr[offset++] = (uint8_t)token.length();
-              memcpy(ptr + offset, token.c_str(), token.length());
-              offset += token.length();
-              count++;
-
-            }
-
-          }
-
-          GlobalVariable *AFLDictionaryLen = new GlobalVariable(
-              M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
-              "__afl_dictionary_len");
-          ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
-          StoreInst *  StoreDictLen =
-              IRB.CreateStore(const_len, AFLDictionaryLen);
-          StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
-                                    MDNode::get(C, None));
-
-          ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
-          GlobalVariable *AFLInternalDictionary = new GlobalVariable(
-              M, ArrayTy, true, GlobalValue::ExternalLinkage,
-              ConstantDataArray::get(
-                  C, *(new ArrayRef<char>((char *)ptr, offset))),
-              "__afl_internal_dictionary");
-          AFLInternalDictionary->setInitializer(ConstantDataArray::get(
-              C, *(new ArrayRef<char>((char *)ptr, offset))));
-          AFLInternalDictionary->setConstant(true);
-
-          GlobalVariable *AFLDictionary = new GlobalVariable(
-              M, PointerType::get(Int8Ty, 0), false,
-              GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
-
-          Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
-          Value *AFLDictPtr =
-              IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
-          StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
-          StoreDict->setMetadata(M.getMDKindID("nosanitize"),
-                                 MDNode::get(C, None));
-
-        }
-
-      }
-
-    }
-
-    // count basic blocks for comparison with classic instrumentation
-
-    u32 edges = 0;
-    for (auto &F : M) {
-
-      if (F.size() < function_minimum_size) continue;
-
-      for (auto &BB : F) {
-
-        bool would_instrument = false;
-
-        for (BasicBlock *Pred : predecessors(&BB)) {
-
-          int count = 0;
-          for (BasicBlock *Succ : successors(Pred))
-            if (Succ != NULL) count++;
-
-          if (count > 1) would_instrument = true;
-
-        }
-
-        if (would_instrument == true) edges++;
-
-      }
-
-    }
-
-    /* Say something nice. */
-
-    if (!be_quiet) {
-
-      if (!inst_blocks)
-        WARNF("No instrumentation targets found.");
-      else {
-
-        char modeline[100];
-        snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
-                 getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
-                 getenv("AFL_USE_ASAN") ? ", ASAN" : "",
-                 getenv("AFL_USE_MSAN") ? ", MSAN" : "",
-                 getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
-                 getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
-        OKF("Instrumented %u locations for %u edges in %u functions (%llu, "
-            "%llu) with no collisions (on "
-            "average %llu collisions would be in afl-gcc/afl-clang-fast for %u "
-            "edges) (%s mode).",
-            inst_blocks, locations, functions, total_rs, total_hs,
-            calculateCollisions(edges), edges, modeline);
-
-      }
-
-    }
-
-    return true;
-
-  }
-
-};  // end of struct InsTrim
-
-}  // end of anonymous namespace
-
-char InsTrimLTO::ID = 0;
-
-static void registerInsTrimLTO(const PassManagerBuilder &,
-                               legacy::PassManagerBase &PM) {
-
-  PM.add(new InsTrimLTO());
-
-}
-
-static RegisterPass<InsTrimLTO> X("afl-lto-instrim",
-                                  "afl++ InsTrim LTO instrumentation pass",
-                                  false, false);
-
-static RegisterStandardPasses RegisterInsTrimLTO(
-    PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerInsTrimLTO);
-
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index 300951fb..12509ab2 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -128,6 +128,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     be_quiet = 1;
 
+  if (getenv("AFL_LLVM_CMPLOG")) autodictionary = 0;
+
   if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
 
     if ((documentFile = fopen(ptr, "a")) == NULL)
@@ -142,8 +144,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
   /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
   map_addr = 0;
 
-  if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2;
-
   if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
 
     uint64_t val;
@@ -602,17 +602,41 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     for (auto &BB : F) {
 
-      uint32_t succ = 0;
+      if (F.size() == 1) {
+
+        InsBlocks.push_back(&BB);
+        continue;
 
-      if (F.size() == 1) InsBlocks.push_back(&BB);
+      }
 
+      uint32_t succ = 0;
       for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB); SI != SE;
            ++SI)
         if ((*SI)->size() > 0) succ++;
-
       if (succ < 2)  // no need to instrument
         continue;
 
+      if (BlockList.size()) {
+
+        int skip = 0;
+        for (uint32_t k = 0; k < BlockList.size(); k++) {
+
+          if (&BB == BlockList[k]) {
+
+            if (debug)
+              fprintf(stderr,
+                      "DEBUG: Function %s skipping BB with/after __afl_loop\n",
+                      F.getName().str().c_str());
+            skip = 1;
+
+          }
+
+        }
+
+        if (skip) continue;
+
+      }
+
       InsBlocks.push_back(&BB);
 
     }
@@ -631,28 +655,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
         uint32_t                  fs = origBB->getParent()->size();
         uint32_t                  countto;
 
-        if (BlockList.size()) {
-
-          int skip = 0;
-          for (uint32_t k = 0; k < BlockList.size(); k++) {
-
-            if (origBB == BlockList[k]) {
-
-              if (debug)
-                fprintf(
-                    stderr,
-                    "DEBUG: Function %s skipping BB with/after __afl_loop\n",
-                    F.getName().str().c_str());
-              skip = 1;
-
-            }
-
-          }
-
-          if (skip) continue;
-
-        }
-
         for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
              SI != SE; ++SI) {
 
diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc
index 0206080f..86c6f3c6 100644
--- a/llvm_mode/afl-llvm-pass.so.cc
+++ b/llvm_mode/afl-llvm-pass.so.cc
@@ -182,10 +182,6 @@ bool AFLCoverage::runOnModule(Module &M) {
 #endif
   skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
 
-  if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
-      getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
-    function_minimum_size = 2;
-
   unsigned PrevLocSize = 0;
 
   char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 094c30b9..1452c55e 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -627,7 +627,7 @@ void destroy_extras(afl_state_t *afl) {
 
   }
 
-  ck_free(afl->extras);
+  afl_free(afl->extras);
 
 }
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index aeb290bd..0ce35cb7 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -206,7 +206,8 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
                afl->plot_prev_qc == afl->queue_cycle &&
                afl->plot_prev_uc == afl->unique_crashes &&
                afl->plot_prev_uh == afl->unique_hangs &&
-               afl->plot_prev_md == afl->max_depth) ||
+               afl->plot_prev_md == afl->max_depth &&
+               afl->plot_prev_ed == afl->fsrv.total_execs) ||
       unlikely(!afl->queue_cycle) ||
       unlikely(get_cur_time() - afl->start_time <= 60)) {
 
@@ -222,6 +223,7 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
   afl->plot_prev_uc = afl->unique_crashes;
   afl->plot_prev_uh = afl->unique_hangs;
   afl->plot_prev_md = afl->max_depth;
+  afl->plot_prev_ed = afl->fsrv.total_execs;
 
   /* Fields in the file:
 
@@ -229,12 +231,13 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
      favored_not_fuzzed, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
      execs_per_sec */
 
-  fprintf(afl->fsrv.plot_file,
-          "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n",
-          get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
-          afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
-          bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
-          eps);                                            /* ignore errors */
+  fprintf(
+      afl->fsrv.plot_file,
+      "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu\n",
+      get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
+      afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
+      bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
+      afl->plot_prev_ed);                                  /* ignore errors */
 
   fflush(afl->fsrv.plot_file);