about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.clang-format1
-rwxr-xr-x.custom-format.py4
-rw-r--r--GNUmakefile49
-rw-r--r--README.md2
-rw-r--r--docs/Changelog.md8
-rw-r--r--docs/custom_mutators.md9
-rw-r--r--docs/env_variables.md19
-rw-r--r--examples/afl_network_proxy/GNUmakefile2
-rw-r--r--examples/afl_network_proxy/afl-network-server.c4
-rw-r--r--examples/afl_untracer/Makefile10
-rw-r--r--examples/afl_untracer/README.md47
-rw-r--r--examples/afl_untracer/afl-untracer.c85
-rw-r--r--examples/afl_untracer/ida_get_patchpoints.py3
-rw-r--r--include/afl-fuzz.h17
-rw-r--r--include/alloc-inl.h14
-rw-r--r--include/types.h6
-rw-r--r--libtokencap/libtokencap.so.c2
-rw-r--r--llvm_mode/GNUmakefile27
-rw-r--r--llvm_mode/LLVMInsTrim.so.cc17
-rw-r--r--llvm_mode/README.lto.md29
-rw-r--r--llvm_mode/afl-clang-fast.c141
-rw-r--r--llvm_mode/afl-llvm-common.cc40
-rw-r--r--llvm_mode/afl-llvm-common.h9
-rw-r--r--llvm_mode/afl-llvm-lto-instrim.so.cc935
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc75
-rw-r--r--llvm_mode/afl-llvm-lto-whitelist.so.cc2
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc17
-rw-r--r--llvm_mode/afl-llvm-rt-lto.o.c4
-rw-r--r--llvm_mode/afl-llvm-rt.o.c6
-rw-r--r--llvm_mode/compare-transform-pass.so.cc2
-rw-r--r--llvm_mode/split-switches-pass.so.cc2
-rwxr-xr-xqemu_mode/build_qemu_support.sh3
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-inl.h3
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-translate-inl.h2
-rw-r--r--qemu_mode/patches/syscall.diff9
-rw-r--r--src/afl-analyze.c2
-rw-r--r--src/afl-as.c2
-rw-r--r--src/afl-common.c18
-rw-r--r--src/afl-fuzz-bitmap.c4
-rw-r--r--src/afl-fuzz-mutators.c207
-rw-r--r--src/afl-fuzz-one.c197
-rw-r--r--src/afl-fuzz-python.c55
-rw-r--r--src/afl-fuzz-queue.c19
-rw-r--r--src/afl-fuzz-run.c77
-rw-r--r--src/afl-fuzz-stats.c6
-rw-r--r--src/afl-fuzz.c18
-rw-r--r--src/afl-showmap.c3
-rw-r--r--src/afl-tmin.c2
-rw-r--r--test/test-multiple-mutators.c24
-rwxr-xr-xtest/test.sh33
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
-rw-r--r--unicorn_mode/samples/persistent/COMPILE.md4
-rw-r--r--unicorn_mode/samples/persistent/Makefile9
m---------unicorn_mode/unicornafl0
-rwxr-xr-xunicorn_mode/update_uc_ref.sh24
55 files changed, 1842 insertions, 469 deletions
diff --git a/.clang-format b/.clang-format
index fd5d9a41..bf15cdc0 100644
--- a/.clang-format
+++ b/.clang-format
@@ -72,7 +72,6 @@ IncludeCategories:
     Priority:        3
 IncludeIsMainRegex: '([-_](test|unittest))?$'
 IndentCaseLabels: true
-IndentPPDirectives: None
 IndentWidth:     2
 IndentWrappedFunctionNames: false
 JavaScriptQuotes: Leave
diff --git a/.custom-format.py b/.custom-format.py
index 164815b1..6f1b0bfa 100755
--- a/.custom-format.py
+++ b/.custom-format.py
@@ -70,8 +70,8 @@ def custom_format(filename):
     out = ""
     
     for line in src.split("\n"):
-        if line.startswith("#"):
-            if line.startswith("#define"):
+        if line.lstrip().startswith("#"):
+            if line[line.find("#")+1:].lstrip().startswith("define"):
                 in_define = True
         
         if "/*" in line and not line.strip().startswith("/*") and line.endswith("*/") and len(line) < (COLUMN_LIMIT-2):
diff --git a/GNUmakefile b/GNUmakefile
index 3a1ae521..d3e9275c 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -52,12 +52,28 @@ endif
 
 ifneq "$(shell uname)" "Darwin"
  ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
-	CFLAGS_OPT = -march=native
+	CFLAGS_OPT += -march=native
  endif
  # OS X does not like _FORTIFY_SOURCE=2
  CFLAGS_OPT += -D_FORTIFY_SOURCE=2
 endif
 
+ifdef STATIC
+  $(info Compiling static version of binaries)
+  # Disable python for static compilation to simplify things
+  PYTHON_OK=0
+  PYFLAGS=
+
+  CFLAGS_OPT += -static
+  LDFLAGS += -lm -lpthread -lz -lutil
+endif
+
+ifdef PROFILING
+  $(info Compiling with profiling information, for analysis: gprof ./afl-fuzz gmon.out > prof.txt)
+  CFLAGS_OPT += -pg -DPROFILING=1
+  LDFLAGS += -pg
+endif
+
 ifneq "$(shell uname -m)" "x86_64"
  ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
   ifneq "$(shell uname -m)" "amd64"
@@ -142,23 +158,23 @@ else
 endif
 
 ifneq "$(filter Linux GNU%,$(shell uname))" ""
-  LDFLAGS  += -ldl
+  LDFLAGS += -ldl
 endif
 
 ifneq "$(findstring FreeBSD, $(shell uname))" ""
-  CFLAGS += -pthread
-  LDFLAGS  += -lpthread
+  CFLAGS  += -pthread
+  LDFLAGS += -lpthread
 endif
 
 ifneq "$(findstring NetBSD, $(shell uname))" ""
-  CFLAGS += -pthread
-  LDFLAGS  += -lpthread
+  CFLAGS  += -pthread
+  LDFLAGS += -lpthread
 endif
 
 ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
-  TEST_CC   = afl-gcc
+  TEST_CC  = afl-gcc
 else
-  TEST_CC   = afl-clang
+  TEST_CC  = afl-clang
 endif
 
 COMM_HDR    = include/alloc-inl.h include/config.h include/debug.h include/types.h
@@ -184,17 +200,8 @@ ifeq "$(shell svn proplist . 2>/dev/null && echo 1 || echo 0)" "1"
   IN_REPO=1
 endif
 
-ifdef STATIC
-  $(info Compiling static version of binaries)
-  # Disable python for static compilation to simplify things
-  PYTHON_OK=0
-  PYFLAGS=
-  COMPILE_STATIC = -static
-  LDFLAGS += -lm
-endif
-
 ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
-ASAN_LDFLAGS+=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
+ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
 
 ifdef ASAN_BUILD
   $(info Compiling ASAN version of binaries)
@@ -202,12 +209,6 @@ ifdef ASAN_BUILD
   LDFLAGS+=$(ASAN_LDFLAGS)
 endif
 
-ifdef PROFILING
-  $(info Compiling profiling version of binaries)
-  CFLAGS+=-pg
-  LDFLAGS+=-pg
-endif
-
 ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
 	SHMAT_OK=1
 else
diff --git a/README.md b/README.md
index 690451a2..04ead78e 100644
--- a/README.md
+++ b/README.md
@@ -137,7 +137,7 @@ afl++ has many build options.
 The easiest is to build and install everything:
 
 ```shell
-$ sudo apt install build-essential libtool-bin python3 automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools llvm
+$ sudo apt install build-essential libtool-bin python3 automake flex bison libglib2.0-dev libpixman-1-dev clang python-setuptools llvm
 $ make distrib
 $ sudo make install
 ```
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 54564a5d..0b5c11e8 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -16,9 +16,12 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
      - an old, old bug in afl that would show negative stability in rare
        circumstances is now hopefully fixed
   - llvm_mode:
+     - afl-clang-fast/lto now do not skip single block functions. This
+       behaviour can be reactivated with AFL_LLVM_SKIPSINGLEBLOCK
      - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed
        address for the shared memory map is used as this increases the
        fuzzing speed
+     - InsTrim now has an LTO version! :-) That is the best and fastest mode!
      - fixes to LTO mode if instrumented edges > MAP_SIZE
      - CTX and NGRAM can now be used together
      - CTX and NGRAM are now also supported in CFG/INSTRIM mode
@@ -38,7 +41,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     network (not fuzzing tcp/ip services but running afl-fuzz on one system
     and the target being on an embedded device)
   - added examples/afl_untracer which does a binary-only fuzzing with the
-    modifications done in memory
+    modifications done in memory (intel32/64 and aarch64 support)
   - added examples/afl_proxy which can be easily used to fuzz and instrument
     non-standard things
   - all:
@@ -2571,3 +2574,6 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
 ### Version 0.21b (2013-11-12):
 
   - Initial public release.
+
+  - Added support for use of multiple custom mutators which can be specified using 
+    the environment variable AFL_CUSTOM_MUTATOR_LIBRARY.
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 49ce761e..3cd874b9 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -16,6 +16,10 @@ fuzzing by using libraries that perform mutations according to a given grammar.
 
 The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY`
 or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function.
+Now afl also supports multiple custom mutators which can be specified in the same `AFL_CUSTOM_MUTATOR_LIBRARY` environment variable like this.
+```bash
+export AFL_CUSTOM_MUTATOR_LIBRARY="full/path/to/mutator_first.so;full/path/to/mutator_second.so"
+```
 Please see [APIs](#2-apis) and [Usage](#3-usage) for detail.
 
 The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage).
@@ -209,12 +213,15 @@ For C/C++ mutator, the source code must be compiled as a shared object:
 ```bash
 gcc -shared -Wall -O3 example.c -o example.so
 ```
+Note that if you specify multiple custom mutators, the corresponding functions will
+be called in the order in which they are specified. e.g first `pre_save` function of
+`example_first.so` will be called and then that of `example_second.so`
 
 ### Run
 
 C/C++
 ```bash
-export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so
+export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so"
 afl-fuzz /path/to/program
 ```
 
diff --git a/docs/env_variables.md b/docs/env_variables.md
index ed81c8a3..36e5a432 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -83,6 +83,10 @@ 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
@@ -116,6 +120,9 @@ Then there are a few specific features that are only available in llvm_mode:
     afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only
     built if LLVM 11 or newer is used.
 
+   - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
+     (recommended)
+
    - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target
      binary based on string compare and memory compare functions.
      afl-fuzz will automatically get these transmitted when starting to
@@ -139,7 +146,13 @@ Then there are a few specific features that are only available in llvm_mode:
 
 ### INSTRIM
 
-    This feature increases the speed by ~15% without any disadvantages.
+    This feature increases the speed by ~15% without any disadvantages to the
+    classic instrumentation.
+
+    Note that there is also an LTO version (if you have llvm 11 or higher) -
+    that is the best instrumentation we have. Use `afl-clang-lto` to activate.
+    The InsTrim LTO version additionally has all the options and features of
+    LTO (see above).
 
     - Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode
 
@@ -147,10 +160,6 @@ Then there are a few specific features that are only available in llvm_mode:
       afl-fuzz will only be able to see the path the loop took, but not how
       many times it was called (unless it is a complex loop).
 
-    - Setting AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 will skip instrumenting
-      functions with a single basic block. This is useful for most C and
-      some C++ targets.
-
     See llvm_mode/README.instrim.md
 
 ### NGRAM
diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile
index cf1cbad5..25a3df82 100644
--- a/examples/afl_network_proxy/GNUmakefile
+++ b/examples/afl_network_proxy/GNUmakefile
@@ -6,6 +6,8 @@ PROGRAMS = afl-network-client afl-network-server
 
 HASH=\#
 
+CFLAGS += -Wno-pointer-sign
+
 ifdef STATIC
   CFLAGS += -static
 endif
diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c
index 2de91cbd..59064b2c 100644
--- a/examples/afl_network_proxy/afl-network-server.c
+++ b/examples/afl_network_proxy/afl-network-server.c
@@ -142,6 +142,8 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
 
   }
 
+  return ret;
+
 }
 
 /* Handle Ctrl-C and the like. */
@@ -665,7 +667,7 @@ int main(int argc, char **argv_orig, char **envp) {
   while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) {
 
     // fprintf(stderr, "received %u\n", in_len);
-    run_target(fsrv, use_argv, in_data, in_len, 1);
+    (void)run_target(fsrv, use_argv, in_data, in_len, 1);
 
     memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size);
 
diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile
index 5c525877..14a09b41 100644
--- a/examples/afl_untracer/Makefile
+++ b/examples/afl_untracer/Makefile
@@ -1,10 +1,16 @@
+ifdef DEBUG
+  OPT=-O0
+else
+  OPT=-O3
+endif
+
 all:	afl-untracer libtestinstr.so
 
 afl-untracer:	afl-untracer.c
-	$(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl -pthread
+	$(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl
 
 libtestinstr.so:	libtestinstr.c
-	$(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c
+	$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
 
 clean:
 	rm -f afl-untracer libtestinstr.so *~ core
diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md
index 4ff96423..05fd8776 100644
--- a/examples/afl_untracer/README.md
+++ b/examples/afl_untracer/README.md
@@ -1,19 +1,58 @@
-# afl-untracer
+# afl-untracer - fast fuzzing of binary-only libraries
+
+## Introduction
 
 afl-untracer is an example skeleton file which can easily be used to fuzz
 a closed source library.
 
-It requires less memory than qemu_mode however it is way
+It requires less memory and is x3-5 faster than qemu_mode however it is way
 more course grained and does not provide interesting features like compcov
 or cmplog.
 
-Read and modify afl-untracer.c then `make` and use it as the afl-fuzz target
-(or even remote via afl-network-proxy).
+Supported is so far Intel (i386/x86_64) and AARCH64.
+
+## How-to
+
+### Modify afl-untracer.c
+
+Read and modify afl-untracer.c then `make`.
+To adapt afl-untracer.c to your needs, read the header of the file and then
+search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
+
+### Generate patches.txt file
 
 To generate the `patches.txt` file for your target library use the
 `ida_get_patchpoints.py` script for IDA Pro or
 `ghidra_get_patchpoints.java` for Ghidra.
 
+The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`.
+
+To easily run the scripts without needing to run the GUI with Ghidra:
+```
+$ /opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
+$ rm -rf /tmp/tmp$$
+```
+
+### Fuzzing
+
+Example (after modifying afl-untracer.c to your needs, compiling and creating
+patches.txt):
+```
+AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
+```
+(or even remote via afl-network-proxy).
+
+### Testing and debugging
+
+For testing/debugging you can try:
+```
+make DEBUG=1
+AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer
+```
+and then you can easily set breakpoints to "breakpoint" and "fuzz".
+
+# Background
+
 This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
 and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
 This implementation is slower because the traps are not patched out with each
diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c
index d319b530..af16a6bf 100644
--- a/examples/afl_untracer/afl-untracer.c
+++ b/examples/afl_untracer/afl-untracer.c
@@ -156,7 +156,7 @@ void read_library_information() {
         liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
         if (debug)
           fprintf(
-              stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
+              stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
               liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
               liblist[liblist_cnt].addr_start,
               liblist[liblist_cnt].addr_end - 1);
@@ -276,6 +276,18 @@ library_list_t *find_library(char *name) {
 
 }
 
+/* for having an easy breakpoint location after loading the shared library */
+// this seems to work for clang too. nice :) requires gcc 4.4+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+void        breakpoint() {
+
+  if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
+
+}
+
+#pragma GCC pop_options
+
 /* Error reporting to forkserver controller */
 
 void send_forkserver_error(int error) {
@@ -433,10 +445,17 @@ static void __afl_end_testcase(int status) {
 
 }
 
+#ifdef __aarch64__
+#define SHADOW(addr)                                     \
+  ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
+                MEMORY_MAP_DECREMENT -                   \
+                ((uintptr_t)addr & 0x7) * 0x10000000000))
+#else
 #define SHADOW(addr)                                     \
   ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
                 MEMORY_MAP_DECREMENT -                   \
                 ((uintptr_t)addr & 0x3) * 0x10000000000))
+#endif
 
 void setup_trap_instrumentation() {
 
@@ -452,8 +471,12 @@ void setup_trap_instrumentation() {
   FILE *patches = fopen(filename, "r");
   if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
 
-  // Index into the coverage bitmap for the current trap instruction.
-  int bitmap_index = 0;
+    // Index into the coverage bitmap for the current trap instruction.
+#ifdef __aarch64__
+  uint64_t bitmap_index = 0;
+#else
+  uint32_t bitmap_index = 0;
+#endif
 
   while ((nread = getline(&line, &len, patches)) != -1) {
 
@@ -485,9 +508,15 @@ void setup_trap_instrumentation() {
                    PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
         FATAL("Failed to mprotect library %s writable", line);
 
-      // Create shadow memory.
+        // Create shadow memory.
+#ifdef __aarch64__
+      for (int i = 0; i < 8; i++) {
+
+#else
       for (int i = 0; i < 4; i++) {
 
+#endif
+
         void *shadow_addr = SHADOW(lib_addr + i);
         void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
@@ -513,12 +542,18 @@ void setup_trap_instrumentation() {
     if (bitmap_index >= __afl_map_size)
       FATAL("Too many basic blocks to instrument");
 
-    uint32_t *shadow = SHADOW(lib_addr + offset);
+#ifdef __arch64__
+    uint64_t
+#else
+    uint32_t
+#endif
+        *shadow = SHADOW(lib_addr + offset);
     if (*shadow != 0) continue;  // skip duplicates
 
       // Make lookup entry in shadow memory.
 
-#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__))
+#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
+     defined(__i386__))
 
     // this is for Intel x64
 
@@ -531,15 +566,29 @@ void setup_trap_instrumentation() {
               lib_addr, offset, lib_addr + offset, orig_byte, shadow,
               bitmap_index, *shadow);
 
+#elif defined(__aarch64__)
+
+    // this is for aarch64
+
+    uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
+    uint32_t  orig_bytes = *patch_bytes;
+    *shadow = (bitmap_index << 32) | orig_bytes;
+    *patch_bytes = 0xd4200000;  // replace instruction with debug trap
+    if (debug)
+      fprintf(stderr,
+              "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
+              lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
+              bitmap_index, *shadow);
+
 #else
-      // this will be ARM and AARCH64
-      // for ARM we will need to identify if the code is in thumb or ARM
-#error "non x86_64 not supported yet"
-      //__arm__:
-      // linux thumb: 0xde01
-      // linux arm: 0xe7f001f0
-      //__aarch64__:
-      // linux aarch64: 0xd4200000
+    // this will be ARM and AARCH64
+    // for ARM we will need to identify if the code is in thumb or ARM
+#error "non x86_64/aarch64 not supported yet"
+    //__arm__:
+    // linux thumb: 0xde01
+    // linux arm: 0xe7f001f0
+    //__aarch64__:
+    // linux aarch64: 0xd4200000
 #endif
 
     bitmap_index++;
@@ -573,8 +622,15 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
   ctx->uc_mcontext->__ss.__rip -= 1;
   addr = ctx->uc_mcontext->__ss.__rip;
 #elif defined(__linux__)
+#if defined(__x86_64__) || defined(__i386__)
   ctx->uc_mcontext.gregs[REG_RIP] -= 1;
   addr = ctx->uc_mcontext.gregs[REG_RIP];
+#elif defined(__aarch64__)
+  ctx->uc_mcontext.pc -= 4;
+  addr = ctx->uc_mcontext.pc;
+#else
+#error "Unsupported processor"
+#endif
 #elif defined(__FreeBSD__) && defined(__LP64__)
   ctx->uc_mcontext.mc_rip -= 1;
   addr = ctx->uc_mcontext.mc_rip;
@@ -642,6 +698,7 @@ int main(int argc, char *argv[]) {
   // END STEP 2
 
   /* setup instrumentation, shared memory and forkserver */
+  breakpoint();
   read_library_information();
   setup_trap_instrumentation();
   __afl_map_shm();
diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py
index c7e8f899..43cf6d89 100644
--- a/examples/afl_untracer/ida_get_patchpoints.py
+++ b/examples/afl_untracer/ida_get_patchpoints.py
@@ -57,3 +57,6 @@ with open(home + "/Desktop/patches.txt", "w") as f:
     f.write('\n')
 
 print("Done, found {} patchpoints".format(len(patchpoints)))
+
+# For headless script running remove the comment from the next line
+#ida_pro.qexit()
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 2203cfdf..9f306b7e 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -33,7 +33,9 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE 1
 #endif
+#ifndef _FILE_OFFSET_BITS
 #define _FILE_OFFSET_BITS 64
+#endif
 
 #ifdef __ANDROID__
 #include "android-ashmem.h"
@@ -607,6 +609,9 @@ typedef struct afl_state {
 
   u8 *   ex_buf;
   size_t ex_size;
+  u32    custom_mutators_count;
+
+  list_t custom_mutator_list;
 
   /* this is a fixed buffer of size map_size that can be used by any function if
    * they do not call another function */
@@ -620,6 +625,7 @@ struct custom_mutator {
   void *      dh;
   u8 *        pre_save_buf;
   size_t      pre_save_size;
+  u8          stacked_custom_prob, stacked_custom;
 
   void *data;                                    /* custom mutator data ptr */
 
@@ -808,15 +814,16 @@ void read_afl_environment(afl_state_t *, char **);
 /**** Prototypes ****/
 
 /* Custom mutators */
-void setup_custom_mutator(afl_state_t *);
-void destroy_custom_mutator(afl_state_t *);
-u8   trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf);
+void setup_custom_mutators(afl_state_t *);
+void destroy_custom_mutators(afl_state_t *);
+u8   trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf,
+                      struct custom_mutator *mutator);
 
 /* Python */
 #ifdef USE_PYTHON
 
-void load_custom_mutator_py(afl_state_t *, char *);
-void finalize_py_module(void *);
+struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
+void                   finalize_py_module(void *);
 
 size_t pre_save_py(void *, u8 *, size_t, u8 **);
 s32    init_trim_py(void *, u8 *, size_t);
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
index e5547fe0..485446de 100644
--- a/include/alloc-inl.h
+++ b/include/alloc-inl.h
@@ -214,8 +214,8 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
 
 }
 
-/* In non-debug mode, we just do straightforward aliasing of the above functions
-   to user-visible names such as ck_alloc(). */
+/* In non-debug mode, we just do straightforward aliasing of the above
+   functions to user-visible names such as ck_alloc(). */
 
 #define ck_alloc DFL_ck_alloc
 #define ck_alloc_nozero DFL_ck_alloc_nozero
@@ -247,7 +247,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
 
 /* Macro to enforce allocation limits as a last-resort defense against
    integer overflows. */
-
 #define ALLOC_CHECK_SIZE(_s)                                          \
   do {                                                                \
                                                                       \
@@ -358,7 +357,6 @@ static inline void DFL_ck_free(void *mem) {
   if (!mem) return;
 
   CHECK_PTR(mem);
-
 #ifdef DEBUG_BUILD
 
   /* Catch pointer issues sooner. */
@@ -542,8 +540,8 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
 
 #ifndef DEBUG_BUILD
 
-/* In non-debug mode, we just do straightforward aliasing of the above functions
-   to user-visible names such as ck_alloc(). */
+/* In non-debug mode, we just do straightforward aliasing of the above
+   functions to user-visible names such as ck_alloc(). */
 
 #define ck_alloc DFL_ck_alloc
 #define ck_alloc_nozero DFL_ck_alloc_nozero
@@ -558,8 +556,8 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
 
 #else
 
-/* In debugging mode, we also track allocations to detect memory leaks, and the
-   flow goes through one more layer of indirection. */
+/* In debugging mode, we also track allocations to detect memory leaks, and
+   the flow goes through one more layer of indirection. */
 
 /* Alloc tracking data structures: */
 
diff --git a/include/types.h b/include/types.h
index e7ff131d..72d2ba51 100644
--- a/include/types.h
+++ b/include/types.h
@@ -89,6 +89,7 @@ typedef int64_t s64;
     _a < _b ? _a : _b;      \
                             \
   })
+
 #define MAX(a, b)           \
   ({                        \
                             \
@@ -97,6 +98,7 @@ typedef int64_t s64;
     _a > _b ? _a : _b;      \
                             \
   })
+
 #endif                                                              /* !MIN */
 
 #define SWAP16(_x)                    \
@@ -154,8 +156,12 @@ typedef int64_t s64;
 #define MEM_BARRIER() __asm__ volatile("" ::: "memory")
 
 #if __GNUC__ < 6
+#ifndef likely
 #define likely(_x) (_x)
+#endif
+#ifndef unlikely
 #define unlikely(_x) (_x)
+#endif
 #else
 #ifndef likely
 #define likely(_x) __builtin_expect(!!(_x), 1)
diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c
index 1588239c..56b2cd4b 100644
--- a/libtokencap/libtokencap.so.c
+++ b/libtokencap/libtokencap.so.c
@@ -45,7 +45,9 @@
 #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
 #include <sys/types.h>
 #include <sys/sysctl.h>
+#if !defined __NetBSD__
 #include <sys/user.h>
+#endif
 #include <sys/mman.h>
 #endif
 
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 93886e47..ab14e545 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -43,8 +43,9 @@ LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.
 LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
 LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
 LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
+LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
 LLVM_STDCXX = gnu++11
-LLVM_APPLE = $(shell clang -v 2>&1 | grep -iq apple && echo 1 || echo 0)
+LLVM_APPLE_XCODE = $(shell clang -v 2>&1 | grep -q Apple && echo 1 || echo 0)
 LLVM_LTO   = 0
 
 ifeq "$(LLVMVER)" ""
@@ -74,7 +75,7 @@ ifeq "$(LLVM_LTO)" "0"
   $(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.)
 endif
 
-ifeq "$(LLVM_APPLE)" "1"
+ifeq "$(LLVM_APPLE_XCODE)" "1"
   $(warning llvm_mode will not compile with Xcode clang...)
 endif
 
@@ -200,7 +201,8 @@ override CFLAGS += -Wall \
                -g -Wno-pointer-sign -I ../include/ \
                -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
                -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
-               -DLLVM_VERSION=\"$(LLVMVER)\"  -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
+               -DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
+               -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
                -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
                -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
 ifdef AFL_TRACE_PC
@@ -211,13 +213,15 @@ CXXFLAGS          ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
 override CXXFLAGS += -Wall -g -I ../include/ \
                      -DVERSION=\"$(VERSION)\" -Wno-variadic-macros
 
-CLANG_CFL    = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS)
+CLANG_CFL    = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fpic $(CXXFLAGS)
 CLANG_LFL    = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
 
 
 # User teor2345 reports that this is required to make things work on MacOS X.
 ifeq "$(shell uname)" "Darwin"
   CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
+else
+  CLANG_CFL += -Wl,-znodelete
 endif
 
 ifeq "$(shell uname)" "OpenBSD"
@@ -238,14 +242,14 @@ ifeq "$(TEST_MMAP)" "1"
         LDFLAGS += -Wno-deprecated-declarations
 endif
 
-  PROGS      = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.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
+  PROGS      = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.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
 
 # If prerequisites are not given, warn, do not build anything, and exit with code 0
 ifeq "$(LLVMVER)" ""
   NO_BUILD = 1
 endif
 
-ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE)" "00"
+ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
   NO_BUILD = 1
 endif
 
@@ -277,7 +281,7 @@ no_build:
 
 test_deps:
 	@echo "[*] Checking for working 'llvm-config'..."
- ifneq "$(LLVM_APPLE)" "1"
+ ifneq "$(LLVM_APPLE_XCODE)" "1"
 	@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo "    (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
  endif
 	@echo "[*] Checking for working '$(CC)'..."
@@ -296,7 +300,7 @@ afl-common.o: ../src/afl-common.c
 	$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
 
 ../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
-	$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
+	$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -Dxxx
 	ln -sf afl-clang-fast ../afl-clang-fast++
 ifneq "$(AFL_CLANG_FLTO)" ""
 ifeq "$(LLVM_LTO)" "1"
@@ -330,6 +334,11 @@ ifeq "$(LLVM_LTO)" "1"
 	@$(CLANG_BIN) $(CFLAGS) -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_CFL) -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_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
@@ -373,7 +382,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-rt-lto*.o ../afl-llvm-lto-whitelist.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-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_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
 	if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc
index ad046a8b..837b093a 100644
--- a/llvm_mode/LLVMInsTrim.so.cc
+++ b/llvm_mode/LLVMInsTrim.so.cc
@@ -103,7 +103,6 @@ struct InsTrim : public ModulePass {
   bool runOnModule(Module &M) override {
 
     char be_quiet = 0;
-    int  ngram_size = 0;
 
     if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
 
@@ -134,15 +133,17 @@ struct InsTrim : public ModulePass {
 
     }
 
-    if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL)
+    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");
+    unsigned int PrevLocSize = 0;
+    char *       ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
     if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
     char *ctx_str = getenv("AFL_LLVM_CTX");
 
 #ifdef AFL_HAVE_VECTOR_INTRINSICS
+    unsigned int ngram_size = 0;
     /* Decide previous location vector size (must be a power of two) */
     VectorType *PrevLocTy;
 
@@ -340,6 +341,7 @@ struct InsTrim : public ModulePass {
           if (MS.find(&BB) == MS.end()) { continue; }
           IRBuilder<> IRB(&*BB.getFirstInsertionPt());
 
+#ifdef AFL_HAVE_VECTOR_INTRINSICS
           if (ngram_size) {
 
             LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
@@ -356,7 +358,10 @@ struct InsTrim : public ModulePass {
                 ->setMetadata(M.getMDKindID("nosanitize"),
                               MDNode::get(C, None));
 
-          } else {
+          } else
+
+#endif
+          {
 
             IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc);
 
@@ -394,7 +399,7 @@ struct InsTrim : public ModulePass {
               if ((callInst = dyn_cast<CallInst>(&IN))) {
 
                 Function *Callee = callInst->getCalledFunction();
-                if (!Callee || Callee->size() < 2)
+                if (!Callee || Callee->size() < function_minimum_size)
                   continue;
                 else {
 
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index d8e4766d..fa5b8665 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -6,6 +6,8 @@ This version requires a current llvm 11 compiled from the github master.
 
 1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
    coverage than anything else that is out there in the AFL world
+  1a. Set AFL_LLVM_INSTRUMENT=CFG if you want the InsTrimLTO version
+      (recommended)
 
 2. You can use it together with llvm_mode: laf-intel and whitelisting
    features and can be combined with cmplog/Redqueen
@@ -14,6 +16,11 @@ This version requires a current llvm 11 compiled from the github master.
 
 4. AUTODICTIONARY feature! see below
 
+5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib` also
+   note that if that target uses _init functions or early constructors then
+   also set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise
+
+
 ## Introduction and problem description
 
 A big issue with how afl/afl++ works is that the basic block IDs that are
@@ -41,7 +48,7 @@ and many dead ends until we got to this:
    -fsanitize=coverage edge coverage mode :)
 
 The result:
- * 10-20% speed gain compared to llvm_mode
+ * 10-25% speed gain compared to llvm_mode
  * guaranteed non-colliding edge coverage :-)
  * The compile time especially for libraries can be longer
 
@@ -80,11 +87,13 @@ Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc.
 
 Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and
 laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
-Instrim does not - but we can not really use it anyway for our approach.
+InsTrim (control flow graph instrumentation) is supported and recommended!
+  (set `AFL_LLVM_INSTRUMENT=CFG`)
 
 Example:
 ```
-CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
+CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
+export AFL_LLVM_INSTRUMENT=CFG
 make
 ```
 
@@ -130,15 +139,27 @@ Other targets ignore environment variables and need the parameters set via
 afl-clang-lto is still work in progress.
 
 Known issues:
-  * Anything that llvm11 cannot compile, afl-clang-lto can not compile either - obviously
+  * Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously
   * Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
 
 Hence if building a target with afl-clang-lto fails try to build it with llvm11
 and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
 `CXXFLAGS=-flto=full`).
+
+An example that does not build with llvm 11 and LTO is ffmpeg.
+
 If this succeeeds then there is an issue with afl-clang-lto. Please report at
 [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
 
+### Target crashes immediately
+
+If the target is using early constructors (priority values smaller than 6)
+or have their own _init/.init functions and these are instrumented then the
+target will likely crash when started. This can be avoided by compiling with
+`AFL_LLVM_MAP_DYNAMIC=1` .
+
+This can e.g. happen with OpenSSL.
+
 ## Upcoming Work
 
 1. Currently the LTO whitelist feature does not allow to instrument main,
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 2d1b427c..07754d1d 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -43,13 +43,13 @@ static u8 * obj_path;                  /* Path to runtime libraries         */
 static u8 **cc_params;                 /* Parameters passed to the real CC  */
 static u32  cc_par_cnt = 1;            /* Param count, including argv0      */
 static u8   llvm_fullpath[PATH_MAX];
-static u8   instrument_mode, instrument_opt_mode, ngram_size;
-static u8 * lto_flag = AFL_CLANG_FLTO;
-static u8 * march_opt = CFLAGS_OPT;
-static u8   debug;
-static u8   cwd[4096];
-static u8   cmplog_mode;
-u8          use_stdin = 0;                                         /* dummy */
+static u8  instrument_mode, instrument_opt_mode, ngram_size, lto_mode, cpp_mode;
+static u8 *lto_flag = AFL_CLANG_FLTO;
+static u8 *march_opt = CFLAGS_OPT;
+static u8  debug;
+static u8  cwd[4096];
+static u8  cmplog_mode;
+u8         use_stdin = 0;                                          /* dummy */
 
 enum {
 
@@ -170,7 +170,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   else
     ++name;
 
-  if (instrument_mode == INSTRUMENT_LTO)
+  if (lto_mode)
     if (lto_flag[0] != '-')
       FATAL(
           "Using afl-clang-lto is not possible because Makefile magic did not "
@@ -184,6 +184,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     else
       sprintf(llvm_fullpath, CLANGPP_BIN);
     cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath;
+    cpp_mode = 1;
 
   } else if (!strcmp(name, "afl-clang-fast") ||
 
@@ -205,12 +206,18 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
-  /* There are three ways to compile with afl-clang-fast. In the traditional
+  if (lto_mode && cpp_mode)
+    cc_params[cc_par_cnt++] = "-lc++";  // needed by fuzzbench, early
+
+  /* There are several ways to compile with afl-clang-fast. In the traditional
      mode, we use afl-llvm-pass.so, then there is libLLVMInsTrim.so which is
-     much faster but has less coverage. Finally there is the experimental
-     'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
-     instead. For trace-pc-guard see:
+     faster and creates less map pollution.
+     Then there is the 'trace-pc-guard' mode, we use native LLVM
+     instrumentation callbacks instead. For trace-pc-guard see:
      http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
+     The best instrumentatation is with the LTO modes, the classic and
+     InsTrimLTO, the latter is faster. The LTO modes are activated by using
+     afl-clang-lto(++)
    */
 
   // laf
@@ -227,8 +234,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   if (getenv("LAF_TRANSFORM_COMPARES") ||
       getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
 
-    if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") &&
-        instrument_mode != INSTRUMENT_LTO)
+    if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && lto_mode)
       WARNF(
           "using AFL_LLVM_LAF_TRANSFORM_COMPARES together with "
           "AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only "
@@ -281,7 +287,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
-  if (instrument_mode == INSTRUMENT_LTO) {
+  if (lto_mode) {
 
     if (getenv("AFL_LLVM_WHITELIST") != NULL) {
 
@@ -295,8 +301,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
     cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
-    cc_params[cc_par_cnt++] = alloc_printf(
-        "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
+    if (instrument_mode == INSTRUMENT_CFG)
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path);
+    else
+      cc_params[cc_par_cnt++] = alloc_printf(
+          "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
     cc_params[cc_par_cnt++] = lto_flag;
 
   } else {
@@ -323,6 +333,22 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   cc_params[cc_par_cnt++] = "-Qunused-arguments";
 
+  // in case LLVM is installed not via a package manager or "make install"
+  // e.g. compiled download or compiled from github then it's ./lib directory
+  // might not be in the search path. Add it if so.
+  u8 *libdir = strdup(LLVM_LIBDIR);
+  if (cpp_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
+      strncmp(libdir, "/lib", 4)) {
+
+    cc_params[cc_par_cnt++] = "-rpath";
+    cc_params[cc_par_cnt++] = libdir;
+
+  } else {
+
+    free(libdir);
+
+  }
+
   /* Detect stray -v calls from ./configure scripts. */
 
   while (--argc) {
@@ -391,7 +417,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   if (getenv("AFL_USE_CFISAN")) {
 
-    if (instrument_mode != INSTRUMENT_LTO) {
+    if (!lto_mode) {
 
       uint32_t i = 0, found = 0;
       while (envp[i] != NULL && !found)
@@ -417,9 +443,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
       getenv("LAF_TRANSFORM_COMPARES") ||
-      (instrument_mode == INSTRUMENT_LTO &&
-       (getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
-        getenv("AFL_LLVM_AUTODICTIONARY")))) {
+      (lto_mode && (getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
+                    getenv("AFL_LLVM_AUTODICTIONARY")))) {
 
     cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
     cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
@@ -500,7 +525,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     case 0:
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
-      if (instrument_mode == INSTRUMENT_LTO)
+      if (lto_mode)
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
       break;
@@ -509,7 +534,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);
       if (access(cc_params[cc_par_cnt - 1], R_OK))
         FATAL("-m32 is not supported by your compiler");
-      if (instrument_mode == INSTRUMENT_LTO) {
+      if (lto_mode) {
 
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
@@ -524,7 +549,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);
       if (access(cc_params[cc_par_cnt - 1], R_OK))
         FATAL("-m64 is not supported by your compiler");
-      if (instrument_mode == INSTRUMENT_LTO) {
+      if (lto_mode) {
 
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
@@ -548,7 +573,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 int main(int argc, char **argv, char **envp) {
 
   int   i;
-  char *callname = "afl-clang-fast", *ptr;
+  char *callname = "afl-clang-fast", *ptr = NULL;
 
   if (getenv("AFL_DEBUG")) {
 
@@ -630,7 +655,13 @@ int main(int argc, char **argv, char **envp) {
       if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
           strncasecmp(ptr, "instrim", strlen("instrim")) == 0) {
 
-        if (!instrument_mode || instrument_mode == INSTRUMENT_CFG)
+        if (instrument_mode == INSTRUMENT_LTO) {
+
+          instrument_mode = INSTRUMENT_CFG;
+          lto_mode = 1;
+
+        } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG)
+
           instrument_mode = INSTRUMENT_CFG;
         else
           FATAL("main instrumentation mode already set with %s",
@@ -640,9 +671,10 @@ int main(int argc, char **argv, char **envp) {
 
       if (strncasecmp(ptr, "lto", strlen("lto")) == 0) {
 
+        lto_mode = 1;
         if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
           instrument_mode = INSTRUMENT_LTO;
-        else
+        else if (instrument_mode != INSTRUMENT_CFG)
           FATAL("main instrumentation mode already set with %s",
                 instrument_mode_string[instrument_mode]);
 
@@ -684,37 +716,54 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
-  if (!instrument_opt_mode)
-    ptr = instrument_mode_string[instrument_mode];
-  else if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
-    ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]);
-  else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM)
-    ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode],
-                       ngram_size);
-  else
-    ptr = alloc_printf("%s + CTX + NGRAM-%u",
-                       instrument_mode_string[instrument_mode], ngram_size);
-
   if (strstr(argv[0], "afl-clang-lto") != NULL) {
 
-    if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO) {
+    if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO ||
+        instrument_mode == INSTRUMENT_CFG) {
 
+      lto_mode = 1;
       callname = "afl-clang-lto";
-      instrument_mode = INSTRUMENT_LTO;
-      ptr = instrument_mode_string[instrument_mode];
+      if (!instrument_mode) {
+
+        instrument_mode = INSTRUMENT_LTO;
+        ptr = instrument_mode_string[instrument_mode];
+
+      }
 
     } else {
 
       if (!be_quiet)
         WARNF("afl-clang-lto called with mode %s, using that mode instead",
-              ptr);
+              instrument_mode_string[instrument_mode]);
 
     }
 
   }
 
+  if (instrument_opt_mode && lto_mode)
+    FATAL(
+        "CTX and NGRAM can not be used in LTO mode (and would make LTO "
+        "useless)");
+
+  if (!instrument_opt_mode) {
+
+    if (lto_mode && instrument_mode == INSTRUMENT_CFG)
+      ptr = alloc_printf("InsTrimLTO");
+    else
+      ptr = instrument_mode_string[instrument_mode];
+
+  } else if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
+
+    ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]);
+  else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM)
+    ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode],
+                       ngram_size);
+  else
+    ptr = alloc_printf("%s + CTX + NGRAM-%u",
+                       instrument_mode_string[instrument_mode], ngram_size);
+
 #ifndef AFL_CLANG_FLTO
-  if (instrument_mode == INSTRUMENT_LTO)
+  if (lto_mode)
     FATAL(
         "instrumentation mode LTO specified but LLVM support not available "
         "(requires LLVM 11 or higher)");
@@ -733,7 +782,7 @@ int main(int argc, char **argv, char **envp) {
 
   if (argc < 2 || strcmp(argv[1], "-h") == 0) {
 
-    if (instrument_mode != INSTRUMENT_LTO)
+    if (!lto_mode)
       printf("afl-clang-fast" VERSION " by <lszekeres@google.com> in %s mode\n",
              ptr);
     else
@@ -831,7 +880,7 @@ int main(int argc, char **argv, char **envp) {
 
              getenv("AFL_DEBUG") != NULL) {
 
-    if (instrument_mode != INSTRUMENT_LTO)
+    if (!lto_mode)
 
       SAYF(cCYA "afl-clang-fast" VERSION cRST
                 " by <lszekeres@google.com> in %s mode\n",
@@ -846,7 +895,7 @@ int main(int argc, char **argv, char **envp) {
   }
 
   u8 *ptr2;
-  if (!be_quiet && instrument_mode != INSTRUMENT_LTO &&
+  if (!be_quiet && !lto_mode &&
       ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) {
 
     u32 map_size = atoi(ptr2);
diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc
index 04dd9475..db604e14 100644
--- a/llvm_mode/afl-llvm-common.cc
+++ b/llvm_mode/afl-llvm-common.cc
@@ -43,10 +43,29 @@ char *getBBName(const llvm::BasicBlock *BB) {
 /* Note: this blacklist check is also called in isInWhitelist() */
 bool isBlacklisted(const llvm::Function *F) {
 
+  // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
+  // fuzzing campaign installations, e.g. oss-fuzz
+
   static const char *Blacklist[] = {
 
-      "asan.", "llvm.",      "sancov.", "__ubsan_handle_", "ign.", "__afl_",
-      "_fini", "__libc_csu", "__asan",  "__msan",          "msan."
+      "asan.",
+      "llvm.",
+      "sancov.",
+      "__ubsan_handle_",
+      "ign.",
+      "__afl_",
+      "_fini",
+      "__libc_csu",
+      "__asan",
+      "__msan",
+      "msan.",
+      "LLVMFuzzer",
+      "maybe_duplicate_stderr",
+      "discard_output",
+      "close_stdout",
+      "dup_and_close_stderr",
+      "maybe_close_fd_mask",
+      "ExecuteFilesOnyByOne"
 
   };
 
@@ -201,3 +220,20 @@ bool isInWhitelist(llvm::Function *F) {
 
 }
 
+// Calculate the number of average collisions that would occur if all
+// location IDs would be assigned randomly (like normal afl/afl++).
+// This uses the "balls in bins" algorithm.
+unsigned long long int calculateCollisions(uint32_t edges) {
+
+  double                 bins = MAP_SIZE;
+  double                 balls = edges;
+  double                 step1 = 1 - (1 / bins);
+  double                 step2 = pow(step1, balls);
+  double                 step3 = bins * step2;
+  double                 step4 = round(step3);
+  unsigned long long int empty = step4;
+  unsigned long long int collisions = edges - (MAP_SIZE - empty);
+  return collisions;
+
+}
+
diff --git a/llvm_mode/afl-llvm-common.h b/llvm_mode/afl-llvm-common.h
index 5b5e08d0..cf14d2e1 100644
--- a/llvm_mode/afl-llvm-common.h
+++ b/llvm_mode/afl-llvm-common.h
@@ -32,10 +32,11 @@ typedef long double max_align_t;
 #include "llvm/Support/CFG.h"
 #endif
 
-char *getBBName(const llvm::BasicBlock *BB);
-bool  isBlacklisted(const llvm::Function *F);
-void  initWhitelist();
-bool  isInWhitelist(llvm::Function *F);
+char *                 getBBName(const llvm::BasicBlock *BB);
+bool                   isBlacklisted(const llvm::Function *F);
+void                   initWhitelist();
+bool                   isInWhitelist(llvm::Function *F);
+unsigned long long int calculateCollisions(uint32_t edges);
 
 #endif
 
diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc
new file mode 100644
index 00000000..a7d9b756
--- /dev/null
+++ b/llvm_mode/afl-llvm-lto-instrim.so.cc
@@ -0,0 +1,935 @@
+/*
+   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, debug = 0, autodictionary = 0;
+  uint32_t be_quiet = 0, 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;
+
+    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_AUTODICTIONARY") ||
+        getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
+      autodictionary = 1;
+
+    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 (isBlacklisted(&F)) 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++);
+
+        } 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);
+
+          }
+
+          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) {
+
+          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) return 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 (%llu, %llu) with no collisions (on "
+            "average %llu collisions would be in afl-gcc/afl-clang-fast for %u "
+            "edges) (%s mode).",
+            inst_blocks, 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 838e45af..f44b336e 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -1,14 +1,9 @@
 /*
-   american fuzzy lop++ - LLVM-mode instrumentation pass
-   ---------------------------------------------------
+   american fuzzy lop++ - LLVM LTO instrumentation pass
+   ----------------------------------------------------
 
-   Written by Laszlo Szekeres <lszekeres@google.com> and
-              Michal Zalewski
+   Written by Marc Heuse <mh@mh-sec.de>
 
-   LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
-   from afl-as.c are Michal's fault.
-
-   Copyright 2015, 2016 Google Inc. All rights reserved.
    Copyright 2019-2020 AFLplusplus Project. All rights reserved.
 
    Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +12,7 @@
 
      http://www.apache.org/licenses/LICENSE-2.0
 
-   This library is plugged into LLVM when invoking clang through afl-clang-fast.
-   It tells the compiler to add code roughly equivalent to the bits discussed
-   in ../afl-as.h.
+   This library is plugged into LLVM when invoking clang through afl-clang-lto.
 
  */
 
@@ -32,11 +25,12 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <sys/time.h>
 
 #include <list>
 #include <string>
 #include <fstream>
-#include <sys/time.h>
+#include <set>
 
 #include "llvm/Config/llvm-config.h"
 #include "llvm/ADT/Statistic.h"
@@ -56,7 +50,6 @@
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/Pass.h"
 
-#include <set>
 #include "afl-llvm-common.h"
 
 using namespace llvm;
@@ -90,27 +83,11 @@ class AFLLTOPass : public ModulePass {
 
   }
 
-  // Calculate the number of average collisions that would occur if all
-  // location IDs would be assigned randomly (like normal afl/afl++).
-  // This uses the "balls in bins" algorithm.
-  unsigned long long int calculateCollisions(uint32_t edges) {
-
-    double                 bins = MAP_SIZE;
-    double                 balls = edges;
-    double                 step1 = 1 - (1 / bins);
-    double                 step2 = pow(step1, balls);
-    double                 step3 = bins * step2;
-    double                 step4 = round(step3);
-    unsigned long long int empty = step4;
-    unsigned long long int collisions = edges - (MAP_SIZE - empty);
-    return collisions;
-
-  }
-
   bool runOnModule(Module &M) override;
 
  protected:
   int      afl_global_id = 1, debug = 0, autodictionary = 0;
+  uint32_t function_minimum_size = 1;
   uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
   uint64_t map_addr = 0x10000;
   char *   skip_nozero = NULL;
@@ -131,8 +108,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
   IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
   IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
 
-  if (getenv("AFL_DEBUG")) debug = 1;
-
   /* Show a banner */
 
   if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
@@ -150,6 +125,10 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
   if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
 
+  if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
+      getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
+    function_minimum_size = 2;
+
   if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
 
     uint64_t val;
@@ -185,12 +164,10 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
   if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); }
 
-  /* Get globals for the SHM region and the previous location. Note that
-     __afl_prev_loc is thread-local. */
+  /* Get/set the globals for the SHM region. */
 
   GlobalVariable *AFLMapPtr = NULL;
-  ;
-  Value *MapPtrFixed = NULL;
+  Value *         MapPtrFixed = NULL;
 
   if (!map_addr) {
 
@@ -217,7 +194,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     // fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str());
 
-    if (F.size() < 2) continue;
+    if (F.size() < function_minimum_size) continue;
     if (isBlacklisted(&F)) continue;
 
     std::vector<BasicBlock *> InsBlocks;
@@ -354,11 +331,15 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
                 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
-                  if (auto *Array =
-                          dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+                  if (Var->hasInitializer()) {
+
+                    if (auto *Array = dyn_cast<ConstantDataArray>(
+                            Var->getInitializer())) {
 
-                    HasStr2 = true;
-                    Str2 = Array->getAsString().str();
+                      HasStr2 = true;
+                      Str2 = Array->getAsString().str();
+
+                    }
 
                   }
 
@@ -426,11 +407,15 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
                 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
-                  if (auto *Array =
-                          dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+                  if (Var->hasInitializer()) {
+
+                    if (auto *Array = dyn_cast<ConstantDataArray>(
+                            Var->getInitializer())) {
+
+                      HasStr1 = true;
+                      Str1 = Array->getAsString().str();
 
-                    HasStr1 = true;
-                    Str1 = Array->getAsString().str();
+                    }
 
                   }
 
diff --git a/llvm_mode/afl-llvm-lto-whitelist.so.cc b/llvm_mode/afl-llvm-lto-whitelist.so.cc
index 5e157472..a116c4ea 100644
--- a/llvm_mode/afl-llvm-lto-whitelist.so.cc
+++ b/llvm_mode/afl-llvm-lto-whitelist.so.cc
@@ -111,7 +111,7 @@ bool AFLwhitelist::runOnModule(Module &M) {
 
   char be_quiet = 0;
 
-  if (isatty(2) && !getenv("AFL_QUIET")) {
+  if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
 
     SAYF(cCYA "afl-llvm-lto-whitelist" VERSION cRST
               " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc
index 0d9e0aba..2d23ad21 100644
--- a/llvm_mode/afl-llvm-pass.so.cc
+++ b/llvm_mode/afl-llvm-pass.so.cc
@@ -84,6 +84,7 @@ class AFLCoverage : public ModulePass {
   uint32_t ngram_size = 0;
   uint32_t debug = 0;
   uint32_t map_size = MAP_SIZE;
+  uint32_t function_minimum_size = 1;
   char *   ctx_str = NULL, *skip_nozero = NULL;
 
 };
@@ -182,6 +183,10 @@ 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");
@@ -294,13 +299,15 @@ bool AFLCoverage::runOnModule(Module &M) {
 
     if (!isInWhitelist(&F)) continue;
 
+    if (F.size() < function_minimum_size) continue;
+
     for (auto &BB : F) {
 
       BasicBlock::iterator IP = BB.getFirstInsertionPt();
       IRBuilder<>          IRB(&(*IP));
 
       // Context sensitive coverage
-      if (ctx_str && &BB == &F.getEntryBlock() && F.size() > 1) {
+      if (ctx_str && &BB == &F.getEntryBlock()) {
 
         // load the context ID of the previous function and write to to a local
         // variable on the stack
@@ -318,7 +325,7 @@ bool AFLCoverage::runOnModule(Module &M) {
             if ((callInst = dyn_cast<CallInst>(&IN))) {
 
               Function *Callee = callInst->getCalledFunction();
-              if (!Callee || Callee->size() < 2)
+              if (!Callee || Callee->size() < function_minimum_size)
                 continue;
               else {
 
@@ -389,11 +396,11 @@ bool AFLCoverage::runOnModule(Module &M) {
       }
 
       // fprintf(stderr, " == %d\n", more_than_one);
-      if (more_than_one != 1) {
+      if (F.size() > 1 && more_than_one != 1) {
 
         // in CTX mode we have to restore the original context for the caller -
         // she might be calling other functions which need the correct CTX
-        if (ctx_str && has_calls && F.size() > 1) {
+        if (ctx_str && has_calls) {
 
           Instruction *Inst = BB.getTerminator();
           if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
@@ -526,7 +533,7 @@ bool AFLCoverage::runOnModule(Module &M) {
       // in CTX mode we have to restore the original context for the caller -
       // she might be calling other functions which need the correct CTX.
       // Currently this is only needed for the Ubuntu clang-6.0 bug
-      if (ctx_str && has_calls && F.size() > 1) {
+      if (ctx_str && has_calls) {
 
         Instruction *Inst = BB.getTerminator();
         if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
diff --git a/llvm_mode/afl-llvm-rt-lto.o.c b/llvm_mode/afl-llvm-rt-lto.o.c
index 5921f968..e53785ff 100644
--- a/llvm_mode/afl-llvm-rt-lto.o.c
+++ b/llvm_mode/afl-llvm-rt-lto.o.c
@@ -10,6 +10,9 @@
 
 */
 
+#include <stdio.h>
+#include <stdlib.h>
+
 // to prevent the function from being removed
 unsigned char __afl_lto_mode = 0;
 
@@ -17,6 +20,7 @@ unsigned char __afl_lto_mode = 0;
 
 __attribute__((constructor(0))) void __afl_auto_init_globals(void) {
 
+  if (getenv("AFL_DEBUG")) fprintf(stderr, "[__afl_auto_init_globals]\n");
   __afl_lto_mode = 1;
 
 }
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 56038f7a..ce8df332 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -63,7 +63,11 @@
    is used for instrumentation output before __afl_map_shm() has a chance to
    run. It will end up as .comm, so it shouldn't be too wasteful. */
 
-u8  __afl_area_initial[MAP_SIZE];
+#ifdef AFL_REAL_LD
+u8 __afl_area_initial[256000];
+#else
+u8                  __afl_area_initial[MAP_SIZE];
+#endif
 u8 *__afl_area_ptr = __afl_area_initial;
 u8 *__afl_dictionary;
 
diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc
index 2111b646..00732dbc 100644
--- a/llvm_mode/compare-transform-pass.so.cc
+++ b/llvm_mode/compare-transform-pass.so.cc
@@ -506,7 +506,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
 bool CompareTransform::runOnModule(Module &M) {
 
-  if (isatty(2) && getenv("AFL_QUIET") == NULL)
+  if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
     llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, "
                     "extended by heiko@hexco.de\n";
   else
diff --git a/llvm_mode/split-switches-pass.so.cc b/llvm_mode/split-switches-pass.so.cc
index 3444d6a1..e8639347 100644
--- a/llvm_mode/split-switches-pass.so.cc
+++ b/llvm_mode/split-switches-pass.so.cc
@@ -418,7 +418,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
 
 bool SplitSwitchesTransform::runOnModule(Module &M) {
 
-  if (isatty(2) && getenv("AFL_QUIET") == NULL)
+  if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
     llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n";
   else
     be_quiet = 1;
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 1b6690c6..bd18927f 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -163,6 +163,8 @@ fi
 
 cd qemu-$VERSION || exit 1
 
+echo Building for CPU target $CPU_TARGET
+
 echo "[*] Applying patches..."
 
 patch -p1 <../patches/elfload.diff || exit 1
@@ -188,6 +190,7 @@ echo "[+] Patching done."
 
 if [ "$STATIC" = "1" ]; then
 
+  echo Building STATIC binary
   ./configure --extra-cflags="-O3 -ggdb -DAFL_QEMU_STATIC_BUILD=1" \
      --disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \
 	  --disable-gcrypt --disable-debug-info --disable-debug-tcg --disable-tcg-interpreter \
diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h
index 6e9ddc3b..78a8f800 100644
--- a/qemu_mode/patches/afl-qemu-cpu-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-inl.h
@@ -123,12 +123,11 @@ struct afl_chain {
 
 /* Some forward decls: */
 
-TranslationBlock *tb_htable_lookup(CPUState *, target_ulong, target_ulong,
-                                   uint32_t, uint32_t);
 static inline TranslationBlock *tb_find(CPUState *, TranslationBlock *, int,
                                         uint32_t);
 static inline void              tb_add_jump(TranslationBlock *tb, int n,
                                             TranslationBlock *tb_next);
+int                             open_self_maps(void *cpu_env, int fd);
 
 /*************************
  * ACTUAL IMPLEMENTATION *
diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
index 014471ca..2e740ad9 100644
--- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
@@ -35,7 +35,7 @@
 #include "tcg.h"
 #include "tcg-op.h"
 
-#if TCG_TARGET_LONG_BITS == 64
+#if TCG_TARGET_REG_BITS == 64
 #define _DEFAULT_MO MO_64
 #else
 #define _DEFAULT_MO MO_32
diff --git a/qemu_mode/patches/syscall.diff b/qemu_mode/patches/syscall.diff
index b8c5ff39..b635a846 100644
--- a/qemu_mode/patches/syscall.diff
+++ b/qemu_mode/patches/syscall.diff
@@ -43,16 +43,17 @@ index b13a170e..3f5cc902 100644
              ts = (TaskState *)cpu->opaque;
              if (flags & CLONE_SETTLS)
                  cpu_set_tls (env, newtls);
-@@ -6554,7 +6558,7 @@ static int open_self_cmdline(void *cpu_env, int fd)
+@@ -6554,7 +6558,8 @@ static int open_self_cmdline(void *cpu_env, int fd)
      return 0;
  }
  
 -static int open_self_maps(void *cpu_env, int fd)
++int open_self_maps(void *cpu_env, int fd);
 +int open_self_maps(void *cpu_env, int fd)
  {
      CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
      TaskState *ts = cpu->opaque;
-@@ -7324,10 +7328,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
+@@ -7324,10 +7329,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
  #ifdef TARGET_NR_stime /* not on alpha */
      case TARGET_NR_stime:
          {
@@ -68,7 +69,7 @@ index b13a170e..3f5cc902 100644
          }
  #endif
  #ifdef TARGET_NR_alarm /* not on alpha */
-@@ -10529,7 +10535,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
+@@ -10529,7 +10536,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
          return TARGET_PAGE_SIZE;
  #endif
      case TARGET_NR_gettid:
@@ -77,7 +78,7 @@ index b13a170e..3f5cc902 100644
  #ifdef TARGET_NR_readahead
      case TARGET_NR_readahead:
  #if TARGET_ABI_BITS == 32
-@@ -10813,8 +10819,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
+@@ -10813,8 +10820,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
          return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
  
      case TARGET_NR_tgkill:
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 8f48b1d0..4e973672 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -723,7 +723,7 @@ static void set_up_environment(void) {
 
     }
 
-    prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, getpid());
+    prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
 
   }
 
diff --git a/src/afl-as.c b/src/afl-as.c
index 486a6afa..cf7f8bb6 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -233,7 +233,7 @@ static void edit_params(int argc, char **argv) {
   }
 
   modified_file =
-      alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(), (u32)time(NULL));
+      alloc_printf("%s/.afl-%u-%u.s", tmp_dir, (u32)getpid(), (u32)time(NULL));
 
 wrap_things_up:
 
diff --git a/src/afl-common.c b/src/afl-common.c
index 54b2e790..d9d57863 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -64,15 +64,15 @@ char *afl_environment_variables[] = {
     "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM",
     "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD",
     "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",
-    "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES",
-    "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS",
-    "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES",
-    "AFL_LLVM_MAP_ADDR", "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE",
-    "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST",
-    "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID",
-    "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN",
-    "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON",
-    "AFL_UNTRACER_FILE",
+    "AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK",
+    "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
+    "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES",
+    "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR",
+    "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE",
+    "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO",
+    "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID",
+    "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV",
+    "AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE",
     "AFL_NO_X86",  // not really an env but we dont want to warn on it
     "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE",
     //"AFL_PERSISTENT", // not implemented anymore, so warn additionally
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 2289183c..d4966889 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -437,13 +437,13 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
 
     sprintf(ret, "src:%06u", afl->current_entry);
 
-    sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
-
     if (afl->splicing_with >= 0) {
 
       sprintf(ret + strlen(ret), "+%06d", afl->splicing_with);
 
     }
+    
+    sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
 
     sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index beb89092..027add49 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -26,27 +26,55 @@
 
 #include "afl-fuzz.h"
 
-void load_custom_mutator(afl_state_t *, const char *);
+struct custom_mutator *load_custom_mutator(afl_state_t *, const char *);
+#ifdef USE_PYTHON
+struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
+#endif
 
-void setup_custom_mutator(afl_state_t *afl) {
+void setup_custom_mutators(afl_state_t *afl) {
 
   /* Try mutator library first */
-  u8 *fn = afl->afl_env.afl_custom_mutator_library;
+  struct custom_mutator *mutator;
+  u8 *                   fn = afl->afl_env.afl_custom_mutator_library;
+  u32                    prev_mutator_count = 0;
 
   if (fn) {
 
-    if (afl->limit_time_sig) {
-
+    if (afl->limit_time_sig)
       FATAL(
           "MOpt and custom mutator are mutually exclusive. We accept pull "
           "requests that integrates MOpt with the optional mutators "
-          "(custom/radamsa/redquenn/...).");
+          "(custom/radamsa/redqueen/...).");
 
-    }
+    u8 *fn_token = (u8 *)strsep((char **)&fn, ";:,");
+
+    if (likely(!fn_token)) {
 
-    load_custom_mutator(afl, fn);
+      mutator = load_custom_mutator(afl, fn);
+      list_append(&afl->custom_mutator_list, mutator);
+      afl->custom_mutators_count++;
 
-    return;
+    } else {
+
+      while (fn_token) {
+
+        if (*fn_token) {  // strsep can be empty if ";;"
+
+          if (afl->not_on_tty && afl->debug)
+            SAYF("[Custom] Processing: %s\n", fn_token);
+          prev_mutator_count = afl->custom_mutators_count;
+          mutator = load_custom_mutator(afl, fn_token);
+          list_append(&afl->custom_mutator_list, mutator);
+          afl->custom_mutators_count++;
+          if (prev_mutator_count > afl->custom_mutators_count)
+            FATAL("Maximum Custom Mutator count reached.");
+          fn_token = (u8 *)strsep((char **)&fn, ";:,");
+
+        }
+
+      }
+
+    }
 
   }
 
@@ -65,7 +93,9 @@ void setup_custom_mutator(afl_state_t *afl) {
 
     }
 
-    load_custom_mutator_py(afl, module_name);
+    struct custom_mutator *mutator = load_custom_mutator_py(afl, module_name);
+    afl->custom_mutators_count++;
+    list_append(&afl->custom_mutator_list, mutator);
 
   }
 
@@ -80,114 +110,87 @@ void setup_custom_mutator(afl_state_t *afl) {
 
 }
 
-void destroy_custom_mutator(afl_state_t *afl) {
+void destroy_custom_mutators(afl_state_t *afl) {
 
-  if (afl->mutator) {
+  if (afl->custom_mutators_count) {
 
-    afl->mutator->afl_custom_deinit(afl->mutator->data);
+    LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, {
 
-    if (afl->mutator->dh) { dlclose(afl->mutator->dh); }
+      if (!el->data) { FATAL("Deintializing NULL mutator"); }
+      el->afl_custom_deinit(el->data);
+      if (el->dh) dlclose(el->dh);
 
-    if (afl->mutator->pre_save_buf) {
+      if (el->pre_save_buf) {
 
-      ck_free(afl->mutator->pre_save_buf);
-      afl->mutator->pre_save_buf = NULL;
-      afl->mutator->pre_save_size = 0;
+        ck_free(el->pre_save_buf);
+        el->pre_save_buf = NULL;
+        el->pre_save_size = 0;
 
-    }
+      }
 
-    ck_free(afl->mutator);
-    afl->mutator = NULL;
+      ck_free(el);
+
+    });
 
   }
 
 }
 
-void load_custom_mutator(afl_state_t *afl, const char *fn) {
+struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
 
-  void *dh;
-  afl->mutator = ck_alloc(sizeof(struct custom_mutator));
-  afl->mutator->pre_save_buf = NULL;
-  afl->mutator->pre_save_size = 0;
+  void *                 dh;
+  struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
 
-  afl->mutator->name = fn;
+  mutator->name = fn;
   ACTF("Loading custom mutator library from '%s'...", fn);
 
   dh = dlopen(fn, RTLD_NOW);
-  if (!dh) { FATAL("%s", dlerror()); }
-  afl->mutator->dh = dh;
+  if (!dh) FATAL("%s", dlerror());
+  mutator->dh = dh;
 
   /* Mutator */
-  /* "afl_custom_init", required */
-  afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
-  if (!afl->mutator->afl_custom_init) {
-
-    FATAL("Symbol 'afl_custom_init' not found.");
-
-  }
-
-  /* "afl_custom_deinit", required */
-  afl->mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
-  if (!afl->mutator->afl_custom_deinit) {
-
-    FATAL("Symbol 'afl_custom_deinit' not found.");
-
-  }
+  /* "afl_custom_init", optional for backward compatibility */
+  mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
+  if (!mutator->afl_custom_init) WARNF("Symbol 'afl_custom_init' not found.");
 
   /* "afl_custom_fuzz" or "afl_custom_mutator", required */
-  afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
-  if (!afl->mutator->afl_custom_fuzz) {
+  mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
+  if (!mutator->afl_custom_fuzz) {
 
     /* Try "afl_custom_mutator" for backward compatibility */
     WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
 
-    afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
-    if (!afl->mutator->afl_custom_fuzz) {
-
+    mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
+    if (!mutator->afl_custom_fuzz)
       FATAL("Symbol 'afl_custom_mutator' not found.");
 
-    }
-
   }
 
   /* "afl_custom_pre_save", optional */
-  afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save");
-  if (!afl->mutator->afl_custom_pre_save) {
-
+  mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save");
+  if (!mutator->afl_custom_pre_save)
     WARNF("Symbol 'afl_custom_pre_save' not found.");
 
-  }
-
   u8 notrim = 0;
   /* "afl_custom_init_trim", optional */
-  afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
-  if (!afl->mutator->afl_custom_init_trim) {
-
+  mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
+  if (!mutator->afl_custom_init_trim)
     WARNF("Symbol 'afl_custom_init_trim' not found.");
 
-  }
-
   /* "afl_custom_trim", optional */
-  afl->mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
-  if (!afl->mutator->afl_custom_trim) {
-
-    WARNF("Symbol 'afl_custom_trim' not found.");
-
-  }
+  mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
+  if (!mutator->afl_custom_trim) WARNF("Symbol 'afl_custom_trim' not found.");
 
   /* "afl_custom_post_trim", optional */
-  afl->mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
-  if (!afl->mutator->afl_custom_post_trim) {
-
+  mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
+  if (!mutator->afl_custom_post_trim)
     WARNF("Symbol 'afl_custom_post_trim' not found.");
 
-  }
-
   if (notrim) {
 
-    afl->mutator->afl_custom_init_trim = NULL;
-    afl->mutator->afl_custom_trim = NULL;
-    afl->mutator->afl_custom_post_trim = NULL;
+    mutator->afl_custom_init_trim = NULL;
+    mutator->afl_custom_trim = NULL;
+    mutator->afl_custom_post_trim = NULL;
     WARNF(
         "Custom mutator does not implement all three trim APIs, standard "
         "trimming will be used.");
@@ -195,53 +198,42 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) {
   }
 
   /* "afl_custom_havoc_mutation", optional */
-  afl->mutator->afl_custom_havoc_mutation =
-      dlsym(dh, "afl_custom_havoc_mutation");
-  if (!afl->mutator->afl_custom_havoc_mutation) {
-
+  mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
+  if (!mutator->afl_custom_havoc_mutation)
     WARNF("Symbol 'afl_custom_havoc_mutation' not found.");
 
-  }
-
   /* "afl_custom_havoc_mutation", optional */
-  afl->mutator->afl_custom_havoc_mutation_probability =
+  mutator->afl_custom_havoc_mutation_probability =
       dlsym(dh, "afl_custom_havoc_mutation_probability");
-  if (!afl->mutator->afl_custom_havoc_mutation_probability) {
-
+  if (!mutator->afl_custom_havoc_mutation_probability)
     WARNF("Symbol 'afl_custom_havoc_mutation_probability' not found.");
 
-  }
-
   /* "afl_custom_queue_get", optional */
-  afl->mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
-  if (!afl->mutator->afl_custom_queue_get) {
-
+  mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
+  if (!mutator->afl_custom_queue_get)
     WARNF("Symbol 'afl_custom_queue_get' not found.");
 
-  }
-
   /* "afl_custom_queue_new_entry", optional */
-  afl->mutator->afl_custom_queue_new_entry =
-      dlsym(dh, "afl_custom_queue_new_entry");
-  if (!afl->mutator->afl_custom_queue_new_entry) {
-
+  mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
+  if (!mutator->afl_custom_queue_new_entry)
     WARNF("Symbol 'afl_custom_queue_new_entry' not found");
 
-  }
-
   OKF("Custom mutator '%s' installed successfully.", fn);
 
   /* Initialize the custom mutator */
-  if (afl->mutator->afl_custom_init) {
+  if (mutator->afl_custom_init)
+    mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
 
-    afl->mutator->data =
-        afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
+  mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
+  mutator->stacked_custom_prob =
+      6;  // like one of the default mutations in havoc
 
-  }
+  return mutator;
 
 }
 
-u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
+u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
+                    struct custom_mutator *mutator) {
 
   u8  needs_write = 0, fault = 0;
   u32 trim_exec = 0;
@@ -254,8 +246,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
   /* Initialize trimming in the custom mutator */
   afl->stage_cur = 0;
-  afl->stage_max =
-      afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len);
+  afl->stage_max = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len);
   if (unlikely(afl->stage_max) < 0) {
 
     FATAL("custom_init_trim error ret: %d", afl->stage_max);
@@ -278,7 +269,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
     u32 cksum;
 
-    size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf);
+    size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf);
 
     if (unlikely(!retbuf)) {
 
@@ -318,8 +309,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
       }
 
       /* Tell the custom mutator that the trimming was successful */
-      afl->stage_cur =
-          afl->mutator->afl_custom_post_trim(afl->mutator->data, 1);
+      afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
 
       if (afl->not_on_tty && afl->debug) {
 
@@ -331,8 +321,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
     } else {
 
       /* Tell the custom mutator that the trimming was unsuccessful */
-      afl->stage_cur =
-          afl->mutator->afl_custom_post_trim(afl->mutator->data, 0);
+      afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 0);
       if (unlikely(afl->stage_cur < 0)) {
 
         FATAL("Error ret in custom_post_trim: %d", afl->stage_cur);
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 6d399a03..ddd15c84 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -384,16 +384,20 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
 #else
 
-  if (unlikely(afl->mutator) && unlikely(afl->mutator->afl_custom_queue_get)) {
+  if (unlikely(afl->custom_mutators_count)) {
 
     /* The custom mutator will decide to skip this test case or not. */
 
-    if (!afl->mutator->afl_custom_queue_get(afl->mutator->data,
-                                            afl->queue_cur->fname)) {
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
-      return 1;
+      if (el->afl_custom_queue_get &&
+          !el->afl_custom_queue_get(el->data, afl->queue_cur->fname)) {
 
-    }
+        return 1;
+
+      }
+
+    });
 
   }
 
@@ -1646,13 +1650,13 @@ custom_mutator_stage:
    * CUSTOM MUTATORS *
    *******************/
 
-  if (likely(!afl->mutator)) { goto havoc_stage; }
-  if (likely(!afl->mutator->afl_custom_fuzz)) { goto havoc_stage; }
+  if (likely(!afl->custom_mutators_count)) { goto havoc_stage; }
 
   afl->stage_name = "custom mutator";
   afl->stage_short = "custom";
   afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100;
   afl->stage_val_type = STAGE_VAL_NONE;
+  bool has_custom_fuzz = false;
 
   if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
 
@@ -1660,98 +1664,112 @@ custom_mutator_stage:
 
   orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
-  for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
+  LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
-    struct queue_entry *target;
-    u32                 tid;
-    u8 *                new_buf;
+    if (el->afl_custom_fuzz) {
 
-  retry_external_pick:
-    /* Pick a random other queue entry for passing to external API */
-    do {
+      has_custom_fuzz = true;
 
-      tid = rand_below(afl, afl->queued_paths);
+      for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
+           ++afl->stage_cur) {
 
-    } while (tid == afl->current_entry && afl->queued_paths > 1);
+        struct queue_entry *target;
+        u32                 tid;
+        u8 *                new_buf;
 
-    target = afl->queue;
+      retry_external_pick:
+        /* Pick a random other queue entry for passing to external API */
+        do {
 
-    while (tid >= 100) {
+          tid = rand_below(afl, afl->queued_paths);
 
-      target = target->next_100;
-      tid -= 100;
+        } while (tid == afl->current_entry && afl->queued_paths > 1);
 
-    }
+        target = afl->queue;
 
-    while (tid--) {
+        while (tid >= 100) {
 
-      target = target->next;
+          target = target->next_100;
+          tid -= 100;
 
-    }
+        }
 
-    /* Make sure that the target has a reasonable length. */
+        while (tid--) {
 
-    while (target && (target->len < 2 || target == afl->queue_cur) &&
-           afl->queued_paths > 1) {
+          target = target->next;
 
-      target = target->next;
-      ++afl->splicing_with;
+        }
 
-    }
+        /* Make sure that the target has a reasonable length. */
 
-    if (!target) { goto retry_external_pick; }
+        while (target && (target->len < 2 || target == afl->queue_cur) &&
+               afl->queued_paths > 1) {
 
-    /* Read the additional testcase into a new buffer. */
-    fd = open(target->fname, O_RDONLY);
-    if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); }
+          target = target->next;
+          ++afl->splicing_with;
 
-    new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len);
-    ck_read(fd, new_buf, target->len, target->fname);
-    close(fd);
+        }
 
-    u8 *mutated_buf = NULL;
+        if (!target) { goto retry_external_pick; }
 
-    size_t mutated_size = afl->mutator->afl_custom_fuzz(
-        afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len,
-        max_seed_size);
+        /* Read the additional testcase into a new buffer. */
+        fd = open(target->fname, O_RDONLY);
+        if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); }
 
-    if (unlikely(!mutated_buf)) {
+        new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len);
+        ck_read(fd, new_buf, target->len, target->fname);
+        close(fd);
 
-      FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
+        u8 *mutated_buf = NULL;
 
-    }
+        size_t mutated_size =
+            el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
+                                target->len, max_seed_size);
 
-    if (mutated_size > 0) {
+        if (unlikely(!mutated_buf)) {
 
-      if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
+          FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
 
-        goto abandon_entry;
+        }
 
-      }
+        if (mutated_size > 0) {
+
+          if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
+
+            goto abandon_entry;
+
+          }
 
-      /* If we're finding new stuff, let's run for a bit longer, limits
-         permitting. */
+          /* If we're finding new stuff, let's run for a bit longer, limits
+            permitting. */
 
-      if (afl->queued_paths != havoc_queued) {
+          if (afl->queued_paths != havoc_queued) {
 
-        if (perf_score <= afl->havoc_max_mult * 100) {
+            if (perf_score <= afl->havoc_max_mult * 100) {
 
-          afl->stage_max *= 2;
-          perf_score *= 2;
+              afl->stage_max *= 2;
+              perf_score *= 2;
+
+            }
+
+            havoc_queued = afl->queued_paths;
+
+          }
 
         }
 
-        havoc_queued = afl->queued_paths;
+        /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */
+        /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy.
+         */
+        memcpy(out_buf, in_buf, len);
 
       }
 
     }
 
-    /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */
-    /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy. */
-    memcpy(out_buf, in_buf, len);
+  });
 
-  }
+  if (!has_custom_fuzz) goto havoc_stage;
 
   new_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
@@ -1803,20 +1821,26 @@ havoc_stage:
 
   havoc_queued = afl->queued_paths;
 
-  u8 stacked_custom = (afl->mutator && afl->mutator->afl_custom_havoc_mutation);
-  u8 stacked_custom_prob = 6;  // like one of the default mutations in havoc
+  if (afl->custom_mutators_count) {
 
-  if (stacked_custom && afl->mutator->afl_custom_havoc_mutation_probability) {
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
-    stacked_custom_prob =
-        afl->mutator->afl_custom_havoc_mutation_probability(afl->mutator->data);
-    if (stacked_custom_prob > 100) {
+      if (el->stacked_custom && el->afl_custom_havoc_mutation_probability) {
 
-      FATAL(
-          "The probability returned by afl_custom_havoc_mutation_propability "
-          "has to be in the range 0-100.");
+        el->stacked_custom_prob =
+            el->afl_custom_havoc_mutation_probability(el->data);
+        if (el->stacked_custom_prob > 100) {
 
-    }
+          FATAL(
+              "The probability returned by "
+              "afl_custom_havoc_mutation_propability "
+              "has to be in the range 0-100.");
+
+        }
+
+      }
+
+    });
 
   }
 
@@ -1831,28 +1855,37 @@ havoc_stage:
 
     for (i = 0; i < use_stacking; ++i) {
 
-      if (stacked_custom && rand_below(afl, 100) < stacked_custom_prob) {
+      if (afl->custom_mutators_count) {
 
-        u8 *   custom_havoc_buf = NULL;
-        size_t new_len = afl->mutator->afl_custom_havoc_mutation(
-            afl->mutator->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE);
-        if (unlikely(!custom_havoc_buf)) {
+        LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
-          FATAL("Error in custom_havoc (return %zd)", new_len);
+          if (el->stacked_custom &&
+              rand_below(afl, 100) < el->stacked_custom_prob) {
 
-        }
+            u8 *   custom_havoc_buf = NULL;
+            size_t new_len = el->afl_custom_havoc_mutation(
+                el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE);
+            if (unlikely(!custom_havoc_buf)) {
+
+              FATAL("Error in custom_havoc (return %zd)", new_len);
 
-        if (likely(new_len > 0 && custom_havoc_buf)) {
+            }
 
-          temp_len = new_len;
-          if (out_buf != custom_havoc_buf) {
+            if (likely(new_len > 0 && custom_havoc_buf)) {
 
-            ck_maybe_grow(BUF_PARAMS(out), temp_len);
-            memcpy(out_buf, custom_havoc_buf, temp_len);
+              temp_len = new_len;
+              if (out_buf != custom_havoc_buf) {
+
+                ck_maybe_grow(BUF_PARAMS(out), temp_len);
+                memcpy(out_buf, custom_havoc_buf, temp_len);
+
+              }
+
+            }
 
           }
 
-        }
+        });
 
       }
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 64cabcad..832dba06 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -71,7 +71,7 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
 
   PyTuple_SetItem(py_args, 1, py_value);
 
-  /* max_size */
+/* max_size */
 #if PY_MAJOR_VERSION >= 3
   py_value = PyLong_FromLong(max_size);
 #else
@@ -295,80 +295,75 @@ void deinit_py(void *py_mutator) {
 
 }
 
-void load_custom_mutator_py(afl_state_t *afl, char *module_name) {
+struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
+                                              char *       module_name) {
 
-  afl->mutator = ck_alloc(sizeof(struct custom_mutator));
-  afl->mutator->pre_save_buf = NULL;
-  afl->mutator->pre_save_size = 0;
+  struct custom_mutator *mutator;
 
-  afl->mutator->name = module_name;
+  mutator = ck_alloc(sizeof(struct custom_mutator));
+  mutator->pre_save_buf = NULL;
+  mutator->pre_save_size = 0;
+
+  mutator->name = module_name;
   ACTF("Loading Python mutator library from '%s'...", module_name);
 
   py_mutator_t *py_mutator;
   py_mutator = init_py_module(afl, module_name);
-  afl->mutator->data = py_mutator;
+  mutator->data = py_mutator;
   if (!py_mutator) { FATAL("Failed to load python mutator."); }
 
   PyObject **py_functions = py_mutator->py_functions;
 
-  if (py_functions[PY_FUNC_INIT]) {
-
-    afl->mutator->afl_custom_init = unsupported;
-
-  }
-
-  if (py_functions[PY_FUNC_DEINIT]) {
-
-    afl->mutator->afl_custom_deinit = deinit_py;
+  if (py_functions[PY_FUNC_INIT]) { mutator->afl_custom_init = unsupported; }
 
-  }
+  if (py_functions[PY_FUNC_DEINIT]) { mutator->afl_custom_deinit = deinit_py; }
 
   /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
      is quite different from the custom mutator. */
-  afl->mutator->afl_custom_fuzz = fuzz_py;
+  mutator->afl_custom_fuzz = fuzz_py;
 
   if (py_functions[PY_FUNC_PRE_SAVE]) {
 
-    afl->mutator->afl_custom_pre_save = pre_save_py;
+    mutator->afl_custom_pre_save = pre_save_py;
 
   }
 
   if (py_functions[PY_FUNC_INIT_TRIM]) {
 
-    afl->mutator->afl_custom_init_trim = init_trim_py;
+    mutator->afl_custom_init_trim = init_trim_py;
 
   }
 
   if (py_functions[PY_FUNC_POST_TRIM]) {
 
-    afl->mutator->afl_custom_post_trim = post_trim_py;
+    mutator->afl_custom_post_trim = post_trim_py;
 
   }
 
-  if (py_functions[PY_FUNC_TRIM]) { afl->mutator->afl_custom_trim = trim_py; }
+  if (py_functions[PY_FUNC_TRIM]) { mutator->afl_custom_trim = trim_py; }
 
   if (py_functions[PY_FUNC_HAVOC_MUTATION]) {
 
-    afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py;
+    mutator->afl_custom_havoc_mutation = havoc_mutation_py;
 
   }
 
   if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]) {
 
-    afl->mutator->afl_custom_havoc_mutation_probability =
+    mutator->afl_custom_havoc_mutation_probability =
         havoc_mutation_probability_py;
 
   }
 
   if (py_functions[PY_FUNC_QUEUE_GET]) {
 
-    afl->mutator->afl_custom_queue_get = queue_get_py;
+    mutator->afl_custom_queue_get = queue_get_py;
 
   }
 
   if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) {
 
-    afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py;
+    mutator->afl_custom_queue_new_entry = queue_new_entry_py;
 
   }
 
@@ -377,6 +372,8 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) {
   /* Initialize the custom mutator */
   init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF));
 
+  return mutator;
+
 }
 
 size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) {
@@ -545,7 +542,7 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
 
   PyTuple_SetItem(py_args, 0, py_value);
 
-  /* max_size */
+/* max_size */
 #if PY_MAJOR_VERSION >= 3
   py_value = PyLong_FromLong(max_size);
 #else
@@ -627,7 +624,7 @@ u8 queue_get_py(void *py_mutator, const u8 *filename) {
 
   py_args = PyTuple_New(1);
 
-  // File name
+// File name
 #if PY_MAJOR_VERSION >= 3
   py_value = PyUnicode_FromString(filename);
 #else
@@ -677,7 +674,7 @@ void queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
 
   py_args = PyTuple_New(2);
 
-  // New queue
+// New queue
 #if PY_MAJOR_VERSION >= 3
   py_value = PyUnicode_FromString(filename_new_queue);
 #else
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index f998c06b..cfeb6c5e 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -140,15 +140,22 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   afl->last_path_time = get_cur_time();
 
-  if (afl->mutator && afl->mutator->afl_custom_queue_new_entry) {
+  if (afl->custom_mutators_count) {
 
-    u8 *fname_orig = NULL;
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
-    /* At the initialization stage, queue_cur is NULL */
-    if (afl->queue_cur) { fname_orig = afl->queue_cur->fname; }
+      if (el->afl_custom_queue_new_entry) {
 
-    afl->mutator->afl_custom_queue_new_entry(afl->mutator->data, fname,
-                                             fname_orig);
+        u8 *fname_orig = NULL;
+
+        /* At the initialization stage, queue_cur is NULL */
+        if (afl->queue_cur) fname_orig = afl->queue_cur->fname;
+
+        el->afl_custom_queue_new_entry(el->data, fname, fname_orig);
+
+      }
+
+    });
 
   }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 692026d4..4a22dad6 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -30,13 +30,37 @@
 
 #include "cmplog.h"
 
+#ifdef PROFILING
+u64 time_spent_working = 0;
+#endif
+
 /* Execute target application, monitoring for timeouts. Return status
    information. The called program will update afl->fsrv->trace_bits. */
 
 fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
                                   u32 timeout) {
 
+#ifdef PROFILING
+  static u64      time_spent_start = 0;
+  struct timespec spec;
+  if (time_spent_start) {
+
+    u64 current;
+    clock_gettime(CLOCK_REALTIME, &spec);
+    current = (spec.tv_sec * 1000000000) + spec.tv_nsec;
+    time_spent_working += (current - time_spent_start);
+
+  }
+
+#endif
+
   fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+
+#ifdef PROFILING
+  clock_gettime(CLOCK_REALTIME, &spec);
+  time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec;
+#endif
+
   // TODO: Don't classify for faults?
   classify_counts(fsrv);
   return res;
@@ -65,21 +89,40 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
 
 #endif
 
-  if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) {
+  if (unlikely(afl->custom_mutators_count)) {
+
+    u8 *    new_buf = NULL;
+    ssize_t new_size = len;
+    void *  new_mem = mem;
+
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+      if (el->afl_custom_pre_save) {
+
+        new_size =
+            el->afl_custom_pre_save(el->data, new_mem, new_size, &new_buf);
 
-    u8 *new_buf = NULL;
+      }
+
+      new_mem = new_buf;
 
-    size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem,
-                                                        len, &new_buf);
+    });
 
-    if (unlikely(!new_buf)) {
+    if (unlikely(!new_buf && (new_size <= 0))) {
 
       FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size);
 
-    }
+    } else if (likely(new_buf)) {
+
+      /* everything as planned. use the new data. */
+      afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size);
 
-    /* everything as planned. use the new data. */
-    afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size);
+    } else {
+
+      /* custom mutators do not has a custom_pre_save function */
+      afl_fsrv_write_to_testcase(&afl->fsrv, mem, len);
+
+    }
 
   } else {
 
@@ -489,9 +532,23 @@ void sync_fuzzers(afl_state_t *afl) {
 u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
   /* Custom mutator trimmer */
-  if (afl->mutator && afl->mutator->afl_custom_trim) {
+  if (afl->custom_mutators_count) {
+
+    u8   trimmed_case = 0;
+    bool custom_trimmed = false;
+
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+      if (el->afl_custom_trim) {
+
+        trimmed_case = trim_case_custom(afl, q, in_buf, el);
+        custom_trimmed = true;
+
+      }
+
+    });
 
-    return trim_case_custom(afl, q, in_buf);
+    if (custom_trimmed) return trimmed_case;
 
   }
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 3cbb2d8c..014ed34d 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -72,7 +72,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       "start_time        : %llu\n"
       "last_update       : %llu\n"
       "run_time          : %llu\n"
-      "fuzzer_pid        : %d\n"
+      "fuzzer_pid        : %u\n"
       "cycles_done       : %llu\n"
       "cycles_wo_finds   : %llu\n"
       "execs_done        : %llu\n"
@@ -106,7 +106,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       "target_mode       : %s%s%s%s%s%s%s%s\n"
       "command_line      : %s\n",
       afl->start_time / 1000, cur_time / 1000,
-      (cur_time - afl->start_time) / 1000, getpid(),
+      (cur_time - afl->start_time) / 1000, (u32)getpid(),
       afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
       afl->fsrv.total_execs,
       afl->fsrv.total_execs /
@@ -792,7 +792,7 @@ void show_stats(afl_state_t *afl) {
 
   }
 
-  if (afl->mutator) {
+  if (afl->custom_mutators_count) {
 
     sprintf(tmp, "%s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 5920f5c0..aaf615e9 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -27,6 +27,10 @@
 #include "cmplog.h"
 #include <limits.h>
 
+#ifdef PROFILING
+extern u64 time_spent_working;
+#endif
+
 static u8 *get_libradamsa_path(u8 *own_loc) {
 
   u8 *tmp, *cp, *rsl, *own_copy;
@@ -644,10 +648,7 @@ int main(int argc, char **argv_orig, char **envp) {
         }
 
         afl->limit_time_puppet = limit_time_puppet2;
-
-        SAYF("limit_time_puppet %d\n", afl->limit_time_puppet);
         afl->swarm_now = 0;
-
         if (afl->limit_time_puppet == 0) { afl->key_puppet = 1; }
 
         int i;
@@ -1073,7 +1074,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   setup_dirs_fds(afl);
 
-  setup_custom_mutator(afl);
+  setup_custom_mutators(afl);
 
   setup_cmdline_file(afl, argv + optind);
 
@@ -1351,10 +1352,17 @@ stop_fuzzing:
 
   }
 
+#ifdef PROFILING
+  SAYF(cYEL "[!] " cRST
+            "Profiling information: %llu ms total work, %llu ns/run\n",
+       time_spent_working / 1000000,
+       time_spent_working / afl->fsrv.total_execs);
+#endif
+
   fclose(afl->fsrv.plot_file);
   destroy_queue(afl);
   destroy_extras(afl);
-  destroy_custom_mutator(afl);
+  destroy_custom_mutators(afl);
   afl_shm_deinit(&afl->shm);
   afl_fsrv_deinit(&afl->fsrv);
   if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index a51d520d..ed59f2f5 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -865,7 +865,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    stdin_file = alloc_printf("%s/.afl-showmap-temp-%u", use_dir, getpid());
+    stdin_file =
+        alloc_printf("%s/.afl-showmap-temp-%u", use_dir, (u32)getpid());
     unlink(stdin_file);
     atexit(at_exit_handler);
     fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 98568473..e15dc72d 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -619,7 +619,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
     }
 
-    out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
+    out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, (u32)getpid());
 
   }
 
diff --git a/test/test-multiple-mutators.c b/test/test-multiple-mutators.c
new file mode 100644
index 00000000..0f6f5c64
--- /dev/null
+++ b/test/test-multiple-mutators.c
@@ -0,0 +1,24 @@
+/**
+ * Test-Case for multiple custom mutators in C
+ * Reference:
+ * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+
+  int  a = 0;
+  char s[16];
+  memset(s, 0, 16);
+  read(0, s, 0xa0);
+
+  if (s[17] != '\x00') { abort(); }
+
+  return 0;
+
+}
+
diff --git a/test/test.sh b/test/test.sh
index 90633a9f..919d7a9c 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -949,7 +949,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
   }
   test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
     unset AFL_CC
-    # Compile the vulnerable program
+    # Compile the vulnerable program for single mutator
     test -e ../afl-clang-fast && {
       ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
     } || {
@@ -959,6 +959,16 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
         ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
       }
     }
+    # Compile the vulnerable program for multiple mutators
+    test -e ../afl-clang-fast && {
+      ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+    } || {
+      test -e ../afl-gcc-fast && {
+        ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+      } || {
+        ../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+      }
+    }
     # Compile the custom mutator
     make -C ../examples/custom_mutators libexamplemutator.so > /dev/null 2>&1
     test -e test-custom-mutator -a -e ${CUSTOM_MUTATOR_PATH}/libexamplemutator.so && {
@@ -986,6 +996,25 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
       # Clean
       rm -rf out errors
 
+      #Run afl-fuzz w/ multiple C mutators
+      $ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 20 seconds"
+      {
+        AFL_CUSTOM_MUTATOR_LIBRARY="${CUSTOM_MUTATOR_PATH}/libexamplemutator.so;${CUSTOM_MUTATOR_PATH}/libexamplemutator.so" ../afl-fuzz -V20 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
+      } >>errors 2>&1
+
+      test -n "$( ls out/crashes/id:000000* 2>/dev/null )" && {  # TODO: update here
+        $ECHO "$GREEN[+] afl-fuzz is working correctly with multiple C mutators"
+      } || {
+        echo CUT------------------------------------------------------------------CUT
+        cat errors
+        echo CUT------------------------------------------------------------------CUT
+        $ECHO "$RED[!] afl-fuzz is not working correctly with multiple C mutators"
+        CODE=1
+      }
+
+      # Clean
+      rm -rf out errors 
+
       # Run afl-fuzz w/ the Python mutator
       $ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds"
       {
@@ -1010,6 +1039,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
       # Clean
       rm -rf in out errors
       rm -rf ${CUSTOM_MUTATOR_PATH}/__pycache__/
+      rm -f test-multiple-mutators
     } || {
       ls .
       ls ${CUSTOM_MUTATOR_PATH}
@@ -1021,6 +1051,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
 
     make -C ../examples/custom_mutators clean > /dev/null 2>&1
     rm -f test-custom-mutator
+    rm -f test-custom-mutators
   } || {
     $ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test"
     INCOMPLETE=1
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index c0cc9e02..336c171b 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-94c1976
+a5b7900
diff --git a/unicorn_mode/samples/persistent/COMPILE.md b/unicorn_mode/samples/persistent/COMPILE.md
index 781f15c0..111dfc54 100644
--- a/unicorn_mode/samples/persistent/COMPILE.md
+++ b/unicorn_mode/samples/persistent/COMPILE.md
@@ -1,6 +1,6 @@
 # C Sample
 
-This shows a simple persistent harness for unicornafl in C
+This shows a simple persistent harness for unicornafl in C.
 In contrast to the normal c harness, this harness manually resets the unicorn state on each new input.
 Thanks to this, we can rerun the testcase in unicorn multiple times, without the need to fork again.
 
@@ -21,4 +21,4 @@ was built in case you want to rebuild it or recompile it for any reason.
 
 The pre-built binary (persistent_target_x86_64.bin) was built using -g -O0 in gcc.
 
-We then load the binary we execute the main function directly.
+We then load the binary and we execute the main function directly.
diff --git a/unicorn_mode/samples/persistent/Makefile b/unicorn_mode/samples/persistent/Makefile
index 9c7ed7aa..9596facc 100644
--- a/unicorn_mode/samples/persistent/Makefile
+++ b/unicorn_mode/samples/persistent/Makefile
@@ -17,9 +17,9 @@ CFLAGS += -Wall -Werror -I../../unicornafl/include
 
 LDFLAGS += -L$(LIBDIR) -lpthread -lm
 
-_LRT = $(_UNIQ)$(UNAME_S:Linux=)
-__LRT = $(_LRT:$(_UNIQ)=-lrt)
-LRT = $(__LRT:$(_UNIQ)=)
+_LRT = $(_UNIQ)$(UNAME_S)
+__LRT = $(_LRT:$(_UNIQ)Linux=-lrt)
+LRT = $(__LRT:$(_UNIQ)$(UNAME_S)=)
 
 LDFLAGS += $(LRT)
 
@@ -48,3 +48,6 @@ debug: harness-debug.o
 
 fuzz: harness
 	../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@
+
+debugmake:
+	@echo UNAME_S=$(UNAME_S), _LRT=$(_LRT), __LRT=$(__LRT), LRT=$(LRT)
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject 94c1976975518691a03602f7ec5a817e2f34118
+Subproject a5b79002ca18219c83f9aec4e71007917c6be2e
diff --git a/unicorn_mode/update_uc_ref.sh b/unicorn_mode/update_uc_ref.sh
index d198fa2a..486f37d6 100755
--- a/unicorn_mode/update_uc_ref.sh
+++ b/unicorn_mode/update_uc_ref.sh
@@ -1,20 +1,40 @@
 #/bin/sh
 
+##################################################
+# AFL++ internal tool to update unicornafl ref.
+# Usage: ./update_uc_ref.sh <new commit hash>
+# If no commit hash was provided, it'll take HEAD.
+##################################################
+
 UC_VERSION_FILE='./UNICORNAFL_VERSION'
 
 NEW_VERSION="$1"
-if [ -z "$NEW_VERSION" ]; then
+
+if [ "$NEW_VERSION" = "-h" ]; then
   echo "Internal script to update bound unicornafl version."
   echo
   echo "Usage: ./update_uc_ref.sh <new commit hash>"
+  echo "If no commit hash is provided, will use HEAD."
+  echo "-h to show this help screen."
   exit 1
 fi
 
 git submodule init && git submodule update || exit 1
-cd ./unicornafl
+cd ./unicornafl || exit 1
 git fetch origin master 1>/dev/null || exit 1
 git stash 1>/dev/null 2>/dev/null
 git stash drop 1>/dev/null 2>/dev/null
+
+if [ -z "$NEW_VERSION" ]; then
+  # No version provided, take HEAD.
+  NEW_VERSION=$(git rev-parse --short HEAD)
+fi
+
+if [ -z "$NEW_VERSION" ]; then
+  echo "Error getting version."
+  exit 1
+fi
+
 git checkout "$NEW_VERSION" || exit 1
 
 cd ..