about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile28
-rw-r--r--README.md2
-rw-r--r--docs/Changelog.md3
-rw-r--r--docs/fuzzing_binary-only_targets.md9
-rw-r--r--docs/fuzzing_in_depth.md4
-rw-r--r--frida_mode/README.md30
-rw-r--r--frida_mode/frida.map2
-rw-r--r--frida_mode/include/instrument.h8
-rw-r--r--frida_mode/include/util.h8
-rw-r--r--frida_mode/src/instrument/instrument.c4
-rw-r--r--frida_mode/src/instrument/instrument_arm32.c25
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c22
-rw-r--r--frida_mode/src/instrument/instrument_x64.c9
-rw-r--r--frida_mode/src/instrument/instrument_x64_cache.c435
-rw-r--r--frida_mode/src/instrument/instrument_x86.c25
-rw-r--r--frida_mode/src/js/api.js15
-rw-r--r--frida_mode/src/js/js_api.c13
-rw-r--r--frida_mode/test/cache/GNUmakefile97
-rw-r--r--frida_mode/test/cache/Makefile22
-rw-r--r--frida_mode/test/cache/cache.c115
-rw-r--r--frida_mode/test/vorbis/GNUmakefile8
-rw-r--r--frida_mode/ts/lib/afl.ts25
-rw-r--r--include/envs.h2
-rw-r--r--include/forkserver.h3
-rw-r--r--instrumentation/afl-llvm-pass.so.cc91
-rw-r--r--instrumentation/cmplog-instructions-pass.cc9
-rw-r--r--instrumentation/compare-transform-pass.so.cc105
-rw-r--r--instrumentation/split-compares-pass.so.cc132
-rw-r--r--instrumentation/split-switches-pass.so.cc107
-rw-r--r--nyx_mode/LIBNYX_VERSION2
-rw-r--r--nyx_mode/PACKER_VERSION2
m---------nyx_mode/QEMU-Nyx0
-rw-r--r--nyx_mode/QEMU_NYX_VERSION2
-rw-r--r--nyx_mode/custom_harness/example.c7
m---------nyx_mode/libnyx0
m---------nyx_mode/packer0
-rw-r--r--src/afl-cc.c36
-rw-r--r--src/afl-forkserver.c11
-rw-r--r--src/afl-fuzz-bitmap.c27
-rw-r--r--src/afl-fuzz-redqueen.c4
-rw-r--r--src/afl-fuzz-run.c2
-rw-r--r--src/afl-fuzz.c16
42 files changed, 977 insertions, 490 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 48dc6ddf..d31c52da 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -76,9 +76,9 @@ else
 endif
 endif
 
-ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
-	SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
-endif
+#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+#	SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
+#endif
 
 #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"
 #  ifndef SOURCE_DATE_EPOCH
@@ -92,12 +92,10 @@ ifneq "$(SYS)" "Darwin"
   #  SPECIAL_PERFORMANCE += -march=native
   #endif
  # OS X does not like _FORTIFY_SOURCE=2
-  ifndef DEBUG
-    CFLAGS_OPT += -D_FORTIFY_SOURCE=2
-  endif
-endif
-
-ifeq "$(SYS)" "Darwin"
+ ifndef DEBUG
+   CFLAGS_OPT += -D_FORTIFY_SOURCE=2
+ endif
+else
   # On some odd MacOS system configurations, the Xcode sdk path is not set correctly
   SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
   LDFLAGS += $(SDK_LD)
@@ -144,12 +142,13 @@ ifdef DEBUG
   $(info Compiling DEBUG version of binaries)
   override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
 else
-  CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
+  CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
 endif
 
 override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
 			-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
+			-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
+# -fstack-protector
 
 ifeq "$(SYS)" "FreeBSD"
   override CFLAGS  += -I /usr/local/include/
@@ -175,7 +174,7 @@ ifeq "$(SYS)" "Haiku"
   SHMAT_OK=0
   override CFLAGS  += -DUSEMMAP=1 -Wno-error=format
   override LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
-  SPECIAL_PERFORMANCE += -DUSEMMAP=1
+  #SPECIAL_PERFORMANCE += -DUSEMMAP=1
 endif
 
 AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
@@ -247,9 +246,6 @@ else
 endif
 
 ifneq "$(filter Linux GNU%,$(SYS))" ""
- ifndef DEBUG
-  override CFLAGS += -D_FORTIFY_SOURCE=2
- endif
   override LDFLAGS += -ldl -lrt -lm
 endif
 
@@ -426,7 +422,7 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
 	@ln -sf afl-as as
 
 src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
-	$(CC) $(CFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
+	$(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
 
 src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
 	$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
diff --git a/README.md b/README.md
index 66b884e2..a29ce792 100644
--- a/README.md
+++ b/README.md
@@ -112,7 +112,7 @@ Step-by-step quick start:
 
 5. You will find found crashes and hangs in the subdirectories `crashes/` and
    `hangs/` in the `-o output_dir` directory. You can replay the crashes by
-   feeding them to the target, e.g.:
+   feeding them to the target, e.g. if your target is using stdin:
 
    ```
    cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]
diff --git a/docs/Changelog.md b/docs/Changelog.md
index f4ae0e43..549d5e4a 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -12,6 +12,9 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
   - fix */build_...sh scripts to work outside of git
   - new custom_mutator: libafl with token fuzzing :)
   - afl-fuzz:
+    - when you just want to compile once and set CMPLOG, then just
+      set -c 0 to tell afl-fuzz that the fuzzing binary is also for
+      CMPLOG.
     - new commandline options -g/G to set min/max length of generated
       fuzz inputs
     - reintroduced AFL_PERSISTENT and AFL_DEFER_FORKSRV to allow
diff --git a/docs/fuzzing_binary-only_targets.md b/docs/fuzzing_binary-only_targets.md
index 1a2b27c7..c97af1b9 100644
--- a/docs/fuzzing_binary-only_targets.md
+++ b/docs/fuzzing_binary-only_targets.md
@@ -48,11 +48,12 @@ The following setup to use QEMU mode is recommended:
 
 Then run as many instances as you have cores left with either -Q mode or - even
 better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
+The binary rewriters all have their own advantages and caveats.
+ZAFL is the best but cannot be used in a business/commercial context.
 
-If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for your
-binary, then you can use afl-fuzz normally and it will have twice the speed
-compared to QEMU mode (but slower than QEMU persistent mode). Note that several
-other binary rewriters exist, all with their advantages and caveats.
+If a binary rewriter works for your target then you can use afl-fuzz normally
+and it will have twice the speed compared to QEMU mode (but slower than QEMU
+persistent mode).
 
 The speed decrease of QEMU mode is at about 50%. However, various options exist
 to increase the speed:
diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md
index ac72c757..a9151a25 100644
--- a/docs/fuzzing_in_depth.md
+++ b/docs/fuzzing_in_depth.md
@@ -817,9 +817,9 @@ Here are some of the most important caveats for AFL++:
 
 - There is no direct support for fuzzing network services, background daemons,
   or interactive apps that require UI interaction to work. You may need to make
-  simple code changes to make them behave in a more traditional way. Preeny may
+  simple code changes to make them behave in a more traditional way. Preeny or libdesock may
   offer a relatively simple option, too - see:
-  [https://github.com/zardus/preeny](https://github.com/zardus/preeny)
+  [https://github.com/zardus/preeny](https://github.com/zardus/preeny) or [https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
 
   Some useful tips for modifying network-based services can be also found at:
   [https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
diff --git a/frida_mode/README.md b/frida_mode/README.md
index 50e3b8d7..4025dba5 100644
--- a/frida_mode/README.md
+++ b/frida_mode/README.md
@@ -151,25 +151,25 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
 * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
   and their instrumented counterparts during block compilation.
 
-  ```
-  ***
+Creating block for 0x7ffff7953313:
+        0x7ffff7953313  mov qword ptr [rax], 0
+        0x7ffff795331a  add rsp, 8
+        0x7ffff795331e  ret
 
-  Creating block for 0x7ffff7953313:
-          0x7ffff7953313  mov qword ptr [rax], 0
-          0x7ffff795331a  add rsp, 8
-          0x7ffff795331e  ret
+Generated block 0x7ffff75e98e2
+        0x7ffff75e98e2  mov qword ptr [rax], 0
+        0x7ffff75e98e9  add rsp, 8
+        0x7ffff75e98ed  lea rsp, [rsp - 0x80]
+        0x7ffff75e98f5  push rcx
+        0x7ffff75e98f6  movabs rcx, 0x7ffff795331e
+        0x7ffff75e9900  jmp 0x7ffff75e9384
 
-  Generated block 0x7ffff75e98e2
-          0x7ffff75e98e2  mov qword ptr [rax], 0
-          0x7ffff75e98e9  add rsp, 8
-          0x7ffff75e98ed  lea rsp, [rsp - 0x80]
-          0x7ffff75e98f5  push rcx
-          0x7ffff75e98f6  movabs rcx, 0x7ffff795331e
-          0x7ffff75e9900  jmp 0x7ffff75e9384
 
   ***
   ```
-
+* `AFL_FRIDA_INST_CACHE_SIZE` - Set the size of the instrumentation cache used
+as a look-up table to cache real to instrumented address block translations.
+Default is 256Mb.
 * `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional
   instructions (e.g. `CMOV` instructions on x64).
 * `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
@@ -178,6 +178,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
 * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
   instrumentation (the default where available). Required to use
   `AFL_FRIDA_INST_TRACE`.
+* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
+instrumented address block translations.
 * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
   report instrumented blocks back to the parent so that it can also instrument
   them and they be inherited by the next child on fork, implies
diff --git a/frida_mode/frida.map b/frida_mode/frida.map
index 41220d4b..6726dbbd 100644
--- a/frida_mode/frida.map
+++ b/frida_mode/frida.map
@@ -9,8 +9,10 @@
     js_api_done;
     js_api_error;
     js_api_set_backpatch_disable;
+    js_api_set_cache_disable;
     js_api_set_debug_maps;
     js_api_set_entrypoint;
+    js_api_set_instrument_cache_size;
     js_api_set_instrument_coverage_file;
     js_api_set_instrument_debug_file;
     js_api_set_instrument_jit;
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
index 20312a4b..4a54ee22 100644
--- a/frida_mode/include/instrument.h
+++ b/frida_mode/include/instrument.h
@@ -22,6 +22,9 @@ extern uint32_t __afl_map_size;
 
 extern __thread guint64 *instrument_previous_pc_addr;
 
+extern gboolean instrument_cache_enabled;
+extern gsize    instrument_cache_size;
+
 void instrument_config(void);
 
 void instrument_init(void);
@@ -59,5 +62,10 @@ void instrument_on_fork(void);
 
 guint64 instrument_get_offset_hash(GumAddress current_rip);
 
+void instrument_cache_config(void);
+void instrument_cache_init(void);
+void instrument_cache_insert(gpointer real_address, gpointer code_address);
+void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
+
 #endif
 
diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h
index bd37687c..b04e0a26 100644
--- a/frida_mode/include/util.h
+++ b/frida_mode/include/util.h
@@ -5,6 +5,14 @@
 
 #include "debug.h"
 
+#ifndef MAP_FIXED_NOREPLACE
+  #ifdef MAP_EXCL
+    #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
+  #else
+    #define MAP_FIXED_NOREPLACE MAP_FIXED
+  #endif
+#endif
+
 #define UNUSED_PARAMETER(x) (void)(x)
 #define IGNORED_RETURN(x) (void)!(x)
 
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index 43560478..003c3d00 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -249,6 +249,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
 
     }
 
+    instrument_cache(instr, output);
+
     if (js_stalker_callback(instr, begin, excluded, output)) {
 
       gum_stalker_iterator_keep(iterator);
@@ -282,6 +284,7 @@ void instrument_config(void) {
   instrument_coverage_config();
   asan_config();
   cmplog_config();
+  instrument_cache_config();
 
 }
 
@@ -392,6 +395,7 @@ void instrument_init(void) {
   instrument_coverage_init();
   instrument_coverage_optimize_init();
   instrument_debug_init();
+  instrument_cache_init();
 
 }
 
diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c
index 705faa64..80f3c26d 100644
--- a/frida_mode/src/instrument/instrument_arm32.c
+++ b/frida_mode/src/instrument/instrument_arm32.c
@@ -5,6 +5,9 @@
 
 #if defined(__arm__)
 
+gboolean instrument_cache_enabled = FALSE;
+gsize    instrument_cache_size = 0;
+
 gboolean instrument_is_coverage_optimize_supported(void) {
 
   return false;
@@ -55,5 +58,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
 
 }
 
+void instrument_cache_config(void) {
+
+}
+
+void instrument_cache_init(void) {
+
+}
+
+void instrument_cache_insert(gpointer real_address, gpointer code_address) {
+
+  UNUSED_PARAMETER(real_address);
+  UNUSED_PARAMETER(code_address);
+
+}
+
+void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+}
+
 #endif
 
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
index 4abc0625..eb736386 100644
--- a/frida_mode/src/instrument/instrument_arm64.c
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -379,5 +379,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
 
 }
 
+void instrument_cache_config(void) {
+
+}
+
+void instrument_cache_init(void) {
+
+}
+
+void instrument_cache_insert(gpointer real_address, gpointer code_address) {
+
+  UNUSED_PARAMETER(real_address);
+  UNUSED_PARAMETER(code_address);
+
+}
+
+void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+}
+
 #endif
 
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
index 4b1a2d68..0bff3e02 100644
--- a/frida_mode/src/instrument/instrument_x64.c
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -202,10 +202,17 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
 
       }
 
-      if (op[0].type != X86_OP_IMM) { return; }
+      if (op[0].type != X86_OP_IMM) {
+
+        instrument_cache_insert(start_address, *target);
+        return;
+
+      }
 
       break;
     case X86_INS_RET:
+      instrument_cache_insert(start_address,
+                              (guint8 *)*target + sizeof(afl_log_code));
       break;
     default:
       return;
diff --git a/frida_mode/src/instrument/instrument_x64_cache.c b/frida_mode/src/instrument/instrument_x64_cache.c
new file mode 100644
index 00000000..3ea4421a
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_x64_cache.c
@@ -0,0 +1,435 @@
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+#include "instrument.h"
+#include "util.h"
+
+#if defined(__x86_64__)
+
+  #define INVALID 1
+  #define DEFAULT_CACHE_SIZE (256ULL << 20)
+
+gboolean         instrument_cache_enabled = TRUE;
+gsize            instrument_cache_size = DEFAULT_CACHE_SIZE;
+static gpointer *map_base = MAP_FAILED;
+
+void instrument_cache_config(void) {
+
+  instrument_cache_enabled = (getenv("AFL_FRIDA_INST_NO_CACHE") == NULL);
+
+  if (getenv("AFL_FRIDA_INST_CACHE_SIZE") != NULL) {
+
+    if (!instrument_cache_enabled) {
+
+      FFATAL(
+          "AFL_FRIDA_INST_CACHE_SIZE incomatible with "
+          "AFL_FRIDA_INST_NO_CACHE");
+
+    }
+
+    instrument_cache_size =
+        util_read_address("AFL_FRIDA_INST_CACHE_SIZE", DEFAULT_CACHE_SIZE);
+    util_log2(instrument_cache_size);
+
+  }
+
+}
+
+void instrument_cache_init(void) {
+
+  FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache:" cYEL " [%c]",
+       instrument_cache_enabled ? 'X' : ' ');
+  if (!instrument_cache_enabled) { return; }
+
+  FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache size:" cYEL " [0x%016lX]",
+       instrument_cache_size);
+
+  const struct rlimit data_limit = {.rlim_cur = RLIM_INFINITY,
+                                    .rlim_max = RLIM_INFINITY};
+
+  if (setrlimit(RLIMIT_AS, &data_limit) != 0) {
+
+    FFATAL("Failed to setrlimit: %d", errno);
+
+  }
+
+  map_base =
+      gum_memory_allocate(NULL, instrument_cache_size, instrument_cache_size,
+                          GUM_PAGE_READ | GUM_PAGE_WRITE);
+  if (map_base == MAP_FAILED) { FFATAL("Failed to map segment: %d", errno); }
+
+  FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache addr:" cYEL " [0x%016lX]",
+       GUM_ADDRESS(map_base));
+
+}
+
+static gpointer *instrument_cache_get_addr(gpointer addr) {
+
+  gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
+  return &map_base[GPOINTER_TO_SIZE(addr) & mask];
+
+}
+
+void instrument_cache_insert(gpointer real_address, gpointer code_address) {
+
+  if (!instrument_cache_enabled) { return; }
+
+  gpointer *target = instrument_cache_get_addr(real_address);
+  if (*target == code_address) {
+
+    return;
+
+  } else if (*target == NULL) {
+
+    *target = code_address;
+
+  } else {
+
+    *target = GSIZE_TO_POINTER(INVALID);
+
+  }
+
+}
+
+static gboolean instrument_cache_relocate(GumAddress old_pc, GumAddress new_pc,
+                                          gint32  old_offset,
+                                          gint32 *new_offset) {
+
+  guint64 old_target = old_pc + old_offset;
+  gint64  relocated = old_target - new_pc;
+
+  if (relocated > G_MAXINT32 || relocated < G_MININT32) { return FALSE; }
+
+  *new_offset = relocated;
+  return TRUE;
+
+}
+
+static void instrument_cache_rewrite_branch_insn(const cs_insn *   instr,
+                                                 GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+  cs_x86 *      x86 = &instr->detail->x86;
+  guint8        modified[sizeof(instr->bytes)] = {0};
+  guint8        offset = 0;
+  guint8        skip = 0;
+
+  g_assert(sizeof(x86->prefix) == 4);
+  g_assert(sizeof(x86->opcode) == 4);
+
+  /*
+   * If the target is simply RAX, we can skip writing the code to load the
+   * RIP
+   */
+  if (x86->operands[0].type == X86_OP_REG ||
+      x86->operands[0].reg == X86_REG_RAX) {
+
+    return;
+
+  }
+
+  /* Write the prefix */
+  for (gsize i = 0; i < sizeof(x86->prefix); i++) {
+
+    if (x86->prefix[i] != 0) {
+
+      if (x86->prefix[i] == 0xf2) {
+
+        skip++;
+
+      } else {
+
+        modified[offset++] = x86->prefix[i];
+        skip++;
+
+      }
+
+    }
+
+  }
+
+  /* Write the REX */
+  if (x86->rex == 0) {
+
+    /*
+     * CALL (near) and JMP (near) default to 64-bit operands, MOV does not,
+     * write REX.W
+     */
+    modified[offset++] = 0x48;
+
+  } else {
+
+    if ((x86->rex & 0xF8) != 0x40) {
+
+      FATAL("Unexpected REX byte: 0x%02x", x86->rex);
+
+    }
+
+    modified[offset++] = x86->rex | 0x08;
+    skip++;
+
+  }
+
+  /*
+   * CALL is FF /2, JMP is FF /4. The remaining op-code fields should thus be
+   * unused
+   */
+
+  if (x86->opcode[0] != 0xFF || x86->opcode[1] != 0x00 ||
+      x86->opcode[2] != 0x00 || x86->opcode[3] != 0x00) {
+
+    FFATAL("Unexpected Op-code: 0x%02x 0x%02x 0x%02x 0x%02x", x86->opcode[0],
+           x86->opcode[1], x86->opcode[2], x86->opcode[3]);
+
+  }
+
+  /* The reg field of the ModRM should be set to 2 for CALL and 4 for JMP */
+  guint8 reg = (x86->modrm >> 3) & 7;
+  if (reg != 0x4 && reg != 0x2) {
+
+    FFATAL("Unexpected Reg: 0x%02x, ModRM: 0x%02x", reg, x86->modrm);
+
+  }
+
+  /* MOV */
+  modified[offset++] = 0x8b;
+  skip++;
+
+  /* Clear the reg field (RAX) */
+  modified[offset++] = x86->modrm & 0xc7;
+  skip++;
+
+  /* Operands */
+  guint8 op_len = instr->size - skip;
+
+  /* If our branch was RIP relative, we'll need to fix-up the offset */
+  if (x86->operands[0].type == X86_OP_MEM &&
+      x86->operands[0].mem.base == X86_REG_RIP) {
+
+    /* RIP relative offsets should be 32-bits */
+    if (op_len != sizeof(gint32)) {
+
+      FFATAL("Unexpected operand length: %d\n", op_len);
+
+    }
+
+    gint32 old_offset = *(gint32 *)&instr->bytes[skip];
+    gint32 new_offset = 0;
+    if (instrument_cache_relocate(instr->address, cw->pc, old_offset,
+                                  &new_offset)) {
+
+      gint32 *output = (gint32 *)&modified[offset];
+      *output = new_offset;
+      offset += sizeof(gint32);
+
+    } else {
+
+      GumAddress target = instr->address + old_offset;
+      gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, target);
+      gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_RAX, GUM_REG_RAX);
+      return;
+
+    }
+
+  } else {
+
+    for (int i = 0; i < op_len; i++) {
+
+      guint8 val = instr->bytes[i + skip];
+      modified[offset++] = val;
+
+    }
+
+  }
+
+  gum_x86_writer_put_bytes(cw, modified, offset);
+
+}
+
+static void instrument_cache_write_push_frame(GumX86Writer *cw) {
+
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(
+      cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))),
+      GUM_REG_XAX);
+  gum_x86_writer_put_lahf(cw);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(
+      cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))),
+      GUM_REG_XAX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(
+      cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))),
+      GUM_REG_XBX);
+
+}
+
+static void instrument_cache_write_pop_frame(GumX86Writer *cw) {
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(
+      cw, GUM_REG_XBX, GUM_REG_XSP,
+      -(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(
+      cw, GUM_REG_XAX, GUM_REG_XSP,
+      -(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))));
+  gum_x86_writer_put_sahf(cw);
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(
+      cw, GUM_REG_XAX, GUM_REG_XSP,
+      -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
+
+}
+
+static void instrument_cache_write_lookup(GumX86Writer *cw) {
+
+  /* &map_base[GPOINTER_TO_SIZE(addr) & MAP_MASK]; */
+
+  gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
+  gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_XBX, mask);
+  gum_x86_writer_put_and_reg_reg(cw, GUM_REG_XAX, GUM_REG_XBX);
+  gum_x86_writer_put_shl_reg_u8(cw, GUM_REG_XAX, util_log2(sizeof(gpointer)));
+  gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_XBX, GPOINTER_TO_SIZE(map_base));
+  gum_x86_writer_put_add_reg_reg(cw, GUM_REG_XAX, GUM_REG_XBX);
+
+  /* Read the return address lookup */
+  gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_XAX, GUM_REG_XAX);
+
+}
+
+void instrument_cache_jmp_call(const cs_insn *instr, GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+  cs_x86 *      x86 = &instr->detail->x86;
+
+  if (x86->op_count != 1) { FFATAL("Unexpected operand count"); }
+
+  if (x86->operands[0].type == X86_OP_IMM) { return; }
+
+  gconstpointer null = cw->code;
+
+  instrument_cache_write_push_frame(cw);
+
+  /*
+   * We are about to re-write the CALL or JMP instruction, but replace the
+   * op-code with that for a MOV into RAX. Since we are keeping the operand from
+   * the JMP exactly the same, it is imperative that the target register state
+   * be exactly the same as how the target left it. Since `LAHF` spoils `RAX` we
+   * must restore it from the stack. We also must avoid adjusting `RSP`, so we
+   * use `MOV` instructions to store our context into the stack beyond the
+   * red-zone.
+   */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(
+      cw, GUM_REG_XAX, GUM_REG_XSP,
+      -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
+
+  instrument_cache_rewrite_branch_insn(instr, output);
+
+  instrument_cache_write_lookup(cw);
+
+  /* Test if its set*/
+  gum_x86_writer_put_cmp_reg_i32(cw, GUM_REG_XAX, INVALID);
+  gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
+
+  /* If it's set, then stash the address beyond the red-zone */
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(
+      cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))),
+      GUM_REG_XAX);
+
+  if (instr->id == X86_INS_JMP) {
+
+    instrument_cache_write_pop_frame(cw);
+    gum_x86_writer_put_jmp_reg_offset_ptr(
+        cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))));
+
+  } else {
+
+    gum_x86_writer_put_mov_reg_address(
+        cw, GUM_REG_XAX, GUM_ADDRESS(instr->address + instr->size));
+    gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_XSP,
+                                              -sizeof(gpointer), GUM_REG_XAX);
+
+    instrument_cache_write_pop_frame(cw);
+
+    gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_XSP, GUM_REG_XSP,
+                                          -sizeof(gpointer));
+    gum_x86_writer_put_jmp_reg_offset_ptr(
+        cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + ((4 - 1) * sizeof(gpointer))));
+
+  }
+
+  /* Tidy up our mess and let FRIDA handle it */
+  gum_x86_writer_put_label(cw, null);
+  instrument_cache_write_pop_frame(cw);
+
+}
+
+void instrument_cache_ret(const cs_insn *instr, GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+  cs_x86 *      x86 = &instr->detail->x86;
+  guint16       n = 0;
+
+  if (x86->op_count != 0) {
+
+    if (x86->operands[0].type != X86_OP_IMM) {
+
+      FFATAL("Unexpected operand type");
+
+    }
+
+    n = x86->operands[0].imm;
+
+  }
+
+  gconstpointer null = cw->code;
+
+  instrument_cache_write_push_frame(cw);
+
+  gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_XAX, GUM_REG_XSP);
+
+  instrument_cache_write_lookup(cw);
+
+  /* Test if its set*/
+  gum_x86_writer_put_cmp_reg_i32(cw, GUM_REG_XAX, INVALID);
+  gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
+
+  /* If it's set, then overwrite our return address and return */
+  gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_XSP, GUM_REG_XAX);
+  instrument_cache_write_pop_frame(cw);
+
+  if (n == 0) {
+
+    gum_x86_writer_put_ret(cw);
+
+  } else {
+
+    gum_x86_writer_put_ret_imm(cw, n);
+
+  }
+
+  /* Tidy up our mess and let FRIDA handle it */
+  gum_x86_writer_put_label(cw, null);
+  instrument_cache_write_pop_frame(cw);
+
+}
+
+void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
+
+  if (!instrument_cache_enabled) { return; }
+
+  switch (instr->id) {
+
+    case X86_INS_RET:
+      instrument_cache_ret(instr, output);
+      break;
+
+    case X86_INS_CALL:
+    case X86_INS_JMP:
+      instrument_cache_jmp_call(instr, output);
+      break;
+
+    default:
+      return;
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
index 916cd0e2..6a899248 100644
--- a/frida_mode/src/instrument/instrument_x86.c
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -6,6 +6,9 @@
 
 #if defined(__i386__)
 
+gboolean instrument_cache_enabled = FALSE;
+gsize    instrument_cache_size = 0;
+
 static GHashTable *coverage_blocks = NULL;
 
   #pragma pack(push, 1)
@@ -242,5 +245,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
 
 }
 
+void instrument_cache_config(void) {
+
+}
+
+void instrument_cache_init(void) {
+
+}
+
+void instrument_cache_insert(gpointer real_address, gpointer code_address) {
+
+  UNUSED_PARAMETER(real_address);
+  UNUSED_PARAMETER(code_address);
+
+}
+
+void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+}
+
 #endif
 
diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js
index 82b8e63d..c1c9d36f 100644
--- a/frida_mode/src/js/api.js
+++ b/frida_mode/src/js/api.js
@@ -69,6 +69,12 @@ class Afl {
         Afl.jsApiSetBackpatchDisable();
     }
     /**
+     * See `AFL_FRIDA_INST_NO_CACHE`.
+     */
+    static setCacheDisable() {
+        Afl.jsApiSetCacheDisable();
+    }
+    /**
      * See `AFL_FRIDA_DEBUG_MAPS`.
      */
     static setDebugMaps() {
@@ -92,6 +98,13 @@ class Afl {
         Afl.jsApiAflSharedMemFuzzing.writeInt(1);
     }
     /**
+     * See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
+     * as an argument.
+     */
+    static setInstrumentCacheSize(size) {
+        Afl.jsApiSetInstrumentCacheSize(size);
+    }
+    /**
      * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
      * as an argument.
      */
@@ -299,8 +312,10 @@ Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
 Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
 Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
 Afl.jsApiSetBackpatchDisable = Afl.jsApiGetFunction("js_api_set_backpatch_disable", "void", []);
+Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "void", []);
 Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
 Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
+Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]);
 Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]);
 Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
 Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
index 89df7803..7cc8ffc7 100644
--- a/frida_mode/src/js/js_api.c
+++ b/frida_mode/src/js/js_api.c
@@ -262,6 +262,19 @@ __attribute__((visibility("default"))) void js_api_set_stalker_adjacent_blocks(
 
 }
 
+__attribute__((visibility("default"))) void js_api_set_cache_disable(void) {
+
+  instrument_cache_enabled = FALSE;
+
+}
+
+__attribute__((visibility("default"))) void js_api_set_instrument_cache_size(
+    gsize size) {
+
+  instrument_cache_size = size;
+
+}
+
 __attribute__((visibility("default"))) void js_api_set_js_main_hook(
     const js_main_hook_t hook) {
 
diff --git a/frida_mode/test/cache/GNUmakefile b/frida_mode/test/cache/GNUmakefile
new file mode 100644
index 00000000..12736a3f
--- /dev/null
+++ b/frida_mode/test/cache/GNUmakefile
@@ -0,0 +1,97 @@
+PWD:=$(shell pwd)/
+ROOT:=$(PWD)../../../
+BUILD_DIR:=$(PWD)build/
+
+TEST_CACHE_SRC:=$(PWD)cache.c
+TEST_CACHE_OBJ:=$(BUILD_DIR)cache
+
+TEST_DATA_DIR:=$(BUILD_DIR)in/
+CACHE_INPUT:=$(TEST_DATA_DIR)in
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ADDR_BIN:=$(ROOT)frida_mode/build/addr
+GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
+
+AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
+
+AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN))
+AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_CACHE_OBJ) LLVMFuzzerTestOneInput $(AFL_FRIDA_BASE_ADDR))
+
+DUMMY_DATA_FILE:=$(BUILD_DIR)dummy.dat
+
+.PHONY: all 32 clean frida frida_noinst debug format
+
+all: $(TEST_CACHE_OBJ)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TEST_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(CACHE_INPUT): | $(TEST_DATA_DIR)
+	echo -n "ABC" > $@
+
+$(TEST_CACHE_OBJ): $(TEST_CACHE_SRC) | $(BUILD_DIR)
+	$(CC) -g $(CFLAGS) $(LDFLAGS) $< -o $@
+
+########## DUMMY #######
+
+$(DUMMY_DATA_FILE): | $(BUILD_DIR)
+	dd if=/dev/zero bs=1048576 count=1 of=$@
+
+frida: $(TEST_CACHE_OBJ) $(CACHE_INPUT) $(DUMMY_DATA_FILE)
+	AFL_FRIDA_INST_INSN=1 \
+	AFL_FRIDA_PERSISTENT_CNT=1000000 \
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-Z \
+		-t 10000+ \
+		-- \
+			$(TEST_CACHE_OBJ) $(DUMMY_DATA_FILE)
+
+frida_nocache: $(TEST_CACHE_OBJ) $(CACHE_INPUT) $(DUMMY_DATA_FILE)
+	AFL_FRIDA_INST_NO_CACHE=1 \
+	AFL_FRIDA_PERSISTENT_CNT=1000000 \
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-Z \
+		-- \
+			$(TEST_CACHE_OBJ) $(DUMMY_DATA_FILE)
+
+debug: $(TEST_CACHE_OBJ) $(CACHE_INPUT)
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--ex 'r $(CACHE_INPUT)' \
+		--args $(TEST_CACHE_OBJ) $(CACHE_INPUT)
+
+show: $(TEST_CACHE_OBJ) $(CACHE_INPUT)
+	gdb \
+		--ex "set disassembly-flavor intel" \
+		--ex "set confirm off" \
+		--ex "symbol-file $(TEST_CACHE_OBJ)" \
+		--ex "x/50i LLVMFuzzerTestOneInput" \
+		--ex "r" \
+		--args $(TEST_CACHE_OBJ) $(CACHE_INPUT)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+format:
+	cd $(ROOT) && echo $(TEST_CACHE_SRC) | xargs -L1 ./.custom-format.py -i
diff --git a/frida_mode/test/cache/Makefile b/frida_mode/test/cache/Makefile
new file mode 100644
index 00000000..961a284c
--- /dev/null
+++ b/frida_mode/test/cache/Makefile
@@ -0,0 +1,22 @@
+all:
+	@echo trying to use GNU make...
+	@gmake all || echo please install GNUmake
+
+32:
+	@echo trying to use GNU make...
+	@gmake 32 || echo please install GNUmake
+
+frida:
+	@gmake frida
+
+frida_nocache:
+	@gmake frida_nocache
+
+debug:
+	@gmake debug
+
+clean:
+	@gmake clean
+
+format:
+	@gmake format
diff --git a/frida_mode/test/cache/cache.c b/frida_mode/test/cache/cache.c
new file mode 100644
index 00000000..b4102205
--- /dev/null
+++ b/frida_mode/test/cache/cache.c
@@ -0,0 +1,115 @@
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void LLVMFuzzerTestOneInput(char *buf, int len);
+
+__asm__ (
+  "LLVMFuzzerTestOneInput:\n"
+  ".func LLVMFuzzerTestOneInput\n"
+  ".global LLVMFuzzerTestOneInput\n"
+  "    jmpq *jmp_offset(%rip)\n"
+  "    nop\n"
+  "    nop\n"
+  "call_target:\n"
+  "    ret\n"
+  "    nop\n"
+  "    nop\n"
+  "jmp_target:\n"
+  "    callq *call_offset(%rip)\n"
+  "    nop\n"
+  "    nop\n"
+  "    leaq rax_offset(%rip), %rax\n"
+  "    jmp (%rax)\n"
+  "    nop\n"
+  "    ud2\n"
+  "    nop\n"
+  "rax_target:\n"
+  "    ret\n"
+  "\n"
+  "\n"
+  ".global jmp_offset\n"
+  ".p2align 3\n"
+  "jmp_offset:\n"
+  "    .quad jmp_target\n"
+  "call_offset:\n"
+  "    .quad call_target\n"
+  "rax_offset:\n"
+  "    .quad rax_target\n"
+);
+
+int main(int argc, char **argv) {
+
+  char * file;
+  int    fd = -1;
+  off_t  len;
+  char * buf = NULL;
+  size_t n_read;
+  int    result = -1;
+
+  if (argc != 2) { return 1; }
+
+  do {
+
+    file = argv[1];
+
+    dprintf(STDERR_FILENO, "Running: %s\n", file);
+
+    fd = open(file, O_RDONLY);
+    if (fd < 0) {
+
+      perror("open");
+      break;
+
+    }
+
+    len = lseek(fd, 0, SEEK_END);
+    if (len < 0) {
+
+      perror("lseek (SEEK_END)");
+      break;
+
+    }
+
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+
+      perror("lseek (SEEK_SET)");
+      break;
+
+    }
+
+    buf = (char *)malloc(len);
+    if (buf == NULL) {
+
+      perror("malloc");
+      break;
+
+    }
+
+    n_read = read(fd, buf, len);
+    if (n_read != len) {
+
+      perror("read");
+      break;
+
+    }
+
+    dprintf(STDERR_FILENO, "Running:    %s: (%zd bytes)\n", file, n_read);
+
+    LLVMFuzzerTestOneInput(buf, len);
+    dprintf(STDERR_FILENO, "Done:    %s: (%zd bytes)\n", file, n_read);
+
+    result = 0;
+
+  } while (false);
+
+  if (buf != NULL) { free(buf); }
+
+  if (fd != -1) { close(fd); }
+
+  return result;
+
+}
+
diff --git a/frida_mode/test/vorbis/GNUmakefile b/frida_mode/test/vorbis/GNUmakefile
index 9cce6c9e..4cb5d417 100644
--- a/frida_mode/test/vorbis/GNUmakefile
+++ b/frida_mode/test/vorbis/GNUmakefile
@@ -125,7 +125,7 @@ vorbis: $(VORBIS_LIB)
 ########## HARNESS #######
 
 $(DECODE_SRC):
-	wget -O $@ $(DECODE_URL)
+	wget -O $@ $(DECODE_URL) || curl -L -o $@ $(DECODE_URL)
 
 $(DECODE_OBJ): $(DECODE_SRC)
 	$(CXX) -o $@ -c $< -I$(VORBIS_DIR)include/ -I$(OGG_DIR)include/
@@ -135,7 +135,7 @@ decode: $(DECODE_OBJ)
 ########## HARNESS #######
 
 $(HARNESS_SRC):
-	wget -O $@ $(HARNESS_URL)
+	wget -O $@ $(HARNESS_URL) || curl -L -o $@ $(HARNESS_URL)
 
 $(HARNESS_OBJ): $(HARNESS_SRC)
 	$(CC) -o $@ -c $<
@@ -165,8 +165,8 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
 
 ###### TEST DATA #######
 
-$(TEST_DATA_FILE): $(TEST_DATA_DIR)
-	wget -O $@ $(TEST_DATA_SRC)
+$(TEST_DATA_FILE): | $(TEST_DATA_DIR)
+	wget -O $@ $(TEST_DATA_SRC) || curl -L -o $@ $(TEST_DATA_SRC)
 
 clean:
 	rm -rf $(BUILD_DIR)
diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts
index 7999b661..a858f074 100644
--- a/frida_mode/ts/lib/afl.ts
+++ b/frida_mode/ts/lib/afl.ts
@@ -85,6 +85,13 @@ class Afl {
   }
 
   /**
+   * See `AFL_FRIDA_INST_NO_CACHE`.
+   */
+  public static setCacheDisable(): void {
+    Afl.jsApiSetCacheDisable();
+  }
+
+  /**
    * See `AFL_FRIDA_DEBUG_MAPS`.
    */
   public static setDebugMaps(): void {
@@ -111,6 +118,14 @@ class Afl {
   }
 
   /**
+   * See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
+   * as an argument.
+   */
+  public static setInstrumentCacheSize(size: number): void {
+    Afl.jsApiSetInstrumentCacheSize(size);
+  }
+
+  /**
    * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
    * as an argument.
    */
@@ -354,6 +369,11 @@ class Afl {
     "void",
     []);
 
+  private static readonly jsApiSetCacheDisable = Afl.jsApiGetFunction(
+    "js_api_set_cache_disable",
+    "void",
+    []);
+
   private static readonly jsApiSetDebugMaps = Afl.jsApiGetFunction(
     "js_api_set_debug_maps",
     "void",
@@ -364,6 +384,11 @@ class Afl {
     "void",
     ["pointer"]);
 
+  private static readonly jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction(
+    "js_api_set_instrument_cache_size",
+    "void",
+    ["size_t"]);
+
   private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction(
     "js_api_set_instrument_coverage_file",
     "void",
diff --git a/include/envs.h b/include/envs.h
index 1f6d33e6..fc276f8f 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -57,10 +57,12 @@ static char *afl_environment_variables[] = {
     "AFL_FRIDA_DEBUG_MAPS",
     "AFL_FRIDA_DRIVER_NO_HOOK",
     "AFL_FRIDA_EXCLUDE_RANGES",
+    "AFL_FRIDA_INST_CACHE_SIZE",
     "AFL_FRIDA_INST_COVERAGE_FILE",
     "AFL_FRIDA_INST_DEBUG_FILE",
     "AFL_FRIDA_INST_INSN",
     "AFL_FRIDA_INST_JIT",
+    "AFL_FRIDA_INST_NO_CACHE",
     "AFL_FRIDA_INST_NO_OPTIMIZE",
     "AFL_FRIDA_INST_NO_PREFETCH",
     "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
diff --git a/include/forkserver.h b/include/forkserver.h
index fd4d283c..5b66e7ec 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -70,6 +70,8 @@ typedef struct {
   enum NyxReturnValue (*nyx_exec)(void *qemu_process);
   uint8_t *(*nyx_get_bitmap_buffer)(void *qemu_process);
   size_t (*nyx_get_bitmap_buffer_size)(void *qemu_process);
+  uint32_t (*nyx_get_aux_string)(void *nyx_process, uint8_t *buffer,
+                                 uint32_t size);
 
 } nyx_plugin_handler_t;
 
@@ -173,6 +175,7 @@ typedef struct afl_forkserver {
   void *                nyx_runner;      /* nyx runner object                */
   u32                   nyx_id;          /* nyx runner id (0 -> master)      */
   u32                   nyx_bind_cpu_id; /* nyx runner cpu id                */
+  char *                nyx_aux_string;
 #endif
 
 } afl_forkserver_t;
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
index be8099bb..6419cd1d 100644
--- a/instrumentation/afl-llvm-pass.so.cc
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -46,21 +46,12 @@ typedef long double max_align_t;
 
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/Pass.h"
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  #include "llvm/Passes/PassPlugin.h"
-  #include "llvm/Passes/PassBuilder.h"
-  #include "llvm/IR/PassManager.h"
-#else
-  #include "llvm/IR/LegacyPassManager.h"
-  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#endif
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
-#if LLVM_VERSION_MAJOR >= 14                /* how about stable interfaces? */
-  #include "llvm/Passes/OptimizationLevel.h"
-#endif
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 
 #if LLVM_VERSION_MAJOR >= 4 || \
     (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
@@ -78,30 +69,17 @@ using namespace llvm;
 
 namespace {
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-class AFLCoverage : public PassInfoMixin<AFLCoverage> {
-
- public:
-  AFLCoverage() {
-
-#else
 class AFLCoverage : public ModulePass {
 
  public:
   static char ID;
   AFLCoverage() : ModulePass(ID) {
 
-#endif
-
     initInstrumentList();
 
   }
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
-#else
   bool runOnModule(Module &M) override;
-#endif
 
  protected:
   uint32_t    ngram_size = 0;
@@ -115,55 +93,7 @@ class AFLCoverage : public ModulePass {
 
 }  // namespace
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
-llvmGetPassPluginInfo() {
-
-  return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
-          /* lambda to insert our pass into the pass pipeline. */
-          [](PassBuilder &PB) {
-
-  #if 1
-    #if LLVM_VERSION_MAJOR <= 13
-            using OptimizationLevel = typename PassBuilder::OptimizationLevel;
-    #endif
-            PB.registerOptimizerLastEPCallback(
-                [](ModulePassManager &MPM, OptimizationLevel OL) {
-
-                  MPM.addPass(AFLCoverage());
-
-                });
-
-  /* TODO LTO registration */
-  #else
-            using PipelineElement = typename PassBuilder::PipelineElement;
-            PB.registerPipelineParsingCallback([](StringRef          Name,
-                                                  ModulePassManager &MPM,
-                                                  ArrayRef<PipelineElement>) {
-
-              if (Name == "AFLCoverage") {
-
-                MPM.addPass(AFLCoverage());
-                return true;
-
-              } else {
-
-                return false;
-
-              }
-
-            });
-
-  #endif
-
-          }};
-
-}
-
-#else
-
 char AFLCoverage::ID = 0;
-#endif
 
 /* needed up to 3.9.0 */
 #if LLVM_VERSION_MAJOR == 3 && \
@@ -189,15 +119,8 @@ uint64_t PowerOf2Ceil(unsigned in) {
     (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
   #define AFL_HAVE_VECTOR_INTRINSICS 1
 #endif
-
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
-
-#else
 bool AFLCoverage::runOnModule(Module &M) {
 
-#endif
-
   LLVMContext &C = M.getContext();
 
   IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
@@ -211,10 +134,6 @@ bool AFLCoverage::runOnModule(Module &M) {
   u32             rand_seed;
   unsigned int    cur_loc = 0;
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  auto PA = PreservedAnalyses::all();
-#endif
-
   /* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
   gettimeofday(&tv, &tz);
   rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
@@ -1079,15 +998,10 @@ bool AFLCoverage::runOnModule(Module &M) {
 
   }
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  return PA;
-#else
   return true;
-#endif
 
 }
 
-#if LLVM_VERSION_MAJOR < 11                         /* use old pass manager */
 static void registerAFLPass(const PassManagerBuilder &,
                             legacy::PassManagerBase &PM) {
 
@@ -1100,5 +1014,4 @@ static RegisterStandardPasses RegisterAFLPass(
 
 static RegisterStandardPasses RegisterAFLPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
-#endif
 
diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc
index 5bd98072..85dec437 100644
--- a/instrumentation/cmplog-instructions-pass.cc
+++ b/instrumentation/cmplog-instructions-pass.cc
@@ -28,6 +28,7 @@
 #include "llvm/Config/llvm-config.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -37,6 +38,7 @@
   #include "llvm/IR/PassManager.h"
 #else
   #include "llvm/IR/LegacyPassManager.h"
+  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #endif
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Pass.h"
@@ -136,7 +138,7 @@ llvmGetPassPluginInfo() {
 #else
 char CmpLogInstructions::ID = 0;
 #endif
-
+  
 template <class Iterator>
 Iterator Unique(Iterator first, Iterator last) {
 
@@ -684,10 +686,10 @@ bool CmpLogInstructions::runOnModule(Module &M) {
 #else
   return true;
 #endif
-
+  
 }
 
-#if LLVM_MAJOR < 11                                 /* use old pass manager */
+#if LLVM_MAJOR < 11                                /* use old pass manager */
 static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
                                            legacy::PassManagerBase &PM) {
 
@@ -708,4 +710,3 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
     registerCmpLogInstructionsPass);
   #endif
 #endif
-
diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc
index 34c88735..9a4e4f00 100644
--- a/instrumentation/compare-transform-pass.so.cc
+++ b/instrumentation/compare-transform-pass.so.cc
@@ -26,23 +26,14 @@
 
 #include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-  #include "llvm/Passes/PassPlugin.h"
-  #include "llvm/Passes/PassBuilder.h"
-  #include "llvm/IR/PassManager.h"
-#else
-  #include "llvm/IR/LegacyPassManager.h"
-  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#endif
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Pass.h"
 #include "llvm/Analysis/ValueTracking.h"
-#if LLVM_VERSION_MAJOR >= 14                /* how about stable interfaces? */
-  #include "llvm/Passes/OptimizationLevel.h"
-#endif
 
 #if LLVM_VERSION_MAJOR >= 4 || \
     (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
@@ -61,21 +52,12 @@ using namespace llvm;
 
 namespace {
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-class CompareTransform : public PassInfoMixin<CompareTransform> {
-
- public:
-  CompareTransform() {
-
-#else
 class CompareTransform : public ModulePass {
 
  public:
   static char ID;
   CompareTransform() : ModulePass(ID) {
 
-#endif
-
     initInstrumentList();
 
   }
@@ -88,18 +70,17 @@ class CompareTransform : public ModulePass {
   const char *getPassName() const override {
 
   #endif
-
-    return "cmplog transform";
+    return "transforms compare functions";
 
   }
 
 #endif
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
-#else
+  //#if LLVM_MAJOR >= 11                             /* use new pass manager */
+  //  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+  //#else
   bool runOnModule(Module &M) override;
-#endif
+  //#endif
 
  private:
   bool transformCmps(Module &M, const bool processStrcmp,
@@ -111,54 +92,7 @@ class CompareTransform : public ModulePass {
 
 }  // namespace
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
-llvmGetPassPluginInfo() {
-
-  return {LLVM_PLUGIN_API_VERSION, "comparetransform", "v0.1",
-          /* lambda to insert our pass into the pass pipeline. */
-          [](PassBuilder &PB) {
-
-  #if 1
-    #if LLVM_VERSION_MAJOR <= 13
-            using OptimizationLevel = typename PassBuilder::OptimizationLevel;
-    #endif
-            PB.registerOptimizerLastEPCallback(
-                [](ModulePassManager &MPM, OptimizationLevel OL) {
-
-                  MPM.addPass(CompareTransform());
-
-                });
-
-  /* TODO LTO registration */
-  #else
-            using PipelineElement = typename PassBuilder::PipelineElement;
-            PB.registerPipelineParsingCallback([](StringRef          Name,
-                                                  ModulePassManager &MPM,
-                                                  ArrayRef<PipelineElement>) {
-
-              if (Name == "comparetransform") {
-
-                MPM.addPass(CompareTransform());
-                return true;
-
-              } else {
-
-                return false;
-
-              }
-
-            });
-
-  #endif
-
-          }};
-
-}
-
-#else
 char CompareTransform::ID = 0;
-#endif
 
 bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
                                      const bool processMemcmp,
@@ -458,7 +392,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
     bool        isCaseInsensitive = false;
     bool        needs_null = false;
     Function *  Callee = callInst->getCalledFunction();
-
     if (Callee) {
 
       if (!Callee->getName().compare("memcmp") ||
@@ -716,14 +649,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
 }
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-PreservedAnalyses CompareTransform::run(Module &M, ModuleAnalysisManager &MAM) {
-
-#else
 bool CompareTransform::runOnModule(Module &M) {
 
-#endif
-
   if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
     printf(
         "Running compare-transform-pass by laf.intel@gmail.com, extended by "
@@ -731,28 +658,13 @@ bool CompareTransform::runOnModule(Module &M) {
   else
     be_quiet = 1;
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-  auto PA = PreservedAnalyses::all();
-#endif
-
   transformCmps(M, true, true, true, true, true);
   verifyModule(M);
 
-#if LLVM_MAJOR >= 11                                /* use new pass manager */
-                     /*  if (modified) {
-                   
-                         PA.abandon<XX_Manager>();
-                   
-                       }*/
-
-  return PA;
-#else
   return true;
-#endif
 
 }
 
-#if LLVM_MAJOR < 11                                 /* use old pass manager */
 static void registerCompTransPass(const PassManagerBuilder &,
                                   legacy::PassManagerBase &PM) {
 
@@ -767,9 +679,8 @@ static RegisterStandardPasses RegisterCompTransPass(
 static RegisterStandardPasses RegisterCompTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass);
 
-  #if LLVM_VERSION_MAJOR >= 11
+#if LLVM_VERSION_MAJOR >= 11
 static RegisterStandardPasses RegisterCompTransPassLTO(
     PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass);
-  #endif
 #endif
 
diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc
index d7bb7aba..0f00fa96 100644
--- a/instrumentation/split-compares-pass.so.cc
+++ b/instrumentation/split-compares-pass.so.cc
@@ -1,7 +1,6 @@
 /*
  * Copyright 2016 laf-intel
  * extended for floating point by Heiko Eißfeldt
- * adapted to new pass manager by Heiko Eißfeldt
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,20 +28,10 @@
 
 #include "llvm/Pass.h"
 #include "llvm/Support/raw_ostream.h"
-
-#if LLVM_MAJOR >= 11
-  #include "llvm/Passes/PassPlugin.h"
-  #include "llvm/Passes/PassBuilder.h"
-  #include "llvm/IR/PassManager.h"
-#else
-  #include "llvm/IR/LegacyPassManager.h"
-  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#endif
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/IR/Module.h"
-#if LLVM_VERSION_MAJOR >= 14                /* how about stable interfaces? */
-  #include "llvm/Passes/OptimizationLevel.h"
-#endif
 
 #include "llvm/IR/IRBuilder.h"
 #if LLVM_VERSION_MAJOR >= 4 || \
@@ -64,31 +53,27 @@ using namespace llvm;
 
 namespace {
 
-#if LLVM_MAJOR >= 11
-class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
-
- public:
-  //  static char ID;
-  SplitComparesTransform() : enableFPSplit(0) {
-
-#else
 class SplitComparesTransform : public ModulePass {
 
  public:
   static char ID;
   SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
 
-#endif
-
     initInstrumentList();
 
   }
 
-#if LLVM_MAJOR >= 11
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
-#else
   bool runOnModule(Module &M) override;
+#if LLVM_VERSION_MAJOR >= 4
+  StringRef getPassName() const override {
+
+#else
+  const char *getPassName() const override {
+
 #endif
+    return "AFL_SplitComparesTransform";
+
+  }
 
  private:
   int enableFPSplit;
@@ -177,54 +162,7 @@ class SplitComparesTransform : public ModulePass {
 
 }  // namespace
 
-#if LLVM_MAJOR >= 11
-extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
-llvmGetPassPluginInfo() {
-
-  return {LLVM_PLUGIN_API_VERSION, "splitcompares", "v0.1",
-          /* lambda to insert our pass into the pass pipeline. */
-          [](PassBuilder &PB) {
-
-  #if 1
-    #if LLVM_VERSION_MAJOR <= 13
-            using OptimizationLevel = typename PassBuilder::OptimizationLevel;
-    #endif
-            PB.registerOptimizerLastEPCallback(
-                [](ModulePassManager &MPM, OptimizationLevel OL) {
-
-                  MPM.addPass(SplitComparesTransform());
-
-                });
-
-  /* TODO LTO registration */
-  #else
-            using PipelineElement = typename PassBuilder::PipelineElement;
-            PB.registerPipelineParsingCallback([](StringRef          Name,
-                                                  ModulePassManager &MPM,
-                                                  ArrayRef<PipelineElement>) {
-
-              if (Name == "splitcompares") {
-
-                MPM.addPass(SplitComparesTransform());
-                return true;
-
-              } else {
-
-                return false;
-
-              }
-
-            });
-
-  #endif
-
-          }};
-
-}
-
-#else
 char SplitComparesTransform::ID = 0;
-#endif
 
 /// This function splits FCMP instructions with xGE or xLE predicates into two
 /// FCMP instructions with predicate xGT or xLT and EQ
@@ -1483,15 +1421,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
 
 }
 
-#if LLVM_MAJOR >= 11
-PreservedAnalyses SplitComparesTransform::run(Module &               M,
-                                              ModuleAnalysisManager &MAM) {
-
-#else
 bool SplitComparesTransform::runOnModule(Module &M) {
 
-#endif
-
   char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
   if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
   if (bitw_env) { target_bitwidth = atoi(bitw_env); }
@@ -1501,7 +1432,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
   if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
       getenv("AFL_DEBUG") != NULL) {
 
-    errs() << "Split-compare-newpass by laf.intel@gmail.com, extended by "
+    errs() << "Split-compare-pass by laf.intel@gmail.com, extended by "
               "heiko@hexco.de (splitting icmp to "
            << target_bitwidth << " bit)\n";
 
@@ -1513,10 +1444,6 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
   }
 
-#if LLVM_MAJOR >= 11
-  auto PA = PreservedAnalyses::all();
-#endif
-
   if (enableFPSplit) {
 
     simplifyFPCompares(M);
@@ -1546,16 +1473,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
           auto op0 = CI->getOperand(0);
           auto op1 = CI->getOperand(1);
-          if (!op0 || !op1) {
-
-#if LLVM_MAJOR >= 11
-            return PA;
-#else
-            return false;
-#endif
-
-          }
-
+          if (!op0 || !op1) { return false; }
           auto iTy1 = dyn_cast<IntegerType>(op0->getType());
           if (iTy1 && isa<IntegerType>(op1->getType())) {
 
@@ -1604,29 +1522,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
   }
 
-  if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
-      getenv("AFL_DEBUG") != NULL) {
-
-    errs() << count << " comparisons found\n";
-
-  }
-
-#if LLVM_MAJOR >= 11
-  /*  if (modified) {
-
-      PA.abandon<XX_Manager>();
-
-    }*/
-
-  return PA;
-#else
   return true;
-#endif
 
 }
 
-#if LLVM_MAJOR < 11                                 /* use old pass manager */
-
 static void registerSplitComparesPass(const PassManagerBuilder &,
                                       legacy::PassManagerBase &PM) {
 
@@ -1640,15 +1539,14 @@ static RegisterStandardPasses RegisterSplitComparesPass(
 static RegisterStandardPasses RegisterSplitComparesTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
 
-  #if LLVM_VERSION_MAJOR >= 11
+#if LLVM_VERSION_MAJOR >= 11
 static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
     PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
     registerSplitComparesPass);
-  #endif
+#endif
 
 static RegisterPass<SplitComparesTransform> X("splitcompares",
                                               "AFL++ split compares",
                                               true /* Only looks at CFG */,
                                               true /* Analysis Pass */);
-#endif
 
diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc
index 96e01a8b..9f9e7eca 100644
--- a/instrumentation/split-switches-pass.so.cc
+++ b/instrumentation/split-switches-pass.so.cc
@@ -27,23 +27,14 @@
 
 #include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  #include "llvm/Passes/PassPlugin.h"
-  #include "llvm/Passes/PassBuilder.h"
-  #include "llvm/IR/PassManager.h"
-#else
-  #include "llvm/IR/LegacyPassManager.h"
-  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#endif
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Pass.h"
 #include "llvm/Analysis/ValueTracking.h"
-#if LLVM_VERSION_MAJOR >= 14                /* how about stable interfaces? */
-  #include "llvm/Passes/OptimizationLevel.h"
-#endif
 
 #include "llvm/IR/IRBuilder.h"
 #if LLVM_VERSION_MAJOR >= 4 || \
@@ -63,42 +54,29 @@ using namespace llvm;
 
 namespace {
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
-
- public:
-  SplitSwitchesTransform() {
-
-#else
 class SplitSwitchesTransform : public ModulePass {
 
  public:
   static char ID;
   SplitSwitchesTransform() : ModulePass(ID) {
 
-#endif
     initInstrumentList();
 
   }
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
-#else
-  bool      runOnModule(Module &M) override;
+  bool runOnModule(Module &M) override;
 
-  #if LLVM_VERSION_MAJOR >= 4
+#if LLVM_VERSION_MAJOR >= 4
   StringRef getPassName() const override {
 
-  #else
+#else
   const char *getPassName() const override {
 
-  #endif
+#endif
     return "splits switch constructs";
 
   }
 
-#endif
-
   struct CaseExpr {
 
     ConstantInt *Val;
@@ -125,54 +103,7 @@ class SplitSwitchesTransform : public ModulePass {
 
 }  // namespace
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
-llvmGetPassPluginInfo() {
-
-  return {LLVM_PLUGIN_API_VERSION, "splitswitches", "v0.1",
-          /* lambda to insert our pass into the pass pipeline. */
-          [](PassBuilder &PB) {
-
-  #if 1
-    #if LLVM_VERSION_MAJOR <= 13
-            using OptimizationLevel = typename PassBuilder::OptimizationLevel;
-    #endif
-            PB.registerOptimizerLastEPCallback(
-                [](ModulePassManager &MPM, OptimizationLevel OL) {
-
-                  MPM.addPass(SplitSwitchesTransform());
-
-                });
-
-  /* TODO LTO registration */
-  #else
-            using PipelineElement = typename PassBuilder::PipelineElement;
-            PB.registerPipelineParsingCallback([](StringRef          Name,
-                                                  ModulePassManager &MPM,
-                                                  ArrayRef<PipelineElement>) {
-
-              if (Name == "splitswitches") {
-
-                MPM.addPass(SplitSwitchesTransform());
-                return true;
-
-              } else {
-
-                return false;
-
-              }
-
-            });
-
-  #endif
-
-          }};
-
-}
-
-#else
 char SplitSwitchesTransform::ID = 0;
-#endif
 
 /* switchConvert - Transform simple list of Cases into list of CaseRange's */
 BasicBlock *SplitSwitchesTransform::switchConvert(
@@ -482,42 +413,19 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
 
 }
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-PreservedAnalyses SplitSwitchesTransform::run(Module &               M,
-                                              ModuleAnalysisManager &MAM) {
-
-#else
 bool SplitSwitchesTransform::runOnModule(Module &M) {
 
-#endif
-
   if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
     printf("Running split-switches-pass by laf.intel@gmail.com\n");
   else
     be_quiet = 1;
-
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-  auto PA = PreservedAnalyses::all();
-#endif
-
   splitSwitches(M);
   verifyModule(M);
 
-#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
-                             /*  if (modified) {
-                           
-                                 PA.abandon<XX_Manager>();
-                           
-                               }*/
-
-  return PA;
-#else
   return true;
-#endif
 
 }
 
-#if LLVM_VERSION_MAJOR < 11                         /* use old pass manager */
 static void registerSplitSwitchesTransPass(const PassManagerBuilder &,
                                            legacy::PassManagerBase &PM) {
 
@@ -532,10 +440,9 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass(
 static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
 
-  #if LLVM_VERSION_MAJOR >= 11
+#if LLVM_VERSION_MAJOR >= 11
 static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
     PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
     registerSplitSwitchesTransPass);
-  #endif
 #endif
 
diff --git a/nyx_mode/LIBNYX_VERSION b/nyx_mode/LIBNYX_VERSION
index b45b4e90..65e119c9 100644
--- a/nyx_mode/LIBNYX_VERSION
+++ b/nyx_mode/LIBNYX_VERSION
@@ -1 +1 @@
-2e45754
+8a77c71
diff --git a/nyx_mode/PACKER_VERSION b/nyx_mode/PACKER_VERSION
index 43488114..d67dee20 100644
--- a/nyx_mode/PACKER_VERSION
+++ b/nyx_mode/PACKER_VERSION
@@ -1 +1 @@
-76100c5
+5d143ee
diff --git a/nyx_mode/QEMU-Nyx b/nyx_mode/QEMU-Nyx
-Subproject c2c69cfc528398d9db9363b92f8c50db4008c98
+Subproject c08e4ac94244a9739b4484b3010abc06b372923
diff --git a/nyx_mode/QEMU_NYX_VERSION b/nyx_mode/QEMU_NYX_VERSION
index be13a784..2d9ee5e3 100644
--- a/nyx_mode/QEMU_NYX_VERSION
+++ b/nyx_mode/QEMU_NYX_VERSION
@@ -1 +1 @@
-c2c69cfc52
+c08e4ac942
diff --git a/nyx_mode/custom_harness/example.c b/nyx_mode/custom_harness/example.c
index dd268534..a67d42c6 100644
--- a/nyx_mode/custom_harness/example.c
+++ b/nyx_mode/custom_harness/example.c
@@ -7,7 +7,7 @@
 #define TRACE_BUFFER_SIZE (64)
 
 #define PAGE_SIZE 0x1000
-#define MMAP_SIZE(x) ((x & ~(PAGE_SIZE-1)) + PAGE_SIZE)
+#define MMAP_SIZE(x) ((x & ~(PAGE_SIZE - 1)) + PAGE_SIZE)
 
 int main(int argc, char **argv) {
 
@@ -30,8 +30,9 @@ int main(int argc, char **argv) {
   /* this is our "bitmap" that is later shared with the fuzzer (you can also
    * pass the pointer of the bitmap used by compile-time instrumentations in
    * your target) */
-  uint8_t *trace_buffer = mmap(NULL, MMAP_SIZE(TRACE_BUFFER_SIZE), PROT_READ | 
-                               PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+  uint8_t *trace_buffer =
+      mmap(NULL, MMAP_SIZE(TRACE_BUFFER_SIZE), PROT_READ | PROT_WRITE,
+           MAP_SHARED | MAP_ANONYMOUS, -1, 0);
   memset(trace_buffer, 0,
          TRACE_BUFFER_SIZE);  // makes sure that the bitmap buffer is already
                               // mapped into the guest's memory (alternatively
diff --git a/nyx_mode/libnyx b/nyx_mode/libnyx
-Subproject 2e45754e271463f446c31a6f467231d8657910e
+Subproject 8a77c71dc8a8c0b73abd8fb9c22e30d565184ef
diff --git a/nyx_mode/packer b/nyx_mode/packer
-Subproject 76100c52db96429350693a6c7284c5c6cbcb6b0
+Subproject 5d143eee4e4dcd12a1fc5d6786dd8da25cbb995
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 4c977303..051e4910 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -473,7 +473,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/split-switches-pass.so", obj_path);
 #endif
-
+        
       }
 
     }
@@ -499,7 +499,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/compare-transform-pass.so", obj_path);
 #endif
-
+        
       }
 
     }
@@ -514,16 +514,11 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       } else {
 
-#if LLVM_MAJOR >= 11
-        cc_params[cc_par_cnt++] =
-            alloc_printf("-fpass-plugin=%s/split-compares-pass.so", obj_path);
-#else
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/split-compares-pass.so", obj_path);
-#endif
 
       }
 
@@ -553,17 +548,11 @@ static void edit_params(u32 argc, char **argv, char **envp) {
             alloc_printf("%s/cmplog-switches-pass.so", obj_path);
 
         // reuse split switches from laf
-#if LLVM_MAJOR >= 11
-        cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
-        cc_params[cc_par_cnt++] =
-            alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path);
-#else
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/split-switches-pass.so", obj_path);
-#endif
 
       }
 
@@ -571,10 +560,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-#if LLVM_MAJOR == 13  // TODO: set to 14 when done FIXME
-    // Use the old pass manager in LLVM 13 which the afl++ passes still use.
-    cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
-#endif
+//#if LLVM_MAJOR >= 13
+//    // Use the old pass manager in LLVM 14 which the afl++ passes still use.
+//    cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
+//#endif
 
     if (lto_mode && !have_c) {
 
@@ -665,16 +654,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       } else {
 
-#if LLVM_MAJOR >= 11
-        cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
-        cc_params[cc_par_cnt++] =
-            alloc_printf("-fpass-plugin=%s/afl-llvm-pass.so", obj_path);
-#else
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
-#endif
 
       }
 
@@ -695,20 +678,23 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
         cc_params[cc_par_cnt++] = alloc_printf(
             "-fpass-plugin=%s/cmplog-instructions-pass.so", obj_path);
+        cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+        cc_params[cc_par_cnt++] = alloc_printf(
+            "-fpass-plugin=%s/cmplog-routines-pass.so", obj_path);
 #else
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
-#endif
 
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] =
             alloc_printf("%s/cmplog-routines-pass.so", obj_path);
-
+#endif
+        
       }
 
     }
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 8997781d..628ff590 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -450,6 +450,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
     fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, 2, 0);
     fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
 
+    fsrv->nyx_aux_string = malloc(0x1000);
+    memset(fsrv->nyx_aux_string, 0, 0x1000);
+
     /* dry run */
     fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, "INIT", 4);
     switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
@@ -1253,7 +1256,13 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
   fsrv->child_pid = -1;
 
 #ifdef __linux__
-  if (fsrv->nyx_mode) { fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); }
+  if (fsrv->nyx_mode) {
+
+    free(fsrv->nyx_aux_string);
+    fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+
+  }
+
 #endif
 
 }
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index b963caf8..971ac494 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -423,10 +423,10 @@ void write_crash_readme(afl_state_t *afl) {
       "them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n"
 
       "Found any cool bugs in open-source tools using afl-fuzz? If yes, please "
-      "drop\n"
-      "an mail at <afl-users@googlegroups.com> once the issues are fixed\n\n"
-
-      "  https://github.com/AFLplusplus/AFLplusplus\n\n",
+      "post\n"
+      "to https://github.com/AFLplusplus/AFLplusplus/issues/286 once the "
+      "issues\n"
+      " are fixed :)\n\n",
 
       afl->orig_cmdline,
       stringify_mem_size(val_buf, sizeof(val_buf),
@@ -771,6 +771,25 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
   ck_write(fd, mem, len, fn);
   close(fd);
 
+#ifdef __linux__
+  if (afl->fsrv.nyx_mode && fault == FSRV_RUN_CRASH) {
+
+    u8 fn_log[PATH_MAX];
+
+    snprintf(fn_log, PATH_MAX, "%s.log", fn);
+    fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+    if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); }
+
+    u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string(
+        afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string, 0x1000);
+
+    ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len, fn_log);
+    close(fd);
+
+  }
+
+#endif
+
   return keeping;
 
 }
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 1e4b1b3c..2f32ef1e 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -2136,7 +2136,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
 
       if ((i % 2)) {
 
-        if (len > idx + i && is_hex(orig_buf + idx + i)) {
+        if (len > idx + i + 1 && is_hex(orig_buf + idx + i)) {
 
           fromhex += 2;
 
@@ -2323,7 +2323,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
         if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
         // fprintf(stderr, "RTN ATTEMPT fromhex %u result %u\n", fromhex,
         // *status);
-        memcpy(buf + idx + i, save + i, i + 1 + off);
+        memcpy(buf + idx, save, i + 1 + off);
 
       }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 5da0e583..2a9d186b 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -232,7 +232,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
 
       memcpy(afl->fsrv.shmem_fuzz, mem, skip_at);
 
-      memcpy(afl->fsrv.shmem_fuzz, mem + skip_at + skip_len, tail_len);
+      memcpy(afl->fsrv.shmem_fuzz + skip_at, mem + skip_at + skip_len, tail_len);
 
     }
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index c73ab38b..c5333056 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -167,7 +167,9 @@ static void usage(u8 *argv0, int more_help) {
       "                  See docs/README.MOpt.md\n"
       "  -c program    - enable CmpLog by specifying a binary compiled for "
       "it.\n"
-      "                  if using QEMU, just use -c 0.\n"
+      "                  if using QEMU/FRIDA or if you the fuzzing target is "
+      "compiled"
+      "                  for CmpLog then just use -c 0.\n"
       "  -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
       "                  1=small files, 2=larger files (default), 3=all "
       "files,\n"
@@ -466,6 +468,9 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
       dlsym(handle, "nyx_get_bitmap_buffer_size");
   if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
 
+  plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
+  if (plugin->nyx_get_aux_string == NULL) { goto fail; }
+
   OKF("libnyx plugin is ready!");
   return plugin;
 
@@ -1458,6 +1463,13 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (!afl->use_banner) { afl->use_banner = argv[optind]; }
 
+  if (afl->shm.cmplog_mode &&
+      (!strcmp("-", afl->cmplog_binary) || !strcmp("0", afl->cmplog_binary))) {
+
+    afl->cmplog_binary = argv[optind];
+
+  }
+
   if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) {
 
     WARNF(cLRD
@@ -1675,7 +1687,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (getenv("LD_PRELOAD")) {
 
     WARNF(
-        "LD_PRELOAD is set, are you sure that is what to you want to do "
+        "LD_PRELOAD is set, are you sure that is what you want to do "
         "instead of using AFL_PRELOAD?");
 
   }