about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--docs/env_variables.md7
-rw-r--r--frida_mode/README.md2
-rw-r--r--frida_mode/frida.map1
-rw-r--r--frida_mode/include/instrument.h3
-rw-r--r--frida_mode/include/module.h11
-rw-r--r--frida_mode/src/instrument/instrument.c10
-rw-r--r--frida_mode/src/instrument/instrument_arm32.c9
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c8
-rw-r--r--frida_mode/src/instrument/instrument_x64.c533
-rw-r--r--frida_mode/src/instrument/instrument_x86.c8
-rw-r--r--frida_mode/src/js/api.js7
-rw-r--r--frida_mode/src/js/js_api.c7
-rw-r--r--frida_mode/src/main.c3
-rw-r--r--frida_mode/src/module.c106
-rw-r--r--frida_mode/src/ranges.c2
-rw-r--r--frida_mode/test/cmov/GNUmakefile87
-rw-r--r--frida_mode/test/cmov/Makefile19
-rw-r--r--frida_mode/test/cmov/cmov.c122
-rw-r--r--frida_mode/test/python/GNUmakefile37
-rw-r--r--frida_mode/test/python/Makefile17
-rw-r--r--frida_mode/ts/lib/afl.ts12
-rw-r--r--include/envs.h1
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc5
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc1
-rw-r--r--instrumentation/afl-llvm-dict2file.so.cc15
-rw-r--r--instrumentation/afl-llvm-lto-instrumentlist.so.cc1
-rw-r--r--instrumentation/afl-llvm-pass.so.cc92
-rw-r--r--instrumentation/cmplog-instructions-pass.cc37
-rw-r--r--instrumentation/compare-transform-pass.so.cc110
-rw-r--r--instrumentation/split-compares-pass.so.cc132
-rw-r--r--instrumentation/split-switches-pass.so.cc107
-rw-r--r--src/afl-cc.c41
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
-rw-r--r--unicorn_mode/samples/compcov_x64/compcov_test_harness.py4
-rw-r--r--unicorn_mode/samples/speedtest/python/harness.py4
m---------unicorn_mode/unicornafl0
36 files changed, 1196 insertions, 367 deletions
diff --git a/docs/env_variables.md b/docs/env_variables.md
index 4626a9b6..edd57fb6 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -518,7 +518,12 @@ checks or alter some of the more exotic semantics of the tool:
     the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz
     ... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would
     theoretically allow fuzzing of AFL++ itself (with 'target' AFL++ using some
-    AFL_ vars that would disrupt work of 'fuzzer' AFL++).
+    AFL_ vars that would disrupt work of 'fuzzer' AFL++). Note that when using
+    QEMU mode, the `AFL_TARGET_ENV` environment variables will apply to QEMU, as
+    well as the target binary. Therefore, in this case, you might want to use
+    QEMU's `QEMU_SET_ENV` environment variable (see QEMU's documentation because
+    the format is different from `AFL_TARGET_ENV`) to apply the environment
+    variables to the target and not QEMU.
 
   - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define
     TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if
diff --git a/frida_mode/README.md b/frida_mode/README.md
index e5b46baf..50e3b8d7 100644
--- a/frida_mode/README.md
+++ b/frida_mode/README.md
@@ -170,6 +170,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
   ***
   ```
 
+* `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
   code. Code is considered to be JIT if the executable segment is not backed by
   a file.
diff --git a/frida_mode/frida.map b/frida_mode/frida.map
index d059bdb6..41220d4b 100644
--- a/frida_mode/frida.map
+++ b/frida_mode/frida.map
@@ -15,6 +15,7 @@
     js_api_set_instrument_debug_file;
     js_api_set_instrument_jit;
     js_api_set_instrument_libraries;
+    js_api_set_instrument_instructions;
     js_api_set_instrument_no_optimize;
     js_api_set_instrument_seed;
     js_api_set_instrument_trace;
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
index abb89c9f..20312a4b 100644
--- a/frida_mode/include/instrument.h
+++ b/frida_mode/include/instrument.h
@@ -12,6 +12,7 @@ extern gboolean instrument_optimize;
 extern gboolean instrument_unique;
 extern guint64  instrument_hash_zero;
 extern char *   instrument_coverage_unstable_filename;
+extern gboolean instrument_coverage_insn;
 
 extern gboolean instrument_use_fixed_seed;
 extern guint64  instrument_fixed_seed;
@@ -33,6 +34,8 @@ gboolean instrument_is_coverage_optimize_supported(void);
 void instrument_coverage_optimize_init(void);
 void instrument_coverage_optimize(const cs_insn *   instr,
                                   GumStalkerOutput *output);
+void instrument_coverage_optimize_insn(const cs_insn *   instr,
+                                       GumStalkerOutput *output);
 
 void     instrument_debug_config(void);
 void     instrument_debug_init(void);
diff --git a/frida_mode/include/module.h b/frida_mode/include/module.h
new file mode 100644
index 00000000..b66f7feb
--- /dev/null
+++ b/frida_mode/include/module.h
@@ -0,0 +1,11 @@
+#ifndef _MODULE_H
+#define _MODULE_H
+
+#include "frida-gumjs.h"
+
+void module_config(void);
+
+void module_init(void);
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index 418b35e8..43560478 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -29,6 +29,7 @@ guint64  instrument_hash_seed = 0;
 gboolean instrument_use_fixed_seed = FALSE;
 guint64  instrument_fixed_seed = 0;
 char *   instrument_coverage_unstable_filename = NULL;
+gboolean instrument_coverage_insn = FALSE;
 
 static GumStalkerTransformer *transformer = NULL;
 
@@ -233,6 +234,12 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
 
     }
 
+    if (instrument_coverage_insn) {
+
+      instrument_coverage_optimize_insn(instr, output);
+
+    }
+
     instrument_debug_instruction(instr->address, instr->size, output);
 
     if (likely(!excluded)) {
@@ -269,6 +276,7 @@ void instrument_config(void) {
   instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0);
   instrument_coverage_unstable_filename =
       (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
+  instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL);
 
   instrument_debug_config();
   instrument_coverage_config();
@@ -294,6 +302,8 @@ void instrument_init(void) {
        instrument_coverage_unstable_filename == NULL
            ? " "
            : instrument_coverage_unstable_filename);
+  FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]",
+       instrument_coverage_insn ? 'X' : ' ');
 
   if (instrument_tracing && instrument_optimize) {
 
diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c
index 16e8eaab..705faa64 100644
--- a/frida_mode/src/instrument/instrument_arm32.c
+++ b/frida_mode/src/instrument/instrument_arm32.c
@@ -20,6 +20,15 @@ void instrument_coverage_optimize(const cs_insn *   instr,
 
 }
 
+void instrument_coverage_optimize_insn(const cs_insn *   instr,
+                                       GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+  FFATAL("Optimized coverage not supported on this architecture");
+
+}
+
 void instrument_coverage_optimize_init(void) {
 
   FWARNF("Optimized coverage not supported on this architecture");
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
index 1a704585..4abc0625 100644
--- a/frida_mode/src/instrument/instrument_arm64.c
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -341,6 +341,14 @@ void instrument_coverage_optimize(const cs_insn *   instr,
 
 }
 
+void instrument_coverage_optimize_insn(const cs_insn *   instr,
+                                       GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+}
+
 void instrument_coverage_optimize_init(void) {
 
   char *shm_env = getenv(SHM_ENV_VAR);
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
index fb84d6d2..4b1a2d68 100644
--- a/frida_mode/src/instrument/instrument_x64.c
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -23,13 +23,39 @@
 
 #if defined(__x86_64__)
 
-  #ifndef MAP_FIXED_NOREPLACE
-    #ifdef MAP_EXCL
-      #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
-    #else
-      #define MAP_FIXED_NOREPLACE MAP_FIXED
-    #endif
-  #endif
+enum jcc_opcodes {
+
+  OPC_JO = 0x70,
+  OPC_JNO = 0x71,
+  OPC_JB = 0x72,
+  OPC_JAE = 0x73,
+  OPC_JE = 0x74,
+  OPC_JNE = 0x75,
+  OPC_JBE = 0x76,
+  OPC_JA = 0x77,
+  OPC_JS = 0x78,
+  OPC_JNS = 0x79,
+  OPC_JP = 0x7a,
+  OPC_JNP = 0x7b,
+  OPC_JL = 0x7c,
+  OPC_JGE = 0x7d,
+  OPC_JLE = 0x7e,
+  OPC_JG = 0x7f,
+
+};
+
+typedef union {
+
+  struct {
+
+    uint8_t opcode;
+    uint8_t distance;
+
+  };
+
+  uint8_t bytes[0];
+
+} jcc_insn;
 
 static GHashTable *coverage_blocks = NULL;
 
@@ -45,8 +71,7 @@ static gboolean instrument_coverage_in_range(gssize offset) {
 
 }
 
-  #ifdef __APPLE__
-    #pragma pack(push, 1)
+  #pragma pack(push, 1)
 
 typedef struct {
 
@@ -54,95 +79,28 @@ typedef struct {
   // shared_mem[cur_location ^ prev_location]++;
   // prev_location = cur_location >> 1;
 
-  //  mov    QWORD PTR [rsp-0x80],rax
-  //  lahf
-  //  mov    QWORD PTR [rsp-0x88],rax
-  //  mov    QWORD PTR [rsp-0x90],rbx
-  //  mov    eax,DWORD PTR [rip+0x333d5a]        # 0x7ffff6ff2740
-  //  mov    DWORD PTR [rip+0x333d3c],0x9fbb        # 0x7ffff6ff2740
-  //  lea    rax,[rip + 0x103f77]
-  //  mov    bl,BYTE PTR [rax]
-  //  add    bl,0x1
-  //  adc    bl,0x0
-  //  mov    BYTE PTR [rax],bl
-  //  mov    rbx,QWORD PTR [rsp-0x90]
-  //  mov    rax,QWORD PTR [rsp-0x88]
-  //  sahf
-  //  mov    rax,QWORD PTR [rsp-0x80]
-
-  uint8_t mov_rax_rsp_88[8];
-  uint8_t lahf;
-  uint8_t mov_rax_rsp_90[8];
-  uint8_t mov_rbx_rsp_98[8];
-
-  uint8_t mov_eax_prev_loc[6];
-  uint8_t mov_prev_loc_curr_loc_shr1[10];
-
-  uint8_t leax_eax_curr_loc[7];
+  // mov    QWORD PTR [rsp-0x88],rax
+  // lahf
+  // mov    QWORD PTR [rsp-0x90],rax
+  // mov    QWORD PTR [rsp-0x98],rbx
 
-  uint8_t mov_rbx_ptr_rax[2];
-  uint8_t add_bl_1[3];
-  uint8_t adc_bl_0[3];
-  uint8_t mov_ptr_rax_rbx[2];
+  // mov    eax,DWORD PTR [rip+0x1312334]
+  // xor    eax,0x3f77
 
-  uint8_t mov_rsp_98_rbx[8];
-  uint8_t mov_rsp_90_rax[8];
-  uint8_t sahf;
-  uint8_t mov_rsp_88_rax[8];
+  // lea    rbx,[rip+0x132338]
+  // add    rax,rbx
 
-} afl_log_code_asm_t;
+  // mov    bl,BYTE PTR [rax]
+  // add    bl,0x1
+  // adc    bl,0x0
+  // mov    BYTE PTR [rax],bl
 
-    #pragma pack(pop)
+  // mov    rbx,QWORD PTR [rsp-0x98]
+  // mov    rax,QWORD PTR [rsp-0x90]
+  // sahf
+  // mov    rax,QWORD PTR [rsp-0x88]
 
-static const afl_log_code_asm_t template =
-    {
-
-        .mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
-        .lahf = 0x9f,
-        .mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
-        .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
-
-        .mov_eax_prev_loc = {0x8b, 0x05},
-        .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
-
-        .leax_eax_curr_loc = {0x48, 0x8d, 0x05},
-        .mov_rbx_ptr_rax = {0x8a, 0x18},
-        .add_bl_1 = {0x80, 0xc3, 0x01},
-        .adc_bl_0 = {0x80, 0xd3, 0x00},
-        .mov_ptr_rax_rbx = {0x88, 0x18},
-
-        .mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
-        .mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
-        .sahf = 0x9e,
-        .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
-
-}
-
-;
-
-  #else
-    #pragma pack(push, 1)
-typedef struct {
-
-  // cur_location = (block_address >> 4) ^ (block_address << 8);
-  // shared_mem[cur_location ^ prev_location]++;
-  // prev_location = cur_location >> 1;
-
-  //  mov    QWORD PTR [rsp-0x80],rax
-  //  lahf
-  //  mov    QWORD PTR [rsp-0x88],rax
-  //  mov    QWORD PTR [rsp-0x90],rbx
-  //  mov    eax,DWORD PTR [rip+0x333d5a]        # 0x7ffff6ff2740
-  //  mov    DWORD PTR [rip+0x333d3c],0x9fbb        # 0x7ffff6ff2740
-  //  xor    eax,0x103f77
-  //  mov    bl,BYTE PTR [rax]
-  //  add    bl,0x1
-  //  adc    bl,0x0
-  //  mov    BYTE PTR [rax],bl
-  //  mov    rbx,QWORD PTR [rsp-0x90]
-  //  mov    rax,QWORD PTR [rsp-0x88]
-  //  sahf
-  //  mov    rax,QWORD PTR [rsp-0x80]
+  // mov    DWORD PTR [rip+0x13122f8],0x9fbb
 
   uint8_t mov_rax_rsp_88[8];
   uint8_t lahf;
@@ -150,10 +108,11 @@ typedef struct {
   uint8_t mov_rbx_rsp_98[8];
 
   uint8_t mov_eax_prev_loc[6];
-  uint8_t mov_prev_loc_curr_loc_shr1[10];
-
   uint8_t xor_eax_curr_loc[5];
 
+  uint8_t lea_rbx_area_ptr[7];
+  uint8_t add_rax_rbx[3];
+
   uint8_t mov_rbx_ptr_rax[2];
   uint8_t add_bl_1[3];
   uint8_t adc_bl_0[3];
@@ -164,9 +123,11 @@ typedef struct {
   uint8_t sahf;
   uint8_t mov_rsp_88_rax[8];
 
+  uint8_t mov_prev_loc_curr_loc_shr1[10];
+
 } afl_log_code_asm_t;
 
-    #pragma pack(pop)
+  #pragma pack(pop)
 
 static const afl_log_code_asm_t template =
     {
@@ -177,9 +138,10 @@ static const afl_log_code_asm_t template =
         .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
 
         .mov_eax_prev_loc = {0x8b, 0x05},
-        .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
-
         .xor_eax_curr_loc = {0x35},
+        .lea_rbx_area_ptr = {0x48, 0x8d, 0x1d},
+        .add_rax_rbx = {0x48, 0x01, 0xd8},
+
         .mov_rbx_ptr_rax = {0x8a, 0x18},
         .add_bl_1 = {0x80, 0xc3, 0x01},
         .adc_bl_0 = {0x80, 0xd3, 0x00},
@@ -190,10 +152,11 @@ static const afl_log_code_asm_t template =
         .sahf = 0x9e,
         .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
 
+        .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05},
+
 }
 
 ;
-  #endif
 
 typedef union {
 
@@ -202,171 +165,12 @@ typedef union {
 
 } afl_log_code;
 
-  #ifdef __APPLE__
-
-void instrument_coverage_optimize_init(void) {
-
-}
-
-  #else
-
-static gboolean instrument_coverage_find_low(const GumRangeDetails *details,
-                                             gpointer               user_data) {
-
-  static GumAddress last_limit = (64ULL << 10);
-  gpointer *        address = (gpointer *)user_data;
-
-  last_limit = GUM_ALIGN_SIZE(last_limit, __afl_map_size);
-
-  if ((details->range->base_address - last_limit) > __afl_map_size) {
-
-    *address = GSIZE_TO_POINTER(last_limit);
-    return FALSE;
-
-  }
-
-  if (details->range->base_address > ((2ULL << 30) - __afl_map_size)) {
-
-    return FALSE;
-
-  }
-
-  /*
-   * Align our buffer on a 64k boundary so that the low 16-bits of the address
-   * are zero, then we can just XOR the base address in, when we XOR with the
-   * current block ID.
-   */
-  last_limit = GUM_ALIGN_SIZE(
-      details->range->base_address + details->range->size, __afl_map_size);
-  return TRUE;
-
-}
-
-static void instrument_coverage_optimize_map_mmap_anon(gpointer address) {
-
-  __afl_area_ptr =
-      mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
-           MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-  if (__afl_area_ptr != address) {
-
-    FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
-
-  }
-
-}
-
-static void instrument_coverage_optimize_map_mmap(char *   shm_file_path,
-                                                  gpointer address) {
-
-  int shm_fd = -1;
-
-  if (munmap(__afl_area_ptr, __afl_map_size) != 0) {
-
-    FATAL("Failed to unmap previous __afl_area_ptr");
-
-  }
-
-  __afl_area_ptr = NULL;
-
-    #if !defined(__ANDROID__)
-  shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
-  if (shm_fd == -1) { FATAL("shm_open() failed\n"); }
-    #else
-  shm_fd = open("/dev/ashmem", O_RDWR);
-  if (shm_fd == -1) { FATAL("open() failed\n"); }
-  if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) {
-
-    FATAL("ioctl(ASHMEM_SET_NAME) failed");
-
-  }
-
-  if (ioctl(shm_fd, ASHMEM_SET_SIZE, __afl_map_size) == -1) {
-
-    FATAL("ioctl(ASHMEM_SET_SIZE) failed");
-
-  }
-
-    #endif
-
-  __afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
-                        MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
-  if (__afl_area_ptr != address) {
-
-    FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
-
-  }
-
-  if (close(shm_fd) != 0) { FATAL("Failed to close shm_fd"); }
-
-}
-
-static void instrument_coverage_optimize_map_shm(guint64  shm_env_val,
-                                                 gpointer address) {
-
-  if (shmdt(__afl_area_ptr) != 0) {
-
-    FATAL("Failed to detach previous __afl_area_ptr");
-
-  }
-
-  __afl_area_ptr = shmat(shm_env_val, address, 0);
-  if (__afl_area_ptr != address) {
-
-    FATAL("Failed to map shm __afl_area_ptr: %d", errno);
-
-  }
-
-}
-
 void instrument_coverage_optimize_init(void) {
 
-  gpointer low_address = NULL;
-
-  gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low,
-                               &low_address);
-
-  FVERBOSE("Low address: %p", low_address);
-
-  if (low_address == 0 ||
-      GPOINTER_TO_SIZE(low_address) > ((2UL << 30) - __afl_map_size)) {
-
-    FATAL("Invalid low_address: %p", low_address);
-
-  }
-
-  ranges_print_debug_maps();
-
-  char *shm_env = getenv(SHM_ENV_VAR);
-  FVERBOSE("SHM_ENV_VAR: %s", shm_env);
-
-  if (shm_env == NULL) {
-
-    FWARNF("SHM_ENV_VAR not set, using anonymous map for debugging purposes");
-
-    instrument_coverage_optimize_map_mmap_anon(low_address);
-
-  } else {
-
-    guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10);
-
-    if (shm_env_val == 0) {
-
-      instrument_coverage_optimize_map_mmap(shm_env, low_address);
-
-    } else {
-
-      instrument_coverage_optimize_map_shm(shm_env_val, low_address);
-
-    }
-
-  }
-
   FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
 
 }
 
-  #endif
-
 static void instrument_coverage_switch(GumStalkerObserver *self,
                                        gpointer            start_address,
                                        const cs_insn *     from_insn,
@@ -431,48 +235,19 @@ static void instrument_coverage_suppress_init(void) {
 
 }
 
-void instrument_coverage_optimize(const cs_insn *   instr,
-                                  GumStalkerOutput *output) {
+static void instrument_coverage_write(GumAddress        address,
+                                      GumStalkerOutput *output) {
 
   afl_log_code  code = {0};
   GumX86Writer *cw = output->writer.x86;
-  guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
-  gsize   map_size_pow2;
-  gsize   area_offset_ror;
-  GumAddress code_addr = 0;
-  if (instrument_previous_pc_addr == NULL) {
-
-    GumAddressSpec spec = {.near_address = cw->code,
-                           .max_distance = 1ULL << 30};
-
-    instrument_previous_pc_addr = gum_memory_allocate_near(
-        &spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
-    *instrument_previous_pc_addr = instrument_hash_zero;
-    FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
-    FVERBOSE("code_addr: %p", cw->code);
-
-  }
-
-  instrument_coverage_suppress_init();
-
-  // gum_x86_writer_put_breakpoint(cw);
-  code_addr = cw->pc;
-  if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
-
-    FATAL("Failed - g_hash_table_add");
-
-  }
+  guint64       area_offset = instrument_get_offset_hash(address);
+  gsize         map_size_pow2;
+  gsize         area_offset_ror;
+  GumAddress    code_addr = cw->pc;
 
   code.code = template;
 
-  gssize curr_loc_shr_1_offset =
-      offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
-      sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
-
-  map_size_pow2 = util_log2(__afl_map_size);
-  area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
-
-  *((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
+  /* mov_prev_loc_curr_loc_shr1 */
 
   gssize prev_loc_value =
       GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
@@ -490,6 +265,8 @@ void instrument_coverage_optimize(const cs_insn *   instr,
 
   *((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
 
+  /* mov_eax_prev_loc */
+
   gssize prev_loc_value2 =
       GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
       (code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
@@ -505,40 +282,172 @@ void instrument_coverage_optimize(const cs_insn *   instr,
 
   *((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2;
 
-  #ifdef __APPLE__
+  /* xor_eax_curr_loc */
 
-  gssize xor_curr_loc_offset = offsetof(afl_log_code, code.leax_eax_curr_loc) +
-                               sizeof(code.code.leax_eax_curr_loc) -
+  gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) +
+                               sizeof(code.code.xor_eax_curr_loc) -
                                sizeof(guint32);
 
-  gssize xor_curr_loc_value =
-      ((GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset) -
-       (code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) +
-        sizeof(code.code.mov_eax_prev_loc)));
+  *((guint32 *)&code.bytes[xor_curr_loc_offset]) = area_offset;
+
+  /* lea_rbx_area_ptr */
+
+  gssize lea_rbx_area_ptr_offset =
+      offsetof(afl_log_code, code.lea_rbx_area_ptr) +
+      sizeof(code.code.lea_rbx_area_ptr) - sizeof(guint32);
+
+  gssize lea_rbx_area_ptr_value =
+      (GPOINTER_TO_SIZE(__afl_area_ptr) -
+       (code_addr + offsetof(afl_log_code, code.lea_rbx_area_ptr) +
+        sizeof(code.code.lea_rbx_area_ptr)));
 
-  if (!instrument_coverage_in_range(xor_curr_loc_value)) {
+  if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) {
 
-    FATAL("Patch out of range (xor_curr_loc_value): 0x%016lX",
-          xor_curr_loc_value);
+    FATAL("Patch out of range (lea_rbx_area_ptr_value): 0x%016lX",
+          lea_rbx_area_ptr_value);
 
   }
 
-  *((guint32 *)&code.bytes[xor_curr_loc_offset]) = xor_curr_loc_value;
+  *((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value;
 
-  #else
+  /* mov_prev_loc_curr_loc_shr1 */
 
-  gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) +
-                               sizeof(code.code.xor_eax_curr_loc) -
-                               sizeof(guint32);
+  gssize curr_loc_shr_1_offset =
+      offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
+      sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
 
-  *((guint32 *)&code.bytes[xor_curr_loc_offset]) =
-      (guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset);
-  #endif
+  map_size_pow2 = util_log2(__afl_map_size);
+  area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
+
+  *((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
 
   gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
 
 }
 
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+  guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
+  if (instrument_previous_pc_addr == NULL) {
+
+    GumAddressSpec spec = {.near_address = cw->code,
+                           .max_distance = 1ULL << 30};
+
+    instrument_previous_pc_addr = gum_memory_allocate_near(
+        &spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
+    *instrument_previous_pc_addr = instrument_hash_zero;
+    FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
+    FVERBOSE("code_addr: %p", cw->code);
+
+  }
+
+  instrument_coverage_suppress_init();
+
+  if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
+
+    FATAL("Failed - g_hash_table_add");
+
+  }
+
+  instrument_coverage_write(GUM_ADDRESS(instr->address), output);
+
+}
+
+void instrument_coverage_optimize_insn(const cs_insn *   instr,
+                                       GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+  jcc_insn      taken, not_taken;
+
+  switch (instr->id) {
+
+    case X86_INS_CMOVA:
+      taken.opcode = OPC_JA;
+      not_taken.opcode = OPC_JBE;
+      break;
+    case X86_INS_CMOVAE:
+      taken.opcode = OPC_JAE;
+      not_taken.opcode = OPC_JB;
+      break;
+    case X86_INS_CMOVB:
+      taken.opcode = OPC_JB;
+      not_taken.opcode = OPC_JAE;
+      break;
+    case X86_INS_CMOVBE:
+      taken.opcode = OPC_JBE;
+      not_taken.opcode = OPC_JA;
+      break;
+    case X86_INS_CMOVE:
+      taken.opcode = OPC_JE;
+      not_taken.opcode = OPC_JNE;
+      break;
+    case X86_INS_CMOVG:
+      taken.opcode = OPC_JG;
+      not_taken.opcode = OPC_JLE;
+      break;
+    case X86_INS_CMOVGE:
+      taken.opcode = OPC_JGE;
+      not_taken.opcode = OPC_JL;
+      break;
+    case X86_INS_CMOVL:
+      taken.opcode = OPC_JL;
+      not_taken.opcode = OPC_JGE;
+      break;
+    case X86_INS_CMOVLE:
+      taken.opcode = OPC_JLE;
+      not_taken.opcode = OPC_JG;
+      break;
+    case X86_INS_CMOVNE:
+      taken.opcode = OPC_JNE;
+      not_taken.opcode = OPC_JE;
+      break;
+    case X86_INS_CMOVNO:
+      taken.opcode = OPC_JNO;
+      not_taken.opcode = OPC_JO;
+      break;
+    case X86_INS_CMOVNP:
+      taken.opcode = OPC_JNP;
+      not_taken.opcode = OPC_JP;
+      break;
+    case X86_INS_CMOVNS:
+      taken.opcode = OPC_JNS;
+      not_taken.opcode = OPC_JS;
+      break;
+    case X86_INS_CMOVO:
+      taken.opcode = OPC_JO;
+      not_taken.opcode = OPC_JNO;
+      break;
+    case X86_INS_CMOVP:
+      taken.opcode = OPC_JP;
+      not_taken.opcode = OPC_JNP;
+      break;
+    case X86_INS_CMOVS:
+      taken.opcode = OPC_JS;
+      not_taken.opcode = OPC_JNS;
+      break;
+    default:
+      return;
+
+  }
+
+  taken.distance = sizeof(afl_log_code);
+  not_taken.distance = sizeof(afl_log_code);
+
+  // gum_x86_writer_put_breakpoint(cw);
+
+  gum_x86_writer_put_bytes(cw, taken.bytes, sizeof(jcc_insn));
+  instrument_coverage_write(GUM_ADDRESS(instr->address), output);
+
+  gum_x86_writer_put_bytes(cw, not_taken.bytes, sizeof(jcc_insn));
+  instrument_coverage_write(GUM_ADDRESS(instr->address + instr->size), output);
+
+  FVERBOSE("Instrument - 0x%016lx: %s %s", instr->address, instr->mnemonic,
+           instr->op_str);
+
+}
+
 void instrument_flush(GumStalkerOutput *output) {
 
   gum_x86_writer_flush(output->writer.x86);
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
index c4e93324..916cd0e2 100644
--- a/frida_mode/src/instrument/instrument_x86.c
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -218,6 +218,14 @@ void instrument_coverage_optimize(const cs_insn *   instr,
 
 }
 
+void instrument_coverage_optimize_insn(const cs_insn *   instr,
+                                       GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+}
+
 void instrument_coverage_optimize_init(void) {
 
 }
diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js
index 52e9e45c..82b8e63d 100644
--- a/frida_mode/src/js/api.js
+++ b/frida_mode/src/js/api.js
@@ -114,6 +114,12 @@ class Afl {
         Afl.jsApiSetInstrumentTrace();
     }
     /**
+     * See `AFL_FRIDA_INST_INSN`
+     */
+    static setInstrumentInstructions() {
+        Afl.jsApiSetInstrumentInstructions();
+    }
+    /**
      * See `AFL_FRIDA_INST_JIT`.
      */
     static setInstrumentJit() {
@@ -297,6 +303,7 @@ Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []
 Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
 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", []);
 Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
 Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
 Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
index 94ec8842..89df7803 100644
--- a/frida_mode/src/js/js_api.c
+++ b/frida_mode/src/js/js_api.c
@@ -142,6 +142,13 @@ js_api_set_prefetch_backpatch_disable(void) {
 
 }
 
+__attribute__((visibility("default"))) void js_api_set_instrument_instructions(
+    void) {
+
+  instrument_coverage_insn = TRUE;
+
+}
+
 __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
     void) {
 
diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c
index d8521300..bb6e4109 100644
--- a/frida_mode/src/main.c
+++ b/frida_mode/src/main.c
@@ -21,6 +21,7 @@
 #include "intercept.h"
 #include "js.h"
 #include "lib.h"
+#include "module.h"
 #include "output.h"
 #include "persistent.h"
 #include "prefetch.h"
@@ -197,6 +198,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
   instrument_config();
   js_config();
   lib_config();
+  module_config();
   output_config();
   persistent_config();
   prefetch_config();
@@ -214,6 +216,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
   entry_init();
   instrument_init();
   lib_init();
+  module_init();
   persistent_init();
   prefetch_init();
   seccomp_init();
diff --git a/frida_mode/src/module.c b/frida_mode/src/module.c
new file mode 100644
index 00000000..65b394cd
--- /dev/null
+++ b/frida_mode/src/module.c
@@ -0,0 +1,106 @@
+#include "intercept.h"
+#include "module.h"
+#include "util.h"
+
+#if defined(__linux__)
+  #include <dlfcn.h>
+  #include <link.h>
+#endif
+
+static guint    page_size = 0;
+static gboolean handle_dlclose = FALSE;
+
+void module_config(void) {
+
+#if defined(__linux__)
+  handle_dlclose = (getenv("AFL_FRIDA_NO_MODULE") == NULL);
+#else
+  FWARNF("AFL_FRIDA_MODULE not supported");
+#endif
+
+}
+
+typedef struct {
+
+  GumMemoryRange    range;
+  GumPageProtection protection;
+  GumFileMapping    file;
+
+} gum_range_t;
+
+gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
+
+  gum_range_t range = {0};
+  GArray *    ranges = (GArray *)user_data;
+
+  range.range = *details->range;
+  range.protection = details->protection;
+  if (details->file != NULL) { range.file = *details->file; }
+
+  g_array_append_val(ranges, range);
+  return FALSE;
+
+}
+
+#if defined(__linux__)
+static int on_dlclose(void *handle) {
+
+  GArray *         ranges = NULL;
+  struct link_map *lm = NULL;
+  gum_range_t *    range = NULL;
+  GumAddress       base;
+  GumAddress       limit;
+  gpointer         mem;
+
+  if (dlinfo(handle, RTLD_DI_LINKMAP, &lm) < 0) {
+
+    FFATAL("Failed to dlinfo: %s", dlerror());
+
+  }
+
+  FVERBOSE("on_dlclose: %s", lm->l_name);
+
+  ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
+  gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
+                              ranges);
+
+  int ret = dlclose(handle);
+  if (ret != 0) {
+
+    FWARNF("dlclose returned: %d (%s)", ret, dlerror());
+    return ret;
+
+  }
+
+  for (guint i = 0; i < ranges->len; i++) {
+
+    range = &g_array_index(ranges, gum_range_t, i);
+    base = range->range.base_address;
+    limit = base + range->range.size;
+    FVERBOSE("Reserving range: 0x%016lx, 0x%016lX", base, limit);
+    mem = gum_memory_allocate(GSIZE_TO_POINTER(base), range->range.size,
+                              page_size, GUM_PAGE_NO_ACCESS);
+    if (mem == NULL) { FATAL("Failed to allocate %p (%d)", mem, errno); }
+
+  }
+
+  g_array_free(ranges, TRUE);
+  return 0;
+
+}
+
+#endif
+
+void module_init(void) {
+
+  FOKF(cBLU "Module" cRST " - " cYEL " [%c]", handle_dlclose ? 'X' : ' ');
+
+#if defined(__linux__)
+  if (!handle_dlclose) { return; }
+
+  page_size = gum_query_page_size();
+  intercept_hook(dlclose, on_dlclose, NULL);
+#endif
+
+}
+
diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c
index 84803453..d47d1c14 100644
--- a/frida_mode/src/ranges.c
+++ b/frida_mode/src/ranges.c
@@ -595,8 +595,6 @@ void ranges_init(void) {
        ranges_inst_jit ? 'X' : ' ');
   FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]",
        ranges_inst_libs ? 'X' : ' ');
-  FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]",
-       ranges_inst_libs ? 'X' : ' ');
 
   print_ranges("include", include_ranges);
   print_ranges("exclude", exclude_ranges);
diff --git a/frida_mode/test/cmov/GNUmakefile b/frida_mode/test/cmov/GNUmakefile
new file mode 100644
index 00000000..96f1ae5b
--- /dev/null
+++ b/frida_mode/test/cmov/GNUmakefile
@@ -0,0 +1,87 @@
+PWD:=$(shell pwd)/
+ROOT:=$(PWD)../../../
+BUILD_DIR:=$(PWD)build/
+
+TEST_CMOV_SRC:=$(PWD)cmov.c
+TEST_CMOV_OBJ:=$(BUILD_DIR)cmov
+
+TEST_DATA_DIR:=$(BUILD_DIR)in/
+CMP_LOG_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_CMOV_OBJ) LLVMFuzzerTestOneInput $(AFL_FRIDA_BASE_ADDR))
+
+DUMMY_DATA_FILE:=$(BUILD_DIR)dummy.dat
+
+.PHONY: all 32 clean frida frida_noinst debug format
+
+all: $(TEST_CMOV_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 $@
+
+$(CMP_LOG_INPUT): | $(TEST_DATA_DIR)
+	echo -n "ABC" > $@
+
+$(TEST_CMOV_OBJ): $(TEST_CMOV_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_CMOV_OBJ) $(CMP_LOG_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_CMOV_OBJ) $(DUMMY_DATA_FILE)
+
+frida_noinst: $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT) $(DUMMY_DATA_FILE)
+	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_CMOV_OBJ) $(DUMMY_DATA_FILE)
+
+debug: $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT)
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--ex 'r $(CMP_LOG_INPUT)' \
+		--args $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+format:
+	cd $(ROOT) && echo $(TEST_CMOV_SRC) | xargs -L1 ./.custom-format.py -i
diff --git a/frida_mode/test/cmov/Makefile b/frida_mode/test/cmov/Makefile
new file mode 100644
index 00000000..9ef6fc8f
--- /dev/null
+++ b/frida_mode/test/cmov/Makefile
@@ -0,0 +1,19 @@
+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
+
+clean:
+	@gmake clean
+
+frida:
+	@gmake frida
+
+format:
+	@gmake format
+
+debug:
+	@gmake debug
diff --git a/frida_mode/test/cmov/cmov.c b/frida_mode/test/cmov/cmov.c
new file mode 100644
index 00000000..08c7c132
--- /dev/null
+++ b/frida_mode/test/cmov/cmov.c
@@ -0,0 +1,122 @@
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static bool cmov_test(char *x, char *y, size_t len) {
+
+  register char * __rdi __asm__("rdi") = x;
+  register char * __rsi __asm__("rsi") = y;
+  register size_t __rcx __asm__("rcx") = len;
+
+  register long __rax __asm__("rax");
+
+  __asm__ __volatile__(
+      "mov $0x1, %%rax\n"
+      "mov $0x0, %%r8\n"
+      "1:\n"
+      "mov (%%rsi), %%bl\n"
+      "mov (%%rdi), %%dl\n"
+      "cmp %%bl, %%dl\n"
+      "cmovne %%r8, %%rax\n"
+      "inc %%rsi\n"
+      "inc %%rdi\n"
+      "dec %%rcx\n"
+      "jnz 1b\n"
+      : "=r"(__rax)
+      : "r"(__rdi), "r"(__rsi)
+      : "r8", "bl", "dl", "memory");
+
+  return __rax;
+
+}
+
+void LLVMFuzzerTestOneInput(char *buf, int len) {
+
+  char match[] = "CBAABC";
+
+  if (len > sizeof(match)) { return; }
+
+  if (cmov_test(buf, match, sizeof(buf)) != 0) {
+
+    printf("Puzzle solved, congrats!\n");
+    abort();
+
+  }
+
+}
+
+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/python/GNUmakefile b/frida_mode/test/python/GNUmakefile
new file mode 100644
index 00000000..e4f7857b
--- /dev/null
+++ b/frida_mode/test/python/GNUmakefile
@@ -0,0 +1,37 @@
+PWD:=$(shell pwd)/
+ROOT:=$(PWD)../../../
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+
+.PHONY: all clean run qemu frida
+
+all:
+	make -C $(ROOT)frida_mode/
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+run:
+	date
+	/usr/bin/python -c 'print("hi");'
+	date
+
+qemu:
+	date
+	$(ROOT)afl-qemu-trace \
+		/usr/bin/python -c 'print("hi");'
+	date
+
+frida:
+	date
+	LD_PRELOAD=$(ROOT)afl-frida-trace.so \
+		python -c 'print("hi");'
+	date
diff --git a/frida_mode/test/python/Makefile b/frida_mode/test/python/Makefile
new file mode 100644
index 00000000..e66cfdef
--- /dev/null
+++ b/frida_mode/test/python/Makefile
@@ -0,0 +1,17 @@
+all:
+	@echo trying to use GNU make...
+	@gmake all || echo please install GNUmake
+
+clean:
+	@gmake clean
+
+run:
+	@gmake run
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
+
+
diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts
index 57d7b5b5..7999b661 100644
--- a/frida_mode/ts/lib/afl.ts
+++ b/frida_mode/ts/lib/afl.ts
@@ -136,6 +136,13 @@ class Afl {
   }
 
   /**
+   * See `AFL_FRIDA_INST_INSN`
+   */
+  public static setInstrumentInstructions(): void {
+    Afl.jsApiSetInstrumentInstructions();
+  }
+
+  /**
    * See `AFL_FRIDA_INST_JIT`.
    */
   public static setInstrumentJit(): void {
@@ -367,6 +374,11 @@ class Afl {
     "void",
     ["pointer"]);
 
+  private static readonly jsApiSetInstrumentInstructions = Afl.jsApiGetFunction(
+    "js_api_set_instrument_instructions",
+    "void",
+    []);
+
   private static readonly jsApiSetInstrumentJit = Afl.jsApiGetFunction(
     "js_api_set_instrument_jit",
     "void",
diff --git a/include/envs.h b/include/envs.h
index f4327d8c..1f6d33e6 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -59,6 +59,7 @@ static char *afl_environment_variables[] = {
     "AFL_FRIDA_EXCLUDE_RANGES",
     "AFL_FRIDA_INST_COVERAGE_FILE",
     "AFL_FRIDA_INST_DEBUG_FILE",
+    "AFL_FRIDA_INST_INSN",
     "AFL_FRIDA_INST_JIT",
     "AFL_FRIDA_INST_NO_OPTIMIZE",
     "AFL_FRIDA_INST_NO_PREFETCH",
diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc
index 6a4a071f..1bdc5376 100644
--- a/instrumentation/SanitizerCoverageLTO.so.cc
+++ b/instrumentation/SanitizerCoverageLTO.so.cc
@@ -17,6 +17,7 @@
 #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/EHPersonalities.h"
 #include "llvm/Analysis/PostDominators.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -757,7 +758,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
             if (!HasStr2) {
 
               auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
-              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+              if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
                 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
@@ -838,7 +839,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
 
               auto Ptr = dyn_cast<ConstantExpr>(Str1P);
 
-              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+              if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
                 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index e4ffeb50..48bb5a2c 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -13,6 +13,7 @@
 #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/EHPersonalities.h"
 #include "llvm/Analysis/PostDominators.h"
 #include "llvm/IR/CFG.h"
diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc
index 39124660..a554c40e 100644
--- a/instrumentation/afl-llvm-dict2file.so.cc
+++ b/instrumentation/afl-llvm-dict2file.so.cc
@@ -435,7 +435,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
           if (!HasStr2) {
 
             auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
-            if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+            if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
               if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
@@ -519,7 +519,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
 
             auto Ptr = dyn_cast<ConstantExpr>(Str1P);
 
-            if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+            if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
               if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
@@ -589,7 +589,6 @@ bool AFLdict2filePass::runOnModule(Module &M) {
 
               if (optLen < 2) { continue; }
               if (literalLength + 1 == optLen) {  // add null byte
-
                 thestring.append("\0", 1);
 
               }
@@ -612,11 +611,17 @@ bool AFLdict2filePass::runOnModule(Module &M) {
                         }
 
             */
-            if (!isStdString && thestring.find('\0', 0) != std::string::npos) {
+
+            if (!isStdString) {
 
               // ensure we do not have garbage
               size_t offset = thestring.find('\0', 0);
-              if (offset + 1 < optLen) optLen = offset + 1;
+              if (offset && offset < optLen && offset + 1 < optLen) {
+
+                optLen = offset + 1;
+
+              }
+
               thestring = thestring.substr(0, optLen);
 
             }
diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
index 35ba9c5a..2ddbc725 100644
--- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc
+++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
@@ -43,6 +43,7 @@
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/IR/CFG.h"
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
index 5246ba08..be8099bb 100644
--- a/instrumentation/afl-llvm-pass.so.cc
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -45,12 +45,22 @@ typedef long double max_align_t;
 #endif
 
 #include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/LegacyPassManager.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/BasicBlock.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.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)
@@ -68,17 +78,30 @@ 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;
@@ -92,7 +115,55 @@ 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 && \
@@ -118,8 +189,15 @@ 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);
@@ -133,6 +211,10 @@ 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();
@@ -997,10 +1079,15 @@ 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) {
 
@@ -1013,4 +1100,5 @@ 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 310f5585..b6d51ef3 100644
--- a/instrumentation/cmplog-instructions-pass.cc
+++ b/instrumentation/cmplog-instructions-pass.cc
@@ -28,11 +28,16 @@
 #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"
-#include "llvm/Transforms/IPO/PassManagerBuilder.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"
+#endif
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Pass.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -55,6 +60,15 @@ using namespace llvm;
 
 namespace {
 
+#if LLVM_MAJOR >= 11           /* use new pass manager */
+class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
+ public:
+  CmpLogInstructions() {
+
+    initInstrumentList();
+
+  }
+#else
 class CmpLogInstructions : public ModulePass {
 
  public:
@@ -64,7 +78,11 @@ class CmpLogInstructions : public ModulePass {
     initInstrumentList();
 
   }
+#endif
 
+#if LLVM_MAJOR >= 11           /* use new pass manager */
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
   bool runOnModule(Module &M) override;
 
 #if LLVM_VERSION_MAJOR >= 4
@@ -77,6 +95,7 @@ class CmpLogInstructions : public ModulePass {
     return "cmplog instructions";
 
   }
+#endif
 
  private:
   bool hookInstrs(Module &M);
@@ -85,7 +104,9 @@ class CmpLogInstructions : public ModulePass {
 
 }  // namespace
 
+#if LLVM_MAJOR <= 10           /* use old pass manager */
 char CmpLogInstructions::ID = 0;
+#endif
 
 template <class Iterator>
 Iterator Unique(Iterator first, Iterator last) {
@@ -613,7 +634,12 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
 
 }
 
+#if LLVM_MAJOR >= 11           /* use new pass manager */
+PreservedAnalyses CmpLogInstructions::run(Module &               M,
+                                              ModuleAnalysisManager &MAM) {
+#else
 bool CmpLogInstructions::runOnModule(Module &M) {
+#endif
 
   if (getenv("AFL_QUIET") == NULL)
     printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
@@ -622,10 +648,15 @@ bool CmpLogInstructions::runOnModule(Module &M) {
   hookInstrs(M);
   verifyModule(M);
 
+#if LLVM_MAJOR >= 11           /* use new pass manager */
+  return PreservedAnalyses::all();
+#else
   return true;
+#endif
 
 }
 
+#if LLVM_MAJOR < 11                                 /* use old pass manager */
 static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
                                            legacy::PassManagerBase &PM) {
 
@@ -645,4 +676,4 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
     PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
     registerCmpLogInstructionsPass);
 #endif
-
+#endif
diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc
index c3a4ee34..cd3f0e6f 100644
--- a/instrumentation/compare-transform-pass.so.cc
+++ b/instrumentation/compare-transform-pass.so.cc
@@ -26,14 +26,23 @@
 
 #include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/LegacyPassManager.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/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)
@@ -52,28 +61,39 @@ 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();
 
   }
 
-  bool runOnModule(Module &M) override;
-
+#if LLVM_MAJOR < 11
 #if LLVM_VERSION_MAJOR >= 4
   StringRef getPassName() const override {
 
 #else
   const char *getPassName() const override {
-
 #endif
-    return "transforms compare functions";
+#endif
 
-  }
+#if LLVM_MAJOR >= 11                                /* use new pass manager */
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+  bool runOnModule(Module &M) override;
+#endif
 
  private:
   bool transformCmps(Module &M, const bool processStrcmp,
@@ -85,7 +105,54 @@ 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,
@@ -246,7 +313,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
           if (!(HasStr1 || HasStr2)) {
 
             auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
-            if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+            if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
               if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
@@ -271,7 +338,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
             if (!HasStr2) {
 
               Ptr = dyn_cast<ConstantExpr>(Str1P);
-              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+              if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
 
                 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
 
@@ -385,6 +452,7 @@ 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") ||
@@ -642,8 +710,14 @@ 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 "
@@ -651,13 +725,28 @@ 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) {
 
@@ -672,8 +761,9 @@ 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 0f00fa96..d7bb7aba 100644
--- a/instrumentation/split-compares-pass.so.cc
+++ b/instrumentation/split-compares-pass.so.cc
@@ -1,6 +1,7 @@
 /*
  * 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.
@@ -28,10 +29,20 @@
 
 #include "llvm/Pass.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.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/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 || \
@@ -53,27 +64,31 @@ 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();
 
   }
 
-  bool runOnModule(Module &M) override;
-#if LLVM_VERSION_MAJOR >= 4
-  StringRef getPassName() const override {
-
+#if LLVM_MAJOR >= 11
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
 #else
-  const char *getPassName() const override {
-
+  bool runOnModule(Module &M) override;
 #endif
-    return "AFL_SplitComparesTransform";
-
-  }
 
  private:
   int enableFPSplit;
@@ -162,7 +177,54 @@ 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
@@ -1421,8 +1483,15 @@ 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); }
@@ -1432,7 +1501,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
   if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
       getenv("AFL_DEBUG") != NULL) {
 
-    errs() << "Split-compare-pass by laf.intel@gmail.com, extended by "
+    errs() << "Split-compare-newpass by laf.intel@gmail.com, extended by "
               "heiko@hexco.de (splitting icmp to "
            << target_bitwidth << " bit)\n";
 
@@ -1444,6 +1513,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
   }
 
+#if LLVM_MAJOR >= 11
+  auto PA = PreservedAnalyses::all();
+#endif
+
   if (enableFPSplit) {
 
     simplifyFPCompares(M);
@@ -1473,7 +1546,16 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
           auto op0 = CI->getOperand(0);
           auto op1 = CI->getOperand(1);
-          if (!op0 || !op1) { return false; }
+          if (!op0 || !op1) {
+
+#if LLVM_MAJOR >= 11
+            return PA;
+#else
+            return false;
+#endif
+
+          }
+
           auto iTy1 = dyn_cast<IntegerType>(op0->getType());
           if (iTy1 && isa<IntegerType>(op1->getType())) {
 
@@ -1522,10 +1604,29 @@ 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) {
 
@@ -1539,14 +1640,15 @@ 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 9f9e7eca..96e01a8b 100644
--- a/instrumentation/split-switches-pass.so.cc
+++ b/instrumentation/split-switches-pass.so.cc
@@ -27,14 +27,23 @@
 
 #include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/LegacyPassManager.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/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 || \
@@ -54,29 +63,42 @@ 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();
 
   }
 
-  bool runOnModule(Module &M) override;
+#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+#else
+  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;
@@ -103,7 +125,54 @@ 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(
@@ -413,19 +482,42 @@ 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) {
 
@@ -440,9 +532,10 @@ 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/src/afl-cc.c b/src/afl-cc.c
index ed57ca1e..3e67085e 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -462,11 +462,17 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       } else {
 
+#if LLVM_MAJOR >= 11                        /* use new pass manager */
+        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
 
       }
 
@@ -482,11 +488,17 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       } else {
 
+#if LLVM_MAJOR >= 11                        /* use new pass manager */
+        cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+        cc_params[cc_par_cnt++] = alloc_printf(
+            "-fpass-plugin=%s/compare-transform-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/compare-transform-pass.so", obj_path);
+#endif
 
       }
 
@@ -502,11 +514,16 @@ 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
 
       }
 
@@ -536,11 +553,17 @@ 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
 
       }
 
@@ -548,9 +571,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-#if LLVM_MAJOR >= 13
-    // fuck you llvm 13
-    cc_params[cc_par_cnt++] = "-fno-experimental-new-pass-manager";
+#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 (lto_mode && !have_c) {
@@ -633,10 +656,16 @@ 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
 
       }
 
@@ -653,11 +682,17 @@ 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/cmplog-instructions-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";
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index 4697a492..fe7be8e1 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-46879845
+a44fa94488d01aba60401ccf81f8bebcce685bf2
diff --git a/unicorn_mode/samples/compcov_x64/compcov_test_harness.py b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py
index 52f0a286..ce96b882 100644
--- a/unicorn_mode/samples/compcov_x64/compcov_test_harness.py
+++ b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py
@@ -19,7 +19,7 @@ import os
 import signal
 
 from unicornafl import *
-from unicornafl.x86_const import *
+from unicorn.x86_const import *
 
 # Path to the file containing the binary to emulate
 BINARY_FILE = os.path.join(
@@ -160,7 +160,7 @@ def main():
     # Emulate the code, allowing it to process the mutated input
 
     print("Starting the AFL fuzz")
-    uc.afl_fuzz(
+    uc_afl_fuzz(uc,
         input_file=args.input_file,
         place_input_callback=place_input_callback,
         exits=[end_address],
diff --git a/unicorn_mode/samples/speedtest/python/harness.py b/unicorn_mode/samples/speedtest/python/harness.py
index 801ef4d1..604adf39 100644
--- a/unicorn_mode/samples/speedtest/python/harness.py
+++ b/unicorn_mode/samples/speedtest/python/harness.py
@@ -20,8 +20,8 @@ import os
 import struct
 
 from unicornafl import *
-from unicornafl.unicorn_const import UC_ARCH_X86, UC_HOOK_CODE, UC_MODE_64
-from unicornafl.x86_const import (
+from unicorn.unicorn_const import UC_ARCH_X86, UC_HOOK_CODE, UC_MODE_64
+from unicorn.x86_const import (
     UC_X86_REG_RAX,
     UC_X86_REG_RDI,
     UC_X86_REG_RIP,
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject 468798455a9f9790d2da369a18ed49fda3a64e8
+Subproject a44fa94488d01aba60401ccf81f8bebcce685bf