about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml12
-rw-r--r--.github/workflows/build_aflplusplus_docker.yaml10
-rw-r--r--.github/workflows/ci.yml4
-rw-r--r--.gitignore4
-rw-r--r--Android.bp143
-rw-r--r--Dockerfile9
-rw-r--r--GNUmakefile56
-rw-r--r--GNUmakefile.gcc_plugin12
-rw-r--r--GNUmakefile.llvm21
-rw-r--r--README.md104
-rw-r--r--TODO.md8
-rwxr-xr-xafl-cmin23
-rwxr-xr-xafl-cmin.bash9
-rwxr-xr-xafl-plot12
-rwxr-xr-xafl-system-config47
-rwxr-xr-xafl-whatsup56
-rw-r--r--custom_mutators/Android.bp6
-rw-r--r--custom_mutators/README.md11
-rw-r--r--custom_mutators/examples/Makefile (renamed from utils/custom_mutators/Makefile)0
-rw-r--r--custom_mutators/examples/README.md (renamed from utils/custom_mutators/README.md)0
-rw-r--r--custom_mutators/examples/XmlMutatorMin.py (renamed from utils/custom_mutators/XmlMutatorMin.py)0
-rw-r--r--custom_mutators/examples/common.py (renamed from utils/custom_mutators/common.py)0
-rw-r--r--custom_mutators/examples/custom_mutator_helpers.h (renamed from utils/custom_mutators/custom_mutator_helpers.h)0
-rw-r--r--custom_mutators/examples/example.c (renamed from utils/custom_mutators/example.c)0
-rw-r--r--custom_mutators/examples/example.py (renamed from utils/custom_mutators/example.py)0
-rw-r--r--custom_mutators/examples/post_library_gif.so.c (renamed from utils/custom_mutators/post_library_gif.so.c)5
-rw-r--r--custom_mutators/examples/post_library_png.so.c (renamed from utils/custom_mutators/post_library_png.so.c)0
-rw-r--r--custom_mutators/examples/simple-chunk-replace.py (renamed from utils/custom_mutators/simple-chunk-replace.py)0
-rw-r--r--custom_mutators/examples/simple_example.c (renamed from utils/custom_mutators/simple_example.c)0
-rw-r--r--custom_mutators/examples/wrapper_afl_min.py (renamed from utils/custom_mutators/wrapper_afl_min.py)0
-rw-r--r--custom_mutators/grammar_mutator/GRAMMAR_VERSION2
-rwxr-xr-xcustom_mutators/grammar_mutator/build_grammar_mutator.sh16
m---------custom_mutators/grammar_mutator/grammar_mutator0
-rw-r--r--custom_mutators/libprotobuf-mutator-example/Android.bp6
-rw-r--r--docs/Changelog.md57
-rw-r--r--docs/INSTALL.md35
-rw-r--r--docs/PATCHES.md43
-rw-r--r--docs/QuickStartGuide.md2
-rw-r--r--docs/binaryonly_fuzzing.md50
-rw-r--r--docs/custom_mutators.md10
-rw-r--r--docs/env_variables.md89
-rw-r--r--docs/ideas.md43
-rw-r--r--docs/life_pro_tips.md2
-rw-r--r--docs/notes_for_asan.md7
-rw-r--r--docs/perf_tips.md3
-rw-r--r--docs/status_screen.md11
-rw-r--r--dynamic_list.txt1
-rw-r--r--frida_mode/.gitignore5
-rw-r--r--frida_mode/GNUmakefile188
-rw-r--r--frida_mode/Makefile13
-rw-r--r--frida_mode/README.md294
-rw-r--r--frida_mode/include/asan.h13
-rw-r--r--frida_mode/include/ctx.h11
-rw-r--r--frida_mode/include/entry.h15
-rw-r--r--frida_mode/include/frida_cmplog.h14
-rw-r--r--frida_mode/include/instrument.h27
-rw-r--r--frida_mode/include/interceptor.h11
-rw-r--r--frida_mode/include/lib.h13
-rw-r--r--frida_mode/include/output.h9
-rw-r--r--frida_mode/include/persistent.h35
-rw-r--r--frida_mode/include/prefetch.h11
-rw-r--r--frida_mode/include/ranges.h13
-rw-r--r--frida_mode/include/stalker.h11
-rw-r--r--frida_mode/include/stats.h28
-rw-r--r--frida_mode/include/util.h14
-rw-r--r--frida_mode/src/asan/asan.c24
-rw-r--r--frida_mode/src/asan/asan_arm.c28
-rw-r--r--frida_mode/src/asan/asan_arm64.c28
-rw-r--r--frida_mode/src/asan/asan_x64.c93
-rw-r--r--frida_mode/src/asan/asan_x86.c93
-rw-r--r--frida_mode/src/cmplog/cmplog.c87
-rw-r--r--frida_mode/src/cmplog/cmplog_arm.c19
-rw-r--r--frida_mode/src/cmplog/cmplog_arm64.c19
-rw-r--r--frida_mode/src/cmplog/cmplog_x64.c272
-rw-r--r--frida_mode/src/cmplog/cmplog_x86.c277
-rw-r--r--frida_mode/src/ctx/ctx_x64.c114
-rw-r--r--frida_mode/src/ctx/ctx_x86.c81
-rw-r--r--frida_mode/src/entry.c50
-rw-r--r--frida_mode/src/instrument/instrument.c199
-rw-r--r--frida_mode/src/instrument/instrument_arm32.c26
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c97
-rw-r--r--frida_mode/src/instrument/instrument_debug.c129
-rw-r--r--frida_mode/src/instrument/instrument_x64.c93
-rw-r--r--frida_mode/src/instrument/instrument_x86.c85
-rw-r--r--frida_mode/src/interceptor.c35
-rw-r--r--frida_mode/src/lib/lib.c179
-rw-r--r--frida_mode/src/lib/lib_apple.c82
-rw-r--r--frida_mode/src/main.c179
-rw-r--r--frida_mode/src/output.c45
-rw-r--r--frida_mode/src/persistent/persistent.c97
-rw-r--r--frida_mode/src/persistent/persistent_arm32.c79
-rw-r--r--frida_mode/src/persistent/persistent_arm64.c122
-rw-r--r--frida_mode/src/persistent/persistent_x64.c326
-rw-r--r--frida_mode/src/persistent/persistent_x86.c267
-rw-r--r--frida_mode/src/prefetch.c112
-rw-r--r--frida_mode/src/ranges.c611
-rw-r--r--frida_mode/src/stalker.c32
-rw-r--r--frida_mode/src/stats/stats.c208
-rw-r--r--frida_mode/src/stats/stats_arm.c36
-rw-r--r--frida_mode/src/stats/stats_arm64.c36
-rw-r--r--frida_mode/src/stats/stats_x64.c307
-rw-r--r--frida_mode/src/stats/stats_x86.c36
-rw-r--r--frida_mode/src/util.c68
-rw-r--r--frida_mode/test/cmplog/GNUmakefile69
-rw-r--r--frida_mode/test/cmplog/Makefile22
-rw-r--r--frida_mode/test/cmplog/cmplog.c100
-rwxr-xr-xfrida_mode/test/cmplog/get_section_addrs.py49
-rw-r--r--frida_mode/test/deferred/GNUmakefile71
-rw-r--r--frida_mode/test/deferred/Makefile13
-rw-r--r--frida_mode/test/deferred/testinstr.c125
-rw-r--r--frida_mode/test/entry_point/GNUmakefile80
-rw-r--r--frida_mode/test/entry_point/Makefile16
-rw-r--r--frida_mode/test/entry_point/testinstr.c121
-rw-r--r--frida_mode/test/exe/GNUmakefile53
-rw-r--r--frida_mode/test/exe/Makefile16
-rw-r--r--frida_mode/test/exe/testinstr.c112
-rw-r--r--frida_mode/test/fasan/GNUmakefile159
-rw-r--r--frida_mode/test/fasan/Makefile22
-rw-r--r--frida_mode/test/fasan/test.c90
-rw-r--r--frida_mode/test/libpcap/GNUmakefile188
-rw-r--r--frida_mode/test/libpcap/Makefile1143
-rw-r--r--frida_mode/test/libpcap/aflpp_qemu_driver_hook.c97
-rwxr-xr-xfrida_mode/test/libpcap/get_symbol_addr.py36
-rw-r--r--frida_mode/test/output/GNUmakefile47
-rw-r--r--frida_mode/test/output/Makefile13
-rw-r--r--frida_mode/test/output/frida_stderr.txt2824
-rw-r--r--frida_mode/test/output/frida_stdout.txt349
-rw-r--r--frida_mode/test/output/testinstr.c112
-rw-r--r--frida_mode/test/persistent_ret/GNUmakefile105
-rw-r--r--frida_mode/test/persistent_ret/Makefile22
-rwxr-xr-xfrida_mode/test/persistent_ret/get_symbol_addr.py36
-rw-r--r--frida_mode/test/persistent_ret/testinstr.c120
-rw-r--r--frida_mode/test/png/GNUmakefile114
-rw-r--r--frida_mode/test/png/Makefile16
-rw-r--r--frida_mode/test/png/persistent/GNUmakefile98
-rw-r--r--frida_mode/test/png/persistent/Makefile22
-rwxr-xr-xfrida_mode/test/png/persistent/get_symbol_addr.py36
-rw-r--r--frida_mode/test/png/persistent/hook/GNUmakefile141
-rw-r--r--frida_mode/test/png/persistent/hook/Makefile28
-rw-r--r--frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c97
-rw-r--r--frida_mode/test/re2/GNUmakefile170
-rw-r--r--frida_mode/test/re2/Makefile22
-rw-r--r--frida_mode/test/re2/aflpp_qemu_driver_hook.c97
-rwxr-xr-xfrida_mode/test/re2/get_symbol_addr.py36
-rw-r--r--frida_mode/test/testinstr/GNUmakefile59
-rw-r--r--frida_mode/test/testinstr/Makefile19
-rw-r--r--frida_mode/test/testinstr/testinstr.c112
-rwxr-xr-xfrida_mode/update_frida_version.sh13
-rw-r--r--include/afl-fuzz.h14
-rw-r--r--include/android-ashmem.h25
-rw-r--r--include/config.h20
-rw-r--r--include/debug.h7
-rw-r--r--include/envs.h27
-rw-r--r--include/forkserver.h15
-rw-r--r--instrumentation/LLVMInsTrim.so.cc599
-rw-r--r--instrumentation/MarkNodes.cc481
-rw-r--r--instrumentation/MarkNodes.h12
-rw-r--r--instrumentation/README.instrim.md30
-rw-r--r--instrumentation/README.llvm.md26
-rw-r--r--instrumentation/README.neverzero.md14
-rw-r--r--instrumentation/README.snapshot.md2
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc50
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc135
-rw-r--r--instrumentation/afl-compiler-rt.o.c27
-rw-r--r--instrumentation/afl-gcc-pass.so.cc4
-rw-r--r--instrumentation/afl-llvm-common.cc7
-rw-r--r--instrumentation/afl-llvm-dict2file.so.cc5
-rw-r--r--instrumentation/afl-llvm-lto-instrumentation.so.cc47
-rw-r--r--instrumentation/afl-llvm-pass.so.cc234
-rw-r--r--instrumentation/split-switches-pass.so.cc2
-rw-r--r--qemu_mode/QEMUAFL_VERSION2
-rw-r--r--qemu_mode/README.md27
-rw-r--r--qemu_mode/README.wine.md21
-rwxr-xr-xqemu_mode/build_qemu_support.sh7
-rw-r--r--qemu_mode/libcompcov/compcovtest.cc163
-rw-r--r--qemu_mode/libqasan/hooks.c10
-rw-r--r--qemu_mode/libqasan/libqasan.c12
m---------qemu_mode/qemuafl0
-rw-r--r--src/afl-analyze.c67
-rw-r--r--src/afl-as.c7
-rw-r--r--src/afl-cc.c122
-rw-r--r--src/afl-common.c79
-rw-r--r--src/afl-forkserver.c137
-rw-r--r--src/afl-fuzz-bitmap.c2
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-extras.c14
-rw-r--r--src/afl-fuzz-init.c132
-rw-r--r--src/afl-fuzz-mutators.c48
-rw-r--r--src/afl-fuzz-one.c677
-rw-r--r--src/afl-fuzz-python.c2
-rw-r--r--src/afl-fuzz-queue.c6
-rw-r--r--src/afl-fuzz-redqueen.c28
-rw-r--r--src/afl-fuzz-run.c43
-rw-r--r--src/afl-fuzz-state.c34
-rw-r--r--src/afl-fuzz-stats.c155
-rw-r--r--src/afl-fuzz.c285
-rw-r--r--src/afl-ld-lto.c38
-rw-r--r--src/afl-showmap.c235
-rw-r--r--src/afl-tmin.c66
-rwxr-xr-xtest/test-all.sh2
-rwxr-xr-xtest/test-custom-mutators.sh6
-rwxr-xr-xtest/test-frida-mode.sh108
-rwxr-xr-xtest/test-llvm.sh55
-rwxr-xr-xtest/test-performance.sh1
-rwxr-xr-xtest/test-pre.sh2
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
-rw-r--r--unicorn_mode/helper_scripts/ida_context_loader.py84
-rw-r--r--unicorn_mode/samples/speedtest/c/Makefile10
-rw-r--r--unicorn_mode/samples/speedtest/python/Makefile11
-rw-r--r--unicorn_mode/samples/speedtest/rust/Makefile12
m---------unicorn_mode/unicornafl0
-rw-r--r--utils/README.md3
-rw-r--r--utils/afl_frida/afl-frida.c4
-rw-r--r--utils/afl_network_proxy/afl-network-server.c5
-rw-r--r--utils/afl_proxy/afl-proxy.c29
-rw-r--r--utils/aflpp_driver/GNUmakefile12
-rw-r--r--utils/aflpp_driver/README.md36
-rw-r--r--utils/aflpp_driver/aflpp_driver.c44
-rw-r--r--utils/aflpp_driver/aflpp_qemu_driver_hook.c21
-rw-r--r--utils/autodict_ql/autodict-ql.py146
-rw-r--r--utils/autodict_ql/build-codeql.sh17
-rw-r--r--utils/autodict_ql/litan.py112
-rw-r--r--utils/autodict_ql/litool.ql10
-rw-r--r--utils/autodict_ql/memcmp-str.ql8
-rw-r--r--utils/autodict_ql/memcmp-strings.py83
-rw-r--r--utils/autodict_ql/qlpack.yml3
-rw-r--r--utils/autodict_ql/readme.md100
-rw-r--r--utils/autodict_ql/stan-strings.py83
-rw-r--r--utils/autodict_ql/strcmp-str.ql8
-rw-r--r--utils/autodict_ql/strcmp-strings.py83
-rw-r--r--utils/autodict_ql/strncmp-str.ql8
-rw-r--r--utils/autodict_ql/strncmp-strings.py83
-rw-r--r--utils/autodict_ql/strtool.ql24
-rwxr-xr-xutils/crash_triage/triage_crashes.sh11
-rw-r--r--utils/libdislocator/libdislocator.so.c21
-rwxr-xr-xutils/qbdi_mode/template.cpp2
-rw-r--r--utils/qemu_persistent_hook/read_into_rdi.c10
237 files changed, 16562 insertions, 2516 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..102722a4
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: AFLplusplusEU
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/workflows/build_aflplusplus_docker.yaml b/.github/workflows/build_aflplusplus_docker.yaml
index be8d795d..8aa5b8f7 100644
--- a/.github/workflows/build_aflplusplus_docker.yaml
+++ b/.github/workflows/build_aflplusplus_docker.yaml
@@ -1,13 +1,11 @@
 name: Publish Docker Images
+
 on:
   push:
     branches: [ stable ]
-    paths:
-    - Dockerfile
-  pull_request:
-    branches: [ stable ]
-    paths:
-    - Dockerfile
+#    paths:
+#    - Dockerfile
+
 jobs:
   push_to_registry:
     name: Push Docker images to Dockerhub
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 31cfceaf..35051a20 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,8 +16,10 @@ jobs:
       - uses: actions/checkout@v2
       - name: debug
         run: apt-cache search plugin-dev | grep gcc- ; echo ; apt-cache search clang-format- | grep clang-format-
+      - name: update
+        run: sudo apt-get update && sudo apt-get upgrade -y
       - name: install packages
-        run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools
+        run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
       - name: compiler installed
         run: gcc -v ; echo ; clang -v
       - name: install gcc plugin
diff --git a/.gitignore b/.gitignore
index 3f440730..8c420b5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,3 +82,7 @@ libAFLDriver.a
 libAFLQemuDriver.a
 test/.afl_performance
 gmon.out
+afl-frida-trace.so
+utils/afl_network_proxy/afl-network-client
+utils/afl_network_proxy/afl-network-server
+*.o.tmp
diff --git a/Android.bp b/Android.bp
index ee076d1e..bf37757d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,5 @@
 cc_defaults {
   name: "afl-defaults",
-  sanitize: {
-    never: true,
-  },
 
   local_include_dirs: [
     "include",
@@ -23,18 +20,44 @@ cc_defaults {
     "-DBIN_PATH=\"out/host/linux-x86/bin\"",
     "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
     "-D__USE_GNU",
-    "-D__aarch64__",
     "-DDEBUG_BUILD",
     "-U_FORTIFY_SOURCE",
     "-ggdb3",
     "-g",
     "-O0",
     "-fno-omit-frame-pointer",
+    "-fPIC",
   ],
+
+  target: {
+    android_arm64: {
+      cflags: [
+        "-D__ANDROID__",
+      ],
+    },
+    android_arm: {
+      cflags: [
+        "-D__ANDROID__",
+      ],
+    },
+    android_x86_64: {
+      cflags: [
+        "-D__ANDROID__",
+      ],
+    },
+    android_x86: {
+      cflags: [
+        "-D__ANDROID__",
+      ],
+    },
+  },
 }
 
 cc_binary {
   name: "afl-fuzz",
+  sanitize: {
+    never: true,
+  },
   host_supported: true,
   compile_multilib: "64",
 
@@ -128,7 +151,6 @@ cc_binary_host {
   ],
 
   cflags: [
-    "-D__ANDROID__",
     "-DAFL_PATH=\"out/host/linux-x86/lib64\"",
     "-DAFL_CLANG_FLTO=\"-flto=full\"",
     "-DUSE_BINDIR=1",
@@ -199,6 +221,7 @@ cc_library_headers {
 
   export_include_dirs: [
     "include",
+    "instrumentation",
   ],
 }
 
@@ -268,6 +291,116 @@ cc_binary {
   ],
 }
 
+cc_binary {
+  name: "afl-fuzz-32",
+  sanitize: {
+    never: true,
+  },
+  host_supported: true,
+  compile_multilib: "32",
+
+  defaults: [
+    "afl-defaults",
+  ],
+
+  srcs: [
+    "src/afl-fuzz*.c",
+    "src/afl-common.c",
+    "src/afl-sharedmem.c",
+    "src/afl-forkserver.c",
+    "src/afl-performance.c",
+  ],
+}
+
+cc_binary_host {
+  name: "afl-cc-32",
+  compile_multilib: "32",
+  static_executable: true,
+
+  defaults: [
+    "afl-defaults",
+  ],
+
+  cflags: [
+    "-DAFL_PATH=\"out/host/linux-x86/lib64\"",
+    "-DAFL_CLANG_FLTO=\"-flto=full\"",
+    "-DUSE_BINDIR=1",
+    "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
+    "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
+    "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
+    "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
+    "-DLLVM_LTO=1",
+    "-DLLVM_MAJOR=11",
+    "-DLLVM_MINOR=2",
+  ],
+
+  srcs: [
+    "src/afl-cc.c",
+    "src/afl-common.c",
+  ],
+
+  symlinks: [
+    "afl-clang-fast-32",
+    "afl-clang-fast++-32",
+  ],
+}
+
+cc_library_static {
+  name: "afl-llvm-rt-32",
+  compile_multilib: "32",
+  vendor_available: true,
+  host_supported: true,
+  recovery_available: true,
+  sdk_version: "9",
+
+  apex_available: [
+    "com.android.adbd",
+    "com.android.appsearch",
+    "com.android.art",
+    "com.android.bluetooth.updatable",
+    "com.android.cellbroadcast",
+    "com.android.conscrypt",
+    "com.android.extservices",
+    "com.android.cronet",
+    "com.android.neuralnetworks",
+    "com.android.media",
+    "com.android.media.swcodec",
+    "com.android.mediaprovider",
+    "com.android.permission",
+    "com.android.runtime",
+    "com.android.resolv",
+    "com.android.tethering",
+    "com.android.wifi",
+    "com.android.sdkext",
+    "com.android.os.statsd",
+    "//any",
+  ],
+
+  defaults: [
+    "afl-defaults",
+  ],
+
+  srcs: [
+    "instrumentation/afl-compiler-rt.o.c",
+  ],
+}
+
+cc_prebuilt_library_static {
+  name: "libfrida-gum-32",
+  compile_multilib: "32",
+  strip: {
+    none: true,
+  },
+
+  srcs: [
+    "utils/afl_frida/android/arm/libfrida-gum.a",
+  ],
+
+  export_include_dirs: [
+    "utils/afl_frida/android/arm",
+  ],
+}
+
 subdirs = [
   "custom_mutators",
 ]
diff --git a/Dockerfile b/Dockerfile
index 1cb00d5d..18fb6367 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -37,7 +37,7 @@ RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main
 
 RUN apt-get update && apt-get full-upgrade -y && \
     apt-get -y install --no-install-suggests --no-install-recommends \
-    gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gdb lcov \
+    gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \
     clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
     libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
     libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
@@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
 
 ENV LLVM_CONFIG=llvm-config-12
 ENV AFL_SKIP_CPUFREQ=1
+ENV AFL_TRY_AFFINITY=1
 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
 
 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
@@ -61,8 +62,10 @@ WORKDIR /AFLplusplus
 RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
     make distrib && make install && make clean
 
-RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
-RUN echo 'export PS1="[afl++]$PS1"' >> ~/.bashrc
+RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
+RUN echo '. /etc/bash_completion' >> ~/.bashrc
+RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
+RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
 ENV IS_DOCKER="1"
 
 # Disabled until we have the container ready
diff --git a/GNUmakefile b/GNUmakefile
index ac8fe796..270746b4 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -36,6 +36,11 @@ SH_PROGS    = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
 MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
 ASAN_OPTIONS=detect_leaks=0
 
+SYS = $(shell uname -s)
+ARCH = $(shell uname -m)
+
+$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
+
 ifdef NO_SPLICING
   override CFLAGS += -DNO_SPLICING
 endif
@@ -82,7 +87,7 @@ endif
 #  endif
 #endif
 
-ifneq "$(shell uname)" "Darwin"
+ifneq "$(SYS)" "Darwin"
   #ifeq "$(HAVE_MARCHNATIVE)" "1"
   #  SPECIAL_PERFORMANCE += -march=native
   #endif
@@ -92,7 +97,7 @@ ifneq "$(shell uname)" "Darwin"
   endif
 endif
 
-ifeq "$(shell uname)" "SunOS"
+ifeq "$(SYS)" "SunOS"
   CFLAGS_OPT += -Wno-format-truncation
   LDFLAGS = -lkstat -lrt
 endif
@@ -119,11 +124,10 @@ ifdef INTROSPECTION
   CFLAGS_OPT += -DINTROSPECTION=1
 endif
 
-
-ifneq "$(shell uname -m)" "x86_64"
- ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
-  ifneq "$(shell uname -m)" "amd64"
-   ifneq "$(shell uname -m)" "i86pc"
+ifneq "$(ARCH)" "x86_64"
+ ifneq "$(patsubst i%86,i386,$(ARCH))" "i386"
+  ifneq "$(ARCH)" "amd64"
+   ifneq "$(ARCH)" "i86pc"
 	AFL_NO_X86=1
    endif
   endif
@@ -141,30 +145,30 @@ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpoi
 			  -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
 			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
 
-ifeq "$(shell uname -s)" "FreeBSD"
+ifeq "$(SYS)" "FreeBSD"
   override CFLAGS  += -I /usr/local/include/
   LDFLAGS += -L /usr/local/lib/
 endif
 
-ifeq "$(shell uname -s)" "DragonFly"
+ifeq "$(SYS)" "DragonFly"
   override CFLAGS  += -I /usr/local/include/
   LDFLAGS += -L /usr/local/lib/
 endif
 
-ifeq "$(shell uname -s)" "OpenBSD"
+ifeq "$(SYS)" "OpenBSD"
   override CFLAGS  += -I /usr/local/include/ -mno-retpoline
   LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
 endif
 
-ifeq "$(shell uname -s)" "NetBSD"
+ifeq "$(SYS)" "NetBSD"
   override CFLAGS  += -I /usr/pkg/include/
   LDFLAGS += -L /usr/pkg/lib/
 endif
 
-ifeq "$(shell uname -s)" "Haiku"
+ifeq "$(SYS)" "Haiku"
   SHMAT_OK=0
   override CFLAGS  += -DUSEMMAP=1 -Wno-error=format -fPIC
-  LDFLAGS += -Wno-deprecated-declarations -lgnu
+  LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
   SPECIAL_PERFORMANCE += -DUSEMMAP=1
 endif
 
@@ -236,24 +240,24 @@ else
     BUILD_DATE ?= $(shell date "+%Y-%m-%d")
 endif
 
-ifneq "$(filter Linux GNU%,$(shell uname))" ""
+ifneq "$(filter Linux GNU%,$(SYS))" ""
  ifndef DEBUG
   override CFLAGS += -D_FORTIFY_SOURCE=2
  endif
   LDFLAGS += -ldl -lrt -lm
 endif
 
-ifneq "$(findstring FreeBSD, $(shell uname))" ""
+ifneq "$(findstring FreeBSD, $(SYS))" ""
   override CFLAGS  += -pthread
   LDFLAGS += -lpthread
 endif
 
-ifneq "$(findstring NetBSD, $(shell uname))" ""
+ifneq "$(findstring NetBSD, $(SYS))" ""
   override CFLAGS  += -pthread
   LDFLAGS += -lpthread
 endif
 
-ifneq "$(findstring OpenBSD, $(shell uname))" ""
+ifneq "$(findstring OpenBSD, $(SYS))" ""
   override CFLAGS  += -pthread
   LDFLAGS += -lpthread
 endif
@@ -485,7 +489,7 @@ unit_clean:
 	@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
 
 .PHONY: unit
-ifneq "$(shell uname)" "Darwin"
+ifneq "$(SYS)" "Darwin"
 unit:	unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
 else
 unit:
@@ -499,25 +503,28 @@ code-format:
 	./.custom-format.py -i instrumentation/*.h
 	./.custom-format.py -i instrumentation/*.cc
 	./.custom-format.py -i instrumentation/*.c
+	./.custom-format.py -i *.h
+	./.custom-format.py -i *.c
 	@#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
 	@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
 	./.custom-format.py -i utils/*/*.c*
 	./.custom-format.py -i utils/*/*.h
 	./.custom-format.py -i test/*.c
+	./.custom-format.py -i frida_mode/src/*.c
+	./.custom-format.py -i frida_mode/include/*.h
+	-./.custom-format.py -i frida_mode/src/*/*.c
 	./.custom-format.py -i qemu_mode/libcompcov/*.c
 	./.custom-format.py -i qemu_mode/libcompcov/*.cc
 	./.custom-format.py -i qemu_mode/libcompcov/*.h
 	./.custom-format.py -i qemu_mode/libqasan/*.c
 	./.custom-format.py -i qemu_mode/libqasan/*.h
-	./.custom-format.py -i *.h
-	./.custom-format.py -i *.c
 
 
 .PHONY: test_build
 ifndef AFL_NO_X86
 test_build: afl-cc afl-gcc afl-as afl-showmap
 	@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
-	@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
+	@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
 	ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
 	echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
 	@rm -f test-instr
@@ -525,7 +532,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap
 	@echo
 	@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
 #	@echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
-#	@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
+#	@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
 #	ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
 #	echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
 #	@rm -f test-instr
@@ -546,7 +553,7 @@ all_done: test_build
 	@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc'  failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
 	@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc'  failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
 	@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
-	@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
+	@if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
 	@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
 
 .NOTPARALLEL: clean all
@@ -593,6 +600,7 @@ distrib: all
 	$(MAKE) -C utils/afl_network_proxy
 	$(MAKE) -C utils/socket_fuzzing
 	$(MAKE) -C utils/argv_fuzzing
+	-$(MAKE) -C frida_mode
 	-cd qemu_mode && sh ./build_qemu_support.sh
 	-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
 
@@ -603,6 +611,7 @@ binary-only: test_shm test_python ready $(PROGS)
 	$(MAKE) -C utils/afl_network_proxy
 	$(MAKE) -C utils/socket_fuzzing
 	$(MAKE) -C utils/argv_fuzzing
+	-$(MAKE) -C frida_mode
 	-cd qemu_mode && sh ./build_qemu_support.sh
 	-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
 
@@ -648,6 +657,7 @@ install: all $(MANPAGES)
 	@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
 	@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
 	@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
+	@if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi
 	@if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
 	@if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
 	@if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin
index aa93c688..b0f90f1b 100644
--- a/GNUmakefile.gcc_plugin
+++ b/GNUmakefile.gcc_plugin
@@ -41,6 +41,8 @@ CXXEFLAGS   := $(CXXFLAGS) -Wall -std=c++11
 CC          ?= gcc
 CXX         ?= g++
 
+SYS = $(shell uname -s)
+
 ifeq "clang" "$(CC)"
         CC  = gcc
         CXX = g++
@@ -75,25 +77,25 @@ ifeq "$(TEST_MMAP)" "1"
 	override CFLAGS_SAFE += -DUSEMMAP=1
 endif
 
-ifneq "$(shell uname -s)" "Haiku"
-ifneq "$(shell uname -s)" "OpenBSD"
+ifneq "$(SYS)" "Haiku"
+ifneq "$(SYS)" "OpenBSD"
   	LDFLAGS += -lrt
 endif
 else
 	CFLAGS_SAFE += -DUSEMMAP=1
 endif
 
-ifeq "$(shell uname -s)" "OpenBSD"
+ifeq "$(SYS)" "OpenBSD"
     CC  = egcc
     CXX = eg++
     PLUGIN_FLAGS += -I/usr/local/include
 endif
 
-ifeq "$(shell uname -s)" "DragonFly"
+ifeq "$(SYS)" "DragonFly"
   	PLUGIN_FLAGS += -I/usr/local/include
 endif
 
-ifeq "$(shell uname -s)" "SunOS"
+ifeq "$(SYS)" "SunOS"
   	PLUGIN_FLAGS += -I/usr/include/gmp
 endif
 
diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm
index 111a847d..2d50badc 100644
--- a/GNUmakefile.llvm
+++ b/GNUmakefile.llvm
@@ -30,11 +30,13 @@ BUILD_DATE  ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/nul
 
 VERSION     = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
 
-ifeq "$(shell uname)" "OpenBSD"
+SYS = $(shell uname -s)
+
+ifeq "$(SYS)" "OpenBSD"
   LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
   HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
   ifeq "$(HAS_OPT)" "1"
-    $(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
+    $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
   endif
 else
   LLVM_CONFIG ?= llvm-config
@@ -43,7 +45,7 @@ endif
 LLVMVER  = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
 LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
 LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
-LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^[0-2]\.' && echo 1 || echo 0 )
+LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 )
 LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 )
 LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
 LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
@@ -59,7 +61,7 @@ ifeq "$(LLVMVER)" ""
 endif
 
 ifeq "$(LLVM_UNSUPPORTED)" "1"
-  $(error llvm_mode only supports llvm from version 3.4 onwards)
+  $(error llvm_mode only supports llvm from version 6.0 onwards)
 endif
 
 ifeq "$(LLVM_TOO_NEW)" "1"
@@ -275,13 +277,13 @@ CLANG_LFL    = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
 
 
 # User teor2345 reports that this is required to make things work on MacOS X.
-ifeq "$(shell uname)" "Darwin"
+ifeq "$(SYS)" "Darwin"
   CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
 else
   CLANG_CPPFL += -Wl,-znodelete
 endif
 
-ifeq "$(shell uname)" "OpenBSD"
+ifeq "$(SYS)" "OpenBSD"
   CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
   CLANG_CPPFL += -mno-retpoline
   CFLAGS += -mno-retpoline
@@ -304,7 +306,7 @@ ifeq "$(TEST_MMAP)" "1"
 endif
 
 PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o 
-PROGS        = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
+PROGS        = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
 
 # If prerequisites are not given, warn, do not build anything, and exit with code 0
 ifeq "$(LLVMVER)" ""
@@ -344,7 +346,7 @@ no_build:
 test_deps:
 	@echo "[*] Checking for working 'llvm-config'..."
  ifneq "$(LLVM_APPLE_XCODE)" "1"
-	@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo "    (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
+	@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo "    (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 )
  endif
 	@echo "[*] Checking for working '$(CC)'..."
 	@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
@@ -382,9 +384,6 @@ endif
 instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
 	$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ 
 
-./libLLVMInsTrim.so: instrumentation/LLVMInsTrim.so.cc instrumentation/MarkNodes.cc instrumentation/afl-llvm-common.o | test_deps
-	-$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< instrumentation/MarkNodes.cc -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
-
 ./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
 ifeq "$(LLVM_MIN_4_0_1)" "0"
 	$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
diff --git a/README.md b/README.md
index 084971f3..ba612edb 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
 
   <img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
 
-  Release Version: [3.12c](https://github.com/AFLplusplus/AFLplusplus/releases)
+  Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases)
 
-  Github Version: 3.13a
+  Github Version: 3.14a
 
   Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
 
@@ -25,7 +25,11 @@
   For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast`
   with `AFL_LLVM_CMPLOG=1`.
 
-## Major changes in afl++ 3.00 + 3.10
+## Major changes in afl++ 3.00 onwards:
+
+With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for
+binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android,
+iOS etc.
 
 With afl++ 3.10 we introduced the following changes from previous behaviours:
   * The '+' feature of the '-t' option now means to  auto-calculate the timeout
@@ -80,30 +84,32 @@ behaviours and defaults:
 
 ## Important features of afl++
 
-  afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1
-  with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and
-  Android support and much, much, much more.
-
-  | Feature/Instrumentation  | afl-gcc | llvm      | gcc_plugin | qemu_mode        | unicorn_mode |
-  | -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:|
-  | NeverZero                | x86[_64]|     x(1)  |     x      |         x        |       x      |
-  | Persistent Mode          |         |     x     |     x      | x86[_64]/arm[64] |       x      |
-  | LAF-Intel / CompCov      |         |     x     |            | x86[_64]/arm[64] | x86[_64]/arm |
-  | CmpLog                   |         |     x     |            | x86[_64]/arm[64] |              |
-  | Selective Instrumentation|         |     x     |     x      |         x        |              |
-  | Non-Colliding Coverage   |         |     x(4)  |            |        (x)(5)    |              |
-  | Ngram prev_loc Coverage  |         |     x(6)  |            |                  |              |
-  | Context Coverage         |         |     x(6)  |            |                  |              |
-  | Auto Dictionary          |         |     x(7)  |            |                  |              |
-  | Snapshot LKM Support     |         |     x(8)  |     x(8)   |        (x)(5)    |              |
-
-  1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
+  afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1
+  with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD,
+  Mac OS, Solaris and Android support and much, much, much more.
+
+  | Feature/Instrumentation  | afl-gcc | llvm      | gcc_plugin | frida_mode | qemu_mode        |unicorn_mode |
+  | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:|
+  | Threadsafe counters      |         |     x(3)  |            |            |                  |              |
+  | NeverZero                | x86[_64]|     x(1)  |     x      |     x      |         x        |       x      |
+  | Persistent Mode          |         |     x     |     x      |  x86[_64]  | x86[_64]/arm[64] |       x      |
+  | LAF-Intel / CompCov      |         |     x     |            |            | x86[_64]/arm[64] | x86[_64]/arm |
+  | CmpLog                   |         |     x     |            |  x86[_64]  | x86[_64]/arm[64] |              |
+  | Selective Instrumentation|         |     x     |     x      |     x      |         x        |              |
+  | Non-Colliding Coverage   |         |     x(4)  |            |            |        (x)(5)    |              |
+  | Ngram prev_loc Coverage  |         |     x(6)  |            |            |                  |              |
+  | Context Coverage         |         |     x(6)  |            |            |                  |              |
+  | Auto Dictionary          |         |     x(7)  |            |            |                  |              |
+  | Snapshot LKM Support     |         |    (x)(8) |    (x)(8)  |            |        (x)(5)    |              |
+  | Shared Memory Testcases  |         |     x     |     x      |     x      |         x        |       x      |
+
+  1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions
   2. GCC creates non-performant code, hence it is disabled in gcc_plugin
-  3. (currently unassigned)
-  4. with pcguard mode and LTO mode for LLVM >= 11
+  3. with `AFL_LLVM_THREADSAFE_INST`, disables NeverZero
+  4. with pcguard mode and LTO mode for LLVM 11 and newer
   5. upcoming, development in the branch
-  6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
-  7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x`
+  6. not compatible with LTO instrumentation and needs at least LLVM v4.1
+  7. automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x`
   8. the snapshot LKM is currently unmaintained due to too many kernel changes coming too fast :-(
 
   Among others, the following features and patches have been integrated:
@@ -140,6 +146,7 @@ behaviours and defaults:
     time when we are satisfied with its stability
   * [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
     checkout which does not compile or has a bug. *We only accept PRs in dev!!*
+  * [release](https://github.com/AFLplusplus/AFLplusplus/tree/release) : the latest release
   * (any other) : experimental branches to work on specific features or testing
     new functionality or changes.
 
@@ -180,7 +187,7 @@ sudo apt-get install -y build-essential python3-dev automake git flex bison libg
 # try to install llvm 11 and install the distro default if that fails
 sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang 
 sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
-git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
+git clone https://github.com/AFLplusplus/AFLplusplus
 cd AFLplusplus
 make distrib
 sudo make install
@@ -249,6 +256,7 @@ Here are some good writeups to show how to effectively use AFL++:
 If you are interested in fuzzing structured data (where you define what the
 structure is), these links have you covered:
  * Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
+ * libprotobuf for afl++: [https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
  * libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
  * libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
 
@@ -288,7 +296,7 @@ anything below 9 is not recommended.
     |
     v
 +---------------------------------+
-| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
+| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
 +---------------------------------+     see [instrumentation/README.llvm.md](instrumentation/README.llvm.md)
     |
     | if not, or if the target fails with LLVM afl-clang-fast/++
@@ -370,7 +378,6 @@ There are many more options and modes available however these are most of the
 time less effective. See:
  * [instrumentation/README.ctx.md](instrumentation/README.ctx.md)
  * [instrumentation/README.ngram.md](instrumentation/README.ngram.md)
- * [instrumentation/README.instrim.md](instrumentation/README.instrim.md)
 
 afl++ performs "never zero" counting in its bitmap. You can read more about this
 here:
@@ -431,7 +438,7 @@ described in [instrumentation/README.lto.md](instrumentation/README.lto.md).
 ##### cmake
 
 For `cmake` build systems this is usually done by:
-`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..`
+`mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..`
 
 Note that if you are using the (better) afl-clang-lto compiler you also have to
 set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
@@ -601,8 +608,9 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same
 For every secondary fuzzer there should be a variation, e.g.:
  * one should fuzz the target that was compiled differently: with sanitizers
    activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
-   export AFL_USE_CFISAN=1 ; `
- * one should fuzz the target with CMPLOG/redqueen (see above)
+   export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`)
+ * one or two should fuzz the target with CMPLOG/redqueen (see above), at
+   least one cmplog instance should follow transformations (`-l AT`)
  * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV
    (see above). Important note: If you run more than one laf-intel/COMPCOV
    fuzzer and you want them to share their intermediate results, the main
@@ -672,8 +680,8 @@ If you see that an important area or a feature has not been covered so far then
 try to find an input that is able to reach that and start a new secondary in
 that fuzzing campaign with that seed as input, let it run for a few minutes,
 then terminate it. The main node will pick it up and make it available to the
-other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
-free core.
+other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or
+`export AFL_TRY_AFFINITY=1` if you have no free core.
 
 Note that you in nearly all cases can never reach full coverage. A lot of
 functionality is usually behind options that were not activated or fuzz e.g.
@@ -784,16 +792,19 @@ How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](
 When source code is *NOT* available, afl++ offers various support for fast,
 on-the-fly instrumentation of black-box binaries. 
 
-If you do not have to use Unicorn the following setup is recommended:
+If you do not have to use Unicorn the following setup is recommended to use
+qemu_mode:
   * run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`)
   * run 1 afl-fuzz -Q instance with QASAN  (`AFL_USE_QASAN=1`)
   * run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`)
+Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the
+LAF instance.
 
 Then run as many instances as you have cores left with either -Q mode or - better -
-use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc.
+use a binary rewriter like afl-dyninst, retrowrite, zaflr, etc.
 
-For Qemu mode, check out the persistent mode and snapshot features, they give
-a huge speed improvement!  
+For Qemu and Frida mode, check out the persistent mode, it gives a huge speed
+improvement if it is possible to use.
 
 ### QEMU
 
@@ -805,18 +816,31 @@ feature by doing:
 cd qemu_mode
 ./build_qemu_support.sh
 ```
-For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) -
-check out the snapshot feature! :-)
+For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
 If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
 The mode is approximately 2-5x slower than compile-time instrumentation, and is
 less conducive to parallelization.
 
 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 persistent mode).
+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.
 
+### Frida
+
+Frida mode is sometimes faster and sometimes slower than Qemu mode.
+It is also newer, lacks COMPCOV, but supports MacOS.
+
+```shell
+cd frida_mode
+make
+```
+For additional instructions and caveats, see [frida_mode/README.md](frida_mode/README.md).
+If possible you should use the persistent mode, see [qemu_frida/README.persistent.md](qemu_frida/README.persistent.md).
+The mode is approximately 2-5x slower than compile-time instrumentation, and is
+less conducive to parallelization.
+
 ### Unicorn
 
 For non-Linux binaries you can use afl++'s unicorn mode which can emulate
diff --git a/TODO.md b/TODO.md
index b8a091ff..398f3d11 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,15 +2,16 @@
 
 ## Roadmap 3.00+
 
+ - align map to 64 bytes but keep real IDs
  - Update afl->pending_not_fuzzed for MOpt
- - CPU affinity for many cores? There seems to be an issue > 96 cores
+ - put fuzz target in top line of UI
  - afl-plot to support multiple plot_data
  - afl_custom_fuzz_splice_optin()
  - afl_custom_splice()
  - intel-pt tracer
  - better autodetection of shifting runtime timeout values
  - cmplog: use colorization input for havoc?
- - cmplog: too much tainted bytes, directly add to dict and skip?
+ - parallel builds for source-only targets
 
 
 ## Further down the road
@@ -35,4 +36,5 @@ qemu_mode:
    up edge numbers that both following cmp paths have been found and then
    disable working on this edge id -> cmplog_intelligence branch
  - use cmplog colorization taint result for havoc locations?
-
+ - new instrumentation option for a thread-safe variant of feedback to shared mem.
+   The user decides, if this is needed (eg the target is multithreaded).
diff --git a/afl-cmin b/afl-cmin
index 778d7487..9fa63ec6 100755
--- a/afl-cmin
+++ b/afl-cmin
@@ -106,6 +106,7 @@ function usage() {
 "  -f file       - location read by the fuzzed program (stdin)\n" \
 "  -m megs       - memory limit for child process ("mem_limit" MB)\n" \
 "  -t msec       - run time limit for child process (none)\n" \
+"  -O            - use binary-only instrumentation (FRIDA mode)\n" \
 "  -Q            - use binary-only instrumentation (QEMU mode)\n" \
 "  -U            - use unicorn-based instrumentation (unicorn mode)\n" \
 "\n" \
@@ -118,11 +119,13 @@ function usage() {
 "Environment variables used:\n" \
 "AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
 "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
-"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \
+"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
 "AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
-"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
-"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \
-"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
+"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
+"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
+"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
+      "printed to stdout\n" \
+"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
    exit 1
 }
 
@@ -140,7 +143,7 @@ BEGIN {
   # process options
   Opterr = 1    # default is to diagnose
   Optind = 1    # skip ARGV[0]
-  while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCQU?")) != -1) {
+  while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
     if (_go_c == "i") {
       if (!Optarg) usage()
       if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
@@ -180,6 +183,12 @@ BEGIN {
       extra_par = extra_par " -e"
       continue
     } else 
+    if (_go_c == "O") {
+      if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+      extra_par = extra_par " -O"
+      frida_mode = 1
+      continue
+    } else 
     if (_go_c == "Q") {
       if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
       extra_par = extra_par " -Q"
@@ -243,7 +252,7 @@ BEGIN {
   if (!stdin_file) {
     found_atat = 0
     for (prog_args_ind in prog_args) {
-      if ("@@" == prog_args[prog_args_ind]) {
+      if (match(prog_args[prog_args_ind], "@@") != 0) {
         found_atat = 1
         break
       }
@@ -275,7 +284,7 @@ BEGIN {
     target_bin = tnew
   }
 
-  if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_mode) {
+  if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
     if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
       print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
       exit 1
diff --git a/afl-cmin.bash b/afl-cmin.bash
index 5b2c3894..f4bd269d 100755
--- a/afl-cmin.bash
+++ b/afl-cmin.bash
@@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
 
 export AFL_QUIET=1
 
-while getopts "+i:o:f:m:t:eQUCh" opt; do
+while getopts "+i:o:f:m:t:eOQUCh" opt; do
 
   case "$opt" in 
 
@@ -83,6 +83,10 @@ while getopts "+i:o:f:m:t:eQUCh" opt; do
     "C")
          export AFL_CMIN_CRASHES_ONLY=1
          ;;
+    "O")
+         EXTRA_PAR="$EXTRA_PAR -O"
+         FRIDA_MODE=1
+         ;;         
     "Q")
          EXTRA_PAR="$EXTRA_PAR -Q"
          QEMU_MODE=1
@@ -118,6 +122,7 @@ Execution control settings:
   -f file       - location read by the fuzzed program (stdin)
   -m megs       - memory limit for child process ($MEM_LIMIT MB)
   -t msec       - run time limit for child process (none)
+  -O            - use binary-only instrumentation (FRIDA mode)
   -Q            - use binary-only instrumentation (QEMU mode)
   -U            - use unicorn-based instrumentation (Unicorn mode)
   
@@ -209,7 +214,7 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
 
 fi
 
-if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
+if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
 
   if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
     echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
diff --git a/afl-plot b/afl-plot
index ba100d3e..60a351ab 100755
--- a/afl-plot
+++ b/afl-plot
@@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt
 
 set output '$outputdir/high_freq.png'
 
-set xdata time
-set timefmt '%s'
-set format x "%b %d\n%H:%M"
+#set xdata time
+#set timefmt '%s'
+#set format x "%b %d\n%H:%M"
 set tics font 'small'
 unset mxtics
 unset mytics
@@ -127,9 +127,8 @@ set key outside
 set autoscale xfixmin
 set autoscale xfixmax
 
-set xlabel "all times in UTC" font "small"
+#set xlabel "all times in UTC" font "small"
 
-set ytics auto
 plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
      '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
@@ -139,7 +138,6 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/low_freq.png'
 
-set ytics 1
 plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
      '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
@@ -148,14 +146,12 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/exec_speed.png'
 
-set ytics auto
 plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
      '$inputdir/plot_data' using 1:11 with lines title '    execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
 
 set terminal png truecolor enhanced size 1000,300 butt
 set output '$outputdir/edges.png'
 
-set ytics auto
 plot '$inputdir/plot_data' using 1:13 with lines title '        edges' linecolor rgb '#0090ff' linewidth 3
 
 _EOF_
diff --git a/afl-system-config b/afl-system-config
index ae37a062..e149e4cd 100755
--- a/afl-system-config
+++ b/afl-system-config
@@ -7,7 +7,7 @@ test "$1" = "-h" -o "$1" = "-hh" && {
   echo afl-system-config has no command line options
   echo
   echo afl-system reconfigures the system to a high performance fuzzing state
-  echo WARNING: this reduces the security of the system
+  echo "WARNING: this reduces the security of the system!"
   echo
   exit 1
 }
@@ -15,14 +15,20 @@ test "$1" = "-h" -o "$1" = "-hh" && {
 DONE=
 PLATFORM=`uname -s`
 echo This reconfigures the system to have a better fuzzing performance.
+echo "WARNING: this reduces the security of the system!"
+echo
 if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
 	echo "Warning: you need to be root to run this!"
 	# we do not exit as other mechanisms exist that allows to do this than
 	# being root. let the errors speak for themselves.
 fi
+sleep 1
 if [ "$PLATFORM" = "Linux" ] ; then
 {
-  sysctl -w kernel.core_pattern=core
+  sysctl -w kernel.core_uses_pid=0
+  # Arch Linux requires core_pattern to be empty :(
+  test -e /etc/arch-release && sysctl -w kernel.core_pattern=
+  test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
   sysctl -w kernel.randomize_va_space=0
   sysctl -w kernel.sched_child_runs_first=1
   sysctl -w kernel.sched_autogroup_enabled=1
@@ -35,12 +41,17 @@ if [ "$PLATFORM" = "Linux" ] ; then
   test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
   test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
   test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
+  test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1
 } > /dev/null
   echo Settings applied.
+  echo
   dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
     echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
     echo '  /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
+    echo
   }
+  echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "FreeBSD" ] ; then
@@ -49,6 +60,7 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then
   sysctl kern.elf64.aslr.enable=0
 } > /dev/null
   echo Settings applied.
+  echo
   cat <<EOF
 In order to suppress core file generation during fuzzing it is recommended to set
 me:\\
@@ -58,11 +70,12 @@ EOF
   echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
   echo '  sysctl hw.ibrs_disable=1'
   echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "OpenBSD" ] ; then
-  echo
   echo 'System security features cannot be disabled on OpenBSD.'
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "DragonFly" ] ; then
@@ -74,35 +87,43 @@ me:\\
 	:coredumpsize=0:
 in the ~/.login_conf file for the user used for fuzzing.
 EOF
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "NetBSD" ] ; then
 {
-  #echo It is recommended to enable unprivileged users to set cpu affinity
-  #echo to be able to use afl-gotcpu meaningfully.
   /sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
 } > /dev/null
   echo Settings applied.
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "Darwin" ] ; then
+  sysctl kern.sysv.shmmax=8388608
+  sysctl kern.sysv.shmseg=48
+  sysctl kern.sysv.shmall=98304
+  echo Settings applied.
+  echo
   if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
-    echo We unload the default crash reporter here
+    echo
+    echo Unloading the default crash reporter
     SL=/System/Library; PL=com.apple.ReportCrash
-    launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
-    sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
-    echo Settings applied.
-  else
-    echo Nothing to do.
+    launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1
+    sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
+    echo
   fi
+  echo It is recommended to disable System Integration Protection for increased performance.
+  echo
   DONE=1
 fi
 if [ "$PLATFORM" = "Haiku" ] ; then
-  SETTINGS=~/config/settings/system/debug_server/settings
+  DEBUG_SERVER_DIR=~/config/settings/system/debug_server
+  [ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR}
+  SETTINGS=${DEBUG_SERVER_DIR}/settings
   [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \
     echo We change the debug_server default_action from user to silently kill; \
     [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \
-    echo Settings applied.; \
+    echo Settings applied.; echo; \
   }
   DONE=1
 fi
diff --git a/afl-whatsup b/afl-whatsup
index e92b24bd..9c2564c6 100755
--- a/afl-whatsup
+++ b/afl-whatsup
@@ -21,32 +21,41 @@
 echo "$0 status check tool for afl-fuzz by Michal Zalewski"
 echo
 test "$1" = "-h" -o "$1" = "-hh" && {
-  echo $0 [-s] output_directory
+  echo "Usage: $0 [-s] [-d] afl_output_directory"
   echo
   echo Options:
-  echo   -s  -  skip details and output summary results only
+  echo "  -s  -  skip details and output summary results only"
+  echo "  -d  -  include dead fuzzer stats"
   echo
   exit 1
 }
 
-if [ "$1" = "-s" ]; then
+unset SUMMARY_ONLY
+unset PROCESS_DEAD
 
-  SUMMARY_ONLY=1
-  DIR="$2"
+while [ "$1" = "-s" -o "$1" = "-d" ]; do
 
-else
+  if [ "$1" = "-s" ]; then
+    SUMMARY_ONLY=1
+  fi
 
-  unset SUMMARY_ONLY
-  DIR="$1"
+  if [ "$1" = "-d" ]; then
+    PROCESS_DEAD=1
+  fi
+  
+  shift
 
-fi
+done
+
+DIR="$1"
 
 if [ "$DIR" = "" ]; then
 
-  echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2
+  echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
   echo 1>&2
-  echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2
-  echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2
+  echo Options: 1>&2
+  echo "  -s  -  skip details and output summary results only" 1>&2
+  echo "  -d  -  include dead fuzzer stats" 1>&2
   echo 1>&2
   exit 1
 
@@ -133,7 +142,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
   sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
   . "$TMP"
 
-  RUN_UNIX=$((CUR_TIME - start_time))
+  RUN_UNIX=$run_time
   RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
   RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
 
@@ -160,7 +169,13 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
     fi
 
     DEAD_CNT=$((DEAD_CNT + 1))
-    continue
+    last_path=0
+
+    if [ "$PROCESS_DEAD" = "" ]; then
+
+      continue
+
+    fi
 
   fi
 
@@ -252,13 +267,24 @@ fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
 
 test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
 
+if [ "$PROCESS_DEAD" = "" ]; then
+
+  TXT="excluded from stats"
+
+else
+
+  TXT="included in stats"
+  ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
+
+fi
+
 echo "Summary stats"
 echo "============="
 echo
 echo "       Fuzzers alive : $ALIVE_CNT"
 
 if [ ! "$DEAD_CNT" = "0" ]; then
-  echo "      Dead or remote : $DEAD_CNT (excluded from stats)"
+  echo "      Dead or remote : $DEAD_CNT ($TXT)"
 fi
 
 echo "      Total run time : $FMT_TIME"
diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp
index 89abc3e9..5c7e06e3 100644
--- a/custom_mutators/Android.bp
+++ b/custom_mutators/Android.bp
@@ -10,6 +10,8 @@ cc_library_shared {
     "-fPIC",
     "-fpermissive",
     "-std=c++11",
+    "-Wno-unused-parameter",
+    "-Wno-unused-variable",
   ],
 
   srcs: [
@@ -77,6 +79,8 @@ cc_library_shared {
     "-O0",
     "-funroll-loops",
     "-fPIC",
+    "-Wno-unused-parameter",
+    "-Wno-unused-function",
   ],
 
   srcs: [
@@ -99,6 +103,8 @@ cc_library_shared {
     "-O0",
     "-funroll-loops",
     "-fPIC",
+    "-Wno-unused-parameter",
+    "-Wno-pointer-sign",
   ],
 
   srcs: [
diff --git a/custom_mutators/README.md b/custom_mutators/README.md
index b0444c85..13172cdc 100644
--- a/custom_mutators/README.md
+++ b/custom_mutators/README.md
@@ -3,6 +3,14 @@
 Custom mutators enhance and alter the mutation strategies of afl++.
 For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
 
+## Examples
+
+The `./examples` folder contains examples for custom mutators in python and C.
+
+## Rust
+
+In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
+
 ## The afl++ Grammar Mutator
 
 If you use git to clone afl++, then the following will incorporate our
@@ -46,3 +54,6 @@ https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4
 has a transform function you need to fill for your protobuf format, however
 needs to be ported to the updated afl++ custom mutator API (not much work):
 https://github.com/thebabush/afl-libprotobuf-mutator
+
+same as above but is for current afl++:
+https://github.com/P1umer/AFLplusplus-protobuf-mutator
diff --git a/utils/custom_mutators/Makefile b/custom_mutators/examples/Makefile
index 9849f3f4..9849f3f4 100644
--- a/utils/custom_mutators/Makefile
+++ b/custom_mutators/examples/Makefile
diff --git a/utils/custom_mutators/README.md b/custom_mutators/examples/README.md
index 655f7a5e..655f7a5e 100644
--- a/utils/custom_mutators/README.md
+++ b/custom_mutators/examples/README.md
diff --git a/utils/custom_mutators/XmlMutatorMin.py b/custom_mutators/examples/XmlMutatorMin.py
index 3e6cd0ff..3e6cd0ff 100644
--- a/utils/custom_mutators/XmlMutatorMin.py
+++ b/custom_mutators/examples/XmlMutatorMin.py
diff --git a/utils/custom_mutators/common.py b/custom_mutators/examples/common.py
index 44a5056a..44a5056a 100644
--- a/utils/custom_mutators/common.py
+++ b/custom_mutators/examples/common.py
diff --git a/utils/custom_mutators/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h
index 62e6efba..62e6efba 100644
--- a/utils/custom_mutators/custom_mutator_helpers.h
+++ b/custom_mutators/examples/custom_mutator_helpers.h
diff --git a/utils/custom_mutators/example.c b/custom_mutators/examples/example.c
index 23add128..23add128 100644
--- a/utils/custom_mutators/example.c
+++ b/custom_mutators/examples/example.c
diff --git a/utils/custom_mutators/example.py b/custom_mutators/examples/example.py
index 3a6d22e4..3a6d22e4 100644
--- a/utils/custom_mutators/example.py
+++ b/custom_mutators/examples/example.py
diff --git a/utils/custom_mutators/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c
index ac10f409..aec05720 100644
--- a/utils/custom_mutators/post_library_gif.so.c
+++ b/custom_mutators/examples/post_library_gif.so.c
@@ -45,6 +45,7 @@
    1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
       and return the original `len`.
 
+   NOTE: the following is currently NOT true, we abort in this case!
    2) If you want to skip this test case altogether and have AFL generate a
       new one, return 0 or set `*out_buf = NULL`.
       Use this sparingly - it's faster than running the target program
@@ -53,14 +54,14 @@
    3) If you want to modify the test case, allocate an appropriately-sized
       buffer, move the data into that buffer, make the necessary changes, and
       then return the new pointer as out_buf. Return an appropriate len
-   afterwards.
+      afterwards.
 
       Note that the buffer will *not* be freed for you. To avoid memory leaks,
       you need to free it or reuse it on subsequent calls (as shown below).
 
       *** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
 
-    Aight. The example below shows a simple postprocessor that tries to make
+    Alright. The example below shows a simple postprocessor that tries to make
     sure that all input files start with "GIF89a".
 
     PS. If you don't like C, you can try out the unix-based wrapper from
diff --git a/utils/custom_mutators/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c
index 941f7e55..941f7e55 100644
--- a/utils/custom_mutators/post_library_png.so.c
+++ b/custom_mutators/examples/post_library_png.so.c
diff --git a/utils/custom_mutators/simple-chunk-replace.py b/custom_mutators/examples/simple-chunk-replace.py
index c57218dd..c57218dd 100644
--- a/utils/custom_mutators/simple-chunk-replace.py
+++ b/custom_mutators/examples/simple-chunk-replace.py
diff --git a/utils/custom_mutators/simple_example.c b/custom_mutators/examples/simple_example.c
index d888ec1f..d888ec1f 100644
--- a/utils/custom_mutators/simple_example.c
+++ b/custom_mutators/examples/simple_example.c
diff --git a/utils/custom_mutators/wrapper_afl_min.py b/custom_mutators/examples/wrapper_afl_min.py
index 5cd60031..5cd60031 100644
--- a/utils/custom_mutators/wrapper_afl_min.py
+++ b/custom_mutators/examples/wrapper_afl_min.py
diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION
index a3fe6bb1..3df8150e 100644
--- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION
+++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION
@@ -1 +1 @@
-b3c4fcf
+b79d51a
diff --git a/custom_mutators/grammar_mutator/build_grammar_mutator.sh b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
index ef145dfe..b6cef66f 100755
--- a/custom_mutators/grammar_mutator/build_grammar_mutator.sh
+++ b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
@@ -106,23 +106,23 @@ git status 1>/dev/null 2>/dev/null
 if [ $? -eq 0 ]; then
   echo "[*] initializing grammar mutator submodule"
   git submodule init || exit 1
-  git submodule update ./grammar-mutator 2>/dev/null # ignore errors
+  git submodule update ./grammar_mutator 2>/dev/null # ignore errors
 else
   echo "[*] cloning grammar mutator"
-  test -d grammar-mutator || {
+  test -d grammar_mutator || {
     CNT=1
-    while [ '!' -d grammar-mutator -a "$CNT" -lt 4 ]; do
-      echo "Trying to clone grammar-mutator (attempt $CNT/3)"
+    while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do
+      echo "Trying to clone grammar_mutator (attempt $CNT/3)"
       git clone "$GRAMMAR_REPO" 
       CNT=`expr "$CNT" + 1`
     done
   }
 fi
 
-test -d grammar-mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
+test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
 echo "[+] Got grammar mutator."
 
-cd "grammar-mutator" || exit 1
+cd "grammar_mutator" || exit 1
 echo "[*] Checking out $GRAMMAR_VERSION"
 sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
 git checkout "$GRAMMAR_VERSION" || exit 1
@@ -134,7 +134,7 @@ echo
 echo
 echo "[+] All successfully prepared!"
 echo "[!] To build for your grammar just do:"
-echo "      cd grammar-mutator"
+echo "      cd grammar_mutator"
 echo "      make GRAMMAR_FILE=/path/to/your/grammar"
-echo "[+] You will find a JSON and RUBY grammar in grammar-mutator/grammars to play with."
+echo "[+] You will find a JSON and RUBY grammar in grammar_mutator/grammars to play with."
 echo
diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator
-Subproject b3c4fcfa6ae28918bc410f7747135eafd4fb726
+Subproject b79d51a8daccbd7a693f9b6765c81ead14f28e2
diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp
index 01f1c23e..4f579735 100644
--- a/custom_mutators/libprotobuf-mutator-example/Android.bp
+++ b/custom_mutators/libprotobuf-mutator-example/Android.bp
@@ -8,6 +8,7 @@ cc_library_shared {
     "-O0",
     "-fPIC",
     "-Wall",
+    "-Wno-unused-parameter",
   ],
 
   srcs: [
@@ -29,4 +30,9 @@ cc_binary {
   srcs: [
     "vuln.c",
   ],
+
+  cflags: [
+    "-Wno-unused-result",
+    "-Wno-unused-parameter",
+  ],
 }
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 5b7d6ab6..1887c099 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -8,6 +8,63 @@
 Want to stay in the loop on major new features? Join our mailing list by
 sending a mail to <afl-users+subscribe@googlegroups.com>.
 
+### Version ++3.13c (release)
+  - Note: plot_data switched to relative time from unix time in 3.10
+  - frida_mode - new mode that uses frida to fuzz binary-only targets,
+    it currently supports persistent mode and cmplog.
+    thanks to @WorksButNotTested!
+  - create a fuzzing dictionary with the help of CodeQL thanks to
+    @microsvuln! see utils/autodict_ql
+  - afl-fuzz:
+    - added patch by @realmadsci to support @@ as part of command line
+      options, e.g. `afl-fuzz ... -- ./target --infile=@@`
+    - add recording of previous fuzz attempts for persistent mode
+      to allow replay of non-reproducable crashes, see
+      AFL_PERSISTENT_RECORD in config.h and docs/envs.h
+    - fixed a bug when trimming for stdin targets
+    - cmplog -l: default cmplog level is now 2, better efficiency.
+      level 3 now performs redqueen on everything. use with care.
+    - better fuzzing strategy yield display for enabled options
+    - ensure one fuzzer sync per cycle
+    - fix afl_custom_queue_new_entry original file name when syncing
+      from fuzzers
+    - fixed a crash when more than one custom mutator was used together
+      with afl_custom_post_process
+    - on a crashing seed potentially the wrong input was disabled
+    - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in
+      -i dir crashes the target or results in a timeout. By default
+      afl++ ignores these and uses them for splicing instead.
+    - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing
+      after no new paths have been found for n seconds
+    - when AFL_FAST_CAL is set a variable path will now be calibrated
+      8 times instead of originally 40. Long calibration is now 20.
+    - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if
+      it fails
+  - afl-cc:
+    - We do not support llvm versions prior 6.0 anymore
+    - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`),
+      note that this disables NeverZero counters.
+    - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD
+    - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks!
+    - Removed InsTrim instrumentation as it is not as good as PCGUARD
+    - Removed automatic linking with -lc++ for LTO mode
+    - Fixed a crash in llvm dict2file when a strncmp length was -1
+    - added --afl-noopt support
+  - utils/aflpp_driver:
+    - aflpp_qemu_driver_hook fixed to work with qemu_mode
+    - aflpp_driver now compiled with -fPIC
+  - unicornafl:
+    - fix MIPS delay slot caching, thanks @JackGrence
+    - fixed aarch64 exit address
+    - execution no longer stops at address 0x0
+  - updated afl-system-config to support Arch Linux weirdness and increase
+    MacOS shared memory
+  - updated the grammar custom mutator to the newest version
+  - add -d (add dead fuzzer stats) to afl-whatsup
+  - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the
+    current filename
+  - afl-showmap/cmin will now process queue items in alphabetical order
+
 ### Version ++3.12c (release)
   - afl-fuzz:
     - added AFL_TARGET_ENV variable to pass extra env vars to the target
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index e3c06c9d..80d452f7 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The
 comes with Xcode is missing some of the essential headers and helper tools.
 See README.llvm.md for advice on how to build the compiler from scratch.
 
+MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
+default settings aren't usable with AFL++. The default settings on 10.14 seem
+to be:
+
+```bash
+$ ipcs -M
+IPC status from <running system> as of XXX
+shminfo:
+        shmmax: 4194304 (max shared memory segment size)
+        shmmin:       1 (min shared memory segment size)
+        shmmni:      32 (max number of shared memory identifiers)
+        shmseg:       8 (max shared memory segments per process)
+        shmall:    1024 (max amount of shared memory in pages)
+```
+
+To temporarily change your settings to something minimally usable with AFL++,
+run these commands as root:
+
+```bash
+sysctl kern.sysv.shmmax=8388608
+sysctl kern.sysv.shmall=4096
+```
+
+If you're running more than one instance of AFL you likely want to make `shmall`
+bigger and increase `shmseg` as well:
+
+```bash
+sysctl kern.sysv.shmmax=8388608
+sysctl kern.sysv.shmseg=48
+sysctl kern.sysv.shmall=98304
+```
+
+See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for
+these settings and how to make them permanent.
+
 ## 4. Linux or *BSD on non-x86 systems
 
 Standard build will fail on non-x86 systems, but you should be able to
diff --git a/docs/PATCHES.md b/docs/PATCHES.md
deleted file mode 100644
index b2cff43a..00000000
--- a/docs/PATCHES.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Applied Patches
-
-The following patches from https://github.com/vanhauser-thc/afl-patches
-have been installed or not installed:
-
-
-## INSTALLED
-```
-afl-llvm-fix.diff			by kcwu(at)csie(dot)org
-afl-sort-all_uniq-fix.diff		by legarrec(dot)vincent(at)gmail(dot)com
-laf-intel.diff				by heiko(dot)eissfeldt(at)hexco(dot)de
-afl-llvm-optimize.diff			by mh(at)mh-sec(dot)de
-afl-fuzz-tmpdir.diff			by mh(at)mh-sec(dot)de
-afl-fuzz-79x24.diff			by heiko(dot)eissfeldt(at)hexco(dot)de
-afl-fuzz-fileextensionopt.diff		tbd
-afl-as-AFL_INST_RATIO.diff		by legarrec(dot)vincent(at)gmail(dot)com
-afl-qemu-ppc64.diff			by william(dot)barsse(at)airbus(dot)com
-afl-qemu-optimize-entrypoint.diff	by mh(at)mh-sec(dot)de
-afl-qemu-speed.diff			by abiondo on github
-afl-qemu-optimize-map.diff		by mh(at)mh-sec(dot)de
-```
-
-+ llvm_mode ngram prev_loc coverage (github.com/adrianherrera/afl-ngram-pass)
-+ Custom mutator (native library) (by kyakdan)
-+ unicorn_mode (modernized and updated by domenukk)
-+ instrim (https://github.com/csienslab/instrim) was integrated
-+ MOpt (github.com/puppet-meteor/MOpt-AFL) was imported
-+ AFLfast additions (github.com/mboehme/aflfast) were incorporated.
-+ Qemu 3.1 upgrade with enhancement patches (github.com/andreafioraldi/afl)
-+ Python mutator modules support (github.com/choller/afl)
-+ Instrument file list in LLVM mode (github.com/choller/afl)
-+ forkserver patch for afl-tmin (github.com/nccgroup/TriforceAFL)
-
-
-## NOT INSTALLED
-
-```
-afl-fuzz-context_sensitive.diff	- changes too much of the behaviour
-afl-tmpfs.diff - same as afl-fuzz-tmpdir.diff but more complex
-afl-cmin-reduce-dataset.diff - unsure of the impact
-afl-llvm-fix2.diff - not needed with the other patches
-```
-
diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md
index 10be409a..d1966170 100644
--- a/docs/QuickStartGuide.md
+++ b/docs/QuickStartGuide.md
@@ -1,6 +1,6 @@
 # AFL quick start guide
 
-You should read [README.md](README.md) - it's pretty short. If you really can't, here's
+You should read [README.md](../README.md) - it's pretty short. If you really can't, here's
 how to hit the ground running:
 
 1) Compile AFL with 'make'. If build fails, see [INSTALL.md](INSTALL.md) for tips.
diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md
index 787d970d..11e1dbeb 100644
--- a/docs/binaryonly_fuzzing.md
+++ b/docs/binaryonly_fuzzing.md
@@ -41,6 +41,33 @@
 
   As it is included in afl++ this needs no URL.
 
+  If you like to code a customized fuzzer without much work, we highly
+  recommend to check out our sister project libafl which will support QEMU
+  too:
+  [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL)
+
+
+## AFL FRIDA
+
+  In frida_mode you can fuzz binary-only targets easily like with QEMU,
+  with the advantage that frida_mode also works on MacOS (both intel and M1).
+
+  If you want to fuzz a binary-only library then you can fuzz it with
+  frida-gum via utils/afl_frida/, you will have to write a harness to
+  call the target function in the library, use afl-frida.c as a template.
+
+  Both come with afl++ so this needs no URL.
+
+  You can also perform remote fuzzing with frida, e.g. if you want to fuzz
+  on iPhone or Android devices, for this you can use
+  [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/)
+  as an intermediate that uses afl++ for fuzzing.
+
+  If you like to code a customized fuzzer without much work, we highly
+  recommend to check out our sister project libafl which supports Frida too:
+  [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL)
+  Working examples already exist :-)
+
 
 ## WINE+QEMU
 
@@ -62,13 +89,6 @@
   As it is included in afl++ this needs no URL.
 
 
-## AFL FRIDA
-
-   If you want to fuzz a binary-only shared library then you can fuzz it with
-   frida-gum via utils/afl_frida/, you will have to write a harness to
-   call the target function in the library, use afl-frida.c as a template.
-
-
 ## AFL UNTRACER
 
    If you want to fuzz a binary-only shared library then you can fuzz it with
@@ -157,19 +177,6 @@
   If anyone finds any coresight implementation for afl please ping me: vh@thc.org
 
 
-## FRIDA
-
-  Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio.
-  What is special is that it is written Python, and scripted with Javascript.
-  It is mostly used to reverse binaries on mobile phones however can be used
-  everywhere.
-
-  There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer)
-
-  There is also an early implementation in an AFL++ test branch:
-  [https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida)
-
-
 ## PIN & DYNAMORIO
 
   Pintool and Dynamorio are dynamic instrumentation engines, and they can be
@@ -205,7 +212,8 @@
   * QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
   * Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
   * S2E: [https://github.com/S2E](https://github.com/S2E)
-  * Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only)
+  * Tinyinst: [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only)
+  * Jackalope: [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope)
   *  ... please send me any missing that are good
 
 
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 61d711e4..129d6676 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -89,11 +89,14 @@ def queue_get(filename):
 
 def queue_new_entry(filename_new_queue, filename_orig_queue):
     pass
-```
 
 def introspection():
     return string
 
+def deinit():  # optional for Python
+    pass
+```
+
 ### Custom Mutation
 
 - `init`:
@@ -120,6 +123,7 @@ def introspection():
     Note that this function is optional - but it makes sense to use it.
     You would only skip this if `post_process` is used to fix checksums etc.
     so if you are using it e.g. as a post processing library.
+    Note that a length > 0 *must* be returned!
 
 - `describe` (optional):
 
@@ -285,8 +289,8 @@ afl-fuzz /path/to/program
 
 ## 4) Example
 
-Please see [example.c](../utils/custom_mutators/example.c) and
-[example.py](../utils/custom_mutators/example.py)
+Please see [example.c](../custom_mutators/examples/example.c) and
+[example.py](../custom_mutators/examples/example.py)
 
 ## 5) Other Resources
 
diff --git a/docs/env_variables.md b/docs/env_variables.md
index 409425f1..38a67bc7 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead:
     overridden.
 
   - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your
-    compiler supports that. Note that fuzzing with ASAN is mildly challenging
+    compiler supports it. Note that fuzzing with ASAN is mildly challenging
     - see [notes_for_asan.md](notes_for_asan.md).
 
     (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the
@@ -64,6 +64,13 @@ make fairly broad use of environmental variables instead:
     there is the Control Flow Integrity sanitizer that can be activated by
     `AFL_USE_CFISAN=1`)
 
+  - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided
+    that your compiler supports it. To perform a leak check within your
+    program at a certain point (such as at the end of an __AFL_LOOP),
+    you can run the macro __AFL_LEAK_CHECK(); which will cause
+    an abort if any memory is leaked (you can combine this with the
+    LSAN_OPTIONS=suppressions option to supress some known leaks).
+
   - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream
     compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
     in your `$PATH`.
@@ -130,16 +137,15 @@ Then there are a few specific features that are only available in instrumentatio
         PCGUARD - our own pcgard based instrumentation (default)
         NATIVE - clang's original pcguard based instrumentation
         CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
-        CFG - InsTrim instrumentation (see below)
         LTO - LTO instrumentation (see below)
         CTX - context sensitive instrumentation (see below)
         NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
         GCC - outdated gcc instrumentation
         CLANG - outdated clang instrumentation
-      In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
-      NGRAM, seperate the options with a comma "," then, e.g.:
-        `AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4`
-      Not that this is a good idea to use both CTX and NGRAM :)
+      In CLASSIC you can also specify CTX and/or NGRAM, seperate the options
+      with a comma "," then, e.g.:
+        `AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4`
+      Note that this is actually not a good idea to use both CTX and NGRAM :)
 
 ### LTO
 
@@ -173,24 +179,6 @@ Then there are a few specific features that are only available in instrumentatio
 
   See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information.
 
-### INSTRIM
-
-  This feature increases the speed by ~15% without any disadvantages to the
-    classic instrumentation.
-
-  Note that there is also an LTO version (if you have llvm 11 or higher) -
-    that is the best instrumentation we have. Use `afl-clang-lto` to activate.
-    The InsTrim LTO version additionally has all the options and features of
-    LTO (see above).
-
-   - Setting `AFL_LLVM_INSTRIM` or `AFL_LLVM_INSTRUMENT=CFG` activates this mode
-
-   - Setting `AFL_LLVM_INSTRIM_LOOPHEAD=1` expands on INSTRIM to optimize loops.
-      afl-fuzz will only be able to see the path the loop took, but not how
-      many times it was called (unless it is a complex loop).
-
-  See [instrumentation/README.instrim.md](../instrumentation/README.instrim.md)
-
 ### NGRAM
 
    - Setting `AFL_LLVM_NGRAM_SIZE` or `AFL_LLVM_INSTRUMENT=NGRAM-{value}`
@@ -243,6 +231,12 @@ Then there are a few specific features that are only available in instrumentatio
 
   See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information.
 
+### Thread safe instrumentation counters (in all modes)
+
+   - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread
+     safe counters. The overhead is a little bit higher compared to the older
+     non-thread safe case. Note that this disables neverzero (see below).
+
 ### NOT_ZERO
 
    - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters
@@ -296,6 +290,13 @@ checks or alter some of the more exotic semantics of the tool:
     normally indicated by the cycle counter in the UI turning green. May be
     convenient for some types of automated jobs.
 
+  - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were 
+    found within a specified period of time (in seconds). May be convenient 
+    for some types of automated jobs.
+
+  - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour
+    which does not allow crashes or timeout seeds in the initial -i corpus.
+
   - `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap,
     afl-tmin and afl-analyze create to gather instrumentation data from
     the target. This must be equal or larger than the size the target was
@@ -317,14 +318,12 @@ checks or alter some of the more exotic semantics of the tool:
     on Linux systems. This slows things down, but lets you run more instances
     of afl-fuzz than would be prudent (if you really want to).
 
+  - Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core
+    on Linux systems, but will not terminate if that fails.
+
   - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary
     that is compiled into the target.
 
-  - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input
-    queue. This can help with rare situations where a program crashes only
-    intermittently, but it's not really recommended under normal operating
-    conditions.
-
   - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for
     deciding if a particular test case is a "hang". The default is 1 second
     or the value of the `-t` parameter, whichever is larger. Dialing the value
@@ -360,6 +359,7 @@ checks or alter some of the more exotic semantics of the tool:
     and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n`
     setting to instruct afl-fuzz to still follow the fork server protocol
     without expecting any instrumentation data in return.
+    Note that this also turns off auto map size detection.
 
   - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
     fuzzer to import test cases from other instances before doing anything
@@ -391,7 +391,8 @@ checks or alter some of the more exotic semantics of the tool:
     may complain of high load prematurely, especially on systems with low core
     counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`.
 
-  - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace.
+  - In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will
+    be searched for afl-qemu-trace and afl-frida-trace.so.
 
   - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip
     prepending `afl-qemu-trace` to your command line. Use this if you wish to use a
@@ -424,6 +425,16 @@ checks or alter some of the more exotic semantics of the tool:
   - Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
     no valid terminal was detected (for virtual consoles)
 
+  - If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md))
+    some targets keep inherent state due which a detected crash testcase does
+    not crash the target again when the testcase is given. To be able to still
+    re-trigger these crashes you can use the `AFL_PERSISTENT_RECORD` variable
+    with a value of how many previous fuzz cases to keep prio a crash.
+    if set to e.g. 10, then the 9 previous inputs are written to
+    out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008
+    and RECORD:000000,cnt:000009 being the crash case.
+    NOTE: This option needs to be enabled in config.h first!
+
   - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
     Others need not apply, unless they also want to disable the
     `/proc/sys/kernel/core_pattern` check.
@@ -561,6 +572,9 @@ The corpus minimization script offers very little customization:
     a modest security risk on multi-user systems with rogue users, but should
     be safe on dedicated fuzzing boxes.
 
+  - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed.
+    This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting.
+
 ## 7) Settings for afl-tmin
 
 Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
@@ -614,7 +628,7 @@ optimal values if not already present in the environment:
     override this by setting `LD_BIND_LAZY` beforehand, but it is almost
     certainly pointless.
 
-  - By default, `ASAN_OPTIONS` are set to:
+  - By default, `ASAN_OPTIONS` are set to (among others):
 ```
     abort_on_error=1
     detect_leaks=0
@@ -635,7 +649,14 @@ optimal values if not already present in the environment:
     msan_track_origins=0
     allocator_may_return_null=1
 ```
-  Be sure to include the first one when customizing anything, since some
-    MSAN versions don't call `abort()` on error, and we need a way to detect
-    faults.
+  - Similarly, the default `LSAN_OPTIONS` are set to:
+```
+    exit_code=23
+    fast_unwind_on_malloc=0
+    symbolize=0
+    print_suppressions=0
+```
+  Be sure to include the first ones for LSAN and MSAN when customizing
+     anything, since some MSAN and LSAN versions don't call `abort()` on
+     error, and we need a way to detect faults.
 
diff --git a/docs/ideas.md b/docs/ideas.md
index 0130cf61..e25d3ba6 100644
--- a/docs/ideas.md
+++ b/docs/ideas.md
@@ -3,42 +3,6 @@
 In the following, we describe a variety of ideas that could be implemented
 for future AFL++ versions.
 
-# GSoC 2021
-
-All GSoC 2021 projects will be in the Rust development language!
-
-## UI for libaflrs
-
-Write a user interface to libaflrs, the upcoming backend of afl++.
-This might look like the afl-fuzz UI, but you can improve on it - and should!
-
-## Schedulers for libaflrs
-
-Schedulers is a mechanism that selects items from the fuzzing corpus based
-on strategy and randomness. One scheduler might focus on long paths,
-another on rarity of edges disocvered, still another on a combination on
-things. Some of the schedulers in afl++ have to be ported, but you are free
-to come up with your own if you want to - and see how it performs.
-
-## Forkserver support for libaflrs
-
-The current libaflrs implementation fuzzes in-memory, however obviously we
-want to support afl instrumented binaries as well.
-Hence a forkserver support needs to be implemented - forking off the target
-and talking to the target via a socketpair and the communication protocol
-within.
-
-## More Observers for libaflrs
-
-An observer is measuring functionality that looks at the target being fuzzed
-and documents something about it. In traditional fuzzing this is the coverage
-in the target, however we want to add various more observers, e.g. stack depth,
-heap usage, etc. - this is a topic for an experienced Rust developer.
-
-# Generic ideas and wishlist - NOT PART OF GSoC 2021 !
-
-The below list is not part of GSoC 2021.
-
 ## Analysis software
 
 Currently analysis is done by using afl-plot, which is rather outdated.
@@ -65,6 +29,13 @@ the current Unicorn instrumentation.
 
 Mentor: any
 
+## Support other programming languages
+
+Other programming languages also use llvm hence they could (easily?) supported
+for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ...
+
+Mentor: vanhauser-thc
+
 ## Machine Learning
 
 Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-)
diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md
index 50ad75d4..13ffcea0 100644
--- a/docs/life_pro_tips.md
+++ b/docs/life_pro_tips.md
@@ -83,5 +83,5 @@ You can find a simple solution in utils/argv_fuzzing.
 ## Attacking a format that uses checksums? 
 
 Remove the checksum-checking code or use a postprocessor!
-See utils/custom_mutators/ for more.
+See `afl_custom_post_process` in custom_mutators/examples/example.c for more.
 
diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md
index 2b3bc028..f55aeaf2 100644
--- a/docs/notes_for_asan.md
+++ b/docs/notes_for_asan.md
@@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that.
 
 (You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
 
+When compiling with AFL_USE_LSAN, the leak sanitizer will normally run
+when the program exits. In order to utilize this check at different times,
+such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();.
+This macro will report a crash in afl-fuzz if any memory is left leaking
+at this stage. You can also use LSAN_OPTIONS and a supressions file
+for more fine-tuned checking, however make sure you keep exitcode=23.
+
 NOTE: if you run several secondary instances, only one should run the target
 compiled with ASAN (and UBSAN, CFISAN), the others should run the target with
 no sanitizers compiled in.
diff --git a/docs/perf_tips.md b/docs/perf_tips.md
index fbcb4d8d..c5968206 100644
--- a/docs/perf_tips.md
+++ b/docs/perf_tips.md
@@ -69,9 +69,6 @@ If you are only interested in specific parts of the code being fuzzed, you can
 instrument_files the files that are actually relevant. This improves the speed and
 accuracy of afl. See instrumentation/README.instrument_list.md
 
-Also use the InsTrim mode on larger binaries, this improves performance and
-coverage a lot.
-
 ## 4. Profile and optimize the binary
 
 Check for any parameters or settings that obviously improve performance. For
diff --git a/docs/status_screen.md b/docs/status_screen.md
index 0329d960..e3abcc5f 100644
--- a/docs/status_screen.md
+++ b/docs/status_screen.md
@@ -251,8 +251,9 @@ exceed it by a margin sufficient to be classified as hangs.
   | arithmetics : 53/2.54M, 0/537k, 0/55.2k             |
   |  known ints : 8/322k, 12/1.32M, 10/1.70M            |
   |  dictionary : 9/52k, 1/53k, 1/24k                   |
-  |       havoc : 1903/20.0M, 0/0                       |
-  |        trim : 20.31%/9201, 17.05%                   |
+  |havoc/splice : 1903/20.0M, 0/0                       |
+  |py/custom/rq : unused, 53/2.54M, unused              |
+  |    trim/eff : 20.31%/9201, 17.05%                   |
   +-----------------------------------------------------+
 ```
 
@@ -268,6 +269,12 @@ goal. Finally, the third number shows the proportion of bytes that, although
 not possible to remove, were deemed to have no effect and were excluded from
 some of the more expensive deterministic fuzzing steps.
 
+Note that when deterministic mutation mode is off (which is the default
+because it is not very efficient) the first five lines display
+"disabled (default, enable with -D)".
+
+Only what is activated will have counter shown.
+
 ### Path geometry
 
 ```
diff --git a/dynamic_list.txt b/dynamic_list.txt
index f0e54d92..d1905d43 100644
--- a/dynamic_list.txt
+++ b/dynamic_list.txt
@@ -21,6 +21,7 @@
   "__afl_coverage_interesting";
   "__afl_fuzz_len";
   "__afl_fuzz_ptr";
+  "__afl_sharedmem_fuzzing";
   "__sanitizer_cov_trace_pc_guard";
   "__sanitizer_cov_trace_pc_guard_init";
   "__cmplog_ins_hook1";
diff --git a/frida_mode/.gitignore b/frida_mode/.gitignore
new file mode 100644
index 00000000..956b9911
--- /dev/null
+++ b/frida_mode/.gitignore
@@ -0,0 +1,5 @@
+build/
+frida_test.dat
+qemu_test.dat
+frida_out/**
+qemu_out/**
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile
new file mode 100644
index 00000000..a0387cac
--- /dev/null
+++ b/frida_mode/GNUmakefile
@@ -0,0 +1,188 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)..)/
+INC_DIR:=$(PWD)include/
+SRC_DIR:=$(PWD)src/
+INCLUDES:=$(wildcard $(INC_DIR)*.h)
+BUILD_DIR:=$(PWD)build/
+OBJ_DIR:=$(BUILD_DIR)obj/
+
+SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
+OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
+CFLAGS+=-fPIC \
+		-D_GNU_SOURCE \
+		-D_FORTIFY_SOURCE=2 \
+		-g \
+		-O3 \
+		-funroll-loops \
+
+RT_CFLAGS:=-Wno-unused-parameter \
+		   -Wno-sign-compare \
+		   -Wno-unused-function \
+		   -Wno-unused-result \
+		   -Wno-int-to-pointer-cast \
+
+LDFLAGS+=-shared \
+		 -lpthread \
+		 -lresolv \
+		 -ldl \
+		 -z noexecstack \
+
+ifdef DEBUG
+CFLAGS+=-Werror \
+		-Wall \
+		-Wextra \
+		-Wpointer-arith
+else
+CFLAGS+=-Wno-pointer-arith
+endif
+
+FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
+FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
+FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+ifeq "$(shell uname)" "Darwin"
+ OS:=macos
+ RT_CFLAGS:=$(RT_CFLAGS) -Wno-deprecated-declarations
+else
+ifdef DEBUG
+ RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor
+endif
+endif
+
+ifeq "$(shell uname)" "Linux"
+ OS:=linux
+endif
+
+ifndef OS
+ $(error "Operating system unsupported")
+endif
+
+GUM_DEVKIT_VERSION=14.2.18
+GUM_DEVKIT_FILENAME=frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
+GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
+
+GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
+GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a
+GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h
+
+FRIDA_DIR:=$(PWD)build/frida-source/
+FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
+FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a
+FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/
+FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h
+FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar
+FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME)
+
+AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c
+AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
+
+.PHONY: all 32 clean format $(FRIDA_GUM)
+
+############################## ALL #############################################
+
+all: $(FRIDA_TRACE)
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $(BUILD_DIR)
+
+$(OBJ_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+############################# FRIDA ############################################
+
+$(FRIDA_MAKEFILE): | $(BUILD_DIR)
+	git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
+
+$(FRIDA_GUM): $(FRIDA_MAKEFILE)
+	cd $(FRIDA_DIR) && make gum-linux-$(ARCH)
+
+$(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM)
+	$(FRIDA_DIR)releng/devkit.py frida-gum linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/
+
+$(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER)
+	cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) .
+
+$(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL): $(FRIDA_GUM_DEVKIT_TARBALL)
+	xz -k -f -0 $(FRIDA_GUM_DEVKIT_TARBALL)
+
+############################# DEVKIT ###########################################
+
+$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+ifdef FRIDA_SOURCE
+$(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR)
+	cp -v $< $@
+else
+$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
+	wget -O $@ $(GUM_DEVKIT_URL)
+endif
+
+$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL)
+	tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
+
+$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL)
+	tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
+
+############################## AFL #############################################
+$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC)
+	$(CC) \
+		$(CFLAGS) \
+		$(RT_CFLAGS) \
+		-I $(ROOT) \
+		-I $(ROOT)include \
+		-o $@ \
+		-c $<
+
+############################# SOURCE ###########################################
+
+define BUILD_SOURCE
+$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR)
+	$(CC) \
+		$(CFLAGS) \
+		-I $(ROOT)include \
+		-I $(FRIDA_BUILD_DIR) \
+		-I $(INC_DIR) \
+		-c $1 \
+		-o $2
+endef
+
+$(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))))
+
+######################## AFL-FRIDA-TRACE #######################################
+
+$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR)
+	$(CC) \
+		$(OBJS) \
+		$(GUM_DEVIT_LIBRARY) \
+		$(AFL_COMPILER_RT_OBJ) \
+		$(LDFLAGS) \
+		-o $@ \
+
+	cp -v $(FRIDA_TRACE) $(ROOT)
+
+############################# CLEAN ############################################
+clean:
+	rm -rf $(BUILD_DIR)
+
+############################# FORMAT ###########################################
+format:
+	cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i
+	cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i
+
+############################# RUN #############################################
diff --git a/frida_mode/Makefile b/frida_mode/Makefile
new file mode 100644
index 00000000..6cd1a64e
--- /dev/null
+++ b/frida_mode/Makefile
@@ -0,0 +1,13 @@
+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
+
+format:
+	@gmake format
diff --git a/frida_mode/README.md b/frida_mode/README.md
new file mode 100644
index 00000000..0103a395
--- /dev/null
+++ b/frida_mode/README.md
@@ -0,0 +1,294 @@
+# FRIDA MODE
+
+The purpose of FRIDA mode is to provide an alternative binary only fuzzer for
+AFL just like that provided by QEMU mode. The intention is to provide a very
+similar user experience, right down to the options provided through environment
+variables.
+
+Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida)
+this requires the code to be fuzzed to be provided as a shared library, it
+cannot be used to fuzz executables. Additionally, it requires the user to write
+a small harness around their target code of interest.
+FRIDA mode instead takes a different approach to avoid these limitations.
+In Frida mode binary programs are instrumented, similarly to QEMU mode.
+
+## Current Progress
+
+As FRIDA mode is new, it is missing a lot of features. The design is such that it
+should be possible to add these features in a similar manner to QEMU mode and
+perhaps leverage some of its design and implementation.
+
+  | Feature/Instrumentation  | frida-mode | Notes                                        |
+  | -------------------------|:----------:|:--------------------------------------------:|
+  | NeverZero                |     x      |                                              |
+  | Persistent Mode          |     x      | (x86/x64 only)(Only on function boundaries)  |
+  | LAF-Intel / CompCov      |     -      | (CMPLOG is better 90% of the time)           |
+  | CMPLOG                   |     x      | (x86/x64 only)                               |
+  | Selective Instrumentation|     x      |                                              |
+  | Non-Colliding Coverage   |     -      | (Not possible in binary-only instrumentation |
+  | Ngram prev_loc Coverage  |     -      |                                              |
+  | Context Coverage         |     -      |                                              |
+  | Auto Dictionary          |     -      |                                              |
+  | Snapshot LKM Support     |     -      |                                              |
+  | In-Memory Test Cases     |     x      | (x86/x64 only)                               |
+
+## Compatibility
+Currently FRIDA mode supports Linux and macOS targets on both x86/x64
+architecture and aarch64. Later releases may add support for aarch32 and Windows
+targets as well as embedded linux environments.
+
+FRIDA has been used on various embedded targets using both uClibc and musl C
+runtime libraries, so porting should be possible. However, the current build
+system does not support cross compilation.
+
+## Getting Started
+
+To build everything run `make`. To build for x86 run `make 32`. Note that in
+x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However,
+the shared library for frida_mode must be since it is injected into the target
+process.
+
+Various tests can be found in subfolders within the `test/` directory. To use
+these, first run `make` to build any dependencies. Then run `make qemu` or
+`make frida` to run on either QEMU of FRIDA mode respectively. To run frida
+tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between
+architectures it may be necessary to run `make clean` first for a given build
+target to remove previously generated binaries for a different architecture.
+
+## Usage
+
+FRIDA mode added some small modifications to `afl-fuzz` and similar tools
+in AFLplusplus. The intention was that it behaves identically to QEMU, but it uses
+the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have
+made more sense for a mode powered by FRIDA Stalker, they were all taken, so
+instead we use 'O' in hommage to the [author](https://github.com/oleavr) of
+FRIDA.
+
+Similarly, the intention is to mimic the use of environment variables used by
+QEMU where possible (by replacing `s/QEMU/FRIDA/g`). Accordingly, the
+following options are currently supported:
+
+* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS`
+* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES`
+* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES`
+* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR`
+* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT`
+* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK`
+* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET`
+* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`
+
+To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`.
+
+## Performance
+
+Additionally, the intention is to be able to make a direct performance
+comparison between the two approaches. Accordingly, FRIDA mode includes various
+test targets based on the [libpng](https://libpng.sourceforge.io/) benchmark
+used by [fuzzbench](https://google.github.io/fuzzbench/) and integrated with the
+[StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c)
+from the llvm project. These tests include basic fork-server support, persistent
+mode and persistent mode with in-memory test-cases. These are built and linked
+without any special modifications to suit FRIDA or QEMU. The test data provided
+with libpng is used as the corpus.
+
+The intention is to add support for FRIDA mode to the FuzzBench project and
+perform a like-for-like comparison with QEMU mode to get an accurate
+appreciation of its performance.
+
+## Design
+
+FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS)
+to inject a shared library (`afl-frida-trace.so`) into the target. This shared
+library is built using the [frida-gum](https://github.com/frida/frida-gum)
+devkit from the [FRIDA](https://github.com/frida/frida) project. One of the
+components of frida-gum is [Stalker](https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb0df8),
+this allows the dynamic instrumentation of running code for AARCH32, AARCH64,
+x86 and x64 architectures. Implementation details can be found
+[here](https://frida.re/docs/stalker/).
+
+Dynamic instrumentation is used to augment the target application with similar
+coverage information to that inserted by `afl-gcc` or `afl-clang`. The shared
+library is also linked to the `compiler-rt` component of AFLplusplus to feedback
+this coverage information to AFL++ and also provide a fork server. It also makes
+use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115)
+support to feedback instrumented blocks from the child to the parent using a
+shared memory region to avoid the need to regenerate instrumented blocks on each
+fork.
+
+Whilst FRIDA allows for a normal C function to be used to augment instrumented
+code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and
+x86/64 targets. By injecting these small snippets of assembly, we avoid having
+to push and pop the full register context. Note that since this instrumentation
+is used on every basic block to generate coverage, it has a large impact on
+performance.
+
+CMPLOG support also adds code to the assembly, however, at present this code
+makes use of a basic C function and is yet to be optimized. Since not all
+instances run CMPLOG mode and instrumentation of the binary is less frequent
+(only on CMP, SUB and CALL instructions) performance is not quite so critical.
+
+## Advanced configuration options
+
+* `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
+
+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_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_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.
+* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks
+`AFL_FRIDA_INST_NO_OPTIMIZE`.
+* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target
+application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
+* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target
+application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
+* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code
+at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user
+to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a
+debugger.
+
+```
+
+gdb \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=XXXXXXXXXX' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_RET=XXXXXXXXXX' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \
+		--ex 'set environment AFL_DEBUG_CHILD=1' \
+		--ex 'set environment LD_PRELOAD=afl-frida-trace.so' \
+		--args <my-executable> [my arguments]
+
+```
+* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being
+instrumented to the given file name. The statistics are written only for the
+child process when new block is instrumented (when the
+`AFL_FRIDA_STATS_INTERVAL` has expired). Note that simply because a new path is
+found does not mean a new block needs to be compiled. It could simply be that
+the existing blocks instrumented have been executed in a different order.
+```
+stats
+-----
+Index:                          2
+Pid:                            1815944
+Time:                           2021-05-28 15:26:41
+Blocks:                         1985
+Instructions:                   9192
+Avg Instructions / Block:       4
+
+Call Immediates:                391 (4.25%)
+Call Immediates Excluded:       65 (0.71%)
+Call Register:                  0 (0.00%)
+Call Memory:                    0 (0.00%)
+
+Jump Immediates:                202 (2.20%)
+Jump Register:                  10 (0.11%)
+Jump Memory:                    12 (0.13%)
+
+Conditional Jump Immediates:    1210 (13.16%)
+Conditional Jump CX Immediate:  0 (0.00%)
+Conditional Jump Register:      0 (0.00%)
+Conditional Jump Memory:        0 (0.00%)
+
+Returns:                        159 (0.00%)
+
+Rip Relative:                   247 (0.00%)
+
+```
+* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics
+information. Stats will be written whenever they are updated if the given
+interval has elapsed since last time they were written.
+* `AFL_FRIDA_STATS_TRANSITIONS` - Also dump the internal stalker counters to
+stderr when the regular stats are written. Note that these stats are reset in
+the child each time a new fork occurs since they are not stored in shared
+memory. Unfortunately, these stats are internal to stalker, so this is the best
+we can do for now.
+```
+stats
+-----
+Index: 2
+Pid:   1816794
+Time:  2021-05-28 15:26:41
+
+
+total_transitions: 786
+        call_imms: 97
+        call_regs: 0
+        call_mems: 0
+        post_call_invokes: 86
+        excluded_call_imms: 29
+        ret_slow_paths: 23
+
+        jmp_imms: 58
+        jmp_mems: 7
+        jmp_regs: 26
+
+        jmp_cond_imms: 460
+        jmp_cond_mems: 0
+        jmp_cond_regs: 0
+        jmp_cond_jcxzs: 0
+
+        jmp_continuations: 0
+```
+## FASAN - Frida Address Sanitizer Mode
+Frida mode also supports FASAN. The design of this is actually quite simple and
+very similar to that used when instrumenting applications compiled from source.
+
+### Address Sanitizer Basics
+
+When Address Sanitizer is used to instrument programs built from source, the
+compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer
+dynamic shared object (DSO). This shared object contains the main logic for Address
+Sanitizer, including setting and managing up the shadow memory. It also provides
+replacement implementations for a number of functions in standard libraries.
+
+These replacements include things like `malloc` and `free` which allows for those
+allocations to be marked in the shadow memory, but also a number of other fuctions.
+Consider `memcpy` for example, this is instrumented to validate the paramters
+(test the source and destination buffers against the shadow memory. This is much
+easier than instrumenting those standard libraries since, first it would require
+you to re-compile them and secondly it would mean that the instrumentation would
+be applied at a more expensive granular level. Lastly, load-widening (typically
+found in highy optimized code) can also make this instrumentation more difficult.
+
+Since the DSO is loaded before all of the standard libraries (in fact it insists
+on being first), the dynamic loader will use it to resolve imports from other
+modules which depend on it.
+
+### FASAN Implementation
+
+FASAN takes a similar approach. It requires the user to add the Address Sanitizer
+DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target.
+Again, it must be first in the list. This means that it is not necessary to
+instrument the standard libraries to detect when an application has provided an
+incorrect argument to `memcpy` for example. This avoids issues with load-widening
+and should also mean a huge improvement in performance.
+
+FASAN then adds instrumentation for any instrucutions which use memory operands and
+then calls into the `__asan_loadN` and `__asan_storeN` functions provided by the DSO
+to validate memory accesses against the shadow memory.
+
+## TODO
+
+The next features to be added are Aarch64 and Aarch32 support as well as looking at
+potential performance improvements. The intention is to achieve feature parity with
+QEMU mode in due course. Contributions are welcome, but please get in touch to
+ensure that efforts are deconflicted.
diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h
new file mode 100644
index 00000000..7a8726e0
--- /dev/null
+++ b/frida_mode/include/asan.h
@@ -0,0 +1,13 @@
+#ifndef _ASAN_H
+#define _ASAN_H
+
+#include "frida-gum.h"
+
+extern gboolean asan_initialized;
+
+void asan_init(void);
+void asan_arch_init(void);
+void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
+
+#endif
+
diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h
new file mode 100644
index 00000000..cbcc892a
--- /dev/null
+++ b/frida_mode/include/ctx.h
@@ -0,0 +1,11 @@
+#ifndef _CTX_H
+#define _CTX_H
+
+#include "frida-gum.h"
+
+#if defined(__x86_64__) || defined(__i386__)
+gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg);
+#endif
+
+#endif
+
diff --git a/frida_mode/include/entry.h b/frida_mode/include/entry.h
new file mode 100644
index 00000000..967831af
--- /dev/null
+++ b/frida_mode/include/entry.h
@@ -0,0 +1,15 @@
+#ifndef _ENTRY_H
+#define _ENTRY_H
+
+#include "frida-gum.h"
+
+extern guint64 entry_start;
+
+void entry_init(void);
+
+void entry_run(void);
+
+void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
+
+#endif
+
diff --git a/frida_mode/include/frida_cmplog.h b/frida_mode/include/frida_cmplog.h
new file mode 100644
index 00000000..b620a472
--- /dev/null
+++ b/frida_mode/include/frida_cmplog.h
@@ -0,0 +1,14 @@
+#ifndef _CMPLOG_H
+#define _CMPLOG_H
+
+extern struct cmp_map *__afl_cmp_map;
+
+void cmplog_init(void);
+
+/* Functions to be implemented by the different architectures */
+void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
+
+gboolean cmplog_is_readable(guint64 addr, size_t size);
+
+#endif
+
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
new file mode 100644
index 00000000..ed92c25a
--- /dev/null
+++ b/frida_mode/include/instrument.h
@@ -0,0 +1,27 @@
+#ifndef _INSTRUMENT_H
+#define _INSTRUMENT_H
+
+#include "frida-gum.h"
+
+#include "config.h"
+
+extern __thread uint64_t previous_pc;
+extern uint8_t *         __afl_area_ptr;
+extern uint32_t          __afl_map_size;
+
+void instrument_init(void);
+
+GumStalkerTransformer *instrument_get_transformer(void);
+
+/* Functions to be implemented by the different architectures */
+gboolean instrument_is_coverage_optimize_supported(void);
+
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output);
+
+void instrument_debug_init(void);
+void instrument_debug_start(uint64_t address, GumStalkerOutput *output);
+void instrument_debug_instruction(uint64_t address, uint16_t size);
+void instrument_debug_end(GumStalkerOutput *output);
+#endif
+
diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h
new file mode 100644
index 00000000..0ff754a4
--- /dev/null
+++ b/frida_mode/include/interceptor.h
@@ -0,0 +1,11 @@
+#ifndef _INTERCEPTOR_H
+#define _INTERCEPTOR_H
+
+#include "frida-gum.h"
+
+void intercept(void *address, gpointer replacement, gpointer user_data);
+void unintercept(void *address);
+void unintercept_self(void);
+
+#endif
+
diff --git a/frida_mode/include/lib.h b/frida_mode/include/lib.h
new file mode 100644
index 00000000..237aecb0
--- /dev/null
+++ b/frida_mode/include/lib.h
@@ -0,0 +1,13 @@
+#ifndef _LIB_H
+#define _LIB_H
+
+#include "frida-gum.h"
+
+void lib_init(void);
+
+guint64 lib_get_text_base(void);
+
+guint64 lib_get_text_limit(void);
+
+#endif
+
diff --git a/frida_mode/include/output.h b/frida_mode/include/output.h
new file mode 100644
index 00000000..53a9fdd3
--- /dev/null
+++ b/frida_mode/include/output.h
@@ -0,0 +1,9 @@
+#ifndef _OUTPUT_H
+#define _OUTPUT_H
+
+#include "frida-gum.h"
+
+void output_init(void);
+
+#endif
+
diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h
new file mode 100644
index 00000000..25b44ab0
--- /dev/null
+++ b/frida_mode/include/persistent.h
@@ -0,0 +1,35 @@
+
+#ifndef _PERSISTENT_H
+#define _PERSISTENT_H
+
+#include "frida-gum.h"
+#include "config.h"
+
+typedef struct arch_api_regs api_regs;
+
+typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base,
+                                       uint8_t *input_buf,
+                                       uint32_t input_buf_len);
+
+extern int __afl_persistent_loop(unsigned int max_cnt);
+
+extern unsigned int * __afl_fuzz_len;
+extern unsigned char *__afl_fuzz_ptr;
+
+extern guint64                persistent_start;
+extern guint64                persistent_count;
+extern guint64                persistent_ret;
+extern guint64                persistent_ret_offset;
+extern gboolean               persistent_debug;
+extern afl_persistent_hook_fn hook;
+
+void persistent_init(void);
+
+/* Functions to be implemented by the different architectures */
+gboolean persistent_is_supported(void);
+
+void persistent_prologue(GumStalkerOutput *output);
+void persistent_epilogue(GumStalkerOutput *output);
+
+#endif
+
diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h
new file mode 100644
index 00000000..8f0cee68
--- /dev/null
+++ b/frida_mode/include/prefetch.h
@@ -0,0 +1,11 @@
+#ifndef _PREFETCH_H
+#define _PREFETCH_H
+
+#include "frida-gum.h"
+
+void prefetch_init(void);
+void prefetch_write(void *addr);
+void prefetch_read(void);
+
+#endif
+
diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h
new file mode 100644
index 00000000..c623f473
--- /dev/null
+++ b/frida_mode/include/ranges.h
@@ -0,0 +1,13 @@
+#ifndef _RANGES_H
+#define _RANGES_H
+
+#include "frida-gum.h"
+
+void ranges_init(void);
+
+gboolean range_is_excluded(gpointer address);
+
+void ranges_exclude();
+
+#endif
+
diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h
new file mode 100644
index 00000000..186ead11
--- /dev/null
+++ b/frida_mode/include/stalker.h
@@ -0,0 +1,11 @@
+#ifndef _STALKER_H
+#define _STALKER_H
+
+#include "frida-gum.h"
+
+void        stalker_init(void);
+GumStalker *stalker_get(void);
+void        stalker_start(void);
+
+#endif
+
diff --git a/frida_mode/include/stats.h b/frida_mode/include/stats.h
new file mode 100644
index 00000000..4271132a
--- /dev/null
+++ b/frida_mode/include/stats.h
@@ -0,0 +1,28 @@
+#ifndef _STATS_H
+#define _STATS_H
+
+#include "frida-gum.h"
+
+typedef struct {
+
+  guint64 num_blocks;
+  guint64 num_instructions;
+  guint64 stats_last_time;
+  guint64 stats_idx;
+  guint64 transitions_idx;
+
+} stats_data_header_t;
+
+extern stats_data_header_t *stats_data;
+
+void stats_init(void);
+void stats_collect(const cs_insn *instr, gboolean begin);
+void stats_print(char *format, ...);
+
+gboolean stats_is_supported_arch(void);
+size_t   stats_data_size_arch(void);
+void     stats_collect_arch(const cs_insn *instr);
+void     stats_write_arch(void);
+
+#endif
+
diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h
new file mode 100644
index 00000000..7b443b5e
--- /dev/null
+++ b/frida_mode/include/util.h
@@ -0,0 +1,14 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include "frida-gum.h"
+
+#define UNUSED_PARAMETER(x) (void)(x)
+#define IGNORED_RETURN(x) (void)!(x)
+
+guint64 util_read_address(char *key);
+
+guint64 util_read_num(char *key);
+
+#endif
+
diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c
new file mode 100644
index 00000000..f78f690c
--- /dev/null
+++ b/frida_mode/src/asan/asan.c
@@ -0,0 +1,24 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "asan.h"
+
+gboolean asan_initialized = FALSE;
+
+void asan_init(void) {
+
+  if (getenv("AFL_USE_FASAN") != NULL) {
+
+    OKF("Frida ASAN mode enabled");
+    asan_arch_init();
+    asan_initialized = TRUE;
+
+  } else {
+
+    OKF("Frida ASAN mode disabled");
+
+  }
+
+}
+
diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c
new file mode 100644
index 00000000..79475ced
--- /dev/null
+++ b/frida_mode/src/asan/asan_arm.c
@@ -0,0 +1,28 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "asan.h"
+#include "util.h"
+
+#if defined(__arm__)
+void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(iterator);
+  if (asan_initialized) {
+
+    FATAL("ASAN mode not supported on this architecture");
+
+  }
+
+}
+
+void asan_arch_init(void) {
+
+  FATAL("ASAN mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c
new file mode 100644
index 00000000..6262ee18
--- /dev/null
+++ b/frida_mode/src/asan/asan_arm64.c
@@ -0,0 +1,28 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "asan.h"
+#include "util.h"
+
+#if defined(__aarch64__)
+void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(iterator);
+  if (asan_initialized) {
+
+    FATAL("ASAN mode not supported on this architecture");
+
+  }
+
+}
+
+void asan_arch_init(void) {
+
+  FATAL("ASAN mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c
new file mode 100644
index 00000000..a2eabe3c
--- /dev/null
+++ b/frida_mode/src/asan/asan_x64.c
@@ -0,0 +1,93 @@
+#include <dlfcn.h>
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "asan.h"
+#include "ctx.h"
+#include "util.h"
+
+#if defined(__x86_64__)
+
+typedef void (*asan_loadN_t)(uint64_t address, uint8_t size);
+typedef void (*asan_storeN_t)(uint64_t address, uint8_t size);
+
+asan_loadN_t  asan_loadN = NULL;
+asan_storeN_t asan_storeN = NULL;
+
+static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
+
+  UNUSED_PARAMETER(user_data);
+
+  cs_x86_op * operand = (cs_x86_op *)user_data;
+  x86_op_mem *mem = &operand->mem;
+  gsize       base = 0;
+  gsize       index = 0;
+  gsize       address;
+  uint8_t     size;
+
+  if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
+
+  if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
+
+  address = base + (mem->scale * index) + mem->disp;
+  size = operand->size;
+
+  if (operand->access == CS_AC_READ) {
+
+    asan_loadN(address, size);
+
+  } else if (operand->access == CS_AC_WRITE) {
+
+    asan_storeN(address, size);
+
+  }
+
+}
+
+void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(iterator);
+
+  cs_x86      x86 = instr->detail->x86;
+  cs_x86_op * operand;
+  x86_op_mem *mem;
+  cs_x86_op * ctx;
+
+  if (!asan_initialized) return;
+
+  if (instr->id == X86_INS_LEA) return;
+
+  if (instr->id == X86_INS_NOP) return;
+
+  for (uint8_t i = 0; i < x86.op_count; i++) {
+
+    operand = &x86.operands[i];
+
+    if (operand->type != X86_OP_MEM) { continue; }
+
+    mem = &operand->mem;
+    if (mem->segment != X86_REG_INVALID) { continue; }
+
+    ctx = g_malloc0(sizeof(cs_x86_op));
+    memcpy(ctx, operand, sizeof(cs_x86_op));
+    gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
+
+  }
+
+}
+
+void asan_arch_init(void) {
+
+  asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
+  asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
+  if (asan_loadN == NULL || asan_storeN == NULL) {
+
+    FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c
new file mode 100644
index 00000000..8490b490
--- /dev/null
+++ b/frida_mode/src/asan/asan_x86.c
@@ -0,0 +1,93 @@
+#include <dlfcn.h>
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "asan.h"
+#include "ctx.h"
+#include "util.h"
+
+#if defined(__i386__)
+
+typedef void (*asan_loadN_t)(gsize address, uint8_t size);
+typedef void (*asan_storeN_t)(gsize address, uint8_t size);
+
+asan_loadN_t  asan_loadN = NULL;
+asan_storeN_t asan_storeN = NULL;
+
+static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
+
+  UNUSED_PARAMETER(user_data);
+
+  cs_x86_op * operand = (cs_x86_op *)user_data;
+  x86_op_mem *mem = &operand->mem;
+  gsize       base = 0;
+  gsize       index = 0;
+  gsize       address;
+  uint8_t     size;
+
+  if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
+
+  if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
+
+  address = base + (mem->scale * index) + mem->disp;
+  size = operand->size;
+
+  if (operand->access == CS_AC_READ) {
+
+    asan_loadN(address, size);
+
+  } else if (operand->access == CS_AC_WRITE) {
+
+    asan_storeN(address, size);
+
+  }
+
+}
+
+void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(iterator);
+
+  cs_x86      x86 = instr->detail->x86;
+  cs_x86_op * operand;
+  x86_op_mem *mem;
+  cs_x86_op * ctx;
+
+  if (!asan_initialized) return;
+
+  if (instr->id == X86_INS_LEA) return;
+
+  if (instr->id == X86_INS_NOP) return;
+
+  for (uint8_t i = 0; i < x86.op_count; i++) {
+
+    operand = &x86.operands[i];
+
+    if (operand->type != X86_OP_MEM) { continue; }
+
+    mem = &operand->mem;
+    if (mem->segment != X86_REG_INVALID) { continue; }
+
+    ctx = g_malloc0(sizeof(cs_x86_op));
+    memcpy(ctx, operand, sizeof(cs_x86_op));
+    gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
+
+  }
+
+}
+
+void asan_arch_init(void) {
+
+  asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
+  asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
+  if (asan_loadN == NULL || asan_storeN == NULL) {
+
+    FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c
new file mode 100644
index 00000000..7b11c350
--- /dev/null
+++ b/frida_mode/src/cmplog/cmplog.c
@@ -0,0 +1,87 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "util.h"
+
+#define DEFAULT_MMAP_MIN_ADDR (32UL << 10)
+
+extern struct cmp_map *__afl_cmp_map;
+
+static GArray *cmplog_ranges = NULL;
+
+static gboolean cmplog_range(const GumRangeDetails *details,
+                             gpointer               user_data) {
+
+  UNUSED_PARAMETER(user_data);
+  GumMemoryRange range = *details->range;
+  g_array_append_val(cmplog_ranges, range);
+  return TRUE;
+
+}
+
+static gint cmplog_sort(gconstpointer a, gconstpointer b) {
+
+  return ((GumMemoryRange *)b)->base_address -
+         ((GumMemoryRange *)a)->base_address;
+
+}
+
+void cmplog_init(void) {
+
+  if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); }
+
+  cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100);
+  gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL);
+  g_array_sort(cmplog_ranges, cmplog_sort);
+
+  for (guint i = 0; i < cmplog_ranges->len; i++) {
+
+    GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
+    OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER
+        "X",
+        range->base_address, range->base_address + range->size);
+
+  }
+
+}
+
+static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit,
+                                GumAddress outer_base, GumAddress outer_limit) {
+
+  return (inner_base >= outer_base && inner_limit <= outer_limit);
+
+}
+
+gboolean cmplog_is_readable(guint64 addr, size_t size) {
+
+  if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized");
+
+  /*
+   * The Linux kernel prevents mmap from allocating from the very bottom of the
+   * address space to mitigate NULL pointer dereference attacks. The exact size
+   * is set by sysctl by setting mmap_min_addr and 64k is suggested on most
+   * platforms with 32k on ARM systems. We therefore fail fast if the address
+   * is lower than this. This should avoid some overhead when functions are
+   * called where one of the parameters is a size, or a some other small value.
+   */
+  if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; }
+
+  GumAddress inner_base = addr;
+  GumAddress inner_limit = inner_base + size;
+
+  for (guint i = 0; i < cmplog_ranges->len; i++) {
+
+    GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
+    GumAddress      outer_base = range->base_address;
+    GumAddress      outer_limit = outer_base + range->size;
+
+    if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit))
+      return true;
+
+  }
+
+  return false;
+
+}
+
diff --git a/frida_mode/src/cmplog/cmplog_arm.c b/frida_mode/src/cmplog/cmplog_arm.c
new file mode 100644
index 00000000..5af28f3f
--- /dev/null
+++ b/frida_mode/src/cmplog/cmplog_arm.c
@@ -0,0 +1,19 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "frida_cmplog.h"
+#include "util.h"
+
+#if defined(__arm__)
+void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(iterator);
+  if (__afl_cmp_map == NULL) { return; }
+  FATAL("CMPLOG mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/cmplog/cmplog_arm64.c b/frida_mode/src/cmplog/cmplog_arm64.c
new file mode 100644
index 00000000..187d0162
--- /dev/null
+++ b/frida_mode/src/cmplog/cmplog_arm64.c
@@ -0,0 +1,19 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "frida_cmplog.h"
+#include "util.h"
+
+#if defined(__aarch64__)
+void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(iterator);
+  if (__afl_cmp_map == NULL) { return; }
+  FATAL("CMPLOG mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c
new file mode 100644
index 00000000..9f56c32a
--- /dev/null
+++ b/frida_mode/src/cmplog/cmplog_x64.c
@@ -0,0 +1,272 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+#include "cmplog.h"
+
+#include "ctx.h"
+#include "frida_cmplog.h"
+#include "util.h"
+
+#if defined(__x86_64__)
+
+typedef struct {
+
+  x86_op_type type;
+  uint8_t     size;
+
+  union {
+
+    x86_op_mem mem;
+    x86_reg    reg;
+    int64_t    imm;
+
+  };
+
+} cmplog_ctx_t;
+
+typedef struct {
+
+  cmplog_ctx_t operand1;
+  cmplog_ctx_t operand2;
+
+} cmplog_pair_ctx_t;
+
+static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size,
+                                x86_op_mem *mem, gsize *val) {
+
+  gsize base = 0;
+  gsize index = 0;
+  gsize address;
+
+  if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base);
+
+  if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index);
+
+  address = base + (index * mem->scale) + mem->disp;
+
+  if (!cmplog_is_readable(address, size)) { return FALSE; }
+
+  switch (size) {
+
+    case 1:
+      *val = *((guint8 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    case 2:
+      *val = *((guint16 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    case 4:
+      *val = *((guint32 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    case 8:
+      *val = *((guint64 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    default:
+      FATAL("Invalid operand size: %d\n", size);
+
+  }
+
+  return FALSE;
+
+}
+
+static gboolean cmplog_get_operand_value(GumCpuContext *context,
+                                         cmplog_ctx_t *ctx, gsize *val) {
+
+  switch (ctx->type) {
+
+    case X86_OP_REG:
+      *val = ctx_read_reg(context, ctx->reg);
+      return TRUE;
+    case X86_OP_IMM:
+      *val = ctx->imm;
+      return TRUE;
+    case X86_OP_MEM:
+      return cmplog_read_mem(context, ctx->size, &ctx->mem, val);
+    default:
+      FATAL("Invalid operand type: %d\n", ctx->type);
+
+  }
+
+  return FALSE;
+
+}
+
+static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
+
+  UNUSED_PARAMETER(user_data);
+
+  gsize address = ctx_read_reg(context, X86_REG_RIP);
+  gsize rdi = ctx_read_reg(context, X86_REG_RDI);
+  gsize rsi = ctx_read_reg(context, X86_REG_RSI);
+
+  if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return;
+
+  if (!cmplog_is_readable(rdi, 32) || !cmplog_is_readable(rsi, 32)) return;
+
+  void *ptr1 = GSIZE_TO_POINTER(rdi);
+  void *ptr2 = GSIZE_TO_POINTER(rsi);
+
+  uintptr_t k = address;
+
+  k = (k >> 4) ^ (k << 8);
+  k &= CMP_MAP_W - 1;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+
+  __afl_cmp_map->headers[k].shape = 31;
+
+  hits &= CMP_MAP_RTN_H - 1;
+  gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1,
+             32);
+  gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2,
+             32);
+
+}
+
+static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
+                                          cs_x86_op *   operand) {
+
+  ctx->type = operand->type;
+  ctx->size = operand->size;
+  switch (operand->type) {
+
+    case X86_OP_REG:
+      gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg));
+      break;
+    case X86_OP_IMM:
+      gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t));
+      break;
+    case X86_OP_MEM:
+      gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem));
+      break;
+    default:
+      FATAL("Invalid operand type: %d\n", operand->type);
+
+  }
+
+}
+
+static void cmplog_instrument_call(const cs_insn *     instr,
+                                   GumStalkerIterator *iterator) {
+
+  cs_x86     x86 = instr->detail->x86;
+  cs_x86_op *operand;
+
+  if (instr->id != X86_INS_CALL) return;
+
+  if (x86.op_count != 1) return;
+
+  operand = &x86.operands[0];
+
+  if (operand->type == X86_OP_INVALID) return;
+  if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID)
+    return;
+
+  gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL);
+
+}
+
+static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
+                                  gsize operand2, uint8_t size) {
+
+  gsize address = ctx_read_reg(context, X86_REG_RIP);
+
+  register uintptr_t k = (uintptr_t)address;
+
+  k = (k >> 4) ^ (k << 8);
+  k &= CMP_MAP_W - 1;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+
+  __afl_cmp_map->headers[k].shape = (size - 1);
+
+  hits &= CMP_MAP_H - 1;
+  __afl_cmp_map->log[k][hits].v0 = operand1;
+  __afl_cmp_map->log[k][hits].v1 = operand2;
+
+}
+
+static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
+
+  cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data;
+  gsize              operand1;
+  gsize              operand2;
+
+  if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
+
+  if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; }
+  if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; }
+
+  cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
+
+}
+
+static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
+                                                  cs_x86_op *         operand1,
+                                                  cs_x86_op *operand2) {
+
+  cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
+  if (ctx == NULL) return;
+
+  cmplog_instrument_put_operand(&ctx->operand1, operand1);
+  cmplog_instrument_put_operand(&ctx->operand2, operand2);
+
+  gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx,
+                                   g_free);
+
+}
+
+static void cmplog_instrument_cmp_sub(const cs_insn *     instr,
+                                      GumStalkerIterator *iterator) {
+
+  cs_x86     x86 = instr->detail->x86;
+  cs_x86_op *operand1;
+  cs_x86_op *operand2;
+
+  switch (instr->id) {
+
+    case X86_INS_CMP:
+    case X86_INS_SUB:
+      break;
+    default:
+      return;
+
+  }
+
+  if (x86.op_count != 2) return;
+
+  operand1 = &x86.operands[0];
+  operand2 = &x86.operands[1];
+
+  if (operand1->type == X86_OP_INVALID) return;
+  if (operand2->type == X86_OP_INVALID) return;
+
+  if ((operand1->type == X86_OP_MEM) &&
+      (operand1->mem.segment != X86_REG_INVALID))
+    return;
+
+  if ((operand2->type == X86_OP_MEM) &&
+      (operand2->mem.segment != X86_REG_INVALID))
+    return;
+
+  cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2);
+
+}
+
+void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  if (__afl_cmp_map == NULL) return;
+
+  cmplog_instrument_call(instr, iterator);
+  cmplog_instrument_cmp_sub(instr, iterator);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/cmplog/cmplog_x86.c b/frida_mode/src/cmplog/cmplog_x86.c
new file mode 100644
index 00000000..a27df0af
--- /dev/null
+++ b/frida_mode/src/cmplog/cmplog_x86.c
@@ -0,0 +1,277 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+#include "cmplog.h"
+
+#include "ctx.h"
+#include "frida_cmplog.h"
+#include "util.h"
+
+#if defined(__i386__)
+
+typedef struct {
+
+  x86_op_type type;
+  uint8_t     size;
+
+  union {
+
+    x86_op_mem mem;
+    x86_reg    reg;
+    int64_t    imm;
+
+  };
+
+} cmplog_ctx_t;
+
+typedef struct {
+
+  cmplog_ctx_t operand1;
+  cmplog_ctx_t operand2;
+
+} cmplog_pair_ctx_t;
+
+static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size,
+                                x86_op_mem *mem, gsize *val) {
+
+  gsize base = 0;
+  gsize index = 0;
+  gsize address;
+
+  if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base);
+
+  if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index);
+
+  address = base + (index * mem->scale) + mem->disp;
+
+  if (!cmplog_is_readable(address, size)) { return FALSE; }
+
+  switch (size) {
+
+    case 1:
+      *val = *((guint8 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    case 2:
+      *val = *((guint16 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    case 4:
+      *val = *((guint32 *)GSIZE_TO_POINTER(address));
+      return TRUE;
+    default:
+      FATAL("Invalid operand size: %d\n", size);
+
+  }
+
+  return FALSE;
+
+}
+
+static gboolean cmplog_get_operand_value(GumCpuContext *context,
+                                         cmplog_ctx_t *ctx, gsize *val) {
+
+  switch (ctx->type) {
+
+    case X86_OP_REG:
+      *val = ctx_read_reg(context, ctx->reg);
+      return TRUE;
+    case X86_OP_IMM:
+      *val = ctx->imm;
+      return TRUE;
+    case X86_OP_MEM:
+      return cmplog_read_mem(context, ctx->size, &ctx->mem, val);
+    default:
+      FATAL("Invalid operand type: %d\n", ctx->type);
+
+  }
+
+  return FALSE;
+
+}
+
+static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
+
+  UNUSED_PARAMETER(user_data);
+
+  gsize  address = ctx_read_reg(context, X86_REG_EIP);
+  gsize *esp = (gsize *)ctx_read_reg(context, X86_REG_ESP);
+
+  if (!cmplog_is_readable(GPOINTER_TO_SIZE(esp), 12)) return;
+
+  /*
+   * This callout is place immediately before the call instruction, and hence
+   * the return address is not yet pushed on the top of the stack.
+   */
+  gsize arg1 = esp[0];
+  gsize arg2 = esp[1];
+
+  if (((G_MAXULONG - arg1) < 32) || ((G_MAXULONG - arg2) < 32)) return;
+
+  if (!cmplog_is_readable(arg1, 32) || !cmplog_is_readable(arg2, 32)) return;
+
+  void *ptr1 = GSIZE_TO_POINTER(arg1);
+  void *ptr2 = GSIZE_TO_POINTER(arg2);
+
+  uintptr_t k = address;
+
+  k = (k >> 4) ^ (k << 8);
+  k &= CMP_MAP_W - 1;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+
+  __afl_cmp_map->headers[k].shape = 31;
+
+  hits &= CMP_MAP_RTN_H - 1;
+  gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1,
+             32);
+  gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2,
+             32);
+
+}
+
+static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx,
+                                          cs_x86_op *   operand) {
+
+  ctx->type = operand->type;
+  ctx->size = operand->size;
+  switch (operand->type) {
+
+    case X86_OP_REG:
+      gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg));
+      break;
+    case X86_OP_IMM:
+      gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t));
+      break;
+    case X86_OP_MEM:
+      gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem));
+      break;
+    default:
+      FATAL("Invalid operand type: %d\n", operand->type);
+
+  }
+
+}
+
+static void cmplog_instrument_call(const cs_insn *     instr,
+                                   GumStalkerIterator *iterator) {
+
+  cs_x86     x86 = instr->detail->x86;
+  cs_x86_op *operand;
+
+  if (instr->id != X86_INS_CALL) return;
+
+  if (x86.op_count != 1) return;
+
+  operand = &x86.operands[0];
+
+  if (operand->type == X86_OP_INVALID) return;
+  if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID)
+    return;
+
+  gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL);
+
+}
+
+static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
+                                  gsize operand2, uint8_t size) {
+
+  gsize address = ctx_read_reg(context, X86_REG_EIP);
+
+  register uintptr_t k = (uintptr_t)address;
+
+  k = (k >> 4) ^ (k << 8);
+  k &= CMP_MAP_W - 1;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+
+  __afl_cmp_map->headers[k].shape = (size - 1);
+
+  hits &= CMP_MAP_H - 1;
+  __afl_cmp_map->log[k][hits].v0 = operand1;
+  __afl_cmp_map->log[k][hits].v1 = operand2;
+
+}
+
+static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
+
+  cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data;
+  gsize              operand1;
+  gsize              operand2;
+
+  if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
+
+  if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; }
+  if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; }
+
+  cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
+
+}
+
+static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
+                                                  cs_x86_op *         operand1,
+                                                  cs_x86_op *operand2) {
+
+  cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
+  if (ctx == NULL) return;
+
+  cmplog_instrument_put_operand(&ctx->operand1, operand1);
+  cmplog_instrument_put_operand(&ctx->operand2, operand2);
+
+  gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx,
+                                   g_free);
+
+}
+
+static void cmplog_instrument_cmp_sub(const cs_insn *     instr,
+                                      GumStalkerIterator *iterator) {
+
+  cs_x86     x86 = instr->detail->x86;
+  cs_x86_op *operand1;
+  cs_x86_op *operand2;
+
+  switch (instr->id) {
+
+    case X86_INS_CMP:
+    case X86_INS_SUB:
+      break;
+    default:
+      return;
+
+  }
+
+  if (x86.op_count != 2) return;
+
+  operand1 = &x86.operands[0];
+  operand2 = &x86.operands[1];
+
+  if (operand1->type == X86_OP_INVALID) return;
+  if (operand2->type == X86_OP_INVALID) return;
+
+  if ((operand1->type == X86_OP_MEM) &&
+      (operand1->mem.segment != X86_REG_INVALID))
+    return;
+
+  if ((operand2->type == X86_OP_MEM) &&
+      (operand2->mem.segment != X86_REG_INVALID))
+    return;
+
+  cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2);
+
+}
+
+void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
+
+  if (__afl_cmp_map == NULL) return;
+
+  cmplog_instrument_call(instr, iterator);
+  cmplog_instrument_cmp_sub(instr, iterator);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c
new file mode 100644
index 00000000..c5900533
--- /dev/null
+++ b/frida_mode/src/ctx/ctx_x64.c
@@ -0,0 +1,114 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "ctx.h"
+
+#if defined(__x86_64__)
+
+  #define X86_REG_8L(LABEL, REG)  \
+    case LABEL: {                 \
+                                  \
+      return REG & GUM_INT8_MASK; \
+                                  \
+    }
+
+  #define X86_REG_8H(LABEL, REG)          \
+    case LABEL: {                         \
+                                          \
+      return (REG & GUM_INT16_MASK) >> 8; \
+                                          \
+    }
+
+  #define X86_REG_16(LABEL, REG)     \
+    case LABEL: {                    \
+                                     \
+      return (REG & GUM_INT16_MASK); \
+                                     \
+    }
+
+  #define X86_REG_32(LABEL, REG)     \
+    case LABEL: {                    \
+                                     \
+      return (REG & GUM_INT32_MASK); \
+                                     \
+    }
+
+  #define X86_REG_64(LABEL, REG) \
+    case LABEL: {                \
+                                 \
+      return (REG);              \
+                                 \
+    }
+
+gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) {
+
+  switch (reg) {
+
+    X86_REG_8L(X86_REG_AL, ctx->rax)
+    X86_REG_8L(X86_REG_BL, ctx->rbx)
+    X86_REG_8L(X86_REG_CL, ctx->rcx)
+    X86_REG_8L(X86_REG_DL, ctx->rdx)
+    X86_REG_8L(X86_REG_BPL, ctx->rbp)
+    X86_REG_8L(X86_REG_SIL, ctx->rsi)
+    X86_REG_8L(X86_REG_DIL, ctx->rdi)
+
+    X86_REG_8H(X86_REG_AH, ctx->rax)
+    X86_REG_8H(X86_REG_BH, ctx->rbx)
+    X86_REG_8H(X86_REG_CH, ctx->rcx)
+    X86_REG_8H(X86_REG_DH, ctx->rdx)
+
+    X86_REG_16(X86_REG_AX, ctx->rax)
+    X86_REG_16(X86_REG_BX, ctx->rbx)
+    X86_REG_16(X86_REG_CX, ctx->rcx)
+    X86_REG_16(X86_REG_DX, ctx->rdx)
+    X86_REG_16(X86_REG_DI, ctx->rdi)
+    X86_REG_16(X86_REG_SI, ctx->rsi)
+    X86_REG_16(X86_REG_BP, ctx->rbp)
+
+    X86_REG_32(X86_REG_EAX, ctx->rax)
+    X86_REG_32(X86_REG_ECX, ctx->rcx)
+    X86_REG_32(X86_REG_EDX, ctx->rdx)
+    X86_REG_32(X86_REG_EBX, ctx->rbx)
+    X86_REG_32(X86_REG_ESP, ctx->rsp)
+    X86_REG_32(X86_REG_EBP, ctx->rbp)
+    X86_REG_32(X86_REG_ESI, ctx->rsi)
+    X86_REG_32(X86_REG_EDI, ctx->rdi)
+    X86_REG_32(X86_REG_R8D, ctx->r8)
+    X86_REG_32(X86_REG_R9D, ctx->r9)
+    X86_REG_32(X86_REG_R10D, ctx->r10)
+    X86_REG_32(X86_REG_R11D, ctx->r11)
+    X86_REG_32(X86_REG_R12D, ctx->r12)
+    X86_REG_32(X86_REG_R13D, ctx->r13)
+    X86_REG_32(X86_REG_R14D, ctx->r14)
+    X86_REG_32(X86_REG_R15D, ctx->r15)
+    X86_REG_32(X86_REG_EIP, ctx->rip)
+
+    X86_REG_64(X86_REG_RAX, ctx->rax)
+    X86_REG_64(X86_REG_RCX, ctx->rcx)
+    X86_REG_64(X86_REG_RDX, ctx->rdx)
+    X86_REG_64(X86_REG_RBX, ctx->rbx)
+    X86_REG_64(X86_REG_RSP, ctx->rsp)
+    X86_REG_64(X86_REG_RBP, ctx->rbp)
+    X86_REG_64(X86_REG_RSI, ctx->rsi)
+    X86_REG_64(X86_REG_RDI, ctx->rdi)
+    X86_REG_64(X86_REG_R8, ctx->r8)
+    X86_REG_64(X86_REG_R9, ctx->r9)
+    X86_REG_64(X86_REG_R10, ctx->r10)
+    X86_REG_64(X86_REG_R11, ctx->r11)
+    X86_REG_64(X86_REG_R12, ctx->r12)
+    X86_REG_64(X86_REG_R13, ctx->r13)
+    X86_REG_64(X86_REG_R14, ctx->r14)
+    X86_REG_64(X86_REG_R15, ctx->r15)
+    X86_REG_64(X86_REG_RIP, ctx->rip)
+
+    default:
+      FATAL("Failed to read register: %d", reg);
+      return 0;
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c
new file mode 100644
index 00000000..45308272
--- /dev/null
+++ b/frida_mode/src/ctx/ctx_x86.c
@@ -0,0 +1,81 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "ctx.h"
+
+#if defined(__i386__)
+
+  #define X86_REG_8L(LABEL, REG)  \
+    case LABEL: {                 \
+                                  \
+      return REG & GUM_INT8_MASK; \
+                                  \
+    }
+
+  #define X86_REG_8H(LABEL, REG)          \
+    case LABEL: {                         \
+                                          \
+      return (REG & GUM_INT16_MASK) >> 8; \
+                                          \
+    }
+
+  #define X86_REG_16(LABEL, REG)     \
+    case LABEL: {                    \
+                                     \
+      return (REG & GUM_INT16_MASK); \
+                                     \
+    }
+
+  #define X86_REG_32(LABEL, REG)     \
+    case LABEL: {                    \
+                                     \
+      return (REG & GUM_INT32_MASK); \
+                                     \
+    }
+
+gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) {
+
+  switch (reg) {
+
+    X86_REG_8L(X86_REG_AL, ctx->eax)
+    X86_REG_8L(X86_REG_BL, ctx->ebx)
+    X86_REG_8L(X86_REG_CL, ctx->ecx)
+    X86_REG_8L(X86_REG_DL, ctx->edx)
+    X86_REG_8L(X86_REG_BPL, ctx->ebp)
+    X86_REG_8L(X86_REG_SIL, ctx->esi)
+    X86_REG_8L(X86_REG_DIL, ctx->edi)
+
+    X86_REG_8H(X86_REG_AH, ctx->eax)
+    X86_REG_8H(X86_REG_BH, ctx->ebx)
+    X86_REG_8H(X86_REG_CH, ctx->ecx)
+    X86_REG_8H(X86_REG_DH, ctx->edx)
+
+    X86_REG_16(X86_REG_AX, ctx->eax)
+    X86_REG_16(X86_REG_BX, ctx->ebx)
+    X86_REG_16(X86_REG_CX, ctx->ecx)
+    X86_REG_16(X86_REG_DX, ctx->edx)
+    X86_REG_16(X86_REG_DI, ctx->edi)
+    X86_REG_16(X86_REG_SI, ctx->esi)
+    X86_REG_16(X86_REG_BP, ctx->ebp)
+
+    X86_REG_32(X86_REG_EAX, ctx->eax)
+    X86_REG_32(X86_REG_ECX, ctx->ecx)
+    X86_REG_32(X86_REG_EDX, ctx->edx)
+    X86_REG_32(X86_REG_EBX, ctx->ebx)
+    X86_REG_32(X86_REG_ESP, ctx->esp)
+    X86_REG_32(X86_REG_EBP, ctx->ebp)
+    X86_REG_32(X86_REG_ESI, ctx->esi)
+    X86_REG_32(X86_REG_EDI, ctx->edi)
+    X86_REG_32(X86_REG_EIP, ctx->eip)
+
+    default:
+      FATAL("Failed to read register: %d", reg);
+      return 0;
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c
new file mode 100644
index 00000000..e71386a0
--- /dev/null
+++ b/frida_mode/src/entry.c
@@ -0,0 +1,50 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "entry.h"
+#include "instrument.h"
+#include "stalker.h"
+#include "util.h"
+
+extern void __afl_manual_init();
+
+guint64 entry_start = 0;
+
+static void entry_launch(void) {
+
+  __afl_manual_init();
+
+  /* Child here */
+  previous_pc = 0;
+
+}
+
+void entry_init(void) {
+
+  entry_start = util_read_address("AFL_ENTRYPOINT");
+  OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_start);
+
+}
+
+void entry_run(void) {
+
+  if (entry_start == 0) { entry_launch(); }
+
+}
+
+static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
+
+  UNUSED_PARAMETER(cpu_context);
+  UNUSED_PARAMETER(user_data);
+  entry_launch();
+
+}
+
+void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(output);
+  gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
+
+}
+
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
new file mode 100644
index 00000000..cd1ac0be
--- /dev/null
+++ b/frida_mode/src/instrument/instrument.c
@@ -0,0 +1,199 @@
+#include <unistd.h>
+
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "asan.h"
+#include "entry.h"
+#include "frida_cmplog.h"
+#include "instrument.h"
+#include "persistent.h"
+#include "prefetch.h"
+#include "ranges.h"
+#include "stalker.h"
+#include "stats.h"
+#include "util.h"
+
+static gboolean               tracing = false;
+static gboolean               optimize = false;
+static GumStalkerTransformer *transformer = NULL;
+
+__thread uint64_t previous_pc = 0;
+
+__attribute__((hot)) static void on_basic_block(GumCpuContext *context,
+                                                gpointer       user_data) {
+
+  UNUSED_PARAMETER(context);
+  /*
+   * This function is performance critical as it is called to instrument every
+   * basic block. By moving our print buffer to a global, we avoid it affecting
+   * the critical path with additional stack adjustments if tracing is not
+   * enabled. If tracing is enabled, then we're printing a load of diagnostic
+   * information so this overhead is unlikely to be noticeable.
+   */
+  static char buffer[200];
+  int         len;
+  GumAddress  current_pc = GUM_ADDRESS(user_data);
+  uint8_t *   cursor;
+  uint64_t    value;
+  if (unlikely(tracing)) {
+
+    /* Avoid any functions which may cause an allocation since the target app
+     * may already be running inside malloc and it isn't designed to be
+     * re-entrant on a single thread */
+    len = snprintf(buffer, sizeof(buffer),
+                   "current_pc: 0x%016" G_GINT64_MODIFIER
+                   "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n",
+                   current_pc, previous_pc);
+
+    IGNORED_RETURN(write(STDOUT_FILENO, buffer, len + 1));
+
+  }
+
+  current_pc = (current_pc >> 4) ^ (current_pc << 8);
+  current_pc &= MAP_SIZE - 1;
+
+  cursor = &__afl_area_ptr[current_pc ^ previous_pc];
+  value = *cursor;
+
+  if (value == 0xff) {
+
+    value = 1;
+
+  } else {
+
+    value++;
+
+  }
+
+  *cursor = value;
+  previous_pc = current_pc >> 1;
+
+}
+
+static void instr_basic_block(GumStalkerIterator *iterator,
+                              GumStalkerOutput *output, gpointer user_data) {
+
+  UNUSED_PARAMETER(user_data);
+
+  const cs_insn *instr;
+  gboolean       begin = TRUE;
+  gboolean       excluded;
+
+  while (gum_stalker_iterator_next(iterator, &instr)) {
+
+    if (instr->address == entry_start) { entry_prologue(iterator, output); }
+    if (instr->address == persistent_start) { persistent_prologue(output); }
+    if (instr->address == persistent_ret) { persistent_epilogue(output); }
+
+    /*
+     * Until we reach AFL_ENTRYPOINT (assumed to be main if not specified) or
+     * AFL_FRIDA_PERSISTENT_ADDR (if specified), we don't mark our ranges
+     * excluded as we wish to remain inside stalker at all times so that we can
+     * instrument our entry point and persistent loop (if present). This allows
+     * the user to exclude ranges which would be traversed between main and the
+     * AFL_ENTRYPOINT, but which they don't want included in their coverage
+     * information when fuzzing.
+     *
+     * Since we have no means to discard the instrumented copies of blocks
+     * (setting the trust threshold simply causes a new copy to be made on each
+     * execution), we instead ensure that we honour the additional
+     * instrumentation requested (e.g. coverage, asan and complog) when a block
+     * is compiled no matter where we are during initialization. We will end up
+     * re-using these blocks if the code under test calls a block which is also
+     * used during initialization.
+     *
+     * Coverage data generated during initialization isn't a problem since the
+     * map is zeroed each time the target is forked or each time the persistent
+     * loop is run.
+     *
+     * Lastly, we don't enable pre-fetching back to the parent until we reach
+     * our AFL_ENTRYPOINT, since it is not until then that we start the
+     * fork-server and thus start executing in the child.
+     */
+    excluded = range_is_excluded(GSIZE_TO_POINTER(instr->address));
+
+    stats_collect(instr, begin);
+
+    if (unlikely(begin)) {
+
+      instrument_debug_start(instr->address, output);
+
+      prefetch_write(GSIZE_TO_POINTER(instr->address));
+
+      if (likely(!excluded)) {
+
+        if (likely(optimize)) {
+
+          instrument_coverage_optimize(instr, output);
+
+        } else {
+
+          gum_stalker_iterator_put_callout(
+              iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL);
+
+        }
+
+      }
+
+      begin = FALSE;
+
+    }
+
+    instrument_debug_instruction(instr->address, instr->size);
+
+    if (likely(!excluded)) {
+
+      asan_instrument(instr, iterator);
+      cmplog_instrument(instr, iterator);
+
+    }
+
+    gum_stalker_iterator_keep(iterator);
+
+  }
+
+  instrument_debug_end(output);
+
+}
+
+void instrument_init(void) {
+
+  optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL);
+  tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL);
+
+  if (!instrument_is_coverage_optimize_supported()) optimize = false;
+
+  OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' ');
+  OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' ');
+
+  if (tracing && optimize) {
+
+    FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible");
+
+  }
+
+  if (__afl_map_size != 0x10000) {
+
+    FATAL("Bad map size: 0x%08x", __afl_map_size);
+
+  }
+
+  transformer =
+      gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
+
+  instrument_debug_init();
+  asan_init();
+  cmplog_init();
+
+}
+
+GumStalkerTransformer *instrument_get_transformer(void) {
+
+  if (transformer == NULL) { FATAL("Instrumentation not initialized"); }
+  return transformer;
+
+}
+
diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c
new file mode 100644
index 00000000..1a3c40bb
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_arm32.c
@@ -0,0 +1,26 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "instrument.h"
+#include "util.h"
+
+#if defined(__arm__)
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+  return false;
+
+}
+
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+  FATAL("Optimized coverage not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
new file mode 100644
index 00000000..fa3afb48
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -0,0 +1,97 @@
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "instrument.h"
+
+#if defined(__aarch64__)
+
+static GumAddress current_log_impl = GUM_ADDRESS(0);
+
+static const guint8 afl_log_code[] = {
+
+    // __afl_area_ptr[current_pc ^ previous_pc]++;
+    // previous_pc = current_pc >> 1;
+    0xE1, 0x0B, 0xBF, 0xA9,  // stp x1, x2, [sp, -0x10]!
+    0xE3, 0x13, 0xBF, 0xA9,  // stp x3, x4, [sp, -0x10]!
+
+    // x0 = current_pc
+    0xe1, 0x01, 0x00, 0x58,  // ldr x1, #0x3c, =&__afl_area_ptr
+    0x21, 0x00, 0x40, 0xf9,  // ldr x1, [x1] (=__afl_area_ptr)
+
+    0xe2, 0x01, 0x00, 0x58,  // ldr x2, #0x3c, =&previous_pc
+    0x42, 0x00, 0x40, 0xf9,  // ldr x2, [x2] (=previous_pc)
+
+    // __afl_area_ptr[current_pc ^ previous_pc]++;
+    0x42, 0x00, 0x00, 0xca,  // eor x2, x2, x0
+    0x23, 0x68, 0x62, 0xf8,  // ldr x3, [x1, x2]
+    0x63, 0x04, 0x00, 0x91,  // add x3, x3, #1
+    0x63, 0x00, 0x1f, 0x9a,  // adc x3, x3, xzr
+    0x23, 0x68, 0x22, 0xf8,  // str x3, [x1, x2]
+
+    // previous_pc = current_pc >> 1;
+    0xe0, 0x07, 0x40, 0x8b,  // add x0, xzr, x0, LSR #1
+    0xe2, 0x00, 0x00, 0x58,  // ldr x2, #0x1c, =&previous_pc
+    0x40, 0x00, 0x00, 0xf9,  // str x0, [x2]
+
+    0xE3, 0x13, 0xc1, 0xA8,  // ldp x3, x4, [sp], #0x10
+    0xE1, 0x0B, 0xc1, 0xA8,  // ldp x1, x2, [sp], #0x10
+    0xC0, 0x03, 0x5F, 0xD6,  // ret
+
+    // &afl_area_ptr_ptr
+    // &afl_prev_loc_ptr
+
+};
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+  return true;
+
+}
+
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output) {
+
+  guint64 current_pc = instr->address;
+  guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
+  area_offset &= MAP_SIZE - 1;
+  GumArm64Writer *cw = output->writer.arm64;
+
+  if (current_log_impl == 0 ||
+      !gum_arm64_writer_can_branch_directly_between(cw, cw->pc,
+                                                    current_log_impl) ||
+      !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128,
+                                                    current_log_impl)) {
+
+    gconstpointer after_log_impl = cw->code + 1;
+
+    gum_arm64_writer_put_b_label(cw, after_log_impl);
+
+    current_log_impl = cw->pc;
+    gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
+
+    uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
+    uint64_t *afl_prev_loc_ptr = &previous_pc;
+    gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
+                               sizeof(afl_area_ptr_ptr));
+    gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
+                               sizeof(afl_prev_loc_ptr));
+
+    gum_arm64_writer_put_label(cw, after_log_impl);
+
+  }
+
+  gum_arm64_writer_put_stp_reg_reg_reg_offset(
+      cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE),
+      GUM_INDEX_PRE_ADJUST);
+  gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset);
+  gum_arm64_writer_put_bl_imm(cw, current_log_impl);
+  gum_arm64_writer_put_ldp_reg_reg_reg_offset(
+      cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE,
+      GUM_INDEX_POST_ADJUST);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c
new file mode 100644
index 00000000..f8c1df77
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_debug.c
@@ -0,0 +1,129 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "util.h"
+
+static int      debugging_fd = -1;
+static gpointer instrument_gen_start = NULL;
+
+static void instrument_debug(char *format, ...) {
+
+  va_list ap;
+  char    buffer[4096] = {0};
+  int     ret;
+  int     len;
+
+  va_start(ap, format);
+  ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap);
+  va_end(ap);
+
+  if (ret < 0) { return; }
+
+  len = strnlen(buffer, sizeof(buffer));
+
+  IGNORED_RETURN(write(debugging_fd, buffer, len));
+
+}
+
+static void instrument_disasm(guint8 *code, guint size) {
+
+  csh      capstone;
+  cs_err   err;
+  cs_insn *insn;
+  size_t   count, i;
+
+  err = cs_open(GUM_DEFAULT_CS_ARCH,
+                GUM_DEFAULT_CS_MODE | GUM_DEFAULT_CS_ENDIAN, &capstone);
+  g_assert(err == CS_ERR_OK);
+
+  count = cs_disasm(capstone, code, size, GPOINTER_TO_SIZE(code), 0, &insn);
+  g_assert(insn != NULL);
+
+  for (i = 0; i != count; i++) {
+
+    instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t%s %s\n", insn[i].address,
+                     insn[i].mnemonic, insn[i].op_str);
+
+  }
+
+  cs_free(insn, count);
+
+  cs_close(&capstone);
+
+}
+
+static gpointer instrument_cur(GumStalkerOutput *output) {
+
+#if defined(__i386__) || defined(__x86_64__)
+  return gum_x86_writer_cur(output->writer.x86);
+#elif defined(__aarch64__)
+  return gum_arm64_writer_cur(output->writer.arm64);
+#elif defined(__arm__)
+  return gum_arm_writer_cur(output->writer.arm);
+#else
+  #error "Unsupported architecture"
+#endif
+
+}
+
+void instrument_debug_init(void) {
+
+  char *filename = getenv("AFL_FRIDA_INST_DEBUG_FILE");
+  OKF("Instrumentation debugging - enabled [%c]", filename == NULL ? ' ' : 'X');
+
+  if (filename == NULL) { return; }
+
+  OKF("Instrumentation debugging - file [%s]", filename);
+
+  if (filename == NULL) { return; }
+
+  char *path = g_canonicalize_filename(filename, g_get_current_dir());
+
+  OKF("Instrumentation debugging - path [%s]", path);
+
+  debugging_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+
+  if (debugging_fd < 0) { FATAL("Failed to open stats file '%s'", path); }
+
+  g_free(path);
+
+}
+
+void instrument_debug_start(uint64_t address, GumStalkerOutput *output) {
+
+  if (likely(debugging_fd < 0)) { return; }
+
+  instrument_gen_start = instrument_cur(output);
+
+  instrument_debug("\n\n***\n\nCreating block for 0x%" G_GINT64_MODIFIER "x:\n",
+                   address);
+
+}
+
+void instrument_debug_instruction(uint64_t address, uint16_t size) {
+
+  if (likely(debugging_fd < 0)) { return; }
+  uint8_t *start = (uint8_t *)GSIZE_TO_POINTER(address);
+  instrument_disasm(start, size);
+
+}
+
+void instrument_debug_end(GumStalkerOutput *output) {
+
+  if (likely(debugging_fd < 0)) { return; }
+  gpointer instrument_gen_end = instrument_cur(output);
+  uint16_t size = GPOINTER_TO_SIZE(instrument_gen_end) -
+                  GPOINTER_TO_SIZE(instrument_gen_start);
+
+  instrument_debug("\nGenerated block %p\n", instrument_gen_start);
+  instrument_disasm(instrument_gen_start, size);
+
+}
+
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
new file mode 100644
index 00000000..901f3bd0
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -0,0 +1,93 @@
+#include "frida-gum.h"
+
+#include "config.h"
+
+#include "instrument.h"
+
+#if defined(__x86_64__)
+
+static GumAddress current_log_impl = GUM_ADDRESS(0);
+
+static const guint8 afl_log_code[] = {
+
+    // 0xcc,
+
+    0x9c,                                                         /* pushfq */
+    0x51,                                                       /* push rcx */
+    0x52,                                                       /* push rdx */
+
+    0x48, 0x8b, 0x0d, 0x28,
+    0x00, 0x00, 0x00,                          /* mov rcx, sym.&previous_pc */
+    0x48, 0x8b, 0x11,                               /* mov rdx, qword [rcx] */
+    0x48, 0x31, 0xfa,                                       /* xor rdx, rdi */
+
+    0x48, 0x03, 0x15, 0x13,
+    0x00, 0x00, 0x00,                     /* add rdx, sym._afl_area_ptr_ptr */
+
+    0x80, 0x02, 0x01,                              /* add byte ptr [rdx], 1 */
+    0x80, 0x12, 0x00,                              /* adc byte ptr [rdx], 0 */
+    0x48, 0xd1, 0xef,                                         /* shr rdi, 1 */
+    0x48, 0x89, 0x39,                               /* mov qword [rcx], rdi */
+
+    0x5a,                                                        /* pop rdx */
+    0x59,                                                        /* pop rcx */
+    0x9d,                                                          /* popfq */
+
+    0xc3,                                                            /* ret */
+    0x90, 0x90, 0x90                                             /* nop pad */
+
+    /* Read-only data goes here: */
+    /* uint8_t* __afl_area_ptr */
+    /* uint64_t* &previous_pc */
+
+};
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+  return true;
+
+}
+
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output) {
+
+  guint64 current_pc = instr->address;
+  guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
+  area_offset &= MAP_SIZE - 1;
+  GumX86Writer *cw = output->writer.x86;
+
+  if (current_log_impl == 0 ||
+      !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) ||
+      !gum_x86_writer_can_branch_directly_between(cw->pc + 128,
+                                                  current_log_impl)) {
+
+    gconstpointer after_log_impl = cw->code + 1;
+
+    gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
+
+    current_log_impl = cw->pc;
+    gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
+
+    uint64_t *afl_prev_loc_ptr = &previous_pc;
+    gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr,
+                             sizeof(__afl_area_ptr));
+    gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
+                             sizeof(afl_prev_loc_ptr));
+
+    gum_x86_writer_put_label(cw, after_log_impl);
+
+  }
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        -GUM_RED_ZONE_SIZE);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset);
+  gum_x86_writer_put_call_address(cw, current_log_impl);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        GUM_RED_ZONE_SIZE);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
new file mode 100644
index 00000000..585bb5b8
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -0,0 +1,85 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "instrument.h"
+#include "util.h"
+
+#if defined(__i386__)
+
+static GumAddress current_log_impl = GUM_ADDRESS(0);
+
+static void instrument_coverage_function(GumX86Writer *cw) {
+
+  gum_x86_writer_put_pushfx(cw);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_ECX);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EDX);
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
+                                     GUM_ADDRESS(&previous_pc));
+  gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_EDX, GUM_REG_ECX);
+  gum_x86_writer_put_xor_reg_reg(cw, GUM_REG_EDX, GUM_REG_EDI);
+
+  gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EDX, GUM_ADDRESS(__afl_area_ptr));
+
+  /* add byte ptr [edx], 1 */
+  uint8_t add_byte_ptr_edx_1[] = {0x80, 0x02, 0x01};
+  gum_x86_writer_put_bytes(cw, add_byte_ptr_edx_1, sizeof(add_byte_ptr_edx_1));
+
+  /* adc byte ptr [edx], 0 */
+  uint8_t adc_byte_ptr_edx_0[] = {0x80, 0x12, 0x00};
+  gum_x86_writer_put_bytes(cw, adc_byte_ptr_edx_0, sizeof(adc_byte_ptr_edx_0));
+
+  gum_x86_writer_put_shr_reg_u8(cw, GUM_REG_EDI, 1);
+  gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_ECX, GUM_REG_EDI);
+
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_EDX);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_ECX);
+  gum_x86_writer_put_popfx(cw);
+  gum_x86_writer_put_ret(cw);
+
+}
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+  return true;
+
+}
+
+void instrument_coverage_optimize(const cs_insn *   instr,
+                                  GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(output);
+
+  guint64 current_pc = instr->address;
+  guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
+  area_offset &= MAP_SIZE - 1;
+  GumX86Writer *cw = output->writer.x86;
+
+  if (current_log_impl == 0 ||
+      !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) ||
+      !gum_x86_writer_can_branch_directly_between(cw->pc + 128,
+                                                  current_log_impl)) {
+
+    gconstpointer after_log_impl = cw->code + 1;
+
+    gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
+
+    current_log_impl = cw->pc;
+    instrument_coverage_function(cw);
+
+    gum_x86_writer_put_label(cw, after_log_impl);
+
+  }
+
+  // gum_x86_writer_put_breakpoint(cw);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EDI);
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDI, area_offset);
+  gum_x86_writer_put_call_address(cw, current_log_impl);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_EDI);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c
new file mode 100644
index 00000000..d2802752
--- /dev/null
+++ b/frida_mode/src/interceptor.c
@@ -0,0 +1,35 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "interceptor.h"
+
+void intercept(void *address, gpointer replacement, gpointer user_data) {
+
+  GumInterceptor *interceptor = gum_interceptor_obtain();
+  gum_interceptor_begin_transaction(interceptor);
+  GumReplaceReturn ret =
+      gum_interceptor_replace(interceptor, address, replacement, user_data);
+  if (ret != GUM_REPLACE_OK) { FATAL("gum_interceptor_attach: %d", ret); }
+  gum_interceptor_end_transaction(interceptor);
+
+}
+
+void unintercept(void *address) {
+
+  GumInterceptor *interceptor = gum_interceptor_obtain();
+
+  gum_interceptor_begin_transaction(interceptor);
+  gum_interceptor_revert(interceptor, address);
+  gum_interceptor_end_transaction(interceptor);
+  gum_interceptor_flush(interceptor);
+
+}
+
+void unintercept_self(void) {
+
+  GumInvocationContext *ctx = gum_interceptor_get_current_invocation();
+  unintercept(ctx->function);
+
+}
+
diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c
new file mode 100644
index 00000000..13a7d1e7
--- /dev/null
+++ b/frida_mode/src/lib/lib.c
@@ -0,0 +1,179 @@
+#ifndef __APPLE__
+  #include <elf.h>
+  #include <fcntl.h>
+  #include <limits.h>
+  #include <stdio.h>
+  #include <sys/mman.h>
+  #include <unistd.h>
+
+  #include "frida-gum.h"
+
+  #include "debug.h"
+
+  #include "lib.h"
+
+  #if defined(__arm__) || defined(__i386__)
+    #define ELFCLASS ELFCLASS32
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Addr Elf_Addr;
+  #elif defined(__aarch64__) || defined(__x86_64__)
+    #define ELFCLASS ELFCLASS64
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Addr Elf_Addr;
+  #else
+    #error "Unsupported platform"
+  #endif
+
+typedef struct {
+
+  gchar      name[PATH_MAX + 1];
+  gchar      path[PATH_MAX + 1];
+  GumAddress base_address;
+  gsize      size;
+
+} lib_details_t;
+
+static guint64 text_base = 0;
+static guint64 text_limit = 0;
+
+static gboolean lib_find_exe(const GumModuleDetails *details,
+                             gpointer                user_data) {
+
+  lib_details_t *lib_details = (lib_details_t *)user_data;
+
+  memcpy(lib_details->name, details->name, PATH_MAX);
+  memcpy(lib_details->path, details->path, PATH_MAX);
+  lib_details->base_address = details->range->base_address;
+  lib_details->size = details->range->size;
+  return FALSE;
+
+}
+
+static void lib_validate_hdr(Elf_Ehdr *hdr) {
+
+  if (hdr->e_ident[0] != ELFMAG0) FATAL("Invalid e_ident[0]");
+  if (hdr->e_ident[1] != ELFMAG1) FATAL("Invalid e_ident[1]");
+  if (hdr->e_ident[2] != ELFMAG2) FATAL("Invalid e_ident[2]");
+  if (hdr->e_ident[3] != ELFMAG3) FATAL("Invalid e_ident[3]");
+  if (hdr->e_ident[4] != ELFCLASS) FATAL("Invalid class");
+
+}
+
+static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) {
+
+  Elf_Phdr *phdr;
+  gboolean  found_preferred_base = FALSE;
+  Elf_Addr  preferred_base;
+  Elf_Shdr *shdr;
+  Elf_Shdr *shstrtab;
+  char *    shstr;
+  char *    section_name;
+  Elf_Shdr *curr;
+  char      text_name[] = ".text";
+
+  phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff);
+  for (size_t i = 0; i < hdr->e_phnum; i++) {
+
+    if (phdr[i].p_type == PT_LOAD) {
+
+      preferred_base = phdr[i].p_vaddr;
+      found_preferred_base = TRUE;
+      break;
+
+    }
+
+  }
+
+  if (!found_preferred_base) { FATAL("Failed to find preferred load address"); }
+
+  OKF("Image preferred load address 0x%016" G_GSIZE_MODIFIER "x",
+      preferred_base);
+
+  shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff);
+  shstrtab = &shdr[hdr->e_shstrndx];
+  shstr = (char *)hdr + shstrtab->sh_offset;
+
+  OKF("shdr: %p", shdr);
+  OKF("shstrtab: %p", shstrtab);
+  OKF("shstr: %p", shstr);
+
+  for (size_t i = 0; i < hdr->e_shnum; i++) {
+
+    curr = &shdr[i];
+
+    if (curr->sh_name == 0) continue;
+
+    section_name = &shstr[curr->sh_name];
+    OKF("Section: %2" G_GSIZE_MODIFIER "u - base: 0x%016" G_GSIZE_MODIFIER
+        "X size: 0x%016" G_GSIZE_MODIFIER "X %s",
+        i, curr->sh_addr, curr->sh_size, section_name);
+    if (memcmp(section_name, text_name, sizeof(text_name)) == 0 &&
+        text_base == 0) {
+
+      text_base = lib_details->base_address + curr->sh_addr - preferred_base;
+      text_limit = text_base + curr->sh_size;
+      OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base);
+      OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit);
+
+    }
+
+  }
+
+}
+
+static void lib_get_text_section(lib_details_t *details) {
+
+  int       fd = -1;
+  off_t     len;
+  Elf_Ehdr *hdr;
+
+  fd = open(details->path, O_RDONLY);
+  if (fd < 0) { FATAL("Failed to open %s", details->path); }
+
+  len = lseek(fd, 0, SEEK_END);
+
+  if (len == (off_t)-1) { FATAL("Failed to lseek %s", details->path); }
+
+  OKF("len: %ld", len);
+
+  hdr = (Elf_Ehdr *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (hdr == MAP_FAILED) { FATAL("Failed to map %s", details->path); }
+
+  lib_validate_hdr(hdr);
+  lib_read_text_section(details, hdr);
+
+  munmap(hdr, len);
+  close(fd);
+
+}
+
+void lib_init(void) {
+
+  lib_details_t lib_details;
+  gum_process_enumerate_modules(lib_find_exe, &lib_details);
+  OKF("Executable: 0x%016" G_GINT64_MODIFIER "x - %s", lib_details.base_address,
+      lib_details.path);
+  lib_get_text_section(&lib_details);
+
+}
+
+guint64 lib_get_text_base(void) {
+
+  if (text_base == 0) FATAL("Lib not initialized");
+  return text_base;
+
+}
+
+guint64 lib_get_text_limit(void) {
+
+  if (text_limit == 0) FATAL("Lib not initialized");
+  return text_limit;
+
+}
+
+#endif
+
diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c
new file mode 100644
index 00000000..8f863861
--- /dev/null
+++ b/frida_mode/src/lib/lib_apple.c
@@ -0,0 +1,82 @@
+#ifdef __APPLE__
+  #include "frida-gum.h"
+
+  #include "debug.h"
+
+  #include "lib.h"
+  #include "util.h"
+
+extern mach_port_t mach_task_self();
+extern void        gum_darwin_enumerate_modules(mach_port_t        task,
+                                                GumFoundModuleFunc func,
+                                                gpointer           user_data);
+
+static guint64 text_base = 0;
+static guint64 text_limit = 0;
+
+static gboolean lib_get_main_module(const GumModuleDetails *details,
+                                    gpointer                user_data) {
+
+  GumDarwinModule **ret = (GumDarwinModule **)user_data;
+  GumDarwinModule * module = gum_darwin_module_new_from_memory(
+      details->path, mach_task_self(), details->range->base_address,
+      GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
+
+  OKF("Found main module: %s", module->name);
+
+  *ret = module;
+
+  return FALSE;
+
+}
+
+gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
+                              gpointer                       user_data) {
+
+  UNUSED_PARAMETER(user_data);
+  static size_t idx = 0;
+  char          text_name[] = "__text";
+
+  OKF("Section: %2lu - base: 0x%016" G_GINT64_MODIFIER
+      "X size: 0x%016" G_GINT64_MODIFIER "X %s",
+      idx++, details->vm_address, details->vm_address + details->size,
+      details->section_name);
+
+  if (memcmp(details->section_name, text_name, sizeof(text_name)) == 0 &&
+      text_base == 0) {
+
+    text_base = details->vm_address;
+    text_limit = details->vm_address + details->size;
+    OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base);
+    OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit);
+
+  }
+
+  return TRUE;
+
+}
+
+void lib_init(void) {
+
+  GumDarwinModule *module = NULL;
+  gum_darwin_enumerate_modules(mach_task_self(), lib_get_main_module, &module);
+  gum_darwin_module_enumerate_sections(module, lib_get_text_section, NULL);
+
+}
+
+guint64 lib_get_text_base(void) {
+
+  if (text_base == 0) FATAL("Lib not initialized");
+  return text_base;
+
+}
+
+guint64 lib_get_text_limit(void) {
+
+  if (text_limit == 0) FATAL("Lib not initialized");
+  return text_limit;
+
+}
+
+#endif
+
diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c
new file mode 100644
index 00000000..1ab9993f
--- /dev/null
+++ b/frida_mode/src/main.c
@@ -0,0 +1,179 @@
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef __APPLE__
+  #include <mach/mach.h>
+  #include <mach-o/dyld_images.h>
+#else
+  #include <sys/wait.h>
+  #include <sys/personality.h>
+#endif
+
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "entry.h"
+#include "instrument.h"
+#include "interceptor.h"
+#include "lib.h"
+#include "output.h"
+#include "persistent.h"
+#include "prefetch.h"
+#include "ranges.h"
+#include "stalker.h"
+#include "stats.h"
+#include "util.h"
+
+#ifdef __APPLE__
+extern mach_port_t mach_task_self();
+extern GumAddress  gum_darwin_find_entrypoint(mach_port_t task);
+#else
+extern int  __libc_start_main(int *(main)(int, char **, char **), int argc,
+                              char **ubp_av, void (*init)(void),
+                              void (*fini)(void), void (*rtld_fini)(void),
+                              void(*stack_end));
+#endif
+
+typedef int *(*main_fn_t)(int argc, char **argv, char **envp);
+
+static main_fn_t main_fn = NULL;
+
+static int on_fork(void) {
+
+  prefetch_read();
+  return fork();
+
+}
+
+#ifdef __APPLE__
+static void on_main_os(int argc, char **argv, char **envp) {
+
+  UNUSED_PARAMETER(argc);
+  UNUSED_PARAMETER(argv);
+  UNUSED_PARAMETER(envp);
+
+}
+
+#else
+static void on_main_os(int argc, char **argv, char **envp) {
+
+  UNUSED_PARAMETER(argc);
+  /* Personality doesn't affect the current process, it only takes effect on
+   * evec */
+  int persona = personality(ADDR_NO_RANDOMIZE);
+  if (persona == -1) { WARNF("Failed to set ADDR_NO_RANDOMIZE: %d", errno); }
+  if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); }
+
+  GumInterceptor *interceptor = gum_interceptor_obtain();
+
+  gum_interceptor_begin_transaction(interceptor);
+  gum_interceptor_revert(interceptor, __libc_start_main);
+  gum_interceptor_end_transaction(interceptor);
+  gum_interceptor_flush(interceptor);
+
+}
+
+#endif
+
+static void embedded_init() {
+
+  static gboolean initialized = false;
+  if (!initialized) {
+
+    gum_init_embedded();
+    initialized = true;
+
+  }
+
+}
+
+void afl_frida_start() {
+
+  embedded_init();
+  stalker_init();
+  lib_init();
+  entry_init();
+  instrument_init();
+  output_init();
+  persistent_init();
+  prefetch_init();
+  ranges_init();
+  stats_init();
+
+  void *fork_addr =
+      GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
+  intercept(fork_addr, on_fork, NULL);
+
+  stalker_start();
+  entry_run();
+
+}
+
+static int *on_main(int argc, char **argv, char **envp) {
+
+  on_main_os(argc, argv, envp);
+
+  unintercept_self();
+
+  afl_frida_start();
+
+  return main_fn(argc, argv, envp);
+
+}
+
+#if defined(EMBEDDED)
+extern int *main(int argc, char **argv, char **envp);
+
+static void intercept_main(void) {
+
+  main_fn = main;
+  intercept(main, on_main, NULL);
+
+}
+
+#elif defined(__APPLE__)
+static void intercept_main(void) {
+
+  mach_port_t task = mach_task_self();
+  OKF("Task Id: %u", task);
+  GumAddress entry = gum_darwin_find_entrypoint(task);
+  OKF("Entry Point: 0x%016" G_GINT64_MODIFIER "x", entry);
+  void *main = GSIZE_TO_POINTER(entry);
+  main_fn = main;
+  intercept(main, on_main, NULL);
+
+}
+
+#else
+static int on_libc_start_main(int *(main)(int, char **, char **), int argc,
+                              char **ubp_av, void (*init)(void),
+                              void (*fini)(void), void (*rtld_fini)(void),
+                              void(*stack_end)) {
+
+  main_fn = main;
+  unintercept_self();
+  intercept(main, on_main, NULL);
+  return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini,
+                           stack_end);
+
+}
+
+static void intercept_main(void) {
+
+  intercept(__libc_start_main, on_libc_start_main, NULL);
+
+}
+
+#endif
+
+__attribute__((constructor)) static void init(void) {
+
+  embedded_init();
+
+  intercept_main();
+
+}
+
diff --git a/frida_mode/src/output.c b/frida_mode/src/output.c
new file mode 100644
index 00000000..8a222b25
--- /dev/null
+++ b/frida_mode/src/output.c
@@ -0,0 +1,45 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "output.h"
+
+static int output_fd = -1;
+
+static void output_redirect(int fd, char *variable) {
+
+  char *filename = getenv(variable);
+  char *path = NULL;
+
+  if (filename == NULL) { return; }
+
+  path = g_canonicalize_filename(filename, g_get_current_dir());
+
+  OKF("Redirect %d -> '%s'", fd, path);
+
+  output_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+
+  g_free(path);
+
+  if (output_fd < 0) { FATAL("Failed to open fd(%d) error %d", fd, errno); }
+
+  if (dup2(output_fd, fd) < 0) {
+
+    FATAL("Failed to set fd(%d) error %d", fd, errno);
+
+  }
+
+}
+
+void output_init(void) {
+
+  output_redirect(STDOUT_FILENO, "AFL_FRIDA_OUTPUT_STDOUT");
+  output_redirect(STDERR_FILENO, "AFL_FRIDA_OUTPUT_STDERR");
+
+}
+
diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c
new file mode 100644
index 00000000..2ec5b9cc
--- /dev/null
+++ b/frida_mode/src/persistent/persistent.c
@@ -0,0 +1,97 @@
+#include <dlfcn.h>
+
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "persistent.h"
+#include "util.h"
+
+int                    __afl_sharedmem_fuzzing = 0;
+afl_persistent_hook_fn hook = NULL;
+guint64                persistent_start = 0;
+guint64                persistent_count = 0;
+guint64                persistent_ret = 0;
+guint64                persistent_ret_offset = 0;
+gboolean               persistent_debug = FALSE;
+
+void persistent_init(void) {
+
+  char *hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK");
+
+  persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR");
+  persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT");
+  persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET");
+  persistent_ret_offset =
+      util_read_address("AFL_FRIDA_PERSISTENT_RETADDR_OFFSET");
+
+  if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; }
+
+  if (persistent_count != 0 && persistent_start == 0) {
+
+    FATAL(
+        "AFL_FRIDA_PERSISTENT_ADDR must be specified if "
+        "AFL_FRIDA_PERSISTENT_CNT is");
+
+  }
+
+  if (persistent_ret != 0 && persistent_start == 0) {
+
+    FATAL(
+        "AFL_FRIDA_PERSISTENT_ADDR must be specified if "
+        "AFL_FRIDA_PERSISTENT_RET is");
+
+  }
+
+  if (persistent_ret_offset != 0 && persistent_ret == 0) {
+
+    FATAL(
+        "AFL_FRIDA_PERSISTENT_RET must be specified if "
+        "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET is");
+
+  }
+
+  if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000;
+
+  if (persistent_count != 0 && persistent_count < 100)
+    WARNF("Persistent count out of recommended range (<100)");
+
+  if (persistent_start != 0 && !persistent_is_supported())
+    FATAL("Persistent mode not supported on this architecture");
+
+  OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)",
+      persistent_start == 0 ? ' ' : 'X', persistent_start);
+  OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)",
+      persistent_start == 0 ? ' ' : 'X', persistent_count);
+  OKF("Instrumentation - hook [%s]", hook_name);
+
+  OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)",
+      persistent_ret == 0 ? ' ' : 'X', persistent_ret);
+  OKF("Instrumentation - persistent ret offset [%c] (%" G_GINT64_MODIFIER "d)",
+      persistent_ret_offset == 0 ? ' ' : 'X', persistent_ret_offset);
+
+  if (hook_name != NULL) {
+
+    void *hook_obj = dlopen(hook_name, RTLD_NOW);
+    if (hook_obj == NULL)
+      FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name);
+
+    int (*afl_persistent_hook_init_ptr)(void) =
+        dlsym(hook_obj, "afl_persistent_hook_init");
+    if (afl_persistent_hook_init_ptr == NULL)
+      FATAL("Failed to find afl_persistent_hook_init in %s", hook_name);
+
+    if (afl_persistent_hook_init_ptr() == 0)
+      FATAL("afl_persistent_hook_init returned a failure");
+
+    hook = (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook");
+    if (hook == NULL)
+      FATAL("Failed to find afl_persistent_hook in %s", hook_name);
+
+    __afl_sharedmem_fuzzing = 1;
+
+  }
+
+}
+
diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c
new file mode 100644
index 00000000..6a3c06fa
--- /dev/null
+++ b/frida_mode/src/persistent/persistent_arm32.c
@@ -0,0 +1,79 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "persistent.h"
+#include "util.h"
+
+#if defined(__arm__)
+
+struct arm_regs {
+
+  uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
+
+  union {
+
+    uint32_t r11;
+    uint32_t fp;
+
+  };
+
+  union {
+
+    uint32_t r12;
+    uint32_t ip;
+
+  };
+
+  union {
+
+    uint32_t r13;
+    uint32_t sp;
+
+  };
+
+  union {
+
+    uint32_t r14;
+    uint32_t lr;
+
+  };
+
+  union {
+
+    uint32_t r15;
+    uint32_t pc;
+
+  };
+
+  uint32_t cpsr;
+
+  uint8_t  vfp_zregs[32][16];
+  uint32_t vfp_xregs[16];
+
+};
+
+typedef struct arm_regs arch_api_regs;
+
+gboolean persistent_is_supported(void) {
+
+  return false;
+
+}
+
+void persistent_prologue(GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(output);
+  FATAL("Persistent mode not supported on this architecture");
+
+}
+
+void persistent_epilogue(GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(output);
+  FATAL("Persistent mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c
new file mode 100644
index 00000000..1215d8da
--- /dev/null
+++ b/frida_mode/src/persistent/persistent_arm64.c
@@ -0,0 +1,122 @@
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "instrument.h"
+#include "util.h"
+
+#if defined(__aarch64__)
+
+struct arm64_regs {
+
+  uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10;
+
+  union {
+
+    uint64_t x11;
+    uint32_t fp_32;
+
+  };
+
+  union {
+
+    uint64_t x12;
+    uint32_t ip_32;
+
+  };
+
+  union {
+
+    uint64_t x13;
+    uint32_t sp_32;
+
+  };
+
+  union {
+
+    uint64_t x14;
+    uint32_t lr_32;
+
+  };
+
+  union {
+
+    uint64_t x15;
+    uint32_t pc_32;
+
+  };
+
+  union {
+
+    uint64_t x16;
+    uint64_t ip0;
+
+  };
+
+  union {
+
+    uint64_t x17;
+    uint64_t ip1;
+
+  };
+
+  uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
+
+  union {
+
+    uint64_t x29;
+    uint64_t fp;
+
+  };
+
+  union {
+
+    uint64_t x30;
+    uint64_t lr;
+
+  };
+
+  union {
+
+    uint64_t x31;
+    uint64_t sp;
+
+  };
+
+  // the zero register is not saved here ofc
+
+  uint64_t pc;
+
+  uint32_t cpsr;
+
+  uint8_t  vfp_zregs[32][16 * 16];
+  uint8_t  vfp_pregs[17][32];
+  uint32_t vfp_xregs[16];
+
+};
+
+typedef struct arm64_regs arch_api_regs;
+
+gboolean persistent_is_supported(void) {
+
+  return false;
+
+}
+
+void persistent_prologue(GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(output);
+  FATAL("Persistent mode not supported on this architecture");
+
+}
+
+void persistent_epilogue(GumStalkerOutput *output) {
+
+  UNUSED_PARAMETER(output);
+  FATAL("Persistent mode not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c
new file mode 100644
index 00000000..4cb960fc
--- /dev/null
+++ b/frida_mode/src/persistent/persistent_x64.c
@@ -0,0 +1,326 @@
+#include <unistd.h>
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "instrument.h"
+#include "persistent.h"
+#include "util.h"
+
+#if defined(__x86_64__)
+
+struct x86_64_regs {
+
+  uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
+      r15;
+
+  union {
+
+    uint64_t rip;
+    uint64_t pc;
+
+  };
+
+  union {
+
+    uint64_t rsp;
+    uint64_t sp;
+
+  };
+
+  union {
+
+    uint64_t rflags;
+    uint64_t flags;
+
+  };
+
+  uint8_t zmm_regs[32][64];
+
+};
+
+typedef struct x86_64_regs arch_api_regs;
+
+static arch_api_regs saved_regs = {0};
+
+gboolean persistent_is_supported(void) {
+
+  return true;
+
+}
+
+static void instrument_persitent_save_regs(GumX86Writer *      cw,
+                                           struct x86_64_regs *regs) {
+
+  GumAddress regs_address = GUM_ADDRESS(regs);
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        -(GUM_RED_ZONE_SIZE));
+
+  /* Should be pushing FPU here, but meh */
+  gum_x86_writer_put_pushfx(cw);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_RAX);
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
+
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1),
+                                            GUM_REG_RBX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2),
+                                            GUM_REG_RCX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3),
+                                            GUM_REG_RDX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4),
+                                            GUM_REG_RDI);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5),
+                                            GUM_REG_RSI);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6),
+                                            GUM_REG_RBP);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7),
+                                            GUM_REG_R8);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8),
+                                            GUM_REG_R9);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9),
+                                            GUM_REG_R10);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10),
+                                            GUM_REG_R11);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11),
+                                            GUM_REG_R12);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12),
+                                            GUM_REG_R13);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13),
+                                            GUM_REG_R14);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14),
+                                            GUM_REG_R15);
+
+  /* Store RIP */
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX,
+                                     GUM_ADDRESS(persistent_start));
+
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15),
+                                            GUM_REG_RBX);
+
+  /* Store adjusted RSP */
+  gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP);
+
+  /* RED_ZONE + Saved flags, RAX, alignment */
+  gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX,
+                                 GUM_RED_ZONE_SIZE + (0x8 * 3));
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16),
+                                            GUM_REG_RBX);
+
+  /* Save the flags */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17),
+                                            GUM_REG_RBX);
+
+  /* Save the RAX */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0),
+                                            GUM_REG_RBX);
+
+  /* Pop the saved values */
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10);
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        (GUM_RED_ZONE_SIZE));
+
+}
+
+static void instrument_persitent_restore_regs(GumX86Writer *      cw,
+                                              struct x86_64_regs *regs) {
+
+  GumAddress regs_address = GUM_ADDRESS(regs);
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX,
+                                            (0x8 * 2));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX,
+                                            (0x8 * 3));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX,
+                                            (0x8 * 4));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX,
+                                            (0x8 * 5));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX,
+                                            (0x8 * 6));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX,
+                                            (0x8 * 7));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX,
+                                            (0x8 * 8));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX,
+                                            (0x8 * 9));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX,
+                                            (0x8 * 10));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX,
+                                            (0x8 * 11));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX,
+                                            (0x8 * 12));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX,
+                                            (0x8 * 13));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX,
+                                            (0x8 * 14));
+
+  /* Don't restore RIP or RSP */
+
+  /* Restore RBX, RAX & Flags */
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        -(GUM_RED_ZONE_SIZE));
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
+                                            (0x8 * 1));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
+                                            (0x8 * 0));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
+                                            (0x8 * 17));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
+
+  gum_x86_writer_put_popfx(cw);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX);
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        (GUM_RED_ZONE_SIZE));
+
+}
+
+static void instrument_exit(GumX86Writer *cw) {
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(_exit));
+  gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_RDI, 0);
+  gum_x86_writer_put_call_reg(cw, GUM_REG_RAX);
+
+}
+
+static int instrument_afl_persistent_loop_func(void) {
+
+  int ret = __afl_persistent_loop(persistent_count);
+  previous_pc = 0;
+  return ret;
+
+}
+
+static void instrument_afl_persistent_loop(GumX86Writer *cw) {
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        -(GUM_RED_ZONE_SIZE));
+  gum_x86_writer_put_call_address_with_arguments(
+      cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
+  gum_x86_writer_put_test_reg_reg(cw, GUM_REG_RAX, GUM_REG_RAX);
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        (GUM_RED_ZONE_SIZE));
+
+}
+
+static void persistent_prologue_hook(GumX86Writer *      cw,
+                                     struct x86_64_regs *regs) {
+
+  if (hook == NULL) return;
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        -(GUM_RED_ZONE_SIZE));
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX,
+                                     GUM_ADDRESS(&__afl_fuzz_len));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0);
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0);
+  gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff);
+  gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI);
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX,
+                                     GUM_ADDRESS(&__afl_fuzz_ptr));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
+
+  gum_x86_writer_put_call_address_with_arguments(
+      cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS,
+      GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER,
+      GUM_REG_RDX, GUM_ARG_REGISTER, GUM_REG_RCX);
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        (GUM_RED_ZONE_SIZE));
+
+}
+
+void persistent_prologue(GumStalkerOutput *output) {
+
+  /*
+   *  SAVE REGS
+   *  SAVE RET
+   *  POP RET
+   * loop:
+   *  CALL instrument_afl_persistent_loop
+   *  TEST EAX, EAX
+   *  JZ end:
+   *  call hook (optionally)
+   *  RESTORE REGS
+   *  call original
+   *  jmp loop:
+   *
+   * end:
+   *  JMP SAVED RET
+   *
+   * original:
+   *  INSTRUMENTED PERSISTENT FUNC
+   */
+
+  GumX86Writer *cw = output->writer.x86;
+
+  gconstpointer loop = cw->code + 1;
+
+  /* Stack must be 16-byte aligned per ABI */
+  instrument_persitent_save_regs(cw, &saved_regs);
+
+  /* pop the return value */
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8));
+
+  /* loop: */
+  gum_x86_writer_put_label(cw, loop);
+
+  /* call instrument_prologue_func */
+  instrument_afl_persistent_loop(cw);
+
+  /* jz done */
+  gconstpointer done = cw->code + 1;
+  gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY);
+
+  /* Optionally call the persistent hook */
+  persistent_prologue_hook(cw, &saved_regs);
+
+  instrument_persitent_restore_regs(cw, &saved_regs);
+  gconstpointer original = cw->code + 1;
+  /* call original */
+
+  gum_x86_writer_put_call_near_label(cw, original);
+
+  /* jmp loop */
+  gum_x86_writer_put_jmp_near_label(cw, loop);
+
+  /* done: */
+  gum_x86_writer_put_label(cw, done);
+
+  instrument_exit(cw);
+
+  /* original: */
+  gum_x86_writer_put_label(cw, original);
+
+  if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
+
+  gum_x86_writer_flush(cw);
+
+}
+
+void persistent_epilogue(GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+
+  if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                        persistent_ret_offset);
+  gum_x86_writer_put_ret(cw);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c
new file mode 100644
index 00000000..b30dfadf
--- /dev/null
+++ b/frida_mode/src/persistent/persistent_x86.c
@@ -0,0 +1,267 @@
+#include "frida-gum.h"
+
+#include "config.h"
+
+#include "instrument.h"
+#include "persistent.h"
+
+#if defined(__i386__)
+
+struct x86_regs {
+
+  uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
+
+  union {
+
+    uint32_t eip;
+    uint32_t pc;
+
+  };
+
+  union {
+
+    uint32_t esp;
+    uint32_t sp;
+
+  };
+
+  union {
+
+    uint32_t eflags;
+    uint32_t flags;
+
+  };
+
+  uint8_t xmm_regs[8][16];
+
+};
+
+typedef struct x86_regs arch_api_regs;
+
+static arch_api_regs saved_regs = {0};
+
+gboolean persistent_is_supported(void) {
+
+  return true;
+
+}
+
+static void instrument_persitent_save_regs(GumX86Writer *   cw,
+                                           struct x86_regs *regs) {
+
+  GumAddress regs_address = GUM_ADDRESS(regs);
+
+  /* Should be pushing FPU here, but meh */
+  gum_x86_writer_put_pushfx(cw);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
+
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1),
+                                            GUM_REG_EBX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2),
+                                            GUM_REG_ECX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3),
+                                            GUM_REG_EDX);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4),
+                                            GUM_REG_EDI);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5),
+                                            GUM_REG_ESI);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6),
+                                            GUM_REG_EBP);
+
+  /* Store RIP */
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX,
+                                     GUM_ADDRESS(persistent_start));
+
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7),
+                                            GUM_REG_EBX);
+
+  /* Store adjusted RSP */
+  gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP);
+
+  /* RED_ZONE + Saved flags, RAX */
+  gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2));
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8),
+                                            GUM_REG_EBX);
+
+  /* Save the flags */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9),
+                                            GUM_REG_EBX);
+
+  /* Save the RAX */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0);
+  gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0),
+                                            GUM_REG_EBX);
+
+  /* Pop the saved values */
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8);
+
+}
+
+static void instrument_persitent_restore_regs(GumX86Writer *   cw,
+                                              struct x86_regs *regs) {
+
+  GumAddress regs_address = GUM_ADDRESS(regs);
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX,
+                                            (0x4 * 2));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX,
+                                            (0x4 * 3));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX,
+                                            (0x4 * 4));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX,
+                                            (0x4 * 5));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
+                                            (0x4 * 6));
+
+  /* Don't restore RIP or RSP */
+
+  /* Restore RBX, RAX & Flags */
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
+                                            (0x4 * 1));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
+
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
+                                            (0x4 * 0));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
+                                            (0x4 * 9));
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
+
+  gum_x86_writer_put_popfx(cw);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
+  gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
+
+}
+
+static void instrument_exit(GumX86Writer *cw) {
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(_exit));
+  gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_EDI, 0);
+  gum_x86_writer_put_push_reg(cw, GUM_REG_EDI);
+  gum_x86_writer_put_call_reg(cw, GUM_REG_EAX);
+
+}
+
+static int instrument_afl_persistent_loop_func(void) {
+
+  int ret = __afl_persistent_loop(persistent_count);
+  previous_pc = 0;
+  return ret;
+
+}
+
+static void instrument_afl_persistent_loop(GumX86Writer *cw) {
+
+  gum_x86_writer_put_call_address_with_arguments(
+      cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
+  gum_x86_writer_put_test_reg_reg(cw, GUM_REG_EAX, GUM_REG_EAX);
+
+}
+
+static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) {
+
+  if (hook == NULL) return;
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
+                                     GUM_ADDRESS(&__afl_fuzz_len));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
+
+  gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDX,
+                                     GUM_ADDRESS(&__afl_fuzz_ptr));
+  gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EDX, 0);
+
+  /* Base address is 64-bits (hence two zero arguments) */
+  gum_x86_writer_put_call_address_with_arguments(
+      cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 5, GUM_ARG_ADDRESS,
+      GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS,
+      GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
+      GUM_REG_ECX);
+
+}
+
+void persistent_prologue(GumStalkerOutput *output) {
+
+  /*
+   *  SAVE REGS
+   *  SAVE RET
+   *  POP RET
+   * loop:
+   *  CALL instrument_afl_persistent_loop
+   *  TEST EAX, EAX
+   *  JZ end:
+   *  call hook (optionally)
+   *  RESTORE REGS
+   *  call original
+   *  jmp loop:
+   *
+   * end:
+   *  JMP SAVED RET
+   *
+   * original:
+   *  INSTRUMENTED PERSISTENT FUNC
+   */
+
+  GumX86Writer *cw = output->writer.x86;
+
+  gconstpointer loop = cw->code + 1;
+
+  /* Stack must be 16-byte aligned per ABI */
+  instrument_persitent_save_regs(cw, &saved_regs);
+
+  /* Pop the return value */
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4));
+
+  /* loop: */
+  gum_x86_writer_put_label(cw, loop);
+
+  /* call instrument_prologue_func */
+  instrument_afl_persistent_loop(cw);
+
+  /* jz done */
+  gconstpointer done = cw->code + 1;
+  gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY);
+
+  /* Optionally call the persistent hook */
+  persistent_prologue_hook(cw, &saved_regs);
+
+  instrument_persitent_restore_regs(cw, &saved_regs);
+  gconstpointer original = cw->code + 1;
+  /* call original */
+  gum_x86_writer_put_call_near_label(cw, original);
+  /* jmp loop */
+  gum_x86_writer_put_jmp_near_label(cw, loop);
+
+  /* done: */
+  gum_x86_writer_put_label(cw, done);
+
+  instrument_exit(cw);
+
+  /* original: */
+  gum_x86_writer_put_label(cw, original);
+
+  if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
+
+  gum_x86_writer_flush(cw);
+
+}
+
+void persistent_epilogue(GumStalkerOutput *output) {
+
+  GumX86Writer *cw = output->writer.x86;
+
+  if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
+
+  gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP,
+                                        persistent_ret_offset);
+
+  gum_x86_writer_put_ret(cw);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c
new file mode 100644
index 00000000..65c09fba
--- /dev/null
+++ b/frida_mode/src/prefetch.c
@@ -0,0 +1,112 @@
+#include <errno.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "prefetch.h"
+#include "stalker.h"
+
+#define TRUST 0
+#define PREFETCH_SIZE 65536
+#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *))
+
+typedef struct {
+
+  size_t count;
+  void * entry[PREFETCH_ENTRIES];
+
+} prefetch_data_t;
+
+static prefetch_data_t *prefetch_data = NULL;
+
+static int prefetch_shm_id = -1;
+
+/*
+ * We do this from the transformer since we need one anyway for coverage, this
+ * saves the need to use an event sink.
+ */
+void prefetch_write(void *addr) {
+
+  /* Bail if we aren't initialized */
+  if (prefetch_data == NULL) return;
+
+  /*
+   * Our shared memory IPC is large enough for about 1000 entries, we can fine
+   * tune this if we need to. But if we have more new blocks that this in a
+   * single run then we ignore them and we'll pick them up next time.
+   */
+  if (prefetch_data->count >= PREFETCH_ENTRIES) return;
+
+  /*
+   * Write the block address to the SHM IPC and increment the number of entries.
+   */
+
+  prefetch_data->entry[prefetch_data->count] = addr;
+  prefetch_data->count++;
+
+}
+
+/*
+ * Read the IPC region one block at the time and prefetch it
+ */
+void prefetch_read(void) {
+
+  GumStalker *stalker = stalker_get();
+  if (prefetch_data == NULL) return;
+
+  for (size_t i = 0; i < prefetch_data->count; i++) {
+
+    void *addr = prefetch_data->entry[i];
+    gum_stalker_prefetch(stalker, addr, 1);
+
+  }
+
+  /*
+   * Reset the entry count to indicate we have finished with it and it can be
+   * refilled by the child.
+   */
+  prefetch_data->count = 0;
+
+}
+
+void prefetch_init(void) {
+
+  g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE);
+  gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL);
+
+  OKF("Instrumentation - prefetch [%c]", prefetch ? 'X' : ' ');
+
+  if (!prefetch) { return; }
+  /*
+   * Make our shared memory, we can attach before we fork, just like AFL does
+   * with the coverage bitmap region and fork will take care of ensuring both
+   * the parent and child see the same consistent memory region.
+   */
+  prefetch_shm_id =
+      shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600);
+  if (prefetch_shm_id < 0) {
+
+    FATAL("prefetch_shm_id < 0 - errno: %d\n", errno);
+
+  }
+
+  prefetch_data = shmat(prefetch_shm_id, NULL, 0);
+  g_assert(prefetch_data != MAP_FAILED);
+
+  /*
+   * Configure the shared memory region to be removed once the process dies.
+   */
+  if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) {
+
+    FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
+
+  }
+
+  /* Clear it, not sure it's necessary, just seems like good practice */
+  memset(prefetch_data, '\0', sizeof(prefetch_data_t));
+
+}
+
diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c
new file mode 100644
index 00000000..ef25b371
--- /dev/null
+++ b/frida_mode/src/ranges.c
@@ -0,0 +1,611 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "lib.h"
+#include "ranges.h"
+#include "stalker.h"
+#include "util.h"
+
+#define MAX_RANGES 20
+
+typedef struct {
+
+  gchar *         suffix;
+  GumMemoryRange *range;
+  gboolean        done;
+
+} convert_name_ctx_t;
+
+GArray *module_ranges = NULL;
+GArray *libs_ranges = NULL;
+GArray *include_ranges = NULL;
+GArray *exclude_ranges = NULL;
+GArray *ranges = NULL;
+
+static void convert_address_token(gchar *token, GumMemoryRange *range) {
+
+  gchar **tokens;
+  int     token_count;
+  tokens = g_strsplit(token, "-", 2);
+  for (token_count = 0; tokens[token_count] != NULL; token_count++) {}
+
+  if (token_count != 2) {
+
+    FATAL("Invalid range (should have two addresses seperated by a '-'): %s\n",
+          token);
+
+  }
+
+  gchar *from_str = tokens[0];
+  gchar *to_str = tokens[1];
+
+  if (!g_str_has_prefix(from_str, "0x")) {
+
+    FATAL("Invalid range: %s - Start address should have 0x prefix: %s\n",
+          token, from_str);
+
+  }
+
+  if (!g_str_has_prefix(to_str, "0x")) {
+
+    FATAL("Invalid range: %s - End address should have 0x prefix: %s\n", token,
+          to_str);
+
+  }
+
+  from_str = &from_str[2];
+  to_str = &to_str[2];
+
+  for (char *c = from_str; *c != '\0'; c++) {
+
+    if (!g_ascii_isxdigit(*c)) {
+
+      FATAL("Invalid range: %s - Start address not formed of hex digits: %s\n",
+            token, from_str);
+
+    }
+
+  }
+
+  for (char *c = to_str; *c != '\0'; c++) {
+
+    if (!g_ascii_isxdigit(*c)) {
+
+      FATAL("Invalid range: %s - End address not formed of hex digits: %s\n",
+            token, to_str);
+
+    }
+
+  }
+
+  guint64 from = g_ascii_strtoull(from_str, NULL, 16);
+  if (from == 0) {
+
+    FATAL("Invalid range: %s - Start failed hex conversion: %s\n", token,
+          from_str);
+
+  }
+
+  guint64 to = g_ascii_strtoull(to_str, NULL, 16);
+  if (to == 0) {
+
+    FATAL("Invalid range: %s - End failed hex conversion: %s\n", token, to_str);
+
+  }
+
+  if (from >= to) {
+
+    FATAL("Invalid range: %s - Start (0x%016" G_GINT64_MODIFIER
+          "x) must be less than end "
+          "(0x%016" G_GINT64_MODIFIER "x)\n",
+          token, from, to);
+
+  }
+
+  range->base_address = from;
+  range->size = to - from;
+
+  g_strfreev(tokens);
+
+}
+
+static gboolean convert_name_token_for_module(const GumModuleDetails *details,
+                                              gpointer user_data) {
+
+  convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
+  if (details->path == NULL) { return true; };
+
+  if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
+
+  OKF("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
+      "x-0x%016" G_GINT64_MODIFIER "x %s",
+      ctx->suffix, details->range->base_address,
+      details->range->base_address + details->range->size, details->path);
+
+  *ctx->range = *details->range;
+  ctx->done = true;
+  return false;
+
+}
+
+static void convert_name_token(gchar *token, GumMemoryRange *range) {
+
+  gchar *            suffix = g_strconcat("/", token, NULL);
+  convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false};
+
+  gum_process_enumerate_modules(convert_name_token_for_module, &ctx);
+  if (!ctx.done) { FATAL("Failed to resolve module: %s\n", token); }
+  g_free(suffix);
+
+}
+
+static void convert_token(gchar *token, GumMemoryRange *range) {
+
+  if (g_strrstr(token, "-")) {
+
+    convert_address_token(token, range);
+
+  } else {
+
+    convert_name_token(token, range);
+
+  }
+
+  OKF("Converted token: %s -> 0x%016" G_GINT64_MODIFIER
+      "x-0x%016" G_GINT64_MODIFIER "x\n",
+      token, range->base_address, range->base_address + range->size);
+
+}
+
+gint range_sort(gconstpointer a, gconstpointer b) {
+
+  return ((GumMemoryRange *)a)->base_address -
+         ((GumMemoryRange *)b)->base_address;
+
+}
+
+static gboolean print_ranges_callback(const GumRangeDetails *details,
+                                      gpointer               user_data) {
+
+  UNUSED_PARAMETER(user_data);
+  if (details->file == NULL) {
+
+    OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X",
+        details->range->base_address,
+        details->range->base_address + details->range->size);
+
+  } else {
+
+    OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER
+        "X %s(0x%016" G_GINT64_MODIFIER "x)",
+        details->range->base_address,
+        details->range->base_address + details->range->size,
+        details->file->path, details->file->offset);
+
+  }
+
+  return true;
+
+}
+
+static void print_ranges(char *key, GArray *ranges) {
+
+  OKF("Range: %s Length: %d", key, ranges->len);
+  for (guint i = 0; i < ranges->len; i++) {
+
+    GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
+    GumAddress      curr_limit = curr->base_address + curr->size;
+    OKF("Range: %s Idx: %3d - 0x%016" G_GINT64_MODIFIER
+        "x-0x%016" G_GINT64_MODIFIER "x",
+        key, i, curr->base_address, curr_limit);
+
+  }
+
+}
+
+static gboolean collect_module_ranges_callback(const GumRangeDetails *details,
+                                               gpointer user_data) {
+
+  GArray *       ranges = (GArray *)user_data;
+  GumMemoryRange range = *details->range;
+  g_array_append_val(ranges, range);
+  return TRUE;
+
+}
+
+static GArray *collect_module_ranges(void) {
+
+  GArray *result;
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+  gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS,
+                               collect_module_ranges_callback, result);
+  print_ranges("Modules", result);
+  return result;
+
+}
+
+static GArray *collect_ranges(char *env_key) {
+
+  char *         env_val;
+  gchar **       tokens;
+  int            token_count;
+  GumMemoryRange range;
+  int            i;
+  GArray *       result;
+
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+
+  env_val = getenv(env_key);
+  if (env_val == NULL) return result;
+
+  tokens = g_strsplit(env_val, ",", MAX_RANGES);
+
+  for (token_count = 0; tokens[token_count] != NULL; token_count++)
+    ;
+
+  for (i = 0; i < token_count; i++) {
+
+    convert_token(tokens[i], &range);
+    g_array_append_val(result, range);
+
+  }
+
+  g_array_sort(result, range_sort);
+
+  /* Check for overlaps */
+  for (i = 1; i < token_count; i++) {
+
+    GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1);
+    GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i);
+    GumAddress      prev_limit = prev->base_address + prev->size;
+    GumAddress      curr_limit = curr->base_address + curr->size;
+    if (prev_limit > curr->base_address) {
+
+      FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER
+            "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER
+            "x-0x%016" G_GINT64_MODIFIER "x",
+            prev->base_address, prev_limit, curr->base_address, curr_limit);
+
+    }
+
+  }
+
+  print_ranges(env_key, result);
+
+  g_strfreev(tokens);
+
+  return result;
+
+}
+
+static GArray *collect_libs_ranges(void) {
+
+  GArray *       result;
+  GumMemoryRange range;
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+
+  if (getenv("AFL_INST_LIBS") == NULL) {
+
+    range.base_address = lib_get_text_base();
+    range.size = lib_get_text_limit() - lib_get_text_base();
+
+  } else {
+
+    range.base_address = 0;
+    range.size = G_MAXULONG;
+
+  }
+
+  g_array_append_val(result, range);
+
+  print_ranges("AFL_INST_LIBS", result);
+
+  return result;
+
+}
+
+static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra,
+                                GumMemoryRange *rb) {
+
+  GumAddress rab = ra->base_address;
+  GumAddress ral = rab + ra->size;
+
+  GumAddress rbb = rb->base_address;
+  GumAddress rbl = rbb + rb->size;
+
+  GumAddress rrb = 0;
+  GumAddress rrl = 0;
+
+  rr->base_address = 0;
+  rr->size = 0;
+
+  /* ra is before rb */
+  if (ral < rbb) { return false; }
+
+  /* ra is after rb */
+  if (rab > rbl) { return true; }
+
+  /* The largest of the two base addresses */
+  rrb = rab > rbb ? rab : rbb;
+
+  /* The smallest of the two limits */
+  rrl = ral < rbl ? ral : rbl;
+
+  rr->base_address = rrb;
+  rr->size = rrl - rrb;
+  return true;
+
+}
+
+static GArray *intersect_ranges(GArray *a, GArray *b) {
+
+  GArray *        result;
+  GumMemoryRange *ra;
+  GumMemoryRange *rb;
+  GumMemoryRange  ri;
+
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+
+  for (guint i = 0; i < a->len; i++) {
+
+    ra = &g_array_index(a, GumMemoryRange, i);
+    for (guint j = 0; j < b->len; j++) {
+
+      rb = &g_array_index(b, GumMemoryRange, j);
+
+      if (!intersect_range(&ri, ra, rb)) { break; }
+
+      if (ri.size == 0) { continue; }
+
+      g_array_append_val(result, ri);
+
+    }
+
+  }
+
+  return result;
+
+}
+
+static GArray *subtract_ranges(GArray *a, GArray *b) {
+
+  GArray *        result;
+  GumMemoryRange *ra;
+  GumAddress      ral;
+  GumMemoryRange *rb;
+  GumMemoryRange  ri;
+  GumMemoryRange  rs;
+
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+
+  for (guint i = 0; i < a->len; i++) {
+
+    ra = &g_array_index(a, GumMemoryRange, i);
+    ral = ra->base_address + ra->size;
+    for (guint j = 0; j < b->len; j++) {
+
+      rb = &g_array_index(b, GumMemoryRange, j);
+
+      /*
+       * If rb is after ra, we have no more possible intersections and we can
+       * simply keep the remaining range
+       */
+      if (!intersect_range(&ri, ra, rb)) { break; }
+
+      /*
+       * If there is no intersection, then rb must be before ra, so we must
+       * continue
+       */
+      if (ri.size == 0) { continue; }
+
+      /*
+       * If the intersection is part way through the range, then we keep the
+       * start of the range
+       */
+      if (ra->base_address < ri.base_address) {
+
+        rs.base_address = ra->base_address;
+        rs.size = ri.base_address - ra->base_address;
+        g_array_append_val(result, rs);
+
+      }
+
+      /*
+       * If the intersection extends past the limit of the range, then we should
+       * continue with the next range
+       */
+      if ((ri.base_address + ri.size) > ral) {
+
+        ra->base_address = ral;
+        ra->size = 0;
+        break;
+
+      }
+
+      /*
+       * Otherwise we advance the base of the range to the end of the
+       * intersection and continue with the remainder of the range
+       */
+      ra->base_address = ri.base_address + ri.size;
+      ra->size = ral - ra->base_address;
+
+    }
+
+    /*
+     * When we have processed all the possible intersections, we add what is
+     * left
+     */
+    if (ra->size != 0) g_array_append_val(result, *ra);
+
+  }
+
+  return result;
+
+}
+
+static GArray *merge_ranges(GArray *a) {
+
+  GArray *        result;
+  GumMemoryRange  rp;
+  GumMemoryRange *r;
+
+  result = g_array_new(false, false, sizeof(GumMemoryRange));
+  if (a->len == 0) return result;
+
+  rp = g_array_index(a, GumMemoryRange, 0);
+
+  for (guint i = 1; i < a->len; i++) {
+
+    r = &g_array_index(a, GumMemoryRange, i);
+
+    if (rp.base_address + rp.size == r->base_address) {
+
+      rp.size += r->size;
+
+    } else {
+
+      g_array_append_val(result, rp);
+      rp.base_address = r->base_address;
+      rp.size = r->size;
+      continue;
+
+    }
+
+  }
+
+  g_array_append_val(result, rp);
+
+  return result;
+
+}
+
+static gboolean exclude_ranges_callback(const GumRangeDetails *details,
+                                        gpointer               user_data) {
+
+  UNUSED_PARAMETER(user_data);
+  gchar *     name;
+  gboolean    found;
+  GumStalker *stalker;
+  if (details->file == NULL) { return TRUE; }
+  name = g_path_get_basename(details->file->path);
+
+  found = (g_strcmp0(name, "afl-frida-trace.so") == 0);
+  g_free(name);
+  if (!found) { return TRUE; }
+
+  stalker = stalker_get();
+  gum_stalker_exclude(stalker, details->range);
+
+  return FALSE;
+
+}
+
+static void ranges_exclude_self(void) {
+
+  gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, exclude_ranges_callback, NULL);
+
+}
+
+void ranges_init(void) {
+
+  GumMemoryRange ri;
+  GArray *       step1;
+  GArray *       step2;
+  GArray *       step3;
+  GArray *       step4;
+
+  if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) {
+
+    gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback,
+                                 NULL);
+
+  }
+
+  module_ranges = collect_module_ranges();
+  libs_ranges = collect_libs_ranges();
+  include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
+
+  /* If include ranges is empty, then assume everything is included */
+  if (include_ranges->len == 0) {
+
+    ri.base_address = 0;
+    ri.size = G_MAXULONG;
+    g_array_append_val(include_ranges, ri);
+
+  }
+
+  exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");
+
+  /* Intersect with .text section of main executable unless AFL_INST_LIBS */
+  step1 = intersect_ranges(module_ranges, libs_ranges);
+  print_ranges("step1", step1);
+
+  /* Intersect with AFL_FRIDA_INST_RANGES */
+  step2 = intersect_ranges(step1, include_ranges);
+  print_ranges("step2", step2);
+
+  /* Subtract AFL_FRIDA_EXCLUDE_RANGES */
+  step3 = subtract_ranges(step2, exclude_ranges);
+  print_ranges("step3", step3);
+
+  /*
+   * After step3, we have the total ranges to be instrumented, we now subtract
+   * that from the original ranges of the modules to configure stalker.
+   */
+
+  step4 = subtract_ranges(module_ranges, step3);
+  print_ranges("step4", step4);
+
+  ranges = merge_ranges(step4);
+  print_ranges("final", ranges);
+
+  g_array_free(step4, TRUE);
+  g_array_free(step3, TRUE);
+  g_array_free(step2, TRUE);
+  g_array_free(step1, TRUE);
+
+  /* *NEVER* stalk the stalker, only bad things will ever come of this! */
+  ranges_exclude_self();
+
+  ranges_exclude();
+
+}
+
+gboolean range_is_excluded(gpointer address) {
+
+  GumAddress test = GUM_ADDRESS(address);
+
+  if (ranges == NULL) { return false; }
+
+  for (guint i = 0; i < ranges->len; i++) {
+
+    GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
+    GumAddress      curr_limit = curr->base_address + curr->size;
+
+    if (test < curr->base_address) { return false; }
+
+    if (test < curr_limit) { return true; }
+
+  }
+
+  return false;
+
+}
+
+void ranges_exclude() {
+
+  GumMemoryRange *r;
+  GumStalker *    stalker = stalker_get();
+
+  OKF("Excluding ranges");
+
+  for (guint i = 0; i < ranges->len; i++) {
+
+    r = &g_array_index(ranges, GumMemoryRange, i);
+    gum_stalker_exclude(stalker, r);
+
+  }
+
+}
+
diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c
new file mode 100644
index 00000000..63f3c529
--- /dev/null
+++ b/frida_mode/src/stalker.c
@@ -0,0 +1,32 @@
+#include "debug.h"
+
+#include "instrument.h"
+#include "stalker.h"
+
+static GumStalker *stalker = NULL;
+
+void stalker_init(void) {
+
+  if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); }
+
+  stalker = gum_stalker_new();
+  if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
+
+  gum_stalker_set_trust_threshold(stalker, 0);
+
+}
+
+GumStalker *stalker_get(void) {
+
+  if (stalker == NULL) { FATAL("Stalker uninitialized"); }
+  return stalker;
+
+}
+
+void stalker_start(void) {
+
+  GumStalkerTransformer *transformer = instrument_get_transformer();
+  gum_stalker_follow_me(stalker, transformer, NULL);
+
+}
+
diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c
new file mode 100644
index 00000000..662fb6d5
--- /dev/null
+++ b/frida_mode/src/stats/stats.c
@@ -0,0 +1,208 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+#include "util.h"
+
+#include "stats.h"
+
+#define MICRO_TO_SEC 1000000
+
+stats_data_header_t *stats_data = NULL;
+
+static int      stats_parent_pid = -1;
+static int      stats_fd = -1;
+static gboolean stats_transitions = FALSE;
+static guint64  stats_interval = 0;
+
+void stats_init(void) {
+
+  stats_parent_pid = getpid();
+  char *filename = getenv("AFL_FRIDA_STATS_FILE");
+  stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL");
+  if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) {
+
+    stats_transitions = TRUE;
+
+  }
+
+  OKF("Stats - file [%s]", filename);
+  OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval);
+
+  if (stats_interval != 0 && filename == NULL) {
+
+    FATAL(
+        "AFL_FRIDA_STATS_FILE must be specified if "
+        "AFL_FRIDA_STATS_INTERVAL is");
+
+  }
+
+  if (stats_interval == 0) { stats_interval = 10; }
+
+  if (filename == NULL) { return; }
+
+  if (!stats_is_supported_arch()) {
+
+    FATAL("Stats is not supported on this architecture");
+
+  }
+
+  char *path = NULL;
+
+  if (filename == NULL) { return; }
+
+  if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); }
+
+  path = g_canonicalize_filename(filename, g_get_current_dir());
+
+  OKF("Stats - path [%s]", path);
+
+  stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+
+  if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); }
+
+  g_free(path);
+
+  size_t data_size = stats_data_size_arch();
+
+  int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600);
+  if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); }
+
+  stats_data = shmat(shm_id, NULL, 0);
+  g_assert(stats_data != MAP_FAILED);
+
+  /*
+   * Configure the shared memory region to be removed once the process dies.
+   */
+  if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
+
+    FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
+
+  }
+
+  /* Clear it, not sure it's necessary, just seems like good practice */
+  memset(stats_data, '\0', data_size);
+
+}
+
+void stats_vprint(int fd, char *format, va_list ap) {
+
+  char buffer[4096] = {0};
+  int  ret;
+  int  len;
+
+  if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; }
+
+  len = strnlen(buffer, sizeof(buffer));
+  IGNORED_RETURN(write(fd, buffer, len));
+
+}
+
+void stats_print_fd(int fd, char *format, ...) {
+
+  va_list ap;
+  va_start(ap, format);
+  stats_vprint(fd, format, ap);
+  va_end(ap);
+
+}
+
+void stats_print(char *format, ...) {
+
+  va_list ap;
+  va_start(ap, format);
+  stats_vprint(stats_fd, format, ap);
+  va_end(ap);
+
+}
+
+void stats_write(void) {
+
+  if (stats_parent_pid == getpid()) { return; }
+
+  GDateTime *date_time = g_date_time_new_now_local();
+  char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S");
+
+  stats_print("stats\n");
+  stats_print("-----\n");
+
+  stats_print("Index:                          %" G_GINT64_MODIFIER "u\n",
+              stats_data->stats_idx++);
+  stats_print("Pid:                            %d\n", getpid());
+  stats_print("Time:                           %s\n", date_time_string);
+  stats_print("Blocks:                         %" G_GINT64_MODIFIER "u\n",
+              stats_data->num_blocks);
+  stats_print("Instructions:                   %" G_GINT64_MODIFIER "u\n",
+              stats_data->num_instructions);
+  stats_print("Avg Instructions / Block:       %" G_GINT64_MODIFIER "u\n",
+              stats_data->num_instructions / stats_data->num_blocks);
+
+  stats_print("\n");
+
+  g_free(date_time_string);
+  g_date_time_unref(date_time);
+
+  stats_write_arch();
+
+  if (stats_transitions) {
+
+    GDateTime *date_time = g_date_time_new_now_local();
+    char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S");
+
+    stats_print_fd(STDERR_FILENO, "stats\n");
+    stats_print_fd(STDERR_FILENO, "-----\n");
+    stats_print_fd(STDERR_FILENO, "Index: %" G_GINT64_MODIFIER "u\n",
+                   stats_data->transitions_idx++);
+    stats_print_fd(STDERR_FILENO, "Pid:   %d\n", getpid());
+    stats_print_fd(STDERR_FILENO, "Time:  %s\n", date_time_string);
+
+    g_free(date_time_string);
+    g_date_time_unref(date_time);
+    gum_stalker_dump_counters();
+
+  }
+
+}
+
+static void stats_maybe_write(void) {
+
+  guint64 current_time;
+
+  if (stats_interval == 0) { return; }
+
+  current_time = g_get_monotonic_time();
+
+  if ((current_time - stats_data->stats_last_time) >
+      (stats_interval * MICRO_TO_SEC)) {
+
+    stats_write();
+    stats_data->stats_last_time = current_time;
+
+  }
+
+}
+
+void stats_collect(const cs_insn *instr, gboolean begin) {
+
+  UNUSED_PARAMETER(instr);
+  UNUSED_PARAMETER(begin);
+
+  if (stats_fd < 0) { return; }
+
+  if (begin) { stats_data->num_blocks++; }
+  stats_data->num_instructions++;
+
+  stats_collect_arch(instr);
+
+  stats_maybe_write();
+
+}
+
diff --git a/frida_mode/src/stats/stats_arm.c b/frida_mode/src/stats/stats_arm.c
new file mode 100644
index 00000000..7eea7f91
--- /dev/null
+++ b/frida_mode/src/stats/stats_arm.c
@@ -0,0 +1,36 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "stats.h"
+#include "util.h"
+
+#if defined(__arm__)
+
+gboolean stats_is_supported_arch(void) {
+
+  return FALSE;
+
+}
+
+size_t stats_data_size_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_write_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_collect_arch(const cs_insn *instr) {
+
+  UNUSED_PARAMETER(instr);
+  FATAL("Stats not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c
new file mode 100644
index 00000000..592af87a
--- /dev/null
+++ b/frida_mode/src/stats/stats_arm64.c
@@ -0,0 +1,36 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "stats.h"
+#include "util.h"
+
+#if defined(__aarch64__)
+
+gboolean stats_is_supported_arch(void) {
+
+  return FALSE;
+
+}
+
+size_t stats_data_size_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_write_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_collect_arch(const cs_insn *instr) {
+
+  UNUSED_PARAMETER(instr);
+  FATAL("Stats not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/stats/stats_x64.c b/frida_mode/src/stats/stats_x64.c
new file mode 100644
index 00000000..c3e8742a
--- /dev/null
+++ b/frida_mode/src/stats/stats_x64.c
@@ -0,0 +1,307 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "ranges.h"
+#include "stats.h"
+#include "util.h"
+
+#if defined(__x86_64__)
+
+typedef struct {
+
+  stats_data_header_t header;
+
+  guint64 num_call_imm;
+  guint64 num_call_imm_excluded;
+  guint64 num_call_reg;
+  guint64 num_call_mem;
+
+  guint64 num_jmp_imm;
+  guint64 num_jmp_reg;
+  guint64 num_jmp_mem;
+
+  guint64 num_jmp_cond_imm;
+  guint64 num_jmp_cond_reg;
+  guint64 num_jmp_cond_mem;
+
+  guint64 num_jmp_cond_jcxz;
+
+  guint64 num_ret;
+
+  guint64 num_rip_relative;
+
+} stats_data_arch_t;
+
+gboolean stats_is_supported_arch(void) {
+
+  return TRUE;
+
+}
+
+size_t stats_data_size_arch(void) {
+
+  return sizeof(stats_data_arch_t);
+
+}
+
+void stats_write_arch(void) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  guint64 num_instructions = stats_data_arch->header.num_instructions;
+
+  stats_print(
+      "Call Immediates:                %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_call_imm,
+      ((float)(stats_data_arch->num_call_imm * 100) / num_instructions));
+  stats_print("Call Immediates Excluded:       %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_call_imm_excluded,
+              ((float)(stats_data_arch->num_call_imm_excluded * 100) /
+               num_instructions));
+  stats_print(
+      "Call Register:                  %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_call_reg,
+      ((float)(stats_data_arch->num_call_reg * 100) / num_instructions));
+  stats_print(
+      "Call Memory:                    %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_call_mem,
+      ((float)(stats_data_arch->num_call_mem * 100) / num_instructions));
+
+  stats_print("\n");
+
+  stats_print("Jump Immediates:                %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_jmp_imm,
+              ((float)(stats_data_arch->num_jmp_imm * 100) / num_instructions));
+  stats_print("Jump Register:                  %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_jmp_reg,
+              ((float)(stats_data_arch->num_jmp_reg * 100) / num_instructions));
+  stats_print("Jump Memory:                    %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_jmp_mem,
+              ((float)(stats_data_arch->num_jmp_mem * 100) / num_instructions));
+
+  stats_print("\n");
+
+  stats_print(
+      "Conditional Jump Immediates:    %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_jmp_cond_imm,
+      ((float)(stats_data_arch->num_jmp_cond_imm * 100) / num_instructions));
+  stats_print(
+      "Conditional Jump CX Immediate:  %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_jmp_cond_jcxz,
+      ((float)(stats_data_arch->num_jmp_cond_jcxz * 100) / num_instructions));
+  stats_print(
+      "Conditional Jump Register:      %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_jmp_cond_reg,
+      ((float)(stats_data_arch->num_jmp_cond_reg * 100) / num_instructions));
+  stats_print(
+      "Conditional Jump Memory:        %" G_GINT64_MODIFIER
+      "u "
+      "(%3.2f%%)\n",
+      stats_data_arch->num_jmp_cond_mem,
+      ((float)(stats_data_arch->num_jmp_cond_mem * 100) / num_instructions));
+
+  stats_print("\n");
+
+  stats_print("Returns:                        %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_ret,
+              (stats_data_arch->num_ret * 100 / num_instructions));
+
+  stats_print("\n");
+
+  stats_print("Rip Relative:                   %" G_GINT64_MODIFIER
+              "u "
+              "(%3.2f%%)\n",
+              stats_data_arch->num_rip_relative,
+              (stats_data_arch->num_rip_relative * 100 / num_instructions));
+
+  stats_print("\n");
+  stats_print("\n");
+
+}
+
+static x86_op_type stats_get_operand_type(const cs_insn *instr) {
+
+  cs_x86 *   x86 = &instr->detail->x86;
+  cs_x86_op *operand;
+
+  if (x86->op_count != 1) {
+
+    FATAL("Unexpected operand count (%d): %s %s\n", x86->op_count,
+          instr->mnemonic, instr->op_str);
+
+  }
+
+  operand = &x86->operands[0];
+
+  return operand->type;
+
+}
+
+static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  cs_x86 *           x86 = &instr->detail->x86;
+  cs_x86_op *        operand = &x86->operands[0];
+
+  if (range_is_excluded((gpointer)operand->imm)) {
+
+    stats_data_arch->num_call_imm_excluded++;
+
+  }
+
+}
+
+static void stats_collect_call_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  x86_op_type        type = stats_get_operand_type(instr);
+  switch (type) {
+
+    case X86_OP_IMM:
+      stats_data_arch->num_call_imm++;
+      stats_collect_call_imm_excluded_arch(instr);
+      break;
+    case X86_OP_REG:
+      stats_data_arch->num_call_reg++;
+      break;
+    case X86_OP_MEM:
+      stats_data_arch->num_call_mem++;
+      break;
+    default:
+      FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str);
+
+  }
+
+}
+
+static void stats_collect_jump_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  x86_op_type        type = stats_get_operand_type(instr);
+  switch (type) {
+
+    case X86_OP_IMM:
+      stats_data_arch->num_jmp_imm++;
+      break;
+    case X86_OP_REG:
+      stats_data_arch->num_jmp_reg++;
+      break;
+    case X86_OP_MEM:
+      stats_data_arch->num_jmp_mem++;
+      break;
+    default:
+      FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str);
+
+  }
+
+}
+
+static void stats_collect_jump_cond_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  x86_op_type        type = stats_get_operand_type(instr);
+  switch (type) {
+
+    case X86_OP_IMM:
+      stats_data_arch->num_jmp_cond_imm++;
+      break;
+    case X86_OP_REG:
+      stats_data_arch->num_jmp_cond_reg++;
+      break;
+    case X86_OP_MEM:
+      stats_data_arch->num_jmp_cond_mem++;
+      break;
+    default:
+      FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str);
+
+  }
+
+}
+
+static void stats_collect_rip_relative_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  cs_x86 *           x86 = &instr->detail->x86;
+  guint              mod;
+  guint              rm;
+
+  if (x86->encoding.modrm_offset == 0) { return; }
+
+  mod = (x86->modrm & 0xc0) >> 6;
+  if (mod != 0) { return; }
+
+  rm = (x86->modrm & 0x07) >> 0;
+  if (rm != 5) { return; }
+
+  stats_data_arch->num_rip_relative++;
+
+}
+
+void stats_collect_arch(const cs_insn *instr) {
+
+  stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data;
+  switch (instr->id) {
+
+    case X86_INS_CALL:
+      stats_collect_call_arch(instr);
+      break;
+    case X86_INS_JMP:
+      stats_collect_jump_arch(instr);
+      break;
+    case X86_INS_JA:
+    case X86_INS_JAE:
+    case X86_INS_JB:
+    case X86_INS_JBE:
+    case X86_INS_JE:
+    case X86_INS_JG:
+    case X86_INS_JGE:
+    case X86_INS_JL:
+    case X86_INS_JLE:
+    case X86_INS_JNE:
+    case X86_INS_JNO:
+    case X86_INS_JNP:
+    case X86_INS_JNS:
+    case X86_INS_JO:
+    case X86_INS_JP:
+    case X86_INS_JS:
+      stats_collect_jump_cond_arch(instr);
+      break;
+    case X86_INS_JECXZ:
+    case X86_INS_JRCXZ:
+      stats_data_arch->num_jmp_cond_jcxz++;
+      break;
+    case X86_INS_RET:
+      stats_data_arch->num_ret++;
+      break;
+    default:
+      stats_collect_rip_relative_arch(instr);
+      break;
+
+  }
+
+}
+
+#endif
+
diff --git a/frida_mode/src/stats/stats_x86.c b/frida_mode/src/stats/stats_x86.c
new file mode 100644
index 00000000..1906e809
--- /dev/null
+++ b/frida_mode/src/stats/stats_x86.c
@@ -0,0 +1,36 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "stats.h"
+#include "util.h"
+
+#if defined(__i386__)
+
+gboolean stats_is_supported_arch(void) {
+
+  return FALSE;
+
+}
+
+size_t stats_data_size_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_write_arch(void) {
+
+  FATAL("Stats not supported on this architecture");
+
+}
+
+void stats_collect_arch(const cs_insn *instr) {
+
+  UNUSED_PARAMETER(instr);
+  FATAL("Stats not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c
new file mode 100644
index 00000000..09e8a58b
--- /dev/null
+++ b/frida_mode/src/util.c
@@ -0,0 +1,68 @@
+#include "util.h"
+
+#include "debug.h"
+
+guint64 util_read_address(char *key) {
+
+  char *value_str = getenv(key);
+
+  if (value_str == NULL) { return 0; }
+
+  if (!g_str_has_prefix(value_str, "0x")) {
+
+    FATAL("Invalid address should have 0x prefix: %s=%s\n", key, value_str);
+
+  }
+
+  char *value_str2 = &value_str[2];
+
+  for (char *c = value_str2; *c != '\0'; c++) {
+
+    if (!g_ascii_isxdigit(*c)) {
+
+      FATAL("Invalid address not formed of hex digits: %s=%s ('%c')\n", key,
+            value_str, *c);
+
+    }
+
+  }
+
+  guint64 value = g_ascii_strtoull(value_str2, NULL, 16);
+  if (value == 0) {
+
+    FATAL("Invalid address failed hex conversion: %s=%s\n", key, value_str2);
+
+  }
+
+  return value;
+
+}
+
+guint64 util_read_num(char *key) {
+
+  char *value_str = getenv(key);
+
+  if (value_str == NULL) { return 0; }
+
+  for (char *c = value_str; *c != '\0'; c++) {
+
+    if (!g_ascii_isdigit(*c)) {
+
+      FATAL("Invalid address not formed of decimal digits: %s=%s\n", key,
+            value_str);
+
+    }
+
+  }
+
+  guint64 value = g_ascii_strtoull(value_str, NULL, 10);
+  if (value == 0) {
+
+    FATAL("Invalid address failed numeric conversion: %s=%s\n", key, value_str);
+
+  }
+
+  return value;
+
+}
+
diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile
new file mode 100644
index 00000000..40de6a09
--- /dev/null
+++ b/frida_mode/test/cmplog/GNUmakefile
@@ -0,0 +1,69 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../../)/
+BUILD_DIR:=$(PWD)build/
+
+TEST_CMPLOG_SRC=$(PWD)cmplog.c
+TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest
+
+TEST_BIN:=$(PWD)../../build/test
+
+
+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
+
+.PHONY: all 32 clean qemu frida format
+
+all: $(TEST_CMPLOG_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 "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" > $@
+
+$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_SRC) | $(BUILD_DIR)
+	$(CXX) -std=c++11 -g $(CFLAGS) $(LDFLAGS) $< -o $@
+
+qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
+	$(ROOT)afl-fuzz \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-c 0 \
+		-l 3AT \
+		-Z \
+		-- \
+			$(TEST_CMPLOG_OBJ) @@
+
+frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
+	$(ROOT)afl-fuzz \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-c 0 \
+		-l 3AT \
+		-Z \
+		-- \
+			$(TEST_CMPLOG_OBJ) @@
+
+debug: $(TEST_CMPLOG_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_CMPLOG_OBJ) $(CMP_LOG_INPUT)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+format:
+	cd $(ROOT) && echo $(TEST_CMPLOG_SRC) | xargs -L1 ./.custom-format.py -i
diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile
new file mode 100644
index 00000000..606b43a5
--- /dev/null
+++ b/frida_mode/test/cmplog/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
+
+clean:
+	@gmake clean
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
+
+format:
+	@gmake format
+
+debug:
+	@gmake debug
diff --git a/frida_mode/test/cmplog/cmplog.c b/frida_mode/test/cmplog/cmplog.c
new file mode 100644
index 00000000..99010645
--- /dev/null
+++ b/frida_mode/test/cmplog/cmplog.c
@@ -0,0 +1,100 @@
+/////////////////////////////////////////////////////////////////////////
+//
+// Author: Mateusz Jurczyk (mjurczyk@google.com)
+//
+// Copyright 2019-2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// solution: echo -ne 'The quick brown fox jumps over the lazy
+// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+
+  char buffer[44] = {/* zero padding */};
+
+  FILE *file = stdin;
+
+  if (argc > 1) {
+
+    if ((file = fopen(argv[1], "r")) == NULL) {
+
+      perror(argv[1]);
+      exit(-1);
+
+    }
+
+  }
+
+  fread(buffer, 1, sizeof(buffer) - 1, file);
+
+  if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||
+      strncmp(&buffer[20], "jumps over ", 11) != 0 ||
+      strcmp(&buffer[31], "the lazy dog") != 0) {
+
+    if (argc > 1) { fclose(file); }
+    return 1;
+
+  }
+
+#if defined(__x86_64__)
+  uint64_t x = 0;
+  fread(&x, sizeof(x), 1, file);
+  if (x != 0xCAFEBABECAFEBABE) {
+
+    if (argc > 1) { fclose(file); }
+    return 2;
+
+  }
+
+#endif
+
+  uint32_t y = 0;
+  fread(&y, sizeof(y), 1, file);
+
+  if (y != 0xDEADC0DE) {
+
+    if (argc > 1) { fclose(file); }
+    return 3;
+
+  }
+
+  uint16_t z = 0;
+  fread(&z, sizeof(z), 1, file);
+
+  switch (z) {
+
+    case 0xBEEF:
+      break;
+
+    default:
+      if (argc > 1) { fclose(file); }
+      return 4;
+
+  }
+
+  printf("Puzzle solved, congrats!\n");
+  abort();
+
+  if (argc > 1) { fclose(file); }
+
+  return 0;
+
+}
+
diff --git a/frida_mode/test/cmplog/get_section_addrs.py b/frida_mode/test/cmplog/get_section_addrs.py
new file mode 100755
index 00000000..f648808b
--- /dev/null
+++ b/frida_mode/test/cmplog/get_section_addrs.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+
+def process_file(file, section, base):
+    with open(file, "rb") as f:
+        for sect in ELFFile(f).iter_sections():
+            if sect.name == section:
+                start = base + sect.header["sh_offset"]
+                end = start + sect.header["sh_size"]
+                print("0x%016x-0x%016x" % (start, end))
+                return
+
+    print("Section '%s' not found in '%s'" % (section, file))
+
+
+def hex_value(x):
+    return int(x, 16)
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Process some integers.")
+    parser.add_argument(
+        "-f", "--file", dest="file", type=str, help="elf file name", required=True
+    )
+    parser.add_argument(
+        "-s",
+        "--section",
+        dest="section",
+        type=str,
+        help="elf section name",
+        required=True,
+    )
+    parser.add_argument(
+        "-b",
+        "--base",
+        dest="base",
+        type=hex_value,
+        help="elf base address",
+        required=True,
+    )
+
+    args = parser.parse_args()
+    process_file(args.file, args.section, args.base)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile
new file mode 100644
index 00000000..c268ef66
--- /dev/null
+++ b/frida_mode/test/deferred/GNUmakefile
@@ -0,0 +1,71 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000)
+endif
+
+.PHONY: all clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
diff --git a/frida_mode/test/deferred/Makefile b/frida_mode/test/deferred/Makefile
new file mode 100644
index 00000000..07b139e9
--- /dev/null
+++ b/frida_mode/test/deferred/Makefile
@@ -0,0 +1,13 @@
+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
diff --git a/frida_mode/test/deferred/testinstr.c b/frida_mode/test/deferred/testinstr.c
new file mode 100644
index 00000000..8b3688d7
--- /dev/null
+++ b/frida_mode/test/deferred/testinstr.c
@@ -0,0 +1,125 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+int run(char *file) {
+
+  int    fd = -1;
+  off_t  len;
+  char * buf = NULL;
+  size_t n_read;
+  int    result = -1;
+
+  do {
+
+    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 = 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);
+
+    testinstr(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;
+
+}
+
+void slow() {
+
+  usleep(100000);
+
+}
+
+TESTINSTR_SECTION int do_run(char * file) {
+  return run(file);
+}
+
+int main(int argc, char **argv) {
+
+  if (argc != 2) { return 1; }
+  slow();
+  return do_run(argv[1]);
+
+}
+
diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile
new file mode 100644
index 00000000..c99bcecb
--- /dev/null
+++ b/frida_mode/test/entry_point/GNUmakefile
@@ -0,0 +1,80 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000)
+endif
+
+.PHONY: all clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+frida_entry: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
diff --git a/frida_mode/test/entry_point/Makefile b/frida_mode/test/entry_point/Makefile
new file mode 100644
index 00000000..75c57e66
--- /dev/null
+++ b/frida_mode/test/entry_point/Makefile
@@ -0,0 +1,16 @@
+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
+
+frida_entry:
+	@gmake frida
diff --git a/frida_mode/test/entry_point/testinstr.c b/frida_mode/test/entry_point/testinstr.c
new file mode 100644
index 00000000..bd605c52
--- /dev/null
+++ b/frida_mode/test/entry_point/testinstr.c
@@ -0,0 +1,121 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+int run(char *file) {
+
+  int    fd = -1;
+  off_t  len;
+  char * buf = NULL;
+  size_t n_read;
+  int    result = -1;
+
+  do {
+
+    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 = 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);
+
+    testinstr(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;
+
+}
+
+void slow() {
+
+  usleep(100000);
+
+}
+
+int main(int argc, char **argv) {
+
+  if (argc != 2) { return 1; }
+  slow();
+  return run(argv[1]);
+
+}
+
diff --git a/frida_mode/test/exe/GNUmakefile b/frida_mode/test/exe/GNUmakefile
new file mode 100644
index 00000000..86e5a461
--- /dev/null
+++ b/frida_mode/test/exe/GNUmakefile
@@ -0,0 +1,53 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+.PHONY: all 32 clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -no-pie
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+
+qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	$(ROOT)afl-fuzz \
+		-D \
+		-Q \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
diff --git a/frida_mode/test/exe/Makefile b/frida_mode/test/exe/Makefile
new file mode 100644
index 00000000..4bef1ccb
--- /dev/null
+++ b/frida_mode/test/exe/Makefile
@@ -0,0 +1,16 @@
+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
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
diff --git a/frida_mode/test/exe/testinstr.c b/frida_mode/test/exe/testinstr.c
new file mode 100644
index 00000000..5e26fc46
--- /dev/null
+++ b/frida_mode/test/exe/testinstr.c
@@ -0,0 +1,112 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+TESTINSTR_SECTION 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 = 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);
+
+    testinstr(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/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile
new file mode 100644
index 00000000..08b271de
--- /dev/null
+++ b/frida_mode/test/fasan/GNUmakefile
@@ -0,0 +1,159 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+
+TEST_DATA_DIR:=$(BUILD_DIR)in/
+TEST_DATA_FILE:=$(TEST_DATA_DIR)in
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+TEST_SRC:=$(PWD)/test.c
+TEST_BIN:=$(BUILD_DIR)test
+
+CFLAGS+=-fPIC \
+		-D_GNU_SOURCE \
+		-g \
+		-fno-omit-frame-pointer \
+		-Wno-stringop-overflow \
+
+LDFLAGS+=-ldl \
+
+ifdef DEBUG
+CFLAGS+=-Werror \
+		-Wall \
+		-Wextra \
+		-Wpointer-arith
+else
+CFLAGS+=-Wno-pointer-arith
+endif
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+ifeq "$(ARCH)" "x86"
+LIBASAN_FILE:=libclang_rt.asan-i386.so
+endif
+
+ifeq "$(ARCH)" "x86_64"
+LIBASAN_FILE:=libclang_rt.asan-x86_64.so
+endif
+
+ifeq "$(ARCH)" "aarch64"
+LIBASAN_FILE:=libclang_rt.asan-aarch64.so
+endif
+
+# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so
+# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0
+
+LLVM_CONFIG ?= llvm-config
+ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1"
+  $(info Found llvm-config: '$(shell which $(LLVM_CONFIG))')
+else
+  $(warning Cannot find llvm-config)
+endif
+
+LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/
+$(info LLVM_BINDIR: $(LLVM_BINDIR))
+
+CLANG ?= $(LLVM_BINDIR)clang
+ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1"
+  $(info Found clang: '$(CLANG)')
+else
+  $(warning Cannot find clang)
+endif
+
+CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
+$(info Clang version $(CLANGVER))
+
+LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
+$(info LLVM_LIBDIR: $(LLVM_LIBDIR))
+
+LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE)
+
+ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1"
+  $(info Found Address Sanitizer DSO: '$(LIBASAN)')
+else
+  $(error Error cannot find Address Sanitizer DSO)
+endif
+
+
+.PHONY: all 32 clean format frida-noasan frida debug run
+
+############################## ALL #############################################
+
+all: $(TEST_BIN)
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR)
+	$(CC) \
+		$(CFLAGS) \
+		$(LDFLAGS) \
+		-o $@ \
+		$<
+
+$(BUILD_DIR):
+	mkdir -p $(BUILD_DIR)
+
+############################# TESTS ############################################
+
+$(TEST_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TEST_DATA_FILE): | $(TEST_DATA_DIR)
+	echo -n "TUODATM" > $@
+
+frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE)
+		$(ROOT)afl-fuzz \
+			-D \
+			-O \
+			-i $(TEST_DATA_DIR) \
+			-o $(FRIDA_OUT) \
+			-- \
+				$(TEST_BIN)
+
+
+frida: $(TEST_BIN) $(TEST_DATA_FILE)
+	AFL_PRELOAD=$(LIBASAN) \
+	AFL_USE_FASAN=1 \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN)
+
+debug: $(TEST_BIN) $(TEST_DATA_FILE)
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \
+		--ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \
+		--ex 'set environment AFL_USE_FASAN=1' \
+		--ex 'set disassembly-flavor intel' \
+		--ex 'r < $(TEST_DATA_FILE)' \
+		--args $(TEST_BIN) \
+
+run: $(TEST_BIN) $(TEST_DATA_FILE)
+	LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \
+	ASAN_OPTIONS=detect_leaks=false \
+	AFL_USE_FASAN=1 \
+	$(TEST_BIN) < $(TEST_DATA_FILE)
+
+############################# CLEAN ############################################
+clean:
+	rm -rf $(BUILD_DIR)
+
+############################# FORMAT ###########################################
+format:
+	cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i
+
+############################# RUN #############################################
diff --git a/frida_mode/test/fasan/Makefile b/frida_mode/test/fasan/Makefile
new file mode 100644
index 00000000..3b4c71db
--- /dev/null
+++ b/frida_mode/test/fasan/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
+
+clean:
+	@gmake clean
+
+frida-noasan:
+	@gmake frida-noasan
+
+frida:
+	@gmake frida
+
+debug:
+	@gmake debug
+
+run:
+	@gmake run
diff --git a/frida_mode/test/fasan/test.c b/frida_mode/test/fasan/test.c
new file mode 100644
index 00000000..b9a119e6
--- /dev/null
+++ b/frida_mode/test/fasan/test.c
@@ -0,0 +1,90 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNUSED_PARAMETER(x) (void)(x)
+
+#define LOG(x)                              \
+  do {                                      \
+                                            \
+    char buf[] = x;                         \
+    write(STDOUT_FILENO, buf, sizeof(buf)); \
+                                            \
+  } while (false);
+
+void test(char data) {
+
+  char *buf = malloc(10);
+
+  if (buf == NULL) return;
+
+  switch (data) {
+
+    /* Underflow */
+    case 'U':
+      LOG("Underflow\n");
+      buf[-1] = '\0';
+      free(buf);
+      break;
+    /* Overflow */
+    case 'O':
+      LOG("Overflow\n");
+      buf[10] = '\0';
+      free(buf);
+      break;
+    /* Double free */
+    case 'D':
+      LOG("Double free\n");
+      free(buf);
+      free(buf);
+      break;
+    /* Use after free */
+    case 'A':
+      LOG("Use after free\n");
+      free(buf);
+      buf[0] = '\0';
+      break;
+    /* Test Limits (OK) */
+    case 'T':
+      LOG("Test-Limits - No Error\n");
+      buf[0] = 'A';
+      buf[9] = 'I';
+      free(buf);
+      break;
+    case 'M':
+      LOG("Memset too many\n");
+      memset(buf, '\0', 11);
+      free(buf);
+      break;
+    default:
+      LOG("Nop - No Error\n");
+      break;
+
+  }
+
+}
+
+int main(int argc, char **argv) {
+
+  UNUSED_PARAMETER(argc);
+  UNUSED_PARAMETER(argv);
+
+  char input = '\0';
+
+  if (read(STDIN_FILENO, &input, 1) < 0) {
+
+    LOG("Failed to read stdin\n");
+    return 1;
+
+  }
+
+  test(input);
+
+  LOG("DONE\n");
+  return 0;
+
+}
+
diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile
new file mode 100644
index 00000000..e30f2049
--- /dev/null
+++ b/frida_mode/test/libpcap/GNUmakefile
@@ -0,0 +1,188 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+
+AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
+AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
+
+LIBPCAP_BUILD_DIR:=$(BUILD_DIR)libpcap/
+HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
+PCAPTEST_BUILD_DIR:=$(BUILD_DIR)libpcaptest/
+TCPDUMP_BUILD_DIR:=$(BUILD_DIR)tcpdump/
+
+LIBPCAP_PATCH_URL:=https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpcap_fuzz_both/patch.diff
+LIBPCAP_PATCH_FILE:=$(LIBPCAP_BUILD_DIR)patch.diff
+LIBPCAP_URL:=https://github.com/the-tcpdump-group/libpcap.git
+LIBPCAP_DIR:=$(LIBPCAP_BUILD_DIR)libpcap/
+LIBPCAP_CMAKEFILE:=$(LIBPCAP_DIR)CMakeLists.txt
+LIBPCAP_MAKEFILE:=$(LIBPCAP_DIR)Makefile
+LIBPCAP_LIB:=$(LIBPCAP_DIR)libpcap.a
+
+HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c
+HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o
+HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c"
+
+PCAPTEST_SRC_DIR:=$(LIBPCAP_DIR)testprogs/fuzz/
+PCAPTEST_FILE:=$(PCAPTEST_SRC_DIR)fuzz_both.c
+PCAPTEST_OBJ:=$(PCAPTEST_BUILD_DIR)fuzz_both.o
+
+TCPDUMP_URL:=https://github.com/the-tcpdump-group/tcpdump.git
+TCPDUMP_TESTS_DIR:=$(TCPDUMP_BUILD_DIR)tests/
+
+CFLAGS += -fpermissive
+
+LDFLAGS += -lpthread
+
+TEST_BIN:=$(BUILD_DIR)test
+ifeq "$(shell uname)" "Darwin"
+TEST_BIN_LDFLAGS:=-undefined dynamic_lookup
+endif
+
+AFLPP_DRIVER_DUMMY_INPUT:=$(TCPDUMP_TESTS_DIR)in
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000)
+
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000)
+endif
+
+.PHONY: all clean qemu frida hook
+
+all: $(TEST_BIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+######### HARNESS ########
+$(HARNESS_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(HARNESS_FILE): | $(HARNESS_BUILD_DIR)
+	wget -O $@ $(HARNESS_URL)
+
+$(HARNESS_OBJ): $(HARNESS_FILE)
+	$(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $<
+
+######### PCAPTEST ########
+
+$(PCAPTEST_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(PCAPTEST_FILE): | $(LIBPCAP_CMAKEFILE)
+
+$(PCAPTEST_OBJ): $(PCAPTEST_FILE) | $(PCAPTEST_BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -I $(LIBPCAP_DIR) -o $@ -c $<
+
+######### LIBPCAP ########
+
+$(LIBPCAP_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(LIBPCAP_PATCH_FILE): | $(LIBPCAP_BUILD_DIR)
+	wget -O $@ $(LIBPCAP_PATCH_URL)
+
+$(LIBPCAP_CMAKEFILE): $(LIBPCAP_PATCH_FILE) | $(LIBPCAP_BUILD_DIR)
+	git clone --depth 1 $(LIBPCAP_URL) $(LIBPCAP_DIR)
+	git apply $(LIBPCAP_PATCH_FILE)
+
+$(LIBPCAP_MAKEFILE): $(LIBPCAP_CMAKEFILE)
+	cd $(LIBPCAP_DIR) && cmake .
+
+$(LIBPCAP_LIB): $(LIBPCAP_MAKEFILE) $(LIBPCAP_PATCH_FILE)
+	make -C $(LIBPCAP_DIR)
+
+######## TCPDUMP ######
+
+$(TCPDUMP_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TCPDUMP_TESTS_DIR): | $(TCPDUMP_BUILD_DIR)
+	git clone --depth=1 $(TCPDUMP_URL) $(TCPDUMP_BUILD_DIR)
+
+######### TEST ########
+
+$(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB)
+	$(CXX) \
+		$(CFLAGS) \
+		-o $@ \
+		$(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) \
+		-lz \
+		$(LDFLAGS) \
+		$(TEST_BIN_LDFLAGS) \
+
+########## HOOK ########
+
+$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
+	$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
+
+########## DUMMY #######
+
+$(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR)
+	truncate -s 1M $@
+
+###### TEST DATA #######
+
+hook: $(AFLPP_DRIVER_HOOK_OBJ)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR)
+	AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TCPDUMP_TESTS_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR)
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TCPDUMP_TESTS_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+debug:
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
diff --git a/frida_mode/test/libpcap/Makefile b/frida_mode/test/libpcap/Makefile
new file mode 100644
index 00000000..31cacb67
--- /dev/null
+++ b/frida_mode/test/libpcap/Makefile
@@ -0,0 +1,1143 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.16
+
+# Default target executed when no arguments are given to make.
+default_target: all
+
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap/build/libpcap/libpcap
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target install/strip
+install/strip: preinstall
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
+	/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
+.PHONY : install/strip
+
+# Special rule for the target install/strip
+install/strip/fast: preinstall/fast
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
+	/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
+.PHONY : install/strip/fast
+
+# Special rule for the target install/local
+install/local: preinstall
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
+	/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
+.PHONY : install/local
+
+# Special rule for the target install/local
+install/local/fast: preinstall/fast
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
+	/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
+.PHONY : install/local/fast
+
+# Special rule for the target install
+install: preinstall
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+	/usr/bin/cmake -P cmake_install.cmake
+.PHONY : install
+
+# Special rule for the target install
+install/fast: preinstall/fast
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+	/usr/bin/cmake -P cmake_install.cmake
+.PHONY : install/fast
+
+# Special rule for the target list_install_components
+list_install_components:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
+.PHONY : list_install_components
+
+# Special rule for the target list_install_components
+list_install_components/fast: list_install_components
+
+.PHONY : list_install_components/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	/usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+
+.PHONY : rebuild_cache/fast
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+
+.PHONY : edit_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles/progress.marks
+	$(MAKE) -f CMakeFiles/Makefile2 all
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	$(MAKE) -f CMakeFiles/Makefile2 clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	$(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	$(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+#=============================================================================
+# Target rules for targets named pcap
+
+# Build rule for target.
+pcap: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 pcap
+.PHONY : pcap
+
+# fast build rule for target.
+pcap/fast:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/build
+.PHONY : pcap/fast
+
+#=============================================================================
+# Target rules for targets named uninstall
+
+# Build rule for target.
+uninstall: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 uninstall
+.PHONY : uninstall
+
+# fast build rule for target.
+uninstall/fast:
+	$(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/build
+.PHONY : uninstall/fast
+
+#=============================================================================
+# Target rules for targets named pcap_static
+
+# Build rule for target.
+pcap_static: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 pcap_static
+.PHONY : pcap_static
+
+# fast build rule for target.
+pcap_static/fast:
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/build
+.PHONY : pcap_static/fast
+
+#=============================================================================
+# Target rules for targets named SerializeTarget
+
+# Build rule for target.
+SerializeTarget: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 SerializeTarget
+.PHONY : SerializeTarget
+
+# fast build rule for target.
+SerializeTarget/fast:
+	$(MAKE) -f CMakeFiles/SerializeTarget.dir/build.make CMakeFiles/SerializeTarget.dir/build
+.PHONY : SerializeTarget/fast
+
+#=============================================================================
+# Target rules for targets named testprogs
+
+# Build rule for target.
+testprogs: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 testprogs
+.PHONY : testprogs
+
+# fast build rule for target.
+testprogs/fast:
+	$(MAKE) -f testprogs/CMakeFiles/testprogs.dir/build.make testprogs/CMakeFiles/testprogs.dir/build
+.PHONY : testprogs/fast
+
+#=============================================================================
+# Target rules for targets named capturetest
+
+# Build rule for target.
+capturetest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 capturetest
+.PHONY : capturetest
+
+# fast build rule for target.
+capturetest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/capturetest.dir/build.make testprogs/CMakeFiles/capturetest.dir/build
+.PHONY : capturetest/fast
+
+#=============================================================================
+# Target rules for targets named findalldevstest
+
+# Build rule for target.
+findalldevstest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 findalldevstest
+.PHONY : findalldevstest
+
+# fast build rule for target.
+findalldevstest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/findalldevstest.dir/build.make testprogs/CMakeFiles/findalldevstest.dir/build
+.PHONY : findalldevstest/fast
+
+#=============================================================================
+# Target rules for targets named filtertest
+
+# Build rule for target.
+filtertest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 filtertest
+.PHONY : filtertest
+
+# fast build rule for target.
+filtertest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/filtertest.dir/build.make testprogs/CMakeFiles/filtertest.dir/build
+.PHONY : filtertest/fast
+
+#=============================================================================
+# Target rules for targets named findalldevstest-perf
+
+# Build rule for target.
+findalldevstest-perf: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 findalldevstest-perf
+.PHONY : findalldevstest-perf
+
+# fast build rule for target.
+findalldevstest-perf/fast:
+	$(MAKE) -f testprogs/CMakeFiles/findalldevstest-perf.dir/build.make testprogs/CMakeFiles/findalldevstest-perf.dir/build
+.PHONY : findalldevstest-perf/fast
+
+#=============================================================================
+# Target rules for targets named can_set_rfmon_test
+
+# Build rule for target.
+can_set_rfmon_test: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 can_set_rfmon_test
+.PHONY : can_set_rfmon_test
+
+# fast build rule for target.
+can_set_rfmon_test/fast:
+	$(MAKE) -f testprogs/CMakeFiles/can_set_rfmon_test.dir/build.make testprogs/CMakeFiles/can_set_rfmon_test.dir/build
+.PHONY : can_set_rfmon_test/fast
+
+#=============================================================================
+# Target rules for targets named opentest
+
+# Build rule for target.
+opentest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 opentest
+.PHONY : opentest
+
+# fast build rule for target.
+opentest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/opentest.dir/build.make testprogs/CMakeFiles/opentest.dir/build
+.PHONY : opentest/fast
+
+#=============================================================================
+# Target rules for targets named reactivatetest
+
+# Build rule for target.
+reactivatetest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 reactivatetest
+.PHONY : reactivatetest
+
+# fast build rule for target.
+reactivatetest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/reactivatetest.dir/build.make testprogs/CMakeFiles/reactivatetest.dir/build
+.PHONY : reactivatetest/fast
+
+#=============================================================================
+# Target rules for targets named writecaptest
+
+# Build rule for target.
+writecaptest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 writecaptest
+.PHONY : writecaptest
+
+# fast build rule for target.
+writecaptest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/writecaptest.dir/build.make testprogs/CMakeFiles/writecaptest.dir/build
+.PHONY : writecaptest/fast
+
+#=============================================================================
+# Target rules for targets named selpolltest
+
+# Build rule for target.
+selpolltest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 selpolltest
+.PHONY : selpolltest
+
+# fast build rule for target.
+selpolltest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/selpolltest.dir/build.make testprogs/CMakeFiles/selpolltest.dir/build
+.PHONY : selpolltest/fast
+
+#=============================================================================
+# Target rules for targets named threadsignaltest
+
+# Build rule for target.
+threadsignaltest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 threadsignaltest
+.PHONY : threadsignaltest
+
+# fast build rule for target.
+threadsignaltest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/threadsignaltest.dir/build.make testprogs/CMakeFiles/threadsignaltest.dir/build
+.PHONY : threadsignaltest/fast
+
+#=============================================================================
+# Target rules for targets named valgrindtest
+
+# Build rule for target.
+valgrindtest: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 valgrindtest
+.PHONY : valgrindtest
+
+# fast build rule for target.
+valgrindtest/fast:
+	$(MAKE) -f testprogs/CMakeFiles/valgrindtest.dir/build.make testprogs/CMakeFiles/valgrindtest.dir/build
+.PHONY : valgrindtest/fast
+
+#=============================================================================
+# Target rules for targets named fuzz_both
+
+# Build rule for target.
+fuzz_both: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 fuzz_both
+.PHONY : fuzz_both
+
+# fast build rule for target.
+fuzz_both/fast:
+	$(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_both.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_both.dir/build
+.PHONY : fuzz_both/fast
+
+#=============================================================================
+# Target rules for targets named fuzz_filter
+
+# Build rule for target.
+fuzz_filter: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 fuzz_filter
+.PHONY : fuzz_filter
+
+# fast build rule for target.
+fuzz_filter/fast:
+	$(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build
+.PHONY : fuzz_filter/fast
+
+#=============================================================================
+# Target rules for targets named fuzz_pcap
+
+# Build rule for target.
+fuzz_pcap: cmake_check_build_system
+	$(MAKE) -f CMakeFiles/Makefile2 fuzz_pcap
+.PHONY : fuzz_pcap
+
+# fast build rule for target.
+fuzz_pcap/fast:
+	$(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build
+.PHONY : fuzz_pcap/fast
+
+bpf_dump.o: bpf_dump.c.o
+
+.PHONY : bpf_dump.o
+
+# target to build an object file
+bpf_dump.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.o
+.PHONY : bpf_dump.c.o
+
+bpf_dump.i: bpf_dump.c.i
+
+.PHONY : bpf_dump.i
+
+# target to preprocess a source file
+bpf_dump.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.i
+.PHONY : bpf_dump.c.i
+
+bpf_dump.s: bpf_dump.c.s
+
+.PHONY : bpf_dump.s
+
+# target to generate assembly for a file
+bpf_dump.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.s
+.PHONY : bpf_dump.c.s
+
+bpf_filter.o: bpf_filter.c.o
+
+.PHONY : bpf_filter.o
+
+# target to build an object file
+bpf_filter.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.o
+.PHONY : bpf_filter.c.o
+
+bpf_filter.i: bpf_filter.c.i
+
+.PHONY : bpf_filter.i
+
+# target to preprocess a source file
+bpf_filter.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.i
+.PHONY : bpf_filter.c.i
+
+bpf_filter.s: bpf_filter.c.s
+
+.PHONY : bpf_filter.s
+
+# target to generate assembly for a file
+bpf_filter.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.s
+.PHONY : bpf_filter.c.s
+
+bpf_image.o: bpf_image.c.o
+
+.PHONY : bpf_image.o
+
+# target to build an object file
+bpf_image.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.o
+.PHONY : bpf_image.c.o
+
+bpf_image.i: bpf_image.c.i
+
+.PHONY : bpf_image.i
+
+# target to preprocess a source file
+bpf_image.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.i
+.PHONY : bpf_image.c.i
+
+bpf_image.s: bpf_image.c.s
+
+.PHONY : bpf_image.s
+
+# target to generate assembly for a file
+bpf_image.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.s
+.PHONY : bpf_image.c.s
+
+etherent.o: etherent.c.o
+
+.PHONY : etherent.o
+
+# target to build an object file
+etherent.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.o
+.PHONY : etherent.c.o
+
+etherent.i: etherent.c.i
+
+.PHONY : etherent.i
+
+# target to preprocess a source file
+etherent.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.i
+.PHONY : etherent.c.i
+
+etherent.s: etherent.c.s
+
+.PHONY : etherent.s
+
+# target to generate assembly for a file
+etherent.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.s
+.PHONY : etherent.c.s
+
+fad-getad.o: fad-getad.c.o
+
+.PHONY : fad-getad.o
+
+# target to build an object file
+fad-getad.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.o
+.PHONY : fad-getad.c.o
+
+fad-getad.i: fad-getad.c.i
+
+.PHONY : fad-getad.i
+
+# target to preprocess a source file
+fad-getad.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.i
+.PHONY : fad-getad.c.i
+
+fad-getad.s: fad-getad.c.s
+
+.PHONY : fad-getad.s
+
+# target to generate assembly for a file
+fad-getad.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.s
+.PHONY : fad-getad.c.s
+
+fmtutils.o: fmtutils.c.o
+
+.PHONY : fmtutils.o
+
+# target to build an object file
+fmtutils.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.o
+.PHONY : fmtutils.c.o
+
+fmtutils.i: fmtutils.c.i
+
+.PHONY : fmtutils.i
+
+# target to preprocess a source file
+fmtutils.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.i
+.PHONY : fmtutils.c.i
+
+fmtutils.s: fmtutils.c.s
+
+.PHONY : fmtutils.s
+
+# target to generate assembly for a file
+fmtutils.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.s
+.PHONY : fmtutils.c.s
+
+gencode.o: gencode.c.o
+
+.PHONY : gencode.o
+
+# target to build an object file
+gencode.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.o
+.PHONY : gencode.c.o
+
+gencode.i: gencode.c.i
+
+.PHONY : gencode.i
+
+# target to preprocess a source file
+gencode.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.i
+.PHONY : gencode.c.i
+
+gencode.s: gencode.c.s
+
+.PHONY : gencode.s
+
+# target to generate assembly for a file
+gencode.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.s
+.PHONY : gencode.c.s
+
+grammar.o: grammar.c.o
+
+.PHONY : grammar.o
+
+# target to build an object file
+grammar.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.o
+.PHONY : grammar.c.o
+
+grammar.i: grammar.c.i
+
+.PHONY : grammar.i
+
+# target to preprocess a source file
+grammar.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.i
+.PHONY : grammar.c.i
+
+grammar.s: grammar.c.s
+
+.PHONY : grammar.s
+
+# target to generate assembly for a file
+grammar.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.s
+.PHONY : grammar.c.s
+
+missing/strlcat.o: missing/strlcat.c.o
+
+.PHONY : missing/strlcat.o
+
+# target to build an object file
+missing/strlcat.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.o
+.PHONY : missing/strlcat.c.o
+
+missing/strlcat.i: missing/strlcat.c.i
+
+.PHONY : missing/strlcat.i
+
+# target to preprocess a source file
+missing/strlcat.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.i
+.PHONY : missing/strlcat.c.i
+
+missing/strlcat.s: missing/strlcat.c.s
+
+.PHONY : missing/strlcat.s
+
+# target to generate assembly for a file
+missing/strlcat.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.s
+.PHONY : missing/strlcat.c.s
+
+missing/strlcpy.o: missing/strlcpy.c.o
+
+.PHONY : missing/strlcpy.o
+
+# target to build an object file
+missing/strlcpy.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.o
+.PHONY : missing/strlcpy.c.o
+
+missing/strlcpy.i: missing/strlcpy.c.i
+
+.PHONY : missing/strlcpy.i
+
+# target to preprocess a source file
+missing/strlcpy.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.i
+.PHONY : missing/strlcpy.c.i
+
+missing/strlcpy.s: missing/strlcpy.c.s
+
+.PHONY : missing/strlcpy.s
+
+# target to generate assembly for a file
+missing/strlcpy.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.s
+.PHONY : missing/strlcpy.c.s
+
+nametoaddr.o: nametoaddr.c.o
+
+.PHONY : nametoaddr.o
+
+# target to build an object file
+nametoaddr.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.o
+.PHONY : nametoaddr.c.o
+
+nametoaddr.i: nametoaddr.c.i
+
+.PHONY : nametoaddr.i
+
+# target to preprocess a source file
+nametoaddr.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.i
+.PHONY : nametoaddr.c.i
+
+nametoaddr.s: nametoaddr.c.s
+
+.PHONY : nametoaddr.s
+
+# target to generate assembly for a file
+nametoaddr.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.s
+.PHONY : nametoaddr.c.s
+
+optimize.o: optimize.c.o
+
+.PHONY : optimize.o
+
+# target to build an object file
+optimize.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.o
+.PHONY : optimize.c.o
+
+optimize.i: optimize.c.i
+
+.PHONY : optimize.i
+
+# target to preprocess a source file
+optimize.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.i
+.PHONY : optimize.c.i
+
+optimize.s: optimize.c.s
+
+.PHONY : optimize.s
+
+# target to generate assembly for a file
+optimize.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.s
+.PHONY : optimize.c.s
+
+pcap-common.o: pcap-common.c.o
+
+.PHONY : pcap-common.o
+
+# target to build an object file
+pcap-common.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.o
+.PHONY : pcap-common.c.o
+
+pcap-common.i: pcap-common.c.i
+
+.PHONY : pcap-common.i
+
+# target to preprocess a source file
+pcap-common.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.i
+.PHONY : pcap-common.c.i
+
+pcap-common.s: pcap-common.c.s
+
+.PHONY : pcap-common.s
+
+# target to generate assembly for a file
+pcap-common.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.s
+.PHONY : pcap-common.c.s
+
+pcap-linux.o: pcap-linux.c.o
+
+.PHONY : pcap-linux.o
+
+# target to build an object file
+pcap-linux.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.o
+.PHONY : pcap-linux.c.o
+
+pcap-linux.i: pcap-linux.c.i
+
+.PHONY : pcap-linux.i
+
+# target to preprocess a source file
+pcap-linux.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.i
+.PHONY : pcap-linux.c.i
+
+pcap-linux.s: pcap-linux.c.s
+
+.PHONY : pcap-linux.s
+
+# target to generate assembly for a file
+pcap-linux.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.s
+.PHONY : pcap-linux.c.s
+
+pcap-netfilter-linux.o: pcap-netfilter-linux.c.o
+
+.PHONY : pcap-netfilter-linux.o
+
+# target to build an object file
+pcap-netfilter-linux.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.o
+.PHONY : pcap-netfilter-linux.c.o
+
+pcap-netfilter-linux.i: pcap-netfilter-linux.c.i
+
+.PHONY : pcap-netfilter-linux.i
+
+# target to preprocess a source file
+pcap-netfilter-linux.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.i
+.PHONY : pcap-netfilter-linux.c.i
+
+pcap-netfilter-linux.s: pcap-netfilter-linux.c.s
+
+.PHONY : pcap-netfilter-linux.s
+
+# target to generate assembly for a file
+pcap-netfilter-linux.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.s
+.PHONY : pcap-netfilter-linux.c.s
+
+pcap-usb-linux.o: pcap-usb-linux.c.o
+
+.PHONY : pcap-usb-linux.o
+
+# target to build an object file
+pcap-usb-linux.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.o
+.PHONY : pcap-usb-linux.c.o
+
+pcap-usb-linux.i: pcap-usb-linux.c.i
+
+.PHONY : pcap-usb-linux.i
+
+# target to preprocess a source file
+pcap-usb-linux.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.i
+.PHONY : pcap-usb-linux.c.i
+
+pcap-usb-linux.s: pcap-usb-linux.c.s
+
+.PHONY : pcap-usb-linux.s
+
+# target to generate assembly for a file
+pcap-usb-linux.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.s
+.PHONY : pcap-usb-linux.c.s
+
+pcap.o: pcap.c.o
+
+.PHONY : pcap.o
+
+# target to build an object file
+pcap.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.o
+.PHONY : pcap.c.o
+
+pcap.i: pcap.c.i
+
+.PHONY : pcap.i
+
+# target to preprocess a source file
+pcap.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.i
+.PHONY : pcap.c.i
+
+pcap.s: pcap.c.s
+
+.PHONY : pcap.s
+
+# target to generate assembly for a file
+pcap.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.s
+.PHONY : pcap.c.s
+
+savefile.o: savefile.c.o
+
+.PHONY : savefile.o
+
+# target to build an object file
+savefile.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.o
+.PHONY : savefile.c.o
+
+savefile.i: savefile.c.i
+
+.PHONY : savefile.i
+
+# target to preprocess a source file
+savefile.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.i
+.PHONY : savefile.c.i
+
+savefile.s: savefile.c.s
+
+.PHONY : savefile.s
+
+# target to generate assembly for a file
+savefile.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.s
+.PHONY : savefile.c.s
+
+scanner.o: scanner.c.o
+
+.PHONY : scanner.o
+
+# target to build an object file
+scanner.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.o
+.PHONY : scanner.c.o
+
+scanner.i: scanner.c.i
+
+.PHONY : scanner.i
+
+# target to preprocess a source file
+scanner.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.i
+.PHONY : scanner.c.i
+
+scanner.s: scanner.c.s
+
+.PHONY : scanner.s
+
+# target to generate assembly for a file
+scanner.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.s
+.PHONY : scanner.c.s
+
+sf-pcap.o: sf-pcap.c.o
+
+.PHONY : sf-pcap.o
+
+# target to build an object file
+sf-pcap.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.o
+.PHONY : sf-pcap.c.o
+
+sf-pcap.i: sf-pcap.c.i
+
+.PHONY : sf-pcap.i
+
+# target to preprocess a source file
+sf-pcap.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.i
+.PHONY : sf-pcap.c.i
+
+sf-pcap.s: sf-pcap.c.s
+
+.PHONY : sf-pcap.s
+
+# target to generate assembly for a file
+sf-pcap.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.s
+.PHONY : sf-pcap.c.s
+
+sf-pcapng.o: sf-pcapng.c.o
+
+.PHONY : sf-pcapng.o
+
+# target to build an object file
+sf-pcapng.c.o:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.o
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.o
+.PHONY : sf-pcapng.c.o
+
+sf-pcapng.i: sf-pcapng.c.i
+
+.PHONY : sf-pcapng.i
+
+# target to preprocess a source file
+sf-pcapng.c.i:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.i
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.i
+.PHONY : sf-pcapng.c.i
+
+sf-pcapng.s: sf-pcapng.c.s
+
+.PHONY : sf-pcapng.s
+
+# target to generate assembly for a file
+sf-pcapng.c.s:
+	$(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.s
+	$(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.s
+.PHONY : sf-pcapng.c.s
+
+# Help Target
+help:
+	@echo "The following are some of the valid targets for this Makefile:"
+	@echo "... all (the default if no target is provided)"
+	@echo "... clean"
+	@echo "... depend"
+	@echo "... install/strip"
+	@echo "... install/local"
+	@echo "... install"
+	@echo "... list_install_components"
+	@echo "... rebuild_cache"
+	@echo "... edit_cache"
+	@echo "... pcap"
+	@echo "... uninstall"
+	@echo "... pcap_static"
+	@echo "... SerializeTarget"
+	@echo "... testprogs"
+	@echo "... capturetest"
+	@echo "... findalldevstest"
+	@echo "... filtertest"
+	@echo "... findalldevstest-perf"
+	@echo "... can_set_rfmon_test"
+	@echo "... opentest"
+	@echo "... reactivatetest"
+	@echo "... writecaptest"
+	@echo "... selpolltest"
+	@echo "... threadsignaltest"
+	@echo "... valgrindtest"
+	@echo "... fuzz_both"
+	@echo "... fuzz_filter"
+	@echo "... fuzz_pcap"
+	@echo "... bpf_dump.o"
+	@echo "... bpf_dump.i"
+	@echo "... bpf_dump.s"
+	@echo "... bpf_filter.o"
+	@echo "... bpf_filter.i"
+	@echo "... bpf_filter.s"
+	@echo "... bpf_image.o"
+	@echo "... bpf_image.i"
+	@echo "... bpf_image.s"
+	@echo "... etherent.o"
+	@echo "... etherent.i"
+	@echo "... etherent.s"
+	@echo "... fad-getad.o"
+	@echo "... fad-getad.i"
+	@echo "... fad-getad.s"
+	@echo "... fmtutils.o"
+	@echo "... fmtutils.i"
+	@echo "... fmtutils.s"
+	@echo "... gencode.o"
+	@echo "... gencode.i"
+	@echo "... gencode.s"
+	@echo "... grammar.o"
+	@echo "... grammar.i"
+	@echo "... grammar.s"
+	@echo "... missing/strlcat.o"
+	@echo "... missing/strlcat.i"
+	@echo "... missing/strlcat.s"
+	@echo "... missing/strlcpy.o"
+	@echo "... missing/strlcpy.i"
+	@echo "... missing/strlcpy.s"
+	@echo "... nametoaddr.o"
+	@echo "... nametoaddr.i"
+	@echo "... nametoaddr.s"
+	@echo "... optimize.o"
+	@echo "... optimize.i"
+	@echo "... optimize.s"
+	@echo "... pcap-common.o"
+	@echo "... pcap-common.i"
+	@echo "... pcap-common.s"
+	@echo "... pcap-linux.o"
+	@echo "... pcap-linux.i"
+	@echo "... pcap-linux.s"
+	@echo "... pcap-netfilter-linux.o"
+	@echo "... pcap-netfilter-linux.i"
+	@echo "... pcap-netfilter-linux.s"
+	@echo "... pcap-usb-linux.o"
+	@echo "... pcap-usb-linux.i"
+	@echo "... pcap-usb-linux.s"
+	@echo "... pcap.o"
+	@echo "... pcap.i"
+	@echo "... pcap.s"
+	@echo "... savefile.o"
+	@echo "... savefile.i"
+	@echo "... savefile.s"
+	@echo "... scanner.o"
+	@echo "... scanner.i"
+	@echo "... scanner.s"
+	@echo "... sf-pcap.o"
+	@echo "... sf-pcap.i"
+	@echo "... sf-pcap.s"
+	@echo "... sf-pcapng.o"
+	@echo "... sf-pcapng.i"
+	@echo "... sf-pcapng.s"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c
new file mode 100644
index 00000000..059d438d
--- /dev/null
+++ b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c
@@ -0,0 +1,97 @@
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__x86_64__)
+
+struct x86_64_regs {
+
+  uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
+      r15;
+
+  union {
+
+    uint64_t rip;
+    uint64_t pc;
+
+  };
+
+  union {
+
+    uint64_t rsp;
+    uint64_t sp;
+
+  };
+
+  union {
+
+    uint64_t rflags;
+    uint64_t flags;
+
+  };
+
+  uint8_t zmm_regs[32][64];
+
+};
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  memcpy((void *)regs->rdi, input_buf, input_buf_len);
+  regs->rsi = input_buf_len;
+
+}
+
+#elif defined(__i386__)
+
+struct x86_regs {
+
+  uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
+
+  union {
+
+    uint32_t eip;
+    uint32_t pc;
+
+  };
+
+  union {
+
+    uint32_t esp;
+    uint32_t sp;
+
+  };
+
+  union {
+
+    uint32_t eflags;
+    uint32_t flags;
+
+  };
+
+  uint8_t xmm_regs[8][16];
+
+};
+
+void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  void **esp = (void **)regs->esp;
+  void * arg1 = esp[1];
+  void **arg2 = &esp[2];
+  memcpy(arg1, input_buf, input_buf_len);
+  *arg2 = (void *)input_buf_len;
+
+}
+
+#else
+  #pragma error "Unsupported architecture"
+#endif
+
+int afl_persistent_hook_init(void) {
+
+  // 1 for shared memory input (faster), 0 for normal input (you have to use
+  // read(), input_buf will be NULL)
+  return 1;
+
+}
+
diff --git a/frida_mode/test/libpcap/get_symbol_addr.py b/frida_mode/test/libpcap/get_symbol_addr.py
new file mode 100755
index 00000000..1c46e010
--- /dev/null
+++ b/frida_mode/test/libpcap/get_symbol_addr.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+def process_file(file, symbol, base):
+    with open(file, 'rb') as f:
+        elf = ELFFile(f)
+        symtab = elf.get_section_by_name('.symtab')
+        mains = symtab.get_symbol_by_name(symbol)
+        if len(mains) != 1:
+            print ("Failed to find main")
+            return 1
+
+        main_addr = mains[0]['st_value']
+        main = base + main_addr
+        print ("0x%016x" % main)
+        return 0
+
+def hex_value(x):
+    return int(x, 16)
+
+def main():
+    parser = argparse.ArgumentParser(description='Process some integers.')
+    parser.add_argument('-f', '--file', dest='file', type=str,
+                    help='elf file name', required=True)
+    parser.add_argument('-s', '--symbol', dest='symbol', type=str,
+                    help='symbol name', required=True)
+    parser.add_argument('-b', '--base', dest='base', type=hex_value,
+                    help='elf base address', required=True)
+
+    args = parser.parse_args()
+    return process_file (args.file, args.symbol, args.base)
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)
diff --git a/frida_mode/test/output/GNUmakefile b/frida_mode/test/output/GNUmakefile
new file mode 100644
index 00000000..eaa1c4dc
--- /dev/null
+++ b/frida_mode/test/output/GNUmakefile
@@ -0,0 +1,47 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+.PHONY: all 32 clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	AFL_FRIDA_OUTPUT_STDOUT=frida_stdout.txt \
+	AFL_FRIDA_OUTPUT_STDERR=frida_stderr.txt \
+	AFL_FRIDA_STATS_FILE=frida_stats.txt \
+	AFL_FRIDA_STATS_INTERVAL=1 \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
diff --git a/frida_mode/test/output/Makefile b/frida_mode/test/output/Makefile
new file mode 100644
index 00000000..07b139e9
--- /dev/null
+++ b/frida_mode/test/output/Makefile
@@ -0,0 +1,13 @@
+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
diff --git a/frida_mode/test/output/frida_stderr.txt b/frida_mode/test/output/frida_stderr.txt
new file mode 100644
index 00000000..103216cf
--- /dev/null
+++ b/frida_mode/test/output/frida_stderr.txt
@@ -0,0 +1,2824 @@
+
+
+total_transitions: 9
+	call_imms: 1
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 1
+	jmp_mems: 2
+	jmp_regs: 0
+
+	jmp_cond_imms: 2
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 19
+	call_imms: 4
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 2
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 1
+	jmp_mems: 3
+	jmp_regs: 0
+
+	jmp_cond_imms: 6
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 29
+	call_imms: 6
+	call_regs: 1
+	call_mems: 0
+	post_call_invokes: 3
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 2
+	jmp_mems: 3
+	jmp_regs: 0
+
+	jmp_cond_imms: 11
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 39
+	call_imms: 6
+	call_regs: 2
+	call_mems: 0
+	post_call_invokes: 5
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 2
+	jmp_mems: 3
+	jmp_regs: 0
+
+	jmp_cond_imms: 18
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 49
+	call_imms: 7
+	call_regs: 2
+	call_mems: 1
+	post_call_invokes: 6
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 2
+	jmp_mems: 3
+	jmp_regs: 0
+
+	jmp_cond_imms: 25
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 59
+	call_imms: 8
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 6
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 3
+	jmp_mems: 3
+	jmp_regs: 0
+
+	jmp_cond_imms: 31
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 69
+	call_imms: 9
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 7
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 3
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 38
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 79
+	call_imms: 10
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 7
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 4
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 46
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 89
+	call_imms: 10
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 7
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 4
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 56
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 99
+	call_imms: 11
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 9
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 4
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 63
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 109
+	call_imms: 12
+	call_regs: 2
+	call_mems: 3
+	post_call_invokes: 12
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 5
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 68
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 119
+	call_imms: 12
+	call_regs: 2
+	call_mems: 4
+	post_call_invokes: 14
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 6
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 74
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 129
+	call_imms: 14
+	call_regs: 2
+	call_mems: 4
+	post_call_invokes: 16
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 6
+	jmp_mems: 4
+	jmp_regs: 0
+
+	jmp_cond_imms: 80
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 139
+	call_imms: 14
+	call_regs: 2
+	call_mems: 5
+	post_call_invokes: 17
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 6
+	jmp_mems: 5
+	jmp_regs: 0
+
+	jmp_cond_imms: 87
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 149
+	call_imms: 14
+	call_regs: 2
+	call_mems: 6
+	post_call_invokes: 17
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 6
+	jmp_mems: 5
+	jmp_regs: 0
+
+	jmp_cond_imms: 96
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 159
+	call_imms: 15
+	call_regs: 2
+	call_mems: 6
+	post_call_invokes: 18
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 8
+	jmp_mems: 5
+	jmp_regs: 0
+
+	jmp_cond_imms: 102
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 170
+	call_imms: 15
+	call_regs: 2
+	call_mems: 6
+	post_call_invokes: 18
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 10
+	jmp_mems: 5
+	jmp_regs: 0
+
+	jmp_cond_imms: 111
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 180
+	call_imms: 15
+	call_regs: 2
+	call_mems: 6
+	post_call_invokes: 20
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 11
+	jmp_mems: 5
+	jmp_regs: 0
+
+	jmp_cond_imms: 118
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 190
+	call_imms: 16
+	call_regs: 2
+	call_mems: 6
+	post_call_invokes: 20
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 11
+	jmp_mems: 6
+	jmp_regs: 1
+
+	jmp_cond_imms: 125
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 201
+	call_imms: 16
+	call_regs: 2
+	call_mems: 7
+	post_call_invokes: 21
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 13
+	jmp_mems: 6
+	jmp_regs: 1
+
+	jmp_cond_imms: 132
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 211
+	call_imms: 17
+	call_regs: 2
+	call_mems: 7
+	post_call_invokes: 22
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 14
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 138
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 223
+	call_imms: 18
+	call_regs: 2
+	call_mems: 8
+	post_call_invokes: 24
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 15
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 145
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 233
+	call_imms: 18
+	call_regs: 2
+	call_mems: 8
+	post_call_invokes: 25
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 16
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 153
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 244
+	call_imms: 19
+	call_regs: 2
+	call_mems: 9
+	post_call_invokes: 26
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 16
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 161
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+
+
+total_transitions: 254
+	call_imms: 20
+	call_regs: 2
+	call_mems: 9
+	post_call_invokes: 27
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 18
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 167
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 264
+	call_imms: 20
+	call_regs: 2
+	call_mems: 9
+	post_call_invokes: 29
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 20
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 173
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 275
+	call_imms: 21
+	call_regs: 2
+	call_mems: 10
+	post_call_invokes: 30
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 22
+	jmp_mems: 7
+	jmp_regs: 1
+
+	jmp_cond_imms: 179
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 285
+	call_imms: 22
+	call_regs: 2
+	call_mems: 10
+	post_call_invokes: 30
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 23
+	jmp_mems: 8
+	jmp_regs: 1
+
+	jmp_cond_imms: 186
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 295
+	call_imms: 22
+	call_regs: 2
+	call_mems: 10
+	post_call_invokes: 30
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 23
+	jmp_mems: 8
+	jmp_regs: 1
+
+	jmp_cond_imms: 196
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 305
+	call_imms: 22
+	call_regs: 2
+	call_mems: 10
+	post_call_invokes: 30
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 24
+	jmp_mems: 8
+	jmp_regs: 1
+
+	jmp_cond_imms: 205
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 315
+	call_imms: 22
+	call_regs: 2
+	call_mems: 10
+	post_call_invokes: 31
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 26
+	jmp_mems: 8
+	jmp_regs: 1
+
+	jmp_cond_imms: 212
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 326
+	call_imms: 22
+	call_regs: 3
+	call_mems: 10
+	post_call_invokes: 32
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 27
+	jmp_mems: 8
+	jmp_regs: 1
+
+	jmp_cond_imms: 220
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 337
+	call_imms: 23
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 36
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 27
+	jmp_mems: 9
+	jmp_regs: 1
+
+	jmp_cond_imms: 224
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 348
+	call_imms: 24
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 38
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 27
+	jmp_mems: 10
+	jmp_regs: 1
+
+	jmp_cond_imms: 231
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 362
+	call_imms: 26
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 39
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 28
+	jmp_mems: 11
+	jmp_regs: 1
+
+	jmp_cond_imms: 240
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 375
+	call_imms: 27
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 40
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 28
+	jmp_mems: 12
+	jmp_regs: 1
+
+	jmp_cond_imms: 250
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 387
+	call_imms: 28
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 41
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 28
+	jmp_mems: 12
+	jmp_regs: 3
+
+	jmp_cond_imms: 258
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 397
+	call_imms: 29
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 42
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 30
+	jmp_mems: 12
+	jmp_regs: 3
+
+	jmp_cond_imms: 264
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 407
+	call_imms: 29
+	call_regs: 4
+	call_mems: 10
+	post_call_invokes: 42
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 31
+	jmp_mems: 12
+	jmp_regs: 3
+
+	jmp_cond_imms: 273
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 418
+	call_imms: 29
+	call_regs: 4
+	call_mems: 11
+	post_call_invokes: 43
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 32
+	jmp_mems: 12
+	jmp_regs: 3
+
+	jmp_cond_imms: 281
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+
+
+total_transitions: 430
+	call_imms: 32
+	call_regs: 4
+	call_mems: 11
+	post_call_invokes: 45
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 33
+	jmp_mems: 13
+	jmp_regs: 3
+
+	jmp_cond_imms: 286
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 441
+	call_imms: 32
+	call_regs: 4
+	call_mems: 12
+	post_call_invokes: 46
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 33
+	jmp_mems: 13
+	jmp_regs: 3
+
+	jmp_cond_imms: 295
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+
+
+total_transitions: 453
+	call_imms: 33
+	call_regs: 4
+	call_mems: 12
+	post_call_invokes: 49
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 34
+	jmp_mems: 13
+	jmp_regs: 3
+
+	jmp_cond_imms: 302
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 465
+	call_imms: 35
+	call_regs: 4
+	call_mems: 12
+	post_call_invokes: 50
+	excluded_call_imms: 2
+	ret_slow_paths: 1
+
+	jmp_imms: 35
+	jmp_mems: 15
+	jmp_regs: 3
+
+	jmp_cond_imms: 308
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 475
+	call_imms: 38
+	call_regs: 4
+	call_mems: 12
+	post_call_invokes: 51
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 35
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 310
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 485
+	call_imms: 38
+	call_regs: 5
+	call_mems: 12
+	post_call_invokes: 52
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 36
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 317
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 495
+	call_imms: 38
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 52
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 38
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 324
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 506
+	call_imms: 38
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 53
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 39
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 333
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 516
+	call_imms: 40
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 53
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 40
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 340
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 526
+	call_imms: 40
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 54
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 40
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 349
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 540
+	call_imms: 42
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 55
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 42
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 358
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 552
+	call_imms: 43
+	call_regs: 5
+	call_mems: 13
+	post_call_invokes: 57
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 43
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 366
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 563
+	call_imms: 43
+	call_regs: 5
+	call_mems: 14
+	post_call_invokes: 58
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 43
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 375
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 573
+	call_imms: 43
+	call_regs: 5
+	call_mems: 15
+	post_call_invokes: 59
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 44
+	jmp_mems: 16
+	jmp_regs: 3
+
+	jmp_cond_imms: 382
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 583
+	call_imms: 44
+	call_regs: 5
+	call_mems: 15
+	post_call_invokes: 59
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 45
+	jmp_mems: 17
+	jmp_regs: 3
+
+	jmp_cond_imms: 389
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 593
+	call_imms: 45
+	call_regs: 5
+	call_mems: 15
+	post_call_invokes: 60
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 46
+	jmp_mems: 17
+	jmp_regs: 3
+
+	jmp_cond_imms: 396
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 603
+	call_imms: 46
+	call_regs: 6
+	call_mems: 15
+	post_call_invokes: 64
+	excluded_call_imms: 3
+	ret_slow_paths: 3
+
+	jmp_imms: 46
+	jmp_mems: 17
+	jmp_regs: 3
+
+	jmp_cond_imms: 400
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 615
+	call_imms: 46
+	call_regs: 7
+	call_mems: 17
+	post_call_invokes: 64
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 46
+	jmp_mems: 17
+	jmp_regs: 3
+
+	jmp_cond_imms: 407
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 626
+	call_imms: 48
+	call_regs: 8
+	call_mems: 18
+	post_call_invokes: 66
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 46
+	jmp_mems: 18
+	jmp_regs: 3
+
+	jmp_cond_imms: 411
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 637
+	call_imms: 50
+	call_regs: 9
+	call_mems: 19
+	post_call_invokes: 68
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 47
+	jmp_mems: 19
+	jmp_regs: 3
+
+	jmp_cond_imms: 414
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 648
+	call_imms: 52
+	call_regs: 9
+	call_mems: 20
+	post_call_invokes: 70
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 47
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 419
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 660
+	call_imms: 52
+	call_regs: 10
+	call_mems: 20
+	post_call_invokes: 72
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 49
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 426
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 672
+	call_imms: 52
+	call_regs: 10
+	call_mems: 20
+	post_call_invokes: 72
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 51
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 436
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 683
+	call_imms: 53
+	call_regs: 11
+	call_mems: 21
+	post_call_invokes: 73
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 52
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 442
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 697
+	call_imms: 53
+	call_regs: 11
+	call_mems: 22
+	post_call_invokes: 74
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 53
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 453
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 709
+	call_imms: 53
+	call_regs: 13
+	call_mems: 22
+	post_call_invokes: 77
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 53
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 460
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 720
+	call_imms: 53
+	call_regs: 13
+	call_mems: 22
+	post_call_invokes: 77
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 55
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 469
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 730
+	call_imms: 54
+	call_regs: 13
+	call_mems: 24
+	post_call_invokes: 77
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 56
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 475
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 740
+	call_imms: 54
+	call_regs: 13
+	call_mems: 24
+	post_call_invokes: 80
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 57
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 481
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 753
+	call_imms: 54
+	call_regs: 14
+	call_mems: 24
+	post_call_invokes: 81
+	excluded_call_imms: 5
+	ret_slow_paths: 3
+
+	jmp_imms: 58
+	jmp_mems: 20
+	jmp_regs: 3
+
+	jmp_cond_imms: 491
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+
+
+total_transitions: 3
+	call_imms: 0
+	call_regs: 0
+	call_mems: 0
+	post_call_invokes: 0
+	excluded_call_imms: 0
+	ret_slow_paths: 0
+
+	jmp_imms: 1
+	jmp_mems: 1
+	jmp_regs: 0
+
+	jmp_cond_imms: 1
+	jmp_cond_mems: 0
+	jmp_cond_regs: 0
+	jmp_cond_jcxzs: 0
+
+	jmp_continuations: 0
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input
+Running:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
+Done:    /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes)
diff --git a/frida_mode/test/output/frida_stdout.txt b/frida_mode/test/output/frida_stdout.txt
new file mode 100644
index 00000000..8832681d
--- /dev/null
+++ b/frida_mode/test/output/frida_stdout.txt
@@ -0,0 +1,349 @@
+OG Range - 0x00007FFFF7FFE000 - 0x00007FFFF7FFF000
+[+] CMPLOG Range - 0x00007FFFF7FFD000 - 0x00007FFFF7FFE000
+[+] CMPLOG Range - 0x00007FFFF7FFC000 - 0x00007FFFF7FFD000
+[+] CMPLOG Range - 0x00007FFFF7FF3000 - 0x00007FFFF7FFB000
+[+] CMPLOG Range - 0x00007FFFF7FD0000 - 0x00007FFFF7FF3000
+[+] CMPLOG Range - 0x00007FFFF7FCF000 - 0x00007FFFF7FD0000
+[+] CMPLOG Range - 0x00007FFFF7FCE000 - 0x00007FFFF7FCF000
+[+] CMPLOG Range - 0x00007FFFF7FCB000 - 0x00007FFFF7FCE000
+[+] CMPLOG Range - 0x00007FFFF7DC4000 - 0x00007FFFF7FCB000
+[+] CMPLOG Range - 0x00007FFFF7DBC000 - 0x00007FFFF7DC4000
+[+] CMPLOG Range - 0x00007FFFF7DB0000 - 0x00007FFFF7DBC000
+[+] CMPLOG Range - 0x00007FFFF7A94000 - 0x00007FFFF7DB0000
+[+] CMPLOG Range - 0x00007FFFF7942000 - 0x00007FFFF7A94000
+[+] CMPLOG Range - 0x00007FFFF78BF000 - 0x00007FFFF7942000
+[+] CMPLOG Range - 0x00007FFFF78AF000 - 0x00007FFFF78BF000
+[+] CMPLOG Range - 0x00007FFFF78AA000 - 0x00007FFFF78AB000
+[+] CMPLOG Range - 0x00007FFFF78A9000 - 0x00007FFFF78AA000
+[+] CMPLOG Range - 0x00007FFFF78A2000 - 0x00007FFFF78A6000
+[+] CMPLOG Range - 0x00007FFFF789F000 - 0x00007FFFF78A2000
+[+] CMPLOG Range - 0x00007FFFF789C000 - 0x00007FFFF789F000
+[+] CMPLOG Range - 0x00007FFFF7851000 - 0x00007FFFF789B000
+[+] CMPLOG Range - 0x00007FFFF76DB000 - 0x00007FFFF7851000
+[+] CMPLOG Range - 0x00007FFFF76DA000 - 0x00007FFFF76DB000
+[+] CMPLOG Range - 0x00007FFFF76D9000 - 0x00007FFFF76DA000
+[+] CMPLOG Range - 0x00007FFFF76B4000 - 0x00007FFFF76D9000
+[+] CMPLOG Range - 0x00007FFFF76B0000 - 0x00007FFFF76B4000
+[+] CMPLOG Range - 0x00007FFFF76AF000 - 0x00007FFFF76B0000
+[+] CMPLOG Range - 0x00007FFFF76AE000 - 0x00007FFFF76AF000
+[+] CMPLOG Range - 0x00007FFFF76A9000 - 0x00007FFFF76AE000
+[+] CMPLOG Range - 0x00007FFFF7698000 - 0x00007FFFF76A9000
+[+] CMPLOG Range - 0x00007FFFF7691000 - 0x00007FFFF7698000
+[+] CMPLOG Range - 0x00007FFFF768F000 - 0x00007FFFF7691000
+[+] CMPLOG Range - 0x00007FFFF768E000 - 0x00007FFFF768F000
+[+] CMPLOG Range - 0x00007FFFF768D000 - 0x00007FFFF768E000
+[+] CMPLOG Range - 0x00007FFFF7689000 - 0x00007FFFF768C000
+[+] CMPLOG Range - 0x00007FFFF7679000 - 0x00007FFFF7689000
+[+] CMPLOG Range - 0x00007FFFF7675000 - 0x00007FFFF7679000
+[+] CMPLOG Range - 0x00007FFFF7674000 - 0x00007FFFF7675000
+[+] CMPLOG Range - 0x00007FFFF7673000 - 0x00007FFFF7674000
+[+] CMPLOG Range - 0x00007FFFF7672000 - 0x00007FFFF7673000
+[+] CMPLOG Range - 0x00007FFFF7670000 - 0x00007FFFF7672000
+[+] CMPLOG Range - 0x00007FFFF766F000 - 0x00007FFFF7670000
+[+] CMPLOG Range - 0x00007FFFF766D000 - 0x00007FFFF766F000
+[+] Redirect 1 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stdout.txt'
+[+] Redirect 2 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stderr.txt'
+[+] Instrumentation - persistent mode [ ] (0x0000000000000000)
+[+] Instrumentation - persistent count [ ] (0)
+[+] Instrumentation - hook [(null)]
+[+] Instrumentation - persistent ret [ ] (0x0000000000000000)
+[+] Instrumentation - persistent ret offset [ ] (0)
+[+] Instrumentation - prefetch [X]
+[+] Range: Modules Length: 54
+[+] Range: Modules Idx:   0 - 0x0000555555554000-0x0000555555555000
+[+] Range: Modules Idx:   1 - 0x0000555555555000-0x0000555555556000
+[+] Range: Modules Idx:   2 - 0x0000555555556000-0x0000555555557000
+[+] Range: Modules Idx:   3 - 0x0000555555557000-0x0000555555558000
+[+] Range: Modules Idx:   4 - 0x0000555555558000-0x0000555555559000
+[+] Range: Modules Idx:   5 - 0x0000555555559000-0x000055555557a000
+[+] Range: Modules Idx:   6 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: Modules Idx:   7 - 0x00007ffff766d000-0x00007ffff766f000
+[+] Range: Modules Idx:   8 - 0x00007ffff766f000-0x00007ffff7670000
+[+] Range: Modules Idx:   9 - 0x00007ffff7670000-0x00007ffff7672000
+[+] Range: Modules Idx:  10 - 0x00007ffff7672000-0x00007ffff7673000
+[+] Range: Modules Idx:  11 - 0x00007ffff7673000-0x00007ffff7674000
+[+] Range: Modules Idx:  12 - 0x00007ffff7674000-0x00007ffff7675000
+[+] Range: Modules Idx:  13 - 0x00007ffff7675000-0x00007ffff7679000
+[+] Range: Modules Idx:  14 - 0x00007ffff7679000-0x00007ffff7689000
+[+] Range: Modules Idx:  15 - 0x00007ffff7689000-0x00007ffff768c000
+[+] Range: Modules Idx:  16 - 0x00007ffff768c000-0x00007ffff768d000
+[+] Range: Modules Idx:  17 - 0x00007ffff768d000-0x00007ffff768e000
+[+] Range: Modules Idx:  18 - 0x00007ffff768e000-0x00007ffff768f000
+[+] Range: Modules Idx:  19 - 0x00007ffff768f000-0x00007ffff7691000
+[+] Range: Modules Idx:  20 - 0x00007ffff7691000-0x00007ffff7698000
+[+] Range: Modules Idx:  21 - 0x00007ffff7698000-0x00007ffff76a9000
+[+] Range: Modules Idx:  22 - 0x00007ffff76a9000-0x00007ffff76ae000
+[+] Range: Modules Idx:  23 - 0x00007ffff76ae000-0x00007ffff76af000
+[+] Range: Modules Idx:  24 - 0x00007ffff76af000-0x00007ffff76b0000
+[+] Range: Modules Idx:  25 - 0x00007ffff76b0000-0x00007ffff76b4000
+[+] Range: Modules Idx:  26 - 0x00007ffff76b4000-0x00007ffff76d9000
+[+] Range: Modules Idx:  27 - 0x00007ffff76d9000-0x00007ffff76da000
+[+] Range: Modules Idx:  28 - 0x00007ffff76da000-0x00007ffff76db000
+[+] Range: Modules Idx:  29 - 0x00007ffff76db000-0x00007ffff7851000
+[+] Range: Modules Idx:  30 - 0x00007ffff7851000-0x00007ffff789b000
+[+] Range: Modules Idx:  31 - 0x00007ffff789b000-0x00007ffff789c000
+[+] Range: Modules Idx:  32 - 0x00007ffff789c000-0x00007ffff789f000
+[+] Range: Modules Idx:  33 - 0x00007ffff789f000-0x00007ffff78a2000
+[+] Range: Modules Idx:  34 - 0x00007ffff78a2000-0x00007ffff78a6000
+[+] Range: Modules Idx:  35 - 0x00007ffff78a9000-0x00007ffff78aa000
+[+] Range: Modules Idx:  36 - 0x00007ffff78aa000-0x00007ffff78ab000
+[+] Range: Modules Idx:  37 - 0x00007ffff78af000-0x00007ffff78bf000
+[+] Range: Modules Idx:  38 - 0x00007ffff78bf000-0x00007ffff7942000
+[+] Range: Modules Idx:  39 - 0x00007ffff7942000-0x00007ffff7a94000
+[+] Range: Modules Idx:  40 - 0x00007ffff7a94000-0x00007ffff7db0000
+[+] Range: Modules Idx:  41 - 0x00007ffff7db0000-0x00007ffff7dbc000
+[+] Range: Modules Idx:  42 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: Modules Idx:  43 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: Modules Idx:  44 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: Modules Idx:  45 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: Modules Idx:  46 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: Modules Idx:  47 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: Modules Idx:  48 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: Modules Idx:  49 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: Modules Idx:  50 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: Modules Idx:  51 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: Modules Idx:  52 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: Modules Idx:  53 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: AFL_INST_LIBS Length: 1
+[+] Range: AFL_INST_LIBS Idx:   0 - 0x0000555555555160-0x0000555555555335
+[+] Range: step1 Length: 1
+[+] Range: step1 Idx:   0 - 0x0000555555555160-0x0000555555555335
+[+] Range: step2 Length: 1
+[+] Range: step2 Idx:   0 - 0x0000555555555160-0x0000555555555335
+[+] Range: step3 Length: 1
+[+] Range: step3 Idx:   0 - 0x0000555555555160-0x0000555555555335
+[+] Range: step4 Length: 55
+[+] Range: step4 Idx:   0 - 0x0000555555554000-0x0000555555555000
+[+] Range: step4 Idx:   1 - 0x0000555555555000-0x0000555555555160
+[+] Range: step4 Idx:   2 - 0x0000555555555335-0x0000555555556000
+[+] Range: step4 Idx:   3 - 0x0000555555556000-0x0000555555557000
+[+] Range: step4 Idx:   4 - 0x0000555555557000-0x0000555555558000
+[+] Range: step4 Idx:   5 - 0x0000555555558000-0x0000555555559000
+[+] Range: step4 Idx:   6 - 0x0000555555559000-0x000055555557a000
+[+] Range: step4 Idx:   7 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: step4 Idx:   8 - 0x00007ffff766d000-0x00007ffff766f000
+[+] Range: step4 Idx:   9 - 0x00007ffff766f000-0x00007ffff7670000
+[+] Range: step4 Idx:  10 - 0x00007ffff7670000-0x00007ffff7672000
+[+] Range: step4 Idx:  11 - 0x00007ffff7672000-0x00007ffff7673000
+[+] Range: step4 Idx:  12 - 0x00007ffff7673000-0x00007ffff7674000
+[+] Range: step4 Idx:  13 - 0x00007ffff7674000-0x00007ffff7675000
+[+] Range: step4 Idx:  14 - 0x00007ffff7675000-0x00007ffff7679000
+[+] Range: step4 Idx:  15 - 0x00007ffff7679000-0x00007ffff7689000
+[+] Range: step4 Idx:  16 - 0x00007ffff7689000-0x00007ffff768c000
+[+] Range: step4 Idx:  17 - 0x00007ffff768c000-0x00007ffff768d000
+[+] Range: step4 Idx:  18 - 0x00007ffff768d000-0x00007ffff768e000
+[+] Range: step4 Idx:  19 - 0x00007ffff768e000-0x00007ffff768f000
+[+] Range: step4 Idx:  20 - 0x00007ffff768f000-0x00007ffff7691000
+[+] Range: step4 Idx:  21 - 0x00007ffff7691000-0x00007ffff7698000
+[+] Range: step4 Idx:  22 - 0x00007ffff7698000-0x00007ffff76a9000
+[+] Range: step4 Idx:  23 - 0x00007ffff76a9000-0x00007ffff76ae000
+[+] Range: step4 Idx:  24 - 0x00007ffff76ae000-0x00007ffff76af000
+[+] Range: step4 Idx:  25 - 0x00007ffff76af000-0x00007ffff76b0000
+[+] Range: step4 Idx:  26 - 0x00007ffff76b0000-0x00007ffff76b4000
+[+] Range: step4 Idx:  27 - 0x00007ffff76b4000-0x00007ffff76d9000
+[+] Range: step4 Idx:  28 - 0x00007ffff76d9000-0x00007ffff76da000
+[+] Range: step4 Idx:  29 - 0x00007ffff76da000-0x00007ffff76db000
+[+] Range: step4 Idx:  30 - 0x00007ffff76db000-0x00007ffff7851000
+[+] Range: step4 Idx:  31 - 0x00007ffff7851000-0x00007ffff789b000
+[+] Range: step4 Idx:  32 - 0x00007ffff789b000-0x00007ffff789c000
+[+] Range: step4 Idx:  33 - 0x00007ffff789c000-0x00007ffff789f000
+[+] Range: step4 Idx:  34 - 0x00007ffff789f000-0x00007ffff78a2000
+[+] Range: step4 Idx:  35 - 0x00007ffff78a2000-0x00007ffff78a6000
+[+] Range: step4 Idx:  36 - 0x00007ffff78a9000-0x00007ffff78aa000
+[+] Range: step4 Idx:  37 - 0x00007ffff78aa000-0x00007ffff78ab000
+[+] Range: step4 Idx:  38 - 0x00007ffff78af000-0x00007ffff78bf000
+[+] Range: step4 Idx:  39 - 0x00007ffff78bf000-0x00007ffff7942000
+[+] Range: step4 Idx:  40 - 0x00007ffff7942000-0x00007ffff7a94000
+[+] Range: step4 Idx:  41 - 0x00007ffff7a94000-0x00007ffff7db0000
+[+] Range: step4 Idx:  42 - 0x00007ffff7db0000-0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
+0x00007ffff7dbc000
+[+] Range: step4 Idx:  43 - 0x00007ffff7dbc000-0x00007ffff7dc4000
+[+] Range: step4 Idx:  44 - 0x00007ffff7dc4000-0x00007ffff7fcb000
+[+] Range: step4 Idx:  45 - 0x00007ffff7fcb000-0x00007ffff7fce000
+[+] Range: step4 Idx:  46 - 0x00007ffff7fce000-0x00007ffff7fcf000
+[+] Range: step4 Idx:  47 - 0x00007ffff7fcf000-0x00007ffff7fd0000
+[+] Range: step4 Idx:  48 - 0x00007ffff7fd0000-0x00007ffff7ff3000
+[+] Range: step4 Idx:  49 - 0x00007ffff7ff3000-0x00007ffff7ffb000
+[+] Range: step4 Idx:  50 - 0x00007ffff7ffc000-0x00007ffff7ffd000
+[+] Range: step4 Idx:  51 - 0x00007ffff7ffd000-0x00007ffff7ffe000
+[+] Range: step4 Idx:  52 - 0x00007ffff7ffe000-0x00007ffff7fff000
+[+] Range: step4 Idx:  53 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: step4 Idx:  54 - 0xffffffffff600000-0xffffffffff601000
+[+] Range: final Length: 9
+[+] Range: final Idx:   0 - 0x0000555555554000-0x0000555555555160
+[+] Range: final Idx:   1 - 0x0000555555555335-0x000055555557a000
+[+] Range: final Idx:   2 - 0x00007ffff7615000-0x00007ffff7625000
+[+] Range: final Idx:   3 - 0x00007ffff766d000-0x00007ffff78a6000
+[+] Range: final Idx:   4 - 0x00007ffff78a9000-0x00007ffff78ab000
+[+] Range: final Idx:   5 - 0x00007ffff78af000-0x00007ffff7ffb000
+[+] Range: final Idx:   6 - 0x00007ffff7ffc000-0x00007ffff7fff000
+[+] Range: final Idx:   7 - 0x00007ffffffdd000-0x00007ffffffff000
+[+] Range: final Idx:   8 - 0xffffffffff600000-0xffffffffff601000
+Looks like a zero to me!
diff --git a/frida_mode/test/output/testinstr.c b/frida_mode/test/output/testinstr.c
new file mode 100644
index 00000000..5e26fc46
--- /dev/null
+++ b/frida_mode/test/output/testinstr.c
@@ -0,0 +1,112 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+TESTINSTR_SECTION 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 = 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);
+
+    testinstr(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/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile
new file mode 100644
index 00000000..df48d065
--- /dev/null
+++ b/frida_mode/test/persistent_ret/GNUmakefile
@@ -0,0 +1,105 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000aaaaaaaaa000)
+ AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000555555554000)
+ AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x56555000)
+ AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000)
+endif
+
+AFL_FRIDA_PERSISTENT_RETADDR_OFFSET:=0x50
+
+.PHONY: all 32 clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \
+	AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+debug: $(TESTINSTR_DATA_FILE)
+	gdb \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET)' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \
+		--ex 'set environment AFL_DEBUG_CHILD=1' \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+
+run: $(TESTINSTR_DATA_FILE)
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \
+	AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \
+	AFL_DEBUG_CHILD=1 \
+	LD_PRELOAD=$(ROOT)afl-frida-trace.so \
+		$(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
diff --git a/frida_mode/test/persistent_ret/Makefile b/frida_mode/test/persistent_ret/Makefile
new file mode 100644
index 00000000..e3deddbd
--- /dev/null
+++ b/frida_mode/test/persistent_ret/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
+
+clean:
+	@gmake clean
+
+frida:
+	@gmake frida
+
+frida_ret:
+	@gmake frida_ret
+
+debug:
+	@gmake debug
+
+run:
+	@gmake run
diff --git a/frida_mode/test/persistent_ret/get_symbol_addr.py b/frida_mode/test/persistent_ret/get_symbol_addr.py
new file mode 100755
index 00000000..1c46e010
--- /dev/null
+++ b/frida_mode/test/persistent_ret/get_symbol_addr.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+def process_file(file, symbol, base):
+    with open(file, 'rb') as f:
+        elf = ELFFile(f)
+        symtab = elf.get_section_by_name('.symtab')
+        mains = symtab.get_symbol_by_name(symbol)
+        if len(mains) != 1:
+            print ("Failed to find main")
+            return 1
+
+        main_addr = mains[0]['st_value']
+        main = base + main_addr
+        print ("0x%016x" % main)
+        return 0
+
+def hex_value(x):
+    return int(x, 16)
+
+def main():
+    parser = argparse.ArgumentParser(description='Process some integers.')
+    parser.add_argument('-f', '--file', dest='file', type=str,
+                    help='elf file name', required=True)
+    parser.add_argument('-s', '--symbol', dest='symbol', type=str,
+                    help='symbol name', required=True)
+    parser.add_argument('-b', '--base', dest='base', type=hex_value,
+                    help='elf base address', required=True)
+
+    args = parser.parse_args()
+    return process_file (args.file, args.symbol, args.base)
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)
diff --git a/frida_mode/test/persistent_ret/testinstr.c b/frida_mode/test/persistent_ret/testinstr.c
new file mode 100644
index 00000000..6cb88a50
--- /dev/null
+++ b/frida_mode/test/persistent_ret/testinstr.c
@@ -0,0 +1,120 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+void slow() {
+
+  usleep(100000);
+
+}
+
+TESTINSTR_SECTION 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 = 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);
+
+    testinstr(buf, len);
+    dprintf(STDERR_FILENO, "Done:    %s: (%zd bytes)\n", file, n_read);
+
+    slow();
+
+    result = 0;
+
+  } while (false);
+
+  if (buf != NULL) { free(buf); }
+
+  if (fd != -1) { close(fd); }
+
+  return result;
+
+}
+
diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile
new file mode 100644
index 00000000..e05bade2
--- /dev/null
+++ b/frida_mode/test/png/GNUmakefile
@@ -0,0 +1,114 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+
+LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/
+HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
+PNGTEST_BUILD_DIR:=$(BUILD_DIR)pngtest/
+
+LIBPNG_FILE:=$(LIBPNG_BUILD_DIR)libpng-1.2.56.tar.gz
+LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz
+LIBPNG_DIR:=$(LIBPNG_BUILD_DIR)libpng-1.2.56/
+LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile
+LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a
+
+HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c
+HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o
+HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c"
+
+PNGTEST_FILE:=$(PNGTEST_BUILD_DIR)target.cc
+PNGTEST_OBJ:=$(PNGTEST_BUILD_DIR)target.o
+PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc"
+
+TEST_BIN:=$(BUILD_DIR)test
+ifeq "$(shell uname)" "Darwin"
+TEST_BIN_LDFLAGS:=-undefined dynamic_lookup
+endif
+
+TEST_DATA_DIR:=$(LIBPNG_DIR)contrib/pngsuite/
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+.PHONY: all clean qemu frida
+
+all: $(TEST_BIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+######### HARNESS ########
+$(HARNESS_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(HARNESS_FILE): | $(HARNESS_BUILD_DIR)
+	wget -O $@ $(HARNESS_URL)
+
+$(HARNESS_OBJ): $(HARNESS_FILE)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -c $<
+
+######### PNGTEST ########
+
+$(PNGTEST_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR)
+	wget -O $@ $(PNGTEST_URL)
+
+$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR)
+	$(CXX) $(CFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $<
+
+######### LIBPNG ########
+
+$(LIBPNG_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(LIBPNG_FILE): | $(LIBPNG_BUILD_DIR)
+	wget -O $@ $(LIBPNG_URL)
+
+$(LIBPNG_DIR): $(LIBPNG_FILE)
+	tar zxvf $(LIBPNG_FILE) -C $(LIBPNG_BUILD_DIR)
+
+$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR)
+	cd $(LIBPNG_DIR) && ./configure
+
+$(LIBPNG_LIB): $(LIBPNG_MAKEFILE)
+	make -C $(LIBPNG_DIR)
+
+######### TEST ########
+
+$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
+	$(CXX) \
+		$(CFLAGS) \
+		$(LDFLAGS) \
+		-o $@ \
+		$(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \
+		-lz \
+		$(TEST_BIN_LDFLAGS) \
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+qemu: $(TEST_BIN)
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) @@
+
+frida: $(TEST_BIN)
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) @@
diff --git a/frida_mode/test/png/Makefile b/frida_mode/test/png/Makefile
new file mode 100644
index 00000000..4bef1ccb
--- /dev/null
+++ b/frida_mode/test/png/Makefile
@@ -0,0 +1,16 @@
+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
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile
new file mode 100644
index 00000000..ca6f0ff2
--- /dev/null
+++ b/frida_mode/test/png/persistent/GNUmakefile
@@ -0,0 +1,98 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../../..)/
+BUILD_DIR:=$(PWD)build/
+
+TEST_BIN:=$(PWD)../build/test
+TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000)
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x56555000)
+endif
+
+.PHONY: all 32 clean qemu qemu_entry frida frida_entry
+
+all:
+	make -C $(ROOT)frida_mode/test/png/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+qemu: | $(BUILD_DIR)
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) @@
+
+qemu_entry: | $(BUILD_DIR)
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) @@
+
+frida: | $(BUILD_DIR)
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) @@
+
+frida_entry: | $(BUILD_DIR)
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) @@
+
+clean:
+	rm -rf $(BUILD_DIR)
diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile
new file mode 100644
index 00000000..cde0cf30
--- /dev/null
+++ b/frida_mode/test/png/persistent/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
+
+clean:
+	@gmake clean
+
+qemu:
+	@gmake qemu
+
+qemu_entry:
+	@gmake qemu_entry
+
+frida:
+	@gmake frida
+
+frida_entry:
+	@gmake frida_entry
diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py
new file mode 100755
index 00000000..1c46e010
--- /dev/null
+++ b/frida_mode/test/png/persistent/get_symbol_addr.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+def process_file(file, symbol, base):
+    with open(file, 'rb') as f:
+        elf = ELFFile(f)
+        symtab = elf.get_section_by_name('.symtab')
+        mains = symtab.get_symbol_by_name(symbol)
+        if len(mains) != 1:
+            print ("Failed to find main")
+            return 1
+
+        main_addr = mains[0]['st_value']
+        main = base + main_addr
+        print ("0x%016x" % main)
+        return 0
+
+def hex_value(x):
+    return int(x, 16)
+
+def main():
+    parser = argparse.ArgumentParser(description='Process some integers.')
+    parser.add_argument('-f', '--file', dest='file', type=str,
+                    help='elf file name', required=True)
+    parser.add_argument('-s', '--symbol', dest='symbol', type=str,
+                    help='symbol name', required=True)
+    parser.add_argument('-b', '--base', dest='base', type=hex_value,
+                    help='elf base address', required=True)
+
+    args = parser.parse_args()
+    return process_file (args.file, args.symbol, args.base)
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)
diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile
new file mode 100644
index 00000000..82f08fa4
--- /dev/null
+++ b/frida_mode/test/png/persistent/hook/GNUmakefile
@@ -0,0 +1,141 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../../../..)/
+BUILD_DIR:=$(PWD)build/
+
+AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
+AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
+
+CFLAGS+=-O3 \
+		-funroll-loops \
+		-g \
+		-fPIC \
+		-funroll-loops \
+
+LDFLAGS+=-shared \
+
+TEST_BIN:=$(PWD)../../build/test
+TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/
+
+AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000)
+
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000)
+endif
+
+.PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug
+
+all: $(AFLPP_DRIVER_HOOK_OBJ)
+	make -C $(ROOT)frida_mode/test/png/persistent/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+.PHONY: all clean qemu qemu_entry frida frida_entry
+
+all:
+	make -C $(ROOT)frida_mode/test/png/persistent/
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TEST_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
+	truncate -s 1M $@
+
+$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+
+qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
+	AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	$(ROOT)/afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+qemu_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
+	AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	$(ROOT)/afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+frida: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+
+frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+debug:
+	echo $(AFL_FRIDA_PERSISTENT_ADDR)
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ)' \
+		--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \
+		--ex 'set disassembly-flavor intel' \
+		--args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+format:
+	cd $(ROOT) && echo $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i
+
diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile
new file mode 100644
index 00000000..983d009e
--- /dev/null
+++ b/frida_mode/test/png/persistent/hook/Makefile
@@ -0,0 +1,28 @@
+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
+
+format:
+	@gmake format
+
+qemu:
+	@gmake qemu
+
+qemu_entry:
+	@gmake qemu_entry
+
+frida:
+	@gmake frida
+
+frida_entry:
+	@gmake frida_entry
+
+debug:
+	@gmake debug
diff --git a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c
new file mode 100644
index 00000000..059d438d
--- /dev/null
+++ b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c
@@ -0,0 +1,97 @@
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__x86_64__)
+
+struct x86_64_regs {
+
+  uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
+      r15;
+
+  union {
+
+    uint64_t rip;
+    uint64_t pc;
+
+  };
+
+  union {
+
+    uint64_t rsp;
+    uint64_t sp;
+
+  };
+
+  union {
+
+    uint64_t rflags;
+    uint64_t flags;
+
+  };
+
+  uint8_t zmm_regs[32][64];
+
+};
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  memcpy((void *)regs->rdi, input_buf, input_buf_len);
+  regs->rsi = input_buf_len;
+
+}
+
+#elif defined(__i386__)
+
+struct x86_regs {
+
+  uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
+
+  union {
+
+    uint32_t eip;
+    uint32_t pc;
+
+  };
+
+  union {
+
+    uint32_t esp;
+    uint32_t sp;
+
+  };
+
+  union {
+
+    uint32_t eflags;
+    uint32_t flags;
+
+  };
+
+  uint8_t xmm_regs[8][16];
+
+};
+
+void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  void **esp = (void **)regs->esp;
+  void * arg1 = esp[1];
+  void **arg2 = &esp[2];
+  memcpy(arg1, input_buf, input_buf_len);
+  *arg2 = (void *)input_buf_len;
+
+}
+
+#else
+  #pragma error "Unsupported architecture"
+#endif
+
+int afl_persistent_hook_init(void) {
+
+  // 1 for shared memory input (faster), 0 for normal input (you have to use
+  // read(), input_buf will be NULL)
+  return 1;
+
+}
+
diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile
new file mode 100644
index 00000000..9f0b31d3
--- /dev/null
+++ b/frida_mode/test/re2/GNUmakefile
@@ -0,0 +1,170 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+
+AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
+AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
+
+LIBRE2_BUILD_DIR:=$(BUILD_DIR)libre2/
+HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
+RE2TEST_BUILD_DIR:=$(BUILD_DIR)re2test/
+
+LIBRE2_URL:=https://github.com/google/re2.git
+LIBRE2_DIR:=$(LIBRE2_BUILD_DIR)libre2/
+LIBRE2_MAKEFILE:=$(LIBRE2_DIR)Makefile
+LIBRE2_LIB:=$(LIBRE2_DIR)obj/libre2.a
+
+HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c
+HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o
+HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c"
+
+RE2TEST_FILE:=$(RE2TEST_BUILD_DIR)target.cc
+RE2TEST_OBJ:=$(RE2TEST_BUILD_DIR)target.o
+RE2TEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/re2-2014-12-09/target.cc"
+
+LDFLAGS += -lpthread
+
+TEST_BIN:=$(BUILD_DIR)test
+ifeq "$(shell uname)" "Darwin"
+TEST_BIN_LDFLAGS:=-undefined dynamic_lookup
+endif
+
+TEST_DATA_DIR:=$(BUILD_DIR)in/
+AFLPP_DRIVER_DUMMY_INPUT:=$(TEST_DATA_DIR)in
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000)
+
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000)
+endif
+
+.PHONY: all clean qemu frida hook
+
+all: $(TEST_BIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+######### HARNESS ########
+$(HARNESS_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(HARNESS_FILE): | $(HARNESS_BUILD_DIR)
+	wget -O $@ $(HARNESS_URL)
+
+$(HARNESS_OBJ): $(HARNESS_FILE)
+	$(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $<
+
+######### RE2TEST ########
+
+$(RE2TEST_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(RE2TEST_FILE): | $(RE2TEST_BUILD_DIR)
+	wget -O $@ $(RE2TEST_URL)
+
+$(RE2TEST_OBJ): $(RE2TEST_FILE) | $(LIBRE2_MAKEFILE)
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBRE2_DIR) -o $@ -c $<
+
+######### LIBRE2 ########
+
+$(LIBRE2_BUILD_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(LIBRE2_MAKEFILE): $(LIBRE2_BUILD_DIR)
+	git clone https://github.com/google/re2.git $(LIBRE2_DIR)
+	cd $(LIBRE2_DIR) && git checkout 499ef7eff7455ce9c9fae86111d4a77b6ac335de
+
+$(LIBRE2_LIB): $(LIBRE2_MAKEFILE)
+	make -C $(LIBRE2_DIR) -j $(shell nproc)
+
+######### TEST ########
+
+$(TEST_BIN): $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB)
+	$(CXX) \
+		$(CFLAGS) \
+		-o $@ \
+		$(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) \
+		-lz \
+		$(LDFLAGS) \
+		$(TEST_BIN_LDFLAGS) \
+
+########## HOOK ########
+
+$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
+	$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
+
+########## DUMMY #######
+
+$(TEST_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR)
+	truncate -s 1M $@
+
+###### TEST DATA #######
+
+hook: $(AFLPP_DRIVER_HOOK_OBJ)
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT)
+	AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_QEMU_PERSISTENT_GPR=1 \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-Q \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT)
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-V 30 \
+		-O \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
+debug:
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--args $(TEST_BIN) $(TEST_DATA_DIR)basn0g01.re2
diff --git a/frida_mode/test/re2/Makefile b/frida_mode/test/re2/Makefile
new file mode 100644
index 00000000..00b2b287
--- /dev/null
+++ b/frida_mode/test/re2/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
+
+clean:
+	@gmake clean
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
+
+debug:
+	@gmake debug
+
+hook:
+	@gmake hook
diff --git a/frida_mode/test/re2/aflpp_qemu_driver_hook.c b/frida_mode/test/re2/aflpp_qemu_driver_hook.c
new file mode 100644
index 00000000..059d438d
--- /dev/null
+++ b/frida_mode/test/re2/aflpp_qemu_driver_hook.c
@@ -0,0 +1,97 @@
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__x86_64__)
+
+struct x86_64_regs {
+
+  uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
+      r15;
+
+  union {
+
+    uint64_t rip;
+    uint64_t pc;
+
+  };
+
+  union {
+
+    uint64_t rsp;
+    uint64_t sp;
+
+  };
+
+  union {
+
+    uint64_t rflags;
+    uint64_t flags;
+
+  };
+
+  uint8_t zmm_regs[32][64];
+
+};
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  memcpy((void *)regs->rdi, input_buf, input_buf_len);
+  regs->rsi = input_buf_len;
+
+}
+
+#elif defined(__i386__)
+
+struct x86_regs {
+
+  uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
+
+  union {
+
+    uint32_t eip;
+    uint32_t pc;
+
+  };
+
+  union {
+
+    uint32_t esp;
+    uint32_t sp;
+
+  };
+
+  union {
+
+    uint32_t eflags;
+    uint32_t flags;
+
+  };
+
+  uint8_t xmm_regs[8][16];
+
+};
+
+void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
+  void **esp = (void **)regs->esp;
+  void * arg1 = esp[1];
+  void **arg2 = &esp[2];
+  memcpy(arg1, input_buf, input_buf_len);
+  *arg2 = (void *)input_buf_len;
+
+}
+
+#else
+  #pragma error "Unsupported architecture"
+#endif
+
+int afl_persistent_hook_init(void) {
+
+  // 1 for shared memory input (faster), 0 for normal input (you have to use
+  // read(), input_buf will be NULL)
+  return 1;
+
+}
+
diff --git a/frida_mode/test/re2/get_symbol_addr.py b/frida_mode/test/re2/get_symbol_addr.py
new file mode 100755
index 00000000..1c46e010
--- /dev/null
+++ b/frida_mode/test/re2/get_symbol_addr.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+def process_file(file, symbol, base):
+    with open(file, 'rb') as f:
+        elf = ELFFile(f)
+        symtab = elf.get_section_by_name('.symtab')
+        mains = symtab.get_symbol_by_name(symbol)
+        if len(mains) != 1:
+            print ("Failed to find main")
+            return 1
+
+        main_addr = mains[0]['st_value']
+        main = base + main_addr
+        print ("0x%016x" % main)
+        return 0
+
+def hex_value(x):
+    return int(x, 16)
+
+def main():
+    parser = argparse.ArgumentParser(description='Process some integers.')
+    parser.add_argument('-f', '--file', dest='file', type=str,
+                    help='elf file name', required=True)
+    parser.add_argument('-s', '--symbol', dest='symbol', type=str,
+                    help='symbol name', required=True)
+    parser.add_argument('-b', '--base', dest='base', type=hex_value,
+                    help='elf base address', required=True)
+
+    args = parser.parse_args()
+    return process_file (args.file, args.symbol, args.base)
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)
diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile
new file mode 100644
index 00000000..a35073ab
--- /dev/null
+++ b/frida_mode/test/testinstr/GNUmakefile
@@ -0,0 +1,59 @@
+PWD:=$(shell pwd)/
+ROOT:=$(shell realpath $(PWD)../../..)/
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+.PHONY: all 32 clean qemu frida
+
+all: $(TESTINSTBIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+
+qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	$(ROOT)afl-fuzz \
+		-D \
+		-Q \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) @@
+
+debug:
+	gdb \
+		--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
+		--ex 'set disassembly-flavor intel' \
+		--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
diff --git a/frida_mode/test/testinstr/Makefile b/frida_mode/test/testinstr/Makefile
new file mode 100644
index 00000000..f843af19
--- /dev/null
+++ b/frida_mode/test/testinstr/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
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
+
+debug:
+	@gmake debug
diff --git a/frida_mode/test/testinstr/testinstr.c b/frida_mode/test/testinstr/testinstr.c
new file mode 100644
index 00000000..5e26fc46
--- /dev/null
+++ b/frida_mode/test/testinstr/testinstr.c
@@ -0,0 +1,112 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+  #define TESTINSTR_SECTION
+#else
+  #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
+#endif
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
+TESTINSTR_SECTION 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 = 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);
+
+    testinstr(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/update_frida_version.sh b/frida_mode/update_frida_version.sh
new file mode 100755
index 00000000..7d938712
--- /dev/null
+++ b/frida_mode/update_frida_version.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+test -n "$1" && { echo This script has no options. It updates the referenced Frida version in GNUmakefile to the most current one. ; exit 1 ; }
+
+OLD=$(egrep '^GUM_DEVKIT_VERSION=' GNUmakefile 2>/dev/null|awk -F= '{print$2}')
+NEW=$(curl https://github.com/frida/frida/releases/ 2>/dev/null|egrep 'frida-gum-devkit-[0-9.]*-linux-x86_64'|head -n 1|sed 's/.*frida-gum-devkit-//'|sed 's/-linux.*//')
+
+echo Current set version: $OLD
+echo Newest available version: $NEW
+
+test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; }
+
+sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1
+echo Successfully updated GNUmakefile
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 565e9afd..4aba3bdf 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -384,13 +384,15 @@ typedef struct afl_env_vars {
       afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
       afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
       afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
-      afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new;
+      afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
+      afl_exit_on_seed_issues, afl_try_affinity;
 
   u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
-      *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
+      *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
       *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
       *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
-      *afl_testcache_entries, *afl_kill_signal, *afl_target_env;
+      *afl_testcache_entries, *afl_kill_signal, *afl_target_env,
+      *afl_persistent_record, *afl_exit_on_time;
 
 } afl_env_vars_t;
 
@@ -482,7 +484,6 @@ typedef struct afl_state {
       no_unlink,                        /* do not unlink cur_input          */
       debug,                            /* Debug mode                       */
       custom_only,                      /* Custom mutator only mode         */
-      python_only,                      /* Python-only mode                 */
       is_main_node,                     /* if this is the main node         */
       is_secondary_node;                /* if this is a secondary instance  */
 
@@ -571,9 +572,11 @@ typedef struct afl_state {
       blocks_eff_select,                /* Blocks selected as fuzzable      */
       start_time,                       /* Unix start time (ms)             */
       last_sync_time,                   /* Time of last sync                */
+      last_sync_cycle,                  /* Cycle no. of the last sync       */
       last_path_time,                   /* Time for most recent path (ms)   */
       last_crash_time,                  /* Time for most recent crash (ms)  */
-      last_hang_time;                   /* Time for most recent hang (ms)   */
+      last_hang_time,                   /* Time for most recent hang (ms)   */
+      exit_on_time;                     /* Delay to exit if no new paths    */
 
   u32 slowest_exec_ms,                  /* Slowest testcase non hang in ms  */
       subseq_tmouts;                    /* Number of timeouts in a row      */
@@ -1132,6 +1135,7 @@ void   check_if_tty(afl_state_t *);
 void   setup_signal_handlers(void);
 void   save_cmdline(afl_state_t *, u32, char **);
 void   read_foreign_testcases(afl_state_t *, int);
+void   write_crash_readme(afl_state_t *afl);
 
 /* CmpLog */
 
diff --git a/include/android-ashmem.h b/include/android-ashmem.h
index 91699b27..1bfd3220 100644
--- a/include/android-ashmem.h
+++ b/include/android-ashmem.h
@@ -2,26 +2,27 @@
   #ifndef _ANDROID_ASHMEM_H
     #define _ANDROID_ASHMEM_H
 
+    #define _GNU_SOURCE
+    #include <sys/syscall.h>
+    #include <unistd.h>
     #include <fcntl.h>
     #include <linux/ashmem.h>
     #include <sys/ioctl.h>
     #include <sys/mman.h>
-
-    #if __ANDROID_API__ >= 26
-      #define shmat bionic_shmat
-      #define shmctl bionic_shmctl
-      #define shmdt bionic_shmdt
-      #define shmget bionic_shmget
-    #endif
     #include <sys/shm.h>
-    #undef shmat
-    #undef shmctl
-    #undef shmdt
-    #undef shmget
     #include <stdio.h>
-
     #define ASHMEM_DEVICE "/dev/ashmem"
 
+int shmdt(const void *address) {
+
+    #if defined(SYS_shmdt)
+  return syscall(SYS_shmdt, address);
+    #else
+  return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0);
+    #endif
+
+}
+
 int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
 
   int ret = 0;
diff --git a/include/config.h b/include/config.h
index c93a6d51..a1fdd789 100644
--- a/include/config.h
+++ b/include/config.h
@@ -26,7 +26,7 @@
 /* Version string: */
 
 // c = release, a = volatile github dev, e = experimental branch
-#define VERSION "++3.12c"
+#define VERSION "++3.13c"
 
 /******************************************************
  *                                                    *
@@ -71,7 +71,17 @@
 /* Maximum allowed fails per CMP value. Default: 128 */
 #define CMPLOG_FAIL_MAX 96
 
+/* -------------------------------------*/
 /* Now non-cmplog configuration options */
+/* -------------------------------------*/
+
+/* If a persistent target keeps state and found crashes are not reproducable
+   then enable this option and set the AFL_PERSISTENT_RECORD env variable
+   to a number. These number of testcases prior and including the crash case
+   will be kept and written to the crash/ directory as RECORD:... files.
+   Note that every crash will be written, not only unique ones! */
+
+//#define AFL_PERSISTENT_RECORD
 
 /* console output colors: There are three ways to configure its behavior
  * 1. default: colored outputs fixed on: defined USE_COLOR && defined
@@ -144,7 +154,7 @@
    cases that show variable behavior): */
 
 #define CAL_CYCLES 8U
-#define CAL_CYCLES_LONG 40U
+#define CAL_CYCLES_LONG 20U
 
 /* Number of subsequent timeouts before abandoning an input file: */
 
@@ -153,7 +163,7 @@
 /* Maximum number of unique hangs or crashes to record: */
 
 #define KEEP_UNIQUE_HANG 500U
-#define KEEP_UNIQUE_CRASH 5000U
+#define KEEP_UNIQUE_CRASH 10000U
 
 /* Baseline number of random tweaks during a single 'havoc' stage: */
 
@@ -396,6 +406,10 @@
 
 #define MSAN_ERROR 86
 
+/* Distinctive exit code used to indicate LSAN trip condition: */
+
+#define LSAN_ERROR 23
+
 /* Designated file descriptors for forkserver commands (the application will
    use FORKSRV_FD and FORKSRV_FD + 1): */
 
diff --git a/include/debug.h b/include/debug.h
index fc1f39cb..f8df5711 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -362,7 +362,12 @@ static inline const char *colorfilter(const char *x) {
                                                                           \
     s32 _len = (s32)(len);                                                \
     s32 _res = write(_fd, (buf), _len);                                   \
-    if (_res != _len) RPFATAL(_res, "Short write to %s, fd %d", fn, _fd); \
+    if (_res != _len) {                                                   \
+                                                                          \
+      RPFATAL(_res, "Short write to %s, fd %d (%d of %d bytes)", fn, _fd, \
+              _res, _len);                                                \
+                                                                          \
+    }                                                                     \
                                                                           \
   } while (0)
 
diff --git a/include/envs.h b/include/envs.h
index d7578045..15116fc1 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -26,6 +26,7 @@ static char *afl_environment_variables[] = {
     "AFL_BENCH_UNTIL_CRASH",
     "AFL_CAL_FAST",
     "AFL_CC",
+    "AFL_CC_COMPILER",
     "AFL_CMIN_ALLOW_ANY",
     "AFL_CMIN_CRASHES_ONLY",
     "AFL_CMPLOG_ONLY_NEW",
@@ -48,8 +49,28 @@ static char *afl_environment_variables[] = {
     "AFL_DUMB_FORKSRV",
     "AFL_ENTRYPOINT",
     "AFL_EXIT_WHEN_DONE",
+    "AFL_EXIT_ON_TIME",
+    "AFL_EXIT_ON_SEED_ISSUES",
     "AFL_FAST_CAL",
     "AFL_FORCE_UI",
+    "AFL_FRIDA_DEBUG_MAPS",
+    "AFL_FRIDA_EXCLUDE_RANGES",
+    "AFL_FRIDA_INST_DEBUG_FILE",
+    "AFL_FRIDA_INST_NO_OPTIMIZE",
+    "AFL_FRIDA_INST_NO_PREFETCH",
+    "AFL_FRIDA_INST_RANGES",
+    "AFL_FRIDA_INST_TRACE",
+    "AFL_FRIDA_OUTPUT_STDOUT",
+    "AFL_FRIDA_OUTPUT_STDERR",
+    "AFL_FRIDA_PERSISTENT_ADDR",
+    "AFL_FRIDA_PERSISTENT_CNT",
+    "AFL_FRIDA_PERSISTENT_DEBUG",
+    "AFL_FRIDA_PERSISTENT_HOOK",
+    "AFL_FRIDA_PERSISTENT_RET",
+    "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET",
+    "AFL_FRIDA_STATS_FILE",
+    "AFL_FRIDA_STATS_INTERVAL",
+    "AFL_FRIDA_STATS_TRANSITIONS",
     "AFL_FUZZER_ARGS",  // oss-fuzz
     "AFL_GDB",
     "AFL_GCC_ALLOWLIST",
@@ -105,8 +126,10 @@ static char *afl_environment_variables[] = {
     "AFL_NGRAM_SIZE",
     "AFL_LLVM_NOT_ZERO",
     "AFL_LLVM_INSTRUMENT_FILE",
+    "AFL_LLVM_THREADSAFE_INST",
     "AFL_LLVM_SKIP_NEVERZERO",
     "AFL_NO_AFFINITY",
+    "AFL_TRY_AFFINITY",
     "AFL_LLVM_LTO_STARTID",
     "AFL_LLVM_LTO_DONTWRITEID",
     "AFL_NO_ARITH",
@@ -130,6 +153,7 @@ static char *afl_environment_variables[] = {
     "AFL_PASSTHROUGH",
     "AFL_PATH",
     "AFL_PERFORMANCE_FILE",
+    "AFL_PERSISTENT_RECORD",
     "AFL_PRELOAD",
     "AFL_TARGET_ENV",
     "AFL_PYTHON_MODULE",
@@ -173,10 +197,13 @@ static char *afl_environment_variables[] = {
     "AFL_USE_TRACE_PC",
     "AFL_USE_UBSAN",
     "AFL_USE_CFISAN",
+    "AFL_USE_LSAN",
     "AFL_WINE_PATH",
     "AFL_NO_SNAPSHOT",
     "AFL_EXPAND_HAVOC_NOW",
+    "AFL_USE_FASAN",
     "AFL_USE_QASAN",
+    "AFL_PRINT_FILENAMES",
     NULL
 
 };
diff --git a/include/forkserver.h b/include/forkserver.h
index ac027f81..2baa6f0a 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -77,6 +77,10 @@ typedef struct afl_forkserver {
 
   bool qemu_mode;                       /* if running in qemu mode or not   */
 
+  bool frida_mode;                     /* if running in frida mode or not   */
+
+  bool frida_asan;                    /* if running with asan in frida mode */
+
   bool use_stdin;                       /* use stdin for sending data       */
 
   bool no_unlink;                       /* do not unlink cur_input          */
@@ -94,6 +98,17 @@ typedef struct afl_forkserver {
 
   char *cmplog_binary;                  /* the name of the cmplog binary    */
 
+  /* persistent mode replay functionality */
+  u32 persistent_record;                /* persistent replay setting        */
+#ifdef AFL_PERSISTENT_RECORD
+  u32  persistent_record_idx;           /* persistent replay cache ptr      */
+  u32  persistent_record_cnt;           /* persistent replay counter        */
+  u8 * persistent_record_dir;
+  u8 **persistent_record_data;
+  u32 *persistent_record_len;
+  s32  persistent_record_pid;
+#endif
+
   /* Function to kick off the forkserver child */
   void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
 
diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc
deleted file mode 100644
index 62de6ec5..00000000
--- a/instrumentation/LLVMInsTrim.so.cc
+++ /dev/null
@@ -1,599 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-
-#include "llvm/Config/llvm-config.h"
-#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
-typedef long double max_align_t;
-#endif
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#if LLVM_VERSION_MAJOR > 3 || \
-    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
-  #include "llvm/IR/CFG.h"
-  #include "llvm/IR/Dominators.h"
-  #include "llvm/IR/DebugInfo.h"
-#else
-  #include "llvm/Support/CFG.h"
-  #include "llvm/Analysis/Dominators.h"
-  #include "llvm/DebugInfo.h"
-#endif
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/IR/BasicBlock.h"
-#include <unordered_set>
-#include <random>
-#include <list>
-#include <string>
-#include <fstream>
-
-#include "MarkNodes.h"
-#include "afl-llvm-common.h"
-#include "llvm-alternative-coverage.h"
-
-#include "config.h"
-#include "debug.h"
-
-using namespace llvm;
-
-static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
-                                cl::init(false));
-static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
-                                 cl::init(false));
-
-namespace {
-
-struct InsTrim : public ModulePass {
-
- protected:
-  uint32_t function_minimum_size = 1;
-  char *   skip_nozero = NULL;
-
- private:
-  std::mt19937 generator;
-  int          total_instr = 0;
-
-  unsigned int genLabel() {
-
-    return generator() & (MAP_SIZE - 1);
-
-  }
-
- public:
-  static char ID;
-
-  InsTrim() : ModulePass(ID), generator(0) {
-
-    initInstrumentList();
-
-  }
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-
-    AU.addRequired<DominatorTreeWrapperPass>();
-
-  }
-
-#if LLVM_VERSION_MAJOR < 4
-  const char *
-#else
-  StringRef
-#endif
-  getPassName() const override {
-
-    return "InstTrim Instrumentation";
-
-  }
-
-#if LLVM_VERSION_MAJOR > 4 || \
-    (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
-  #define AFL_HAVE_VECTOR_INTRINSICS 1
-#endif
-
-  bool runOnModule(Module &M) override {
-
-    setvbuf(stdout, NULL, _IONBF, 0);
-
-    if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
-
-      SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");
-
-    } else
-
-      be_quiet = 1;
-
-    if (getenv("AFL_DEBUG") != NULL) debug = 1;
-
-    LLVMContext &C = M.getContext();
-
-    IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
-    IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
-
-#if LLVM_VERSION_MAJOR < 9
-    char *neverZero_counters_str;
-    if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
-      if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n");
-#endif
-    skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
-
-    if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
-        getenv("LOOPHEAD") != NULL) {
-
-      LoopHeadOpt = true;
-
-    }
-
-    unsigned int PrevLocSize = 0;
-    char *       ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
-    if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
-    char *caller_str = getenv("AFL_LLVM_CALLER");
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-    unsigned int ngram_size = 0;
-    /* Decide previous location vector size (must be a power of two) */
-    VectorType *PrevLocTy = NULL;
-
-    if (ngram_size_str)
-      if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
-          ngram_size > NGRAM_SIZE_MAX)
-        FATAL(
-            "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
-            "(%u))",
-            NGRAM_SIZE_MAX);
-
-    if (ngram_size)
-      PrevLocSize = ngram_size - 1;
-    else
-#else
-    if (ngram_size_str)
-  #ifdef LLVM_VERSION_STRING
-      FATAL(
-          "Sorry, NGRAM branch coverage is not supported with llvm version %s!",
-          LLVM_VERSION_STRING);
-  #else
-    #ifndef LLVM_VERSION_PATCH
-      FATAL(
-          "Sorry, NGRAM branch coverage is not supported with llvm version "
-          "%d.%d.%d!",
-          LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
-    #else
-      FATAL(
-          "Sorry, NGRAM branch coverage is not supported with llvm version "
-          "%d.%d.%d!",
-          LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH);
-    #endif
-  #endif
-#endif
-      PrevLocSize = 1;
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-    // IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
-    int          PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
-    IntegerType *IntLocTy =
-        IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
-    if (ngram_size)
-      PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
-  #if LLVM_VERSION_MAJOR >= 12
-                                  ,
-                                  false
-  #endif
-      );
-#endif
-
-    /* Get globals for the SHM region and the previous location. Note that
-       __afl_prev_loc is thread-local. */
-
-    GlobalVariable *AFLMapPtr =
-        new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
-                           GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
-    GlobalVariable *AFLPrevLoc;
-    GlobalVariable *AFLContext = NULL;
-    LoadInst *      PrevCaller = NULL;  // for CALLER sensitive coverage
-
-    if (caller_str)
-#if defined(__ANDROID__) || defined(__HAIKU__)
-      AFLContext = new GlobalVariable(
-          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
-#else
-      AFLContext = new GlobalVariable(
-          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx",
-          0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
-#endif
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-    if (ngram_size)
-  #if defined(__ANDROID__) || defined(__HAIKU__)
-      AFLPrevLoc = new GlobalVariable(
-          M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
-          /* Initializer */ nullptr, "__afl_prev_loc");
-  #else
-      AFLPrevLoc = new GlobalVariable(
-          M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
-          /* Initializer */ nullptr, "__afl_prev_loc",
-          /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
-          /* AddressSpace */ 0, /* IsExternallyInitialized */ false);
-  #endif
-    else
-#endif
-#if defined(__ANDROID__) || defined(__HAIKU__)
-      AFLPrevLoc = new GlobalVariable(
-          M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
-#else
-    AFLPrevLoc = new GlobalVariable(
-        M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
-        GlobalVariable::GeneralDynamicTLSModel, 0, false);
-#endif
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-    /* Create the vector shuffle mask for updating the previous block history.
-       Note that the first element of the vector will store cur_loc, so just set
-       it to undef to allow the optimizer to do its thing. */
-
-    SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};
-
-    for (unsigned I = 0; I < PrevLocSize - 1; ++I)
-      PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
-
-    for (int I = PrevLocSize; I < PrevLocVecSize; ++I)
-      PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
-
-    Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
-#endif
-
-    // this is our default
-    MarkSetOpt = true;
-
-    ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
-    ConstantInt *One = ConstantInt::get(Int8Ty, 1);
-
-    u64 total_rs = 0;
-    u64 total_hs = 0;
-
-    scanForDangerousFunctions(&M);
-
-    for (Function &F : M) {
-
-      if (debug) {
-
-        uint32_t bb_cnt = 0;
-
-        for (auto &BB : F)
-          if (BB.size() > 0) ++bb_cnt;
-        DEBUGF("Function %s size %zu %u\n", F.getName().str().c_str(), F.size(),
-               bb_cnt);
-
-      }
-
-      if (!isInInstrumentList(&F)) continue;
-
-      // if the function below our minimum size skip it (1 or 2)
-      if (F.size() < function_minimum_size) { continue; }
-
-      std::unordered_set<BasicBlock *> MS;
-      if (!MarkSetOpt) {
-
-        for (auto &BB : F) {
-
-          MS.insert(&BB);
-
-        }
-
-        total_rs += F.size();
-
-      } else {
-
-        auto Result = markNodes(&F);
-        auto RS = Result.first;
-        auto HS = Result.second;
-
-        MS.insert(RS.begin(), RS.end());
-        if (!LoopHeadOpt) {
-
-          MS.insert(HS.begin(), HS.end());
-          total_rs += MS.size();
-
-        } else {
-
-          DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
-          DominatorTreeWrapperPass *                      DTWP =
-              &getAnalysis<DominatorTreeWrapperPass>(F);
-          auto DT = &DTWP->getDomTree();
-
-          total_rs += RS.size();
-          total_hs += HS.size();
-
-          for (BasicBlock *BB : HS) {
-
-            bool Inserted = false;
-            for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {
-
-              auto Edge = BasicBlockEdge(*BI, BB);
-              if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
-
-                EdgeSet.insert({*BI, BB});
-                Inserted = true;
-                break;
-
-              }
-
-            }
-
-            if (!Inserted) {
-
-              MS.insert(BB);
-              total_rs += 1;
-              total_hs -= 1;
-
-            }
-
-          }
-
-          for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
-
-            auto PredBB = I->first;
-            auto SuccBB = I->second;
-            auto NewBB =
-                SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT, nullptr,
-#if LLVM_VERSION_MAJOR >= 8
-                                       nullptr,
-#endif
-                                       false);
-            MS.insert(NewBB);
-
-          }
-
-        }
-
-        for (BasicBlock &BB : F) {
-
-          if (MS.find(&BB) == MS.end()) { continue; }
-          IRBuilder<> IRB(&*BB.getFirstInsertionPt());
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-          if (ngram_size) {
-
-            LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
-            PrevLoc->setMetadata(M.getMDKindID("nosanitize"),
-                                 MDNode::get(C, None));
-
-            Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
-                PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
-            Value *UpdatedPrevLoc = IRB.CreateInsertElement(
-                ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()),
-                (uint64_t)0);
-
-            IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc)
-                ->setMetadata(M.getMDKindID("nosanitize"),
-                              MDNode::get(C, None));
-
-          } else
-
-#endif
-          {
-
-            IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc);
-
-          }
-
-        }
-
-      }
-
-      int has_calls = 0;
-      for (BasicBlock &BB : F) {
-
-        auto         PI = pred_begin(&BB);
-        auto         PE = pred_end(&BB);
-        IRBuilder<>  IRB(&*BB.getFirstInsertionPt());
-        Value *      L = NULL;
-        unsigned int cur_loc;
-
-        // Context sensitive coverage
-        if (caller_str && &BB == &F.getEntryBlock()) {
-
-          PrevCaller = IRB.CreateLoad(AFLContext);
-          PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
-                                  MDNode::get(C, None));
-
-          // does the function have calls? and is any of the calls larger than
-          // one basic block?
-          has_calls = 0;
-          for (auto &BB2 : F) {
-
-            if (has_calls) break;
-            for (auto &IN : BB2) {
-
-              CallInst *callInst = nullptr;
-              if ((callInst = dyn_cast<CallInst>(&IN))) {
-
-                Function *Callee = callInst->getCalledFunction();
-                if (!Callee || Callee->size() < function_minimum_size)
-                  continue;
-                else {
-
-                  has_calls = 1;
-                  break;
-
-                }
-
-              }
-
-            }
-
-          }
-
-          // if yes we store a context ID for this function in the global var
-          if (has_calls) {
-
-            ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel());
-            StoreInst *  StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
-            StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
-                                  MDNode::get(C, None));
-
-          }
-
-        }  // END of caller_str
-
-        if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
-
-        if (PI == PE) {
-
-          cur_loc = genLabel();
-          L = ConstantInt::get(Int32Ty, cur_loc);
-
-        } else {
-
-          auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
-          DenseMap<BasicBlock *, unsigned> PredMap;
-          for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
-
-            BasicBlock *PBB = *PI;
-            auto        It = PredMap.insert({PBB, genLabel()});
-            unsigned    Label = It.first->second;
-            // cur_loc = Label;
-            PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
-
-          }
-
-          L = PN;
-
-        }
-
-        /* Load prev_loc */
-        LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
-        PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-        Value *PrevLocTrans;
-
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-        /* "For efficiency, we propose to hash the tuple as a key into the
-           hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
-           prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
-
-        if (ngram_size)
-          PrevLocTrans =
-              IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
-        else
-#endif
-          PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
-
-        if (caller_str)
-          PrevLocTrans =
-              IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCaller), Int32Ty);
-
-        /* Load SHM pointer */
-        LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
-        MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-        Value *MapPtrIdx;
-#ifdef AFL_HAVE_VECTOR_INTRINSICS
-        if (ngram_size)
-          MapPtrIdx = IRB.CreateGEP(
-              MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty));
-        else
-#endif
-          MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L));
-
-        /* Update bitmap */
-        LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
-        Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-
-        Value *Incr = IRB.CreateAdd(Counter, One);
-
-#if LLVM_VERSION_MAJOR < 9
-        if (neverZero_counters_str !=
-            NULL)  // with llvm 9 we make this the default as the bug in llvm is
-                   // then fixed
-#else
-        if (!skip_nozero)
-#endif
-        {
-
-          /* hexcoder: Realize a counter that skips zero during overflow.
-           * Once this counter reaches its maximum value, it next increments to
-           * 1
-           *
-           * Instead of
-           * Counter + 1 -> Counter
-           * we inject now this
-           * Counter + 1 -> {Counter, OverflowFlag}
-           * Counter + OverflowFlag -> Counter
-           */
-          auto cf = IRB.CreateICmpEQ(Incr, Zero);
-          auto carry = IRB.CreateZExt(cf, Int8Ty);
-          Incr = IRB.CreateAdd(Incr, carry);
-
-        }
-
-        IRB.CreateStore(Incr, MapPtrIdx)
-            ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
-
-        if (caller_str && has_calls) {
-
-          // in CALLER mode we have to restore the original context for the
-          // caller - she might be calling other functions which need the
-          // correct CALLER
-          Instruction *Inst = BB.getTerminator();
-          if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
-
-            IRBuilder<> Post_IRB(Inst);
-            StoreInst * RestoreCtx =
-                Post_IRB.CreateStore(PrevCaller, AFLContext);
-            RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
-                                    MDNode::get(C, None));
-
-          }
-
-        }
-
-        total_instr++;
-
-      }
-
-    }
-
-    if (!be_quiet) {
-
-      char modeline[100];
-      snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
-               getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
-               getenv("AFL_USE_ASAN") ? ", ASAN" : "",
-               getenv("AFL_USE_MSAN") ? ", MSAN" : "",
-               getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
-               getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
-
-      OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr,
-          total_rs, total_hs, modeline);
-
-    }
-
-    return false;
-
-  }
-
-};  // end of struct InsTrim
-
-}  // end of anonymous namespace
-
-char InsTrim::ID = 0;
-
-static void registerAFLPass(const PassManagerBuilder &,
-                            legacy::PassManagerBase &PM) {
-
-  PM.add(new InsTrim());
-
-}
-
-static RegisterStandardPasses RegisterAFLPass(
-    PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
-
-static RegisterStandardPasses RegisterAFLPass0(
-    PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
-
diff --git a/instrumentation/MarkNodes.cc b/instrumentation/MarkNodes.cc
deleted file mode 100644
index b77466d9..00000000
--- a/instrumentation/MarkNodes.cc
+++ /dev/null
@@ -1,481 +0,0 @@
-#include <algorithm>
-#include <map>
-#include <queue>
-#include <set>
-#include <vector>
-
-#include "llvm/Config/llvm-config.h"
-#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
-typedef long double max_align_t;
-#endif
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/BasicBlock.h"
-#if LLVM_VERSION_MAJOR > 3 || \
-    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
-  #include "llvm/IR/CFG.h"
-#else
-  #include "llvm/Support/CFG.h"
-#endif
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-
-DenseMap<BasicBlock *, uint32_t>    LMap;
-std::vector<BasicBlock *>           Blocks;
-std::set<uint32_t>                  Marked, Markabove;
-std::vector<std::vector<uint32_t> > Succs, Preds;
-
-void reset() {
-
-  LMap.clear();
-  Blocks.clear();
-  Marked.clear();
-  Markabove.clear();
-
-}
-
-uint32_t start_point;
-
-void labelEachBlock(Function *F) {
-
-  // Fake single endpoint;
-  LMap[NULL] = Blocks.size();
-  Blocks.push_back(NULL);
-
-  // Assign the unique LabelID to each block;
-  for (auto I = F->begin(), E = F->end(); I != E; ++I) {
-
-    BasicBlock *BB = &*I;
-    LMap[BB] = Blocks.size();
-    Blocks.push_back(BB);
-
-  }
-
-  start_point = LMap[&F->getEntryBlock()];
-
-}
-
-void buildCFG(Function *F) {
-
-  Succs.resize(Blocks.size());
-  Preds.resize(Blocks.size());
-  for (size_t i = 0; i < Succs.size(); i++) {
-
-    Succs[i].clear();
-    Preds[i].clear();
-
-  }
-
-  for (auto S = F->begin(), E = F->end(); S != E; ++S) {
-
-    BasicBlock *BB = &*S;
-    uint32_t    MyID = LMap[BB];
-
-    for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
-
-      Succs[MyID].push_back(LMap[*I]);
-
-    }
-
-  }
-
-}
-
-std::vector<std::vector<uint32_t> > tSuccs;
-std::vector<bool>                   tag, indfs;
-
-void DFStree(size_t now_id) {
-
-  if (tag[now_id]) return;
-  tag[now_id] = true;
-  indfs[now_id] = true;
-  for (auto succ : tSuccs[now_id]) {
-
-    if (tag[succ] and indfs[succ]) {
-
-      Marked.insert(succ);
-      Markabove.insert(succ);
-      continue;
-
-    }
-
-    Succs[now_id].push_back(succ);
-    Preds[succ].push_back(now_id);
-    DFStree(succ);
-
-  }
-
-  indfs[now_id] = false;
-
-}
-
-void turnCFGintoDAG() {
-
-  tSuccs = Succs;
-  tag.resize(Blocks.size());
-  indfs.resize(Blocks.size());
-  for (size_t i = 0; i < Blocks.size(); ++i) {
-
-    Succs[i].clear();
-    tag[i] = false;
-    indfs[i] = false;
-
-  }
-
-  DFStree(start_point);
-  for (size_t i = 0; i < Blocks.size(); ++i)
-    if (Succs[i].empty()) {
-
-      Succs[i].push_back(0);
-      Preds[0].push_back(i);
-
-    }
-
-}
-
-uint32_t timeStamp;
-namespace DominatorTree {
-
-std::vector<std::vector<uint32_t> > cov;
-std::vector<uint32_t>               dfn, nfd, par, sdom, idom, mom, mn;
-
-bool Compare(uint32_t u, uint32_t v) {
-
-  return dfn[u] < dfn[v];
-
-}
-
-uint32_t eval(uint32_t u) {
-
-  if (mom[u] == u) return u;
-  uint32_t res = eval(mom[u]);
-  if (Compare(sdom[mn[mom[u]]], sdom[mn[u]])) { mn[u] = mn[mom[u]]; }
-  return mom[u] = res;
-
-}
-
-void DFS(uint32_t now) {
-
-  timeStamp += 1;
-  dfn[now] = timeStamp;
-  nfd[timeStamp - 1] = now;
-  for (auto succ : Succs[now]) {
-
-    if (dfn[succ] == 0) {
-
-      par[succ] = now;
-      DFS(succ);
-
-    }
-
-  }
-
-}
-
-void DominatorTree() {
-
-  if (Blocks.empty()) return;
-  uint32_t s = start_point;
-
-  // Initialization
-  mn.resize(Blocks.size());
-  cov.resize(Blocks.size());
-  dfn.resize(Blocks.size());
-  nfd.resize(Blocks.size());
-  par.resize(Blocks.size());
-  mom.resize(Blocks.size());
-  sdom.resize(Blocks.size());
-  idom.resize(Blocks.size());
-
-  for (uint32_t i = 0; i < Blocks.size(); i++) {
-
-    dfn[i] = 0;
-    nfd[i] = Blocks.size();
-    cov[i].clear();
-    idom[i] = mom[i] = mn[i] = sdom[i] = i;
-
-  }
-
-  timeStamp = 0;
-  DFS(s);
-
-  for (uint32_t i = Blocks.size() - 1; i >= 1u; i--) {
-
-    uint32_t now = nfd[i];
-    if (now == Blocks.size()) { continue; }
-    for (uint32_t pre : Preds[now]) {
-
-      if (dfn[pre]) {
-
-        eval(pre);
-        if (Compare(sdom[mn[pre]], sdom[now])) { sdom[now] = sdom[mn[pre]]; }
-
-      }
-
-    }
-
-    cov[sdom[now]].push_back(now);
-    mom[now] = par[now];
-    for (uint32_t x : cov[par[now]]) {
-
-      eval(x);
-      if (Compare(sdom[mn[x]], par[now])) {
-
-        idom[x] = mn[x];
-
-      } else {
-
-        idom[x] = par[now];
-
-      }
-
-    }
-
-  }
-
-  for (uint32_t i = 1; i < Blocks.size(); i += 1) {
-
-    uint32_t now = nfd[i];
-    if (now == Blocks.size()) { continue; }
-    if (idom[now] != sdom[now]) idom[now] = idom[idom[now]];
-
-  }
-
-}
-
-}  // namespace DominatorTree
-
-std::vector<uint32_t>               Visited, InStack;
-std::vector<uint32_t>               TopoOrder, InDeg;
-std::vector<std::vector<uint32_t> > t_Succ, t_Pred;
-
-void Go(uint32_t now, uint32_t tt) {
-
-  if (now == tt) return;
-  Visited[now] = InStack[now] = timeStamp;
-
-  for (uint32_t nxt : Succs[now]) {
-
-    if (Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) {
-
-      Marked.insert(nxt);
-
-    }
-
-    t_Succ[now].push_back(nxt);
-    t_Pred[nxt].push_back(now);
-    InDeg[nxt] += 1;
-    if (Visited[nxt] == timeStamp) { continue; }
-    Go(nxt, tt);
-
-  }
-
-  InStack[now] = 0;
-
-}
-
-void TopologicalSort(uint32_t ss, uint32_t tt) {
-
-  timeStamp += 1;
-
-  Go(ss, tt);
-
-  TopoOrder.clear();
-  std::queue<uint32_t> wait;
-  wait.push(ss);
-  while (not wait.empty()) {
-
-    uint32_t now = wait.front();
-    wait.pop();
-    TopoOrder.push_back(now);
-    for (uint32_t nxt : t_Succ[now]) {
-
-      InDeg[nxt] -= 1;
-      if (InDeg[nxt] == 0u) { wait.push(nxt); }
-
-    }
-
-  }
-
-}
-
-std::vector<std::set<uint32_t> > NextMarked;
-bool                             Indistinguish(uint32_t node1, uint32_t node2) {
-
-  if (NextMarked[node1].size() > NextMarked[node2].size()) {
-
-    uint32_t _swap = node1;
-    node1 = node2;
-    node2 = _swap;
-
-  }
-
-  for (uint32_t x : NextMarked[node1]) {
-
-    if (NextMarked[node2].find(x) != NextMarked[node2].end()) { return true; }
-
-  }
-
-  return false;
-
-}
-
-void MakeUniq(uint32_t now) {
-
-  if (Marked.find(now) == Marked.end()) {
-
-    for (uint32_t pred1 : t_Pred[now]) {
-
-      bool StopFlag = false;
-      for (uint32_t pred2 : t_Pred[now]) {
-
-        if (pred1 == pred2) continue;
-        if (Indistinguish(pred1, pred2)) {
-
-          Marked.insert(now);
-          StopFlag = true;
-          break;
-
-        }
-
-      }
-
-      if (StopFlag) { break; }
-
-    }
-
-  }
-
-  if (Marked.find(now) != Marked.end()) {
-
-    NextMarked[now].insert(now);
-
-  } else {
-
-    for (uint32_t pred : t_Pred[now]) {
-
-      for (uint32_t x : NextMarked[pred]) {
-
-        NextMarked[now].insert(x);
-
-      }
-
-    }
-
-  }
-
-}
-
-bool MarkSubGraph(uint32_t ss, uint32_t tt) {
-
-  TopologicalSort(ss, tt);
-  if (TopoOrder.empty()) return false;
-
-  for (uint32_t i : TopoOrder) {
-
-    NextMarked[i].clear();
-
-  }
-
-  NextMarked[TopoOrder[0]].insert(TopoOrder[0]);
-  for (uint32_t i = 1; i < TopoOrder.size(); i += 1) {
-
-    MakeUniq(TopoOrder[i]);
-
-  }
-
-  // Check if there is an empty path.
-  if (NextMarked[tt].count(TopoOrder[0]) > 0) return true;
-  return false;
-
-}
-
-void MarkVertice() {
-
-  uint32_t s = start_point;
-
-  InDeg.resize(Blocks.size());
-  Visited.resize(Blocks.size());
-  InStack.resize(Blocks.size());
-  t_Succ.resize(Blocks.size());
-  t_Pred.resize(Blocks.size());
-  NextMarked.resize(Blocks.size());
-
-  for (uint32_t i = 0; i < Blocks.size(); i += 1) {
-
-    Visited[i] = InStack[i] = InDeg[i] = 0;
-    t_Succ[i].clear();
-    t_Pred[i].clear();
-
-  }
-
-  timeStamp = 0;
-  uint32_t t = 0;
-  bool     emptyPathExists = true;
-
-  while (s != t) {
-
-    emptyPathExists &= MarkSubGraph(DominatorTree::idom[t], t);
-    t = DominatorTree::idom[t];
-
-  }
-
-  if (emptyPathExists) {
-
-    // Mark all exit blocks to catch the empty path.
-    Marked.insert(t_Pred[0].begin(), t_Pred[0].end());
-
-  }
-
-}
-
-// return {marked nodes}
-std::pair<std::vector<BasicBlock *>, std::vector<BasicBlock *> > markNodes(
-    Function *F) {
-
-  assert(F->size() > 0 && "Function can not be empty");
-
-  reset();
-  labelEachBlock(F);
-  buildCFG(F);
-  turnCFGintoDAG();
-  DominatorTree::DominatorTree();
-  MarkVertice();
-
-  std::vector<BasicBlock *> Result, ResultAbove;
-  for (uint32_t x : Markabove) {
-
-    auto it = Marked.find(x);
-    if (it != Marked.end()) Marked.erase(it);
-    if (x) ResultAbove.push_back(Blocks[x]);
-
-  }
-
-  for (uint32_t x : Marked) {
-
-    if (x == 0) {
-
-      continue;
-
-    } else {
-
-      Result.push_back(Blocks[x]);
-
-    }
-
-  }
-
-  return {Result, ResultAbove};
-
-}
-
diff --git a/instrumentation/MarkNodes.h b/instrumentation/MarkNodes.h
deleted file mode 100644
index 8ddc978d..00000000
--- a/instrumentation/MarkNodes.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __MARK_NODES__
-#define __MARK_NODES__
-
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/Function.h"
-#include <vector>
-
-std::pair<std::vector<llvm::BasicBlock *>, std::vector<llvm::BasicBlock *>>
-markNodes(llvm::Function *F);
-
-#endif
-
diff --git a/instrumentation/README.instrim.md b/instrumentation/README.instrim.md
deleted file mode 100644
index 99f6477a..00000000
--- a/instrumentation/README.instrim.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# InsTrim
-
-InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing
-
-## Introduction
-
-InsTrim is the work of Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang.
-
-It uses a CFG (call flow graph) and markers to instrument just what
-is necessary in the binary (ie less than llvm_mode). As a result the binary is
-about 10-15% faster compared to normal llvm_mode however with some coverage loss.
-It requires at least llvm version 3.8.0 to build.
-If you have LLVM 7+ we recommend PCGUARD instead.
-
-## Usage
-
-Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1`
-during compilation of the target.
-
-There is also special mode which instruments loops in a way so that
-afl-fuzz can see which loop path has been selected but not being able to
-see how often the loop has been rerun.
-This again is a tradeoff for speed for less path information.
-To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
-
-## Background
-
-The paper from Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang:
-[InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]
-(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf)
diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md
index 2705ce0d..8ce5afb9 100644
--- a/instrumentation/README.llvm.md
+++ b/instrumentation/README.llvm.md
@@ -2,11 +2,11 @@
 
   (See [../README.md](../README.md) for the general instruction manual.)
 
-  (See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.)
+  (See [README.gcc_plugin.md](../README.gcc_plugin.md) for the GCC-based instrumentation.)
 
 ## 1) Introduction
 
-! llvm_mode works with llvm versions 3.4 up to 12 !
+! llvm_mode works with llvm versions 6.0 up to 12 !
 
 The code in this directory allows you to instrument programs for AFL using
 true compiler-level instrumentation, instead of the more crude
@@ -101,8 +101,7 @@ instrumentation by either setting `AFL_CC_COMPILER=LLVM` or pass the parameter
 The tool honors roughly the same environmental variables as afl-gcc (see
 [docs/env_variables.md](../docs/env_variables.md)). This includes AFL_USE_ASAN,
 AFL_HARDEN, and AFL_DONT_OPTIMIZE. However AFL_INST_RATIO is not honored
-as it does not serve a good purpose with the more effective PCGUARD, LTO and
- instrim CFG analysis.
+as it does not serve a good purpose with the more effective PCGUARD analysis.
 
 ## 3) Options
 
@@ -116,26 +115,20 @@ For splitting memcmp, strncmp, etc. please see [README.laf-intel.md](README.laf-
 
 Then there are different ways of instrumenting the target:
 
-1. There is an optimized instrumentation strategy that uses CFGs and
-markers to just instrument what is needed. This increases speed by 10-15%
-without any disadvantages
-If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1
-See [README.instrim.md](README.instrim.md)
-
-2. An even better instrumentation strategy uses LTO and link time
+1. An better instrumentation strategy uses LTO and link time
 instrumentation. Note that not all targets can compile in this mode, however
 if it works it is the best option you can use.
 Simply use afl-clang-lto/afl-clang-lto++ to use this option.
 See [README.lto.md](README.lto.md)
 
-3. Alternativly you can choose a completely different coverage method:
+2. Alternativly you can choose a completely different coverage method:
 
-3a. N-GRAM coverage - which combines the previous visited edges with the
+2a. N-GRAM coverage - which combines the previous visited edges with the
 current one. This explodes the map but on the other hand has proven to be
 effective for fuzzing.
 See [README.ngram.md](README.ngram.md)
 
-3b. Context sensitive coverage - which combines the visited edges with an
+2b. Context sensitive coverage - which combines the visited edges with an
 individual caller ID (the function that called the current one)
 [README.ctx.md](README.ctx.md)
 
@@ -151,6 +144,11 @@ is not optimal and was only fixed in llvm 9.
 You can set this with AFL_LLVM_NOT_ZERO=1
 See [README.neverzero.md](README.neverzero.md)
 
+Support for thread safe counters has been added for all modes.
+Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision
+in multi threaded apps for a slightly higher instrumentation overhead.
+This also disables the nozero counter default for performance reasons.
+
 ## 4) Snapshot feature
 
 To speed up fuzzing you can use a linux loadable kernel module which enables
diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md
index 49104e00..9bcae324 100644
--- a/instrumentation/README.neverzero.md
+++ b/instrumentation/README.neverzero.md
@@ -16,11 +16,12 @@ at a very little cost (one instruction per edge).
 (The alternative of saturated counters has been tested also and proved to be
 inferior in terms of path discovery.)
 
-This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is optional if
-the llvm version is below 9 - as there is a perfomance bug that is only fixed
-in version 9 and onwards.
+This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is
+optional if multithread safe counters are selected or the llvm version is below
+9 - as there are severe performance costs in these cases.
 
-If you want to enable this for llvm versions below 9 then set
+If you want to enable this for llvm versions below 9 or thread safe counters
+then set
 
 ```
 export AFL_LLVM_NOT_ZERO=1
@@ -33,3 +34,8 @@ AFL_LLVM_SKIP_NEVERZERO=1
 ```
 If the target does not have extensive loops or functions that are called
 a lot then this can give a small performance boost.
+
+Please note that the default counter implementations are not thread safe!
+
+Support for thread safe counters in mode LLVM CLASSIC can be activated with setting
+`AFL_LLVM_THREADSAFE_INST=1`.
\ No newline at end of file
diff --git a/instrumentation/README.snapshot.md b/instrumentation/README.snapshot.md
index c40a956a..c794c2fd 100644
--- a/instrumentation/README.snapshot.md
+++ b/instrumentation/README.snapshot.md
@@ -1,5 +1,7 @@
 # AFL++ snapshot feature
 
+**NOTE:** the snapshot lkm is currently not supported and needs a maintainer :-)
+
 Snapshotting is a feature that makes a snapshot from a process and then
 restores its state, which is faster then forking it again.
 
diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc
index 6dd390e6..20f1856e 100644
--- a/instrumentation/SanitizerCoverageLTO.so.cc
+++ b/instrumentation/SanitizerCoverageLTO.so.cc
@@ -60,15 +60,14 @@ using namespace llvm;
 
 #define DEBUG_TYPE "sancov"
 
-static const char *const SanCovTracePCIndirName =
-    "__sanitizer_cov_trace_pc_indir";
-static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc";
-// static const char *const SanCovTracePCGuardName =
+const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
+const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
+// const char SanCovTracePCGuardName =
 //    "__sanitizer_cov_trace_pc_guard";
-static const char *const SanCovGuardsSectionName = "sancov_guards";
-static const char *const SanCovCountersSectionName = "sancov_cntrs";
-static const char *const SanCovBoolFlagSectionName = "sancov_bools";
-static const char *const SanCovPCsSectionName = "sancov_pcs";
+const char SanCovGuardsSectionName[] = "sancov_guards";
+const char SanCovCountersSectionName[] = "sancov_cntrs";
+const char SanCovBoolFlagSectionName[] = "sancov_bools";
+const char SanCovPCsSectionName[] = "sancov_pcs";
 
 static cl::opt<int> ClCoverageLevel(
     "lto-coverage-level",
@@ -237,7 +236,8 @@ class ModuleSanitizerCoverage {
   uint32_t                         inst = 0;
   uint32_t                         afl_global_id = 0;
   uint64_t                         map_addr = 0;
-  char *                           skip_nozero = NULL;
+  const char *                     skip_nozero = NULL;
+  const char *                     use_threadsafe_counters = nullptr;
   std::vector<BasicBlock *>        BlockList;
   DenseMap<Value *, std::string *> valueMap;
   std::vector<std::string>         dictionary;
@@ -438,6 +438,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
     be_quiet = 1;
 
   skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+  use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
 
   if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
     if ((afl_global_id = atoi(ptr)) < 0)
@@ -1209,7 +1210,7 @@ void ModuleSanitizerCoverage::instrumentFunction(
     return;  // Should not instrument sanitizer init functions.
   if (F.getName().startswith("__sanitizer_"))
     return;  // Don't instrument __sanitizer_* callbacks.
-  // Don't touch available_externally functions, their actual body is elewhere.
+  // Don't touch available_externally functions, their actual body is elsewhere.
   if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return;
   // Don't instrument MSVC CRT configuration helpers. They may run before normal
   // initialization.
@@ -1496,22 +1497,31 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
     }
 
     /* Update bitmap */
+    if (use_threadsafe_counters) {                                /* Atomic */
 
-    LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
-    Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None));
+      IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+                          llvm::AtomicOrdering::Monotonic);
 
-    Value *Incr = IRB.CreateAdd(Counter, One);
+    } else {
 
-    if (skip_nozero == NULL) {
+      LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+      Counter->setMetadata(Mo->getMDKindID("nosanitize"),
+                           MDNode::get(*Ct, None));
 
-      auto cf = IRB.CreateICmpEQ(Incr, Zero);
-      auto carry = IRB.CreateZExt(cf, Int8Tyi);
-      Incr = IRB.CreateAdd(Incr, carry);
+      Value *Incr = IRB.CreateAdd(Counter, One);
 
-    }
+      if (skip_nozero == NULL) {
 
-    IRB.CreateStore(Incr, MapPtrIdx)
-        ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None));
+        auto cf = IRB.CreateICmpEQ(Incr, Zero);
+        auto carry = IRB.CreateZExt(cf, Int8Tyi);
+        Incr = IRB.CreateAdd(Incr, carry);
+
+      }
+
+      IRB.CreateStore(Incr, MapPtrIdx)
+          ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None));
+
+    }
 
     // done :)
 
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index 09cda9e2..4a8c9e28 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -52,51 +52,42 @@ using namespace llvm;
 
 #define DEBUG_TYPE "sancov"
 
-static const char *const SanCovTracePCIndirName =
-    "__sanitizer_cov_trace_pc_indir";
-static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc";
-static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1";
-static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2";
-static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4";
-static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8";
-static const char *const SanCovTraceConstCmp1 =
-    "__sanitizer_cov_trace_const_cmp1";
-static const char *const SanCovTraceConstCmp2 =
-    "__sanitizer_cov_trace_const_cmp2";
-static const char *const SanCovTraceConstCmp4 =
-    "__sanitizer_cov_trace_const_cmp4";
-static const char *const SanCovTraceConstCmp8 =
-    "__sanitizer_cov_trace_const_cmp8";
-static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4";
-static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8";
-static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep";
-static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch";
-static const char *const SanCovModuleCtorTracePcGuardName =
+const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
+const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
+const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
+const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
+const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4";
+const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8";
+const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
+const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
+const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
+const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8";
+const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4";
+const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8";
+const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep";
+const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
+const char SanCovModuleCtorTracePcGuardName[] =
     "sancov.module_ctor_trace_pc_guard";
-static const char *const SanCovModuleCtor8bitCountersName =
+const char SanCovModuleCtor8bitCountersName[] =
     "sancov.module_ctor_8bit_counters";
-static const char *const SanCovModuleCtorBoolFlagName =
-    "sancov.module_ctor_bool_flag";
+const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag";
 static const uint64_t SanCtorAndDtorPriority = 2;
 
-static const char *const SanCovTracePCGuardName =
-    "__sanitizer_cov_trace_pc_guard";
-static const char *const SanCovTracePCGuardInitName =
-    "__sanitizer_cov_trace_pc_guard_init";
-static const char *const SanCov8bitCountersInitName =
-    "__sanitizer_cov_8bit_counters_init";
-static const char *const SanCovBoolFlagInitName =
-    "__sanitizer_cov_bool_flag_init";
-static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init";
+const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard";
+const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
+const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
+const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
+const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
 
-static const char *const SanCovGuardsSectionName = "sancov_guards";
-static const char *const SanCovCountersSectionName = "sancov_cntrs";
-static const char *const SanCovBoolFlagSectionName = "sancov_bools";
-static const char *const SanCovPCsSectionName = "sancov_pcs";
+const char SanCovGuardsSectionName[] = "sancov_guards";
+const char SanCovCountersSectionName[] = "sancov_cntrs";
+const char SanCovBoolFlagSectionName[] = "sancov_bools";
+const char SanCovPCsSectionName[] = "sancov_pcs";
 
-static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
+const char SanCovLowestStackName[] = "__sancov_lowest_stack";
 
-static char *skip_nozero;
+static const char *skip_nozero;
+static const char *use_threadsafe_counters;
 
 namespace {
 
@@ -320,12 +311,12 @@ std::pair<Value *, Value *> ModuleSanitizerCoverage::CreateSecStartEnd(
     Module &M, const char *Section, Type *Ty) {
 
   GlobalVariable *SecStart = new GlobalVariable(
-      M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage,
-      nullptr, getSectionStart(Section));
+      M, Ty->getPointerElementType(), false,
+      GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section));
   SecStart->setVisibility(GlobalValue::HiddenVisibility);
   GlobalVariable *SecEnd = new GlobalVariable(
-      M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage,
-      nullptr, getSectionEnd(Section));
+      M, Ty->getPointerElementType(), false,
+      GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section));
   SecEnd->setVisibility(GlobalValue::HiddenVisibility);
   IRBuilder<> IRB(M.getContext());
   if (!TargetTriple.isOSBinFormatCOFF())
@@ -396,6 +387,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
     be_quiet = 1;
 
   skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+  use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
 
   initInstrumentList();
   scanForDangerousFunctions(&M);
@@ -573,7 +565,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
 }
 
 // True if block has successors and it dominates all of them.
-static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
+bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
 
   if (succ_begin(BB) == succ_end(BB)) return false;
 
@@ -588,8 +580,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
 }
 
 // True if block has predecessors and it postdominates all of them.
-static bool isFullPostDominator(const BasicBlock *       BB,
-                                const PostDominatorTree *PDT) {
+bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) {
 
   if (pred_begin(BB) == pred_end(BB)) return false;
 
@@ -603,10 +594,10 @@ static bool isFullPostDominator(const BasicBlock *       BB,
 
 }
 
-static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
-                                  const DominatorTree *           DT,
-                                  const PostDominatorTree *       PDT,
-                                  const SanitizerCoverageOptions &Options) {
+bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
+                           const DominatorTree *           DT,
+                           const PostDominatorTree *       PDT,
+                           const SanitizerCoverageOptions &Options) {
 
   // Don't insert coverage for blocks containing nothing but unreachable: we
   // will never call __sanitizer_cov() for them, so counting them in
@@ -636,8 +627,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
 // A twist here is that we treat From->To as a backedge if
 //   * To dominates From or
 //   * To->UniqueSuccessor dominates From
-static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
-                       const DominatorTree *DT) {
+bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
 
   if (DT->dominates(To, From)) return true;
   if (auto Next = To->getUniqueSuccessor())
@@ -651,8 +641,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
 //
 // Note that Cmp pruning is controlled by the same flag as the
 // BB pruning.
-static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
-                             const SanitizerCoverageOptions &Options) {
+bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
+                      const SanitizerCoverageOptions &Options) {
 
   if (!Options.NoPrune)
     if (CMP->hasOneUse())
@@ -1046,7 +1036,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
 
   if (IsEntryBB) {
 
-    // Keep static allocas and llvm.localescape calls in the entry block.  Even
+    // Keep allocas and llvm.localescape calls in the entry block.  Even
     // if we aren't splitting the block, it's nice for allocas to be before
     // calls.
     IP = PrepareToSplitEntryBlock(BB, IP);
@@ -1079,22 +1069,31 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
 
     /* Load counter for CurLoc */
 
-    Value *   MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
-    LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+    Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
 
-    /* Update bitmap */
+    if (use_threadsafe_counters) {
 
-    Value *Incr = IRB.CreateAdd(Counter, One);
+      IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+                          llvm::AtomicOrdering::Monotonic);
 
-    if (skip_nozero == NULL) {
+    } else {
 
-      auto cf = IRB.CreateICmpEQ(Incr, Zero);
-      auto carry = IRB.CreateZExt(cf, Int8Ty);
-      Incr = IRB.CreateAdd(Incr, carry);
+      LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+      /* Update bitmap */
 
-    }
+      Value *Incr = IRB.CreateAdd(Counter, One);
+
+      if (skip_nozero == NULL) {
+
+        auto cf = IRB.CreateICmpEQ(Incr, Zero);
+        auto carry = IRB.CreateZExt(cf, Int8Ty);
+        Incr = IRB.CreateAdd(Incr, carry);
 
-    IRB.CreateStore(Incr, MapPtrIdx);
+      }
+
+      IRB.CreateStore(Incr, MapPtrIdx);
+
+    }
 
     // done :)
 
@@ -1221,17 +1220,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
 
 }
 
-static void registerPCGUARDPass(const PassManagerBuilder &,
-                                legacy::PassManagerBase &PM) {
+void registerPCGUARDPass(const PassManagerBuilder &,
+                         legacy::PassManagerBase &PM) {
 
   auto p = new ModuleSanitizerCoverageLegacyPass();
   PM.add(p);
 
 }
 
-static RegisterStandardPasses RegisterCompTransPass(
+RegisterStandardPasses RegisterCompTransPass(
     PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass);
 
-static RegisterStandardPasses RegisterCompTransPass0(
+RegisterStandardPasses RegisterCompTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass);
 
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index f241447a..2089ce78 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -34,8 +34,10 @@
 #include <errno.h>
 
 #include <sys/mman.h>
-#include <sys/syscall.h>
 #ifndef __HAIKU__
+  #include <sys/syscall.h>
+#endif
+#ifndef USEMMAP
   #include <sys/shm.h>
 #endif
 #include <sys/wait.h>
@@ -76,6 +78,11 @@
   #define MAP_INITIAL_SIZE MAP_SIZE
 #endif
 
+#if defined(__HAIKU__)
+extern ssize_t _kern_write(int fd, off_t pos, const void *buffer,
+                           size_t bufferSize);
+#endif  // HAIKU
+
 u8   __afl_area_initial[MAP_INITIAL_SIZE];
 u8 * __afl_area_ptr_dummy = __afl_area_initial;
 u8 * __afl_area_ptr = __afl_area_initial;
@@ -99,12 +106,10 @@ int __afl_selective_coverage_temp = 1;
 PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
 PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
 u32        __afl_prev_ctx;
-u32        __afl_cmp_counter;
 #else
 __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
 __thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
 __thread u32        __afl_prev_ctx;
-__thread u32        __afl_cmp_counter;
 #endif
 
 int __afl_sharedmem_fuzzing __attribute__((weak));
@@ -1140,6 +1145,18 @@ void __afl_manual_init(void) {
 
 __attribute__((constructor())) void __afl_auto_init(void) {
 
+#ifdef __ANDROID__
+  // Disable handlers in linker/debuggerd, check include/debuggerd/handler.h
+  signal(SIGABRT, SIG_DFL);
+  signal(SIGBUS, SIG_DFL);
+  signal(SIGFPE, SIG_DFL);
+  signal(SIGILL, SIG_DFL);
+  signal(SIGSEGV, SIG_DFL);
+  signal(SIGSTKFLT, SIG_DFL);
+  signal(SIGSYS, SIG_DFL);
+  signal(SIGTRAP, SIG_DFL);
+#endif
+
   if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
 
   if (getenv(DEFER_ENV_VAR)) return;
@@ -1738,7 +1755,11 @@ static int area_is_valid(void *ptr, size_t len) {
 
   if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; }
 
+#ifndef __HAIKU__
   long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len);
+#else
+  long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len);
+#endif  // HAIKU
 
   if (r <= 0 || r > len) return 0;
 
diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc
index 41bb5152..3b7eb878 100644
--- a/instrumentation/afl-gcc-pass.so.cc
+++ b/instrumentation/afl-gcc-pass.so.cc
@@ -177,7 +177,7 @@ int plugin_is_GPL_compatible = 1;
 
 namespace {
 
-static const struct pass_data afl_pass_data = {
+static constexpr struct pass_data afl_pass_data = {
 
     .type = GIMPLE_PASS,
     .name = "afl",
@@ -503,7 +503,7 @@ struct afl_pass : gimple_opt_pass {
     // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
     // fuzzing campaign installations, e.g. oss-fuzz
 
-    static const char *ignoreList[] = {
+    static constexpr const char *ignoreList[] = {
 
         "asan.",
         "llvm.",
diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc
index 74943fb2..af32e2f9 100644
--- a/instrumentation/afl-llvm-common.cc
+++ b/instrumentation/afl-llvm-common.cc
@@ -55,7 +55,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
   // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
   // fuzzing campaign installations, e.g. oss-fuzz
 
-  static const char *ignoreList[] = {
+  static constexpr const char *ignoreList[] = {
 
       "asan.",
       "llvm.",
@@ -94,7 +94,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
 
   }
 
-  static const char *ignoreSubstringList[] = {
+  static constexpr const char *ignoreSubstringList[] = {
 
       "__asan",       "__msan",     "__ubsan", "__lsan",
       "__san",        "__sanitize", "__cxx",   "_GLOBAL__",
@@ -104,7 +104,8 @@ bool isIgnoreFunction(const llvm::Function *F) {
 
   for (auto const &ignoreListFunc : ignoreSubstringList) {
 
-    if (F->getName().contains(ignoreListFunc)) { return true; }
+    // hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
+    if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
 
   }
 
diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc
index c954054b..e2b44b21 100644
--- a/instrumentation/afl-llvm-dict2file.so.cc
+++ b/instrumentation/afl-llvm-dict2file.so.cc
@@ -426,7 +426,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
               ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
               if (ilen) {
 
-                uint64_t literalLength = Str2.size();
+                uint64_t literalLength = Str2.length();
                 uint64_t optLength = ilen->getZExtValue();
                 if (literalLength + 1 == optLength) {
 
@@ -434,6 +434,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
 
                 }
 
+                if (optLength > Str2.length()) { optLength = Str2.length(); }
+
               }
 
               valueMap[Str1P] = new std::string(Str2);
@@ -532,6 +534,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
 
               uint64_t literalLength = optLen;
               optLen = ilen->getZExtValue();
+              if (optLen > thestring.length()) { optLen = thestring.length(); }
               if (optLen < 2) { continue; }
               if (literalLength + 1 == optLen) {  // add null byte
                 thestring.append("\0", 1);
diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc
index 50306224..fe43fbe5 100644
--- a/instrumentation/afl-llvm-lto-instrumentation.so.cc
+++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc
@@ -89,11 +89,12 @@ class AFLLTOPass : public ModulePass {
   bool runOnModule(Module &M) override;
 
  protected:
-  uint32_t afl_global_id = 1, autodictionary = 1;
-  uint32_t function_minimum_size = 1;
-  uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
-  uint64_t map_addr = 0x10000;
-  char *   skip_nozero = NULL;
+  uint32_t               afl_global_id = 1, autodictionary = 1;
+  uint32_t               function_minimum_size = 1;
+  uint32_t               inst_blocks = 0, inst_funcs = 0, total_instr = 0;
+  unsigned long long int map_addr = 0x10000;
+  const char *           skip_nozero = NULL;
+  const char *           use_threadsafe_counters = nullptr;
 
 };
 
@@ -131,6 +132,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     be_quiet = 1;
 
+  use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
+
   if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
 
     if ((documentFile = fopen(ptr, "a")) == NULL)
@@ -176,7 +179,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
   }
 
-  if (debug) { fprintf(stderr, "map address is 0x%lx\n", map_addr); }
+  if (debug) { fprintf(stderr, "map address is 0x%llx\n", map_addr); }
 
   /* Get/set the globals for the SHM region. */
 
@@ -839,22 +842,32 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
           /* Update bitmap */
 
-          LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
-          Counter->setMetadata(M.getMDKindID("nosanitize"),
-                               MDNode::get(C, None));
+          if (use_threadsafe_counters) {
+
+            IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+                                llvm::AtomicOrdering::Monotonic);
 
-          Value *Incr = IRB.CreateAdd(Counter, One);
+          } else {
 
-          if (skip_nozero == NULL) {
+            LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+            Counter->setMetadata(M.getMDKindID("nosanitize"),
+                                 MDNode::get(C, None));
 
-            auto cf = IRB.CreateICmpEQ(Incr, Zero);
-            auto carry = IRB.CreateZExt(cf, Int8Ty);
-            Incr = IRB.CreateAdd(Incr, carry);
+            Value *Incr = IRB.CreateAdd(Counter, One);
 
-          }
+            if (skip_nozero == NULL) {
 
-          IRB.CreateStore(Incr, MapPtrIdx)
-              ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+              auto cf = IRB.CreateICmpEQ(Incr, Zero);
+              auto carry = IRB.CreateZExt(cf, Int8Ty);
+              Incr = IRB.CreateAdd(Incr, carry);
+
+            }
+
+            IRB.CreateStore(Incr, MapPtrIdx)
+                ->setMetadata(M.getMDKindID("nosanitize"),
+                              MDNode::get(C, None));
+
+          }
 
           // done :)
 
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
index 0f773aba..a8f1baff 100644
--- a/instrumentation/afl-llvm-pass.so.cc
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -81,11 +81,12 @@ class AFLCoverage : public ModulePass {
   bool runOnModule(Module &M) override;
 
  protected:
-  uint32_t ngram_size = 0;
-  uint32_t ctx_k = 0;
-  uint32_t map_size = MAP_SIZE;
-  uint32_t function_minimum_size = 1;
-  char *   ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL;
+  uint32_t    ngram_size = 0;
+  uint32_t    ctx_k = 0;
+  uint32_t    map_size = MAP_SIZE;
+  uint32_t    function_minimum_size = 1;
+  const char *ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL;
+  const char *use_threadsafe_counters = nullptr;
 
 };
 
@@ -182,6 +183,38 @@ bool AFLCoverage::runOnModule(Module &M) {
   char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
 #endif
   skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+  use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
+
+  if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) {
+
+    if (use_threadsafe_counters) {
+
+      // disabled unless there is support for other modules as well
+      // (increases documentation complexity)
+      /*      if (!getenv("AFL_LLVM_NOT_ZERO")) { */
+
+      skip_nozero = "1";
+      SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n");
+
+      /*
+
+            } else {
+
+              SAYF(cCYA "afl-llvm-pass" VERSION cRST
+                        " using thread safe not-zero-counters\n");
+
+            }
+
+      */
+
+    } else {
+
+      SAYF(cCYA "afl-llvm-pass" VERSION cRST
+                " using non-thread safe instrumentation\n");
+
+    }
+
+  }
 
   unsigned PrevLocSize = 0;
   unsigned PrevCallerSize = 0;
@@ -388,7 +421,6 @@ bool AFLCoverage::runOnModule(Module &M) {
 #endif
 
   // other constants we need
-  ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
   ConstantInt *One = ConstantInt::get(Int8Ty, 1);
 
   Value *   PrevCtx = NULL;     // CTX sensitive coverage
@@ -410,6 +442,7 @@ bool AFLCoverage::runOnModule(Module &M) {
 
     if (F.size() < function_minimum_size) continue;
 
+    std::list<Value *> todo;
     for (auto &BB : F) {
 
       BasicBlock::iterator IP = BB.getFirstInsertionPt();
@@ -628,37 +661,68 @@ bool AFLCoverage::runOnModule(Module &M) {
 
       /* Update bitmap */
 
-      LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
-      Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+      if (use_threadsafe_counters) {                              /* Atomic */
+                                     /*
+                                     #if LLVM_VERSION_MAJOR < 9
+                                             if (neverZero_counters_str !=
+                                                 NULL) {  // with llvm 9 we make this the default as the bug
+                                     in llvm
+                                                          // is then fixed
+                                     #else
+                                             if (!skip_nozero) {
+                             
+                                     #endif
+                                               // register MapPtrIdx in a todo list
+                                               todo.push_back(MapPtrIdx);
+                             
+                                             } else {
+
+                                     */
+        IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
+                            llvm::AtomicOrdering::Monotonic);
+        /*
+
+                }
+
+        */
 
-      Value *Incr = IRB.CreateAdd(Counter, One);
+      } else {
+
+        LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+        Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+        Value *Incr = IRB.CreateAdd(Counter, One);
 
 #if LLVM_VERSION_MAJOR < 9
-      if (neverZero_counters_str !=
-          NULL) {  // with llvm 9 we make this the default as the bug in llvm is
-                   // then fixed
+        if (neverZero_counters_str !=
+            NULL) {  // with llvm 9 we make this the default as the bug in llvm
+                     // is then fixed
 #else
-      if (!skip_nozero) {
+        if (!skip_nozero) {
 
 #endif
-        /* hexcoder: Realize a counter that skips zero during overflow.
-         * Once this counter reaches its maximum value, it next increments to 1
-         *
-         * Instead of
-         * Counter + 1 -> Counter
-         * we inject now this
-         * Counter + 1 -> {Counter, OverflowFlag}
-         * Counter + OverflowFlag -> Counter
-         */
+          /* hexcoder: Realize a counter that skips zero during overflow.
+           * Once this counter reaches its maximum value, it next increments to
+           * 1
+           *
+           * Instead of
+           * Counter + 1 -> Counter
+           * we inject now this
+           * Counter + 1 -> {Counter, OverflowFlag}
+           * Counter + OverflowFlag -> Counter
+           */
+
+          ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
+          auto         cf = IRB.CreateICmpEQ(Incr, Zero);
+          auto         carry = IRB.CreateZExt(cf, Int8Ty);
+          Incr = IRB.CreateAdd(Incr, carry);
 
-        auto cf = IRB.CreateICmpEQ(Incr, Zero);
-        auto carry = IRB.CreateZExt(cf, Int8Ty);
-        Incr = IRB.CreateAdd(Incr, carry);
+        }
 
-      }
+        IRB.CreateStore(Incr, MapPtrIdx)
+            ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
 
-      IRB.CreateStore(Incr, MapPtrIdx)
-          ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+      }                                                  /* non atomic case */
 
       /* Update prev_loc history vector (by placing cur_loc at the head of the
          vector and shuffle the other elements back by one) */
@@ -715,6 +779,120 @@ bool AFLCoverage::runOnModule(Module &M) {
 
     }
 
+#if 0
+    if (use_threadsafe_counters) {                       /*Atomic NeverZero */
+      // handle the list of registered blocks to instrument
+      for (auto val : todo) {
+
+        /* hexcoder: Realize a thread-safe counter that skips zero during
+         * overflow. Once this counter reaches its maximum value, it next
+         * increments to 1
+         *
+         * Instead of
+         * Counter + 1 -> Counter
+         * we inject now this
+         * Counter + 1 -> {Counter, OverflowFlag}
+         * Counter + OverflowFlag -> Counter
+         */
+
+        /* equivalent c code looks like this
+         * Thanks to
+         https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
+
+            int old = atomic_load_explicit(&Counter, memory_order_relaxed);
+            int new;
+            do {
+
+                 if (old == 255) {
+
+                   new = 1;
+
+                 } else {
+
+                   new = old + 1;
+
+                 }
+
+            } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new,
+
+         memory_order_relaxed, memory_order_relaxed));
+
+         */
+
+        Value *              MapPtrIdx = val;
+        Instruction *        MapPtrIdxInst = cast<Instruction>(val);
+        BasicBlock::iterator it0(&(*MapPtrIdxInst));
+        ++it0;
+        IRBuilder<> IRB(&(*it0));
+
+        // load the old counter value atomically
+        LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
+        Counter->setAlignment(llvm::Align());
+        Counter->setAtomic(llvm::AtomicOrdering::Monotonic);
+        Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+        BasicBlock *BB = IRB.GetInsertBlock();
+        // insert a basic block with the corpus of a do while loop
+        // the calculation may need to repeat, if atomic compare_exchange is not
+        // successful
+
+        BasicBlock::iterator it(*Counter);
+        it++;  // split after load counter
+        BasicBlock *end_bb = BB->splitBasicBlock(it);
+        end_bb->setName("injected");
+
+        // insert the block before the second half of the split
+        BasicBlock *do_while_bb =
+            BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
+
+        // set terminator of BB from target end_bb to target do_while_bb
+        auto term = BB->getTerminator();
+        BranchInst::Create(do_while_bb, BB);
+        term->eraseFromParent();
+
+        // continue to fill instructions into the do_while loop
+        IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt());
+
+        PHINode *PN = IRB.CreatePHI(Int8Ty, 2);
+
+        // compare with maximum value 0xff
+        auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1));
+
+        // increment the counter
+        Value *Incr = IRB.CreateAdd(Counter, One);
+
+        // select the counter value or 1
+        auto *Select = IRB.CreateSelect(Cmp, One, Incr);
+
+        // try to save back the new counter value
+        auto *CmpXchg = IRB.CreateAtomicCmpXchg(
+            MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic,
+            llvm::AtomicOrdering::Monotonic);
+        CmpXchg->setAlignment(llvm::Align());
+        CmpXchg->setWeak(true);
+        CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
+
+        // get the result of trying to update the Counter
+        Value *Success =
+            IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1}));
+        // get the (possibly updated) value of Counter
+        Value *OldVal =
+            IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0}));
+
+        // initially we use Counter
+        PN->addIncoming(Counter, BB);
+        // on retry, we use the updated value
+        PN->addIncoming(OldVal, do_while_bb);
+
+        // if the cmpXchg was not successful, retry
+        IRB.CreateCondBr(Success, end_bb, do_while_bb);
+
+      }
+
+    }
+
+#endif
+
   }
 
   /*
diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc
index 97ab04a4..82f198aa 100644
--- a/instrumentation/split-switches-pass.so.cc
+++ b/instrumentation/split-switches-pass.so.cc
@@ -89,7 +89,7 @@ class SplitSwitchesTransform : public ModulePass {
 
   };
 
-  typedef std::vector<CaseExpr> CaseVector;
+  using CaseVector = std::vector<CaseExpr>;
 
  private:
   bool        splitSwitches(Module &M);
diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION
index 8d95c359..0fb33ae2 100644
--- a/qemu_mode/QEMUAFL_VERSION
+++ b/qemu_mode/QEMUAFL_VERSION
@@ -1 +1 @@
-ddc4a9748d
+d73b0336b4
diff --git a/qemu_mode/README.md b/qemu_mode/README.md
index a14cbe64..d28479d9 100644
--- a/qemu_mode/README.md
+++ b/qemu_mode/README.md
@@ -110,22 +110,23 @@ takes priority over any included ranges or AFL_INST_LIBS.
 
 CompareCoverage is a sub-instrumentation with effects similar to laf-intel.
 
-The environment variable that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL.
-There is also ./libcompcov/ which implements CompareCoverage for *cmp functions
-(splitting memcmp, strncmp, etc. to make these conditions easier solvable by
-afl-fuzz).
+You have to set `AFL_PRELOAD=/path/to/libcompcov.so` together with
+setting the AFL_COMPCOV_LEVEL you want to enable it.
 
 AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate
-values / read-only memory. AFL_COMPCOV_LEVEL=2 instruments all
-comparison instructions and memory comparison functions when libcompcov
-is preloaded.
-AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables also
-the instrumentation of the floating-point comparisons on x86 and x86_64 (experimental).
+values / read-only memory.
+
+AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and memory
+comparison functions when libcompcov is preloaded.
+
+AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables
+also the instrumentation of the floating-point comparisons on x86 and x86_64
+(experimental).
 
 Integer comparison instructions are currently instrumented only
 on the x86, x86_64, arm and aarch64 targets.
 
-Highly recommended.
+Recommended, but not as good as CMPLOG mode (see below).
 
 ## 8) CMPLOG mode
 
@@ -141,7 +142,7 @@ To enable it you must pass on the command line of afl-fuzz:
 
 ## 9) Wine mode
 
-AFL++ QEMU can use Wine to fuzz WIn32 PE binaries. Use the -W flag of afl-fuzz.
+AFL++ QEMU can use Wine to fuzz Win32 PE binaries. Use the -W flag of afl-fuzz.
 
 Note that some binaries require user interaction with the GUI and must be patched.
 
@@ -190,8 +191,8 @@ handlers of the target.
 
 ## 13) Gotchas, feedback, bugs
 
-If you need to fix up checksums or do other cleanup on mutated test cases, see
-utils/custom_mutators/ for a viable solution.
+If you need to fix up checksums or do other cleanups on mutated test cases, see
+`afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution.
 
 Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate
 the "shadow VM" trick employed by the sanitizers and will probably just
diff --git a/qemu_mode/README.wine.md b/qemu_mode/README.wine.md
new file mode 100644
index 00000000..567901cd
--- /dev/null
+++ b/qemu_mode/README.wine.md
@@ -0,0 +1,21 @@
+# How to troubleshoot AFL++'s wine mode
+
+## 1) Debugging
+To turn on wine debugging use the `WINEDEBUG` environment variable, 
+e.g. `WINEDEBUG=+timestamp,+tid,+loaddll`. 
+
+## 2) LoadLibraryA workaround
+The forked process fails to load libraries loaded via `LoadLibrary` 
+if the load happens after the entry point (error code: 87). To resolve 
+this issue, one needs to load any external libraries before the fork happens.
+
+An early DLL load can be achieved by adding the DLL name into the `Import Directory`
+in the PE file. Such an entry can be added manually in any PE editor. 
+
+Alternativly, one can generate a `.lib` file from the DLL exports and link 
+them together with the harness to create an entry in the `Import Directory`. 
+Use `dumpbin /exports <filename>.dll` to extract the exports and paste the 
+exported function names into a `.def` file. Use `lib /def:<deffile> /OUT:<libfile>`
+to generate a `.lib` and add the library to the linker options. Once the usage of 
+an export is detected (`__declspec(dllimport)`), the
+linker adds the early DLL load.
\ No newline at end of file
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 38085389..84f144be 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -9,7 +9,7 @@
 # TCG instrumentation and block chaining support by Andrea Biondo
 #                                    <andrea.biondo965@gmail.com>
 #
-# QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero
+# QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero
 # counters by Andrea Fioraldi <andreafioraldi@gmail.com>
 #
 # Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
@@ -211,8 +211,9 @@ if [ "$STATIC" = "1" ]; then
 
   echo Building STATIC binary
 
+  # static PIE causes https://github.com/AFLplusplus/AFLplusplus/issues/892
   QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \
-    --static \
+    --static --disable-pie \
     --extra-cflags=-DAFL_QEMU_STATIC_BUILD=1 \
     "
 
@@ -360,6 +361,8 @@ if ! command -v "$CROSS" > /dev/null ; then
     make -C unsigaction && echo "[+] unsigaction ready"
     echo "[+] Building libqasan ..."
     make -C libqasan && echo "[+] unsigaction ready"
+    echo "[+] Building qemu libfuzzer helpers ..."
+    make -C ../utils/aflpp_driver
   else
     echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction"
   fi
diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc
index d70bba91..3c975e15 100644
--- a/qemu_mode/libcompcov/compcovtest.cc
+++ b/qemu_mode/libcompcov/compcovtest.cc
@@ -1,67 +1,98 @@
-/////////////////////////////////////////////////////////////////////////

-//

-// Author: Mateusz Jurczyk (mjurczyk@google.com)

-//

-// Copyright 2019-2020 Google LLC

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-// https://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-//

-

-// solution: echo -ne 'The quick brown fox jumps over the lazy

-// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest

-

-#include <cstdint>

-#include <cstdio>

-#include <cstdlib>

-#include <cstring>

-

-int main() {

-
-  char buffer[44] = {/* zero padding */};

-  fread(buffer, 1, sizeof(buffer) - 1, stdin);

-

-  if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||

-      strncmp(&buffer[20], "jumps over ", 11) != 0 ||

-      strcmp(&buffer[31], "the lazy dog") != 0) {

-
-    return 1;

-
-  }

-

-  uint64_t x = 0;

-  fread(&x, sizeof(x), 1, stdin);

-  if (x != 0xCAFEBABECAFEBABE) { return 2; }

-

-  uint32_t y = 0;

-  fread(&y, sizeof(y), 1, stdin);

-  if (y != 0xDEADC0DE) { return 3; }

-

-  uint16_t z = 0;

-  fread(&z, sizeof(z), 1, stdin);

-

-  switch (z) {

-
-    case 0xBEEF:

-      break;

-

-    default:

-      return 4;

-
-  }

-

-  printf("Puzzle solved, congrats!\n");

-  abort();

-  return 0;

-
-}

+/////////////////////////////////////////////////////////////////////////
+//
+// Author: Mateusz Jurczyk (mjurczyk@google.com)
+//
+// Copyright 2019-2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// solution: echo -ne 'The quick brown fox jumps over the lazy
+// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest
+
+#include "../../include/config.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+int main(int argc, char **argv) {
+
+  char buffer[44] = {/* zero padding */};
+
+  FILE *file = stdin;
+
+  if (argc > 1) {
+
+    if ((file = fopen(argv[1], "r")) == NULL) {
+
+      perror(argv[1]);
+      exit(-1);
+
+    }
+
+  }
+
+  fread(buffer, 1, sizeof(buffer) - 1, file);
+
+  if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||
+      strncmp(&buffer[20], "jumps over ", 11) != 0 ||
+      strcmp(&buffer[31], "the lazy dog") != 0) {
+
+    if (argc > 1) { fclose(file); }
+    return 1;
+
+  }
+
+  uint64_t x = 0;
+  fread(&x, sizeof(x), 1, file);
+  if (x != 0xCAFEBABECAFEBABE) {
+
+    if (argc > 1) { fclose(file); }
+    return 2;
+
+  }
+
+  uint32_t y = 0;
+  fread(&y, sizeof(y), 1, file);
+  if (y != 0xDEADC0DE) {
+
+    if (argc > 1) { fclose(file); }
+    return 3;
+
+  }
+
+  uint16_t z = 0;
+  fread(&z, sizeof(z), 1, file);
+
+  switch (z) {
+
+    case 0xBEEF:
+      break;
+
+    default:
+      if (argc > 1) { fclose(file); }
+      return 4;
+
+  }
+
+  printf("Puzzle solved, congrats!\n");
+  abort();
+
+  if (argc > 1) { fclose(file); }
+
+  return 0;
+
+}
 
diff --git a/qemu_mode/libqasan/hooks.c b/qemu_mode/libqasan/hooks.c
index 0e6c3e08..c542521c 100644
--- a/qemu_mode/libqasan/hooks.c
+++ b/qemu_mode/libqasan/hooks.c
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "libqasan.h"
 #include "map_macro.h"
+#include <unistd.h>
+#include <sys/syscall.h>
 
-ssize_t (*__lq_libc_write)(int, const void *, size_t);
-ssize_t (*__lq_libc_read)(int, void *, size_t);
 char *(*__lq_libc_fgets)(char *, int, FILE *);
 int (*__lq_libc_atoi)(const char *);
 long (*__lq_libc_atol)(const char *);
@@ -37,8 +37,6 @@ void __libqasan_init_hooks(void) {
 
   __libqasan_init_malloc();
 
-  __lq_libc_write = ASSERT_DLSYM(write);
-  __lq_libc_read = ASSERT_DLSYM(read);
   __lq_libc_fgets = ASSERT_DLSYM(fgets);
   __lq_libc_atoi = ASSERT_DLSYM(atoi);
   __lq_libc_atol = ASSERT_DLSYM(atol);
@@ -52,7 +50,7 @@ ssize_t write(int fd, const void *buf, size_t count) {
 
   QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
   QASAN_LOAD(buf, count);
-  ssize_t r = __lq_libc_write(fd, buf, count);
+  ssize_t r = syscall(SYS_write, fd, buf, count);
   QASAN_DEBUG("\t\t = %zd\n", r);
 
   return r;
@@ -65,7 +63,7 @@ ssize_t read(int fd, void *buf, size_t count) {
 
   QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
   QASAN_STORE(buf, count);
-  ssize_t r = __lq_libc_read(fd, buf, count);
+  ssize_t r = syscall(SYS_read, fd, buf, count);
   QASAN_DEBUG("\t\t = %zd\n", r);
 
   return r;
diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c
index 9fc4ef7a..6ea24f08 100644
--- a/qemu_mode/libqasan/libqasan.c
+++ b/qemu_mode/libqasan/libqasan.c
@@ -61,10 +61,19 @@ void __libqasan_print_maps(void) {
 
 }
 
-/*__attribute__((constructor))*/ void __libqasan_init() {
+int __libqasan_is_initialized = 0;
+
+__attribute__((constructor)) void __libqasan_init() {
+
+  if (__libqasan_is_initialized) return;
+  __libqasan_is_initialized = 1;
 
   __libqasan_init_hooks();
 
+  if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch();
+
+  if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch();
+
 #ifdef DEBUG
   __qasan_debug = getenv("QASAN_DEBUG") != NULL;
 #endif
@@ -86,7 +95,6 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
   typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
 
   __libqasan_init();
-  if (getenv("AFL_INST_LIBS")) __libqasan_hotpatch();
 
   return orig(main, argc, argv, init, fini, rtld_fini, stack_end);
 
diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl
-Subproject 0fb212daab492411b3e323bc18a3074c1aecfd3
+Subproject d73b0336b451fd034e5f469089fb7ee96c80adf
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index e106cd31..aabdbf1a 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -83,6 +83,7 @@ static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_timed_out;                   /* Child timed out?                  */
 
 static u8 *target_path;
+static u8  frida_mode;
 static u8  qemu_mode;
 static u32 map_size = MAP_SIZE;
 
@@ -717,9 +718,11 @@ static void handle_stop_sig(int sig) {
 
 /* Do basic preparations - persistent fds, filenames, etc. */
 
-static void set_up_environment(void) {
+static void set_up_environment(char **argv) {
 
-  u8 *x;
+  u8 *  x;
+  char *afl_preload;
+  char *frida_afl_preload = NULL;
 
   dev_null_fd = open("/dev/null", O_RDWR);
   if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@@ -781,6 +784,18 @@ static void set_up_environment(void) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "symbolize=0")) {
+
+      FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+    }
+
+  }
+
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -818,12 +833,38 @@ static void set_up_environment(void) {
                          "handle_sigfpe=0:"
                          "handle_sigill=0", 0);
 
+  setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0:"
+         "symbolize=0:"
+         "print_suppressions=0",
+         0);
+
   if (get_afl_env("AFL_PRELOAD")) {
 
     if (qemu_mode) {
 
       /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
 
+    } else if (frida_mode) {
+
+      afl_preload = getenv("AFL_PRELOAD");
+      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+      if (afl_preload) {
+
+        frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+      } else {
+
+        frida_afl_preload = alloc_printf("%s", frida_binary);
+
+      }
+
+      ck_free(frida_binary);
+
+      setenv("LD_PRELOAD", frida_afl_preload, 1);
+      setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
     } else {
 
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
@@ -831,8 +872,17 @@ static void set_up_environment(void) {
 
     }
 
+  } else if (frida_mode) {
+
+    u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+    setenv("LD_PRELOAD", frida_binary, 1);
+    setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+    ck_free(frida_binary);
+
   }
 
+  if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
 }
 
 /* Setup signal handlers, duh. */
@@ -872,6 +922,7 @@ static void usage(u8 *argv0) {
       "  -f file       - input file read by the tested program (stdin)\n"
       "  -t msec       - timeout for each run (%u ms)\n"
       "  -m megs       - memory limit for child process (%u MB)\n"
+      "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine "
@@ -914,7 +965,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
 
-  while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) {
 
     switch (opt) {
 
@@ -1008,6 +1059,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'O':                                               /* FRIDA mode */
+
+        if (frida_mode) { FATAL("Multiple -O options not supported"); }
+
+        frida_mode = 1;
+
+        break;
+
       case 'Q':
 
         if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
@@ -1062,7 +1121,7 @@ int main(int argc, char **argv_orig, char **envp) {
   atexit(at_exit_handler);
   setup_signal_handlers();
 
-  set_up_environment();
+  set_up_environment(argv);
 
   target_path = find_binary(argv[optind]);
   detect_file_args(argv + optind, prog_in, &use_stdin);
diff --git a/src/afl-as.c b/src/afl-as.c
index aebd0ac8..7119d630 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -517,11 +517,12 @@ static void add_instrumentation(void) {
     } else {
 
       char modeline[100];
-      snprintf(modeline, sizeof(modeline), "%s%s%s%s",
+      snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
                getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
                getenv("AFL_USE_ASAN") ? ", ASAN" : "",
                getenv("AFL_USE_MSAN") ? ", MSAN" : "",
-               getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
+               getenv("AFL_USE_UBSAN") ? ", UBSAN" : "",
+               getenv("AFL_USE_LSAN") ? ", LSAN" : "");
 
       OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines,
           use_64bit ? "64" : "32", modeline, inst_ratio);
@@ -585,7 +586,7 @@ int main(int argc, char **argv) {
         "AFL_QUIET: suppress verbose output\n"
         "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n"
         "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n"
-        "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN:\n"
+        "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n"
         "  used in the instrumentation summary message\n",
         argv[0]);
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 80fc0742..486f7468 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -66,7 +66,6 @@ enum {
   INSTRUMENT_CLASSIC = 1,
   INSTRUMENT_AFL = 1,
   INSTRUMENT_PCGUARD = 2,
-  INSTRUMENT_INSTRIM = 3,
   INSTRUMENT_CFG = 3,
   INSTRUMENT_LTO = 4,
   INSTRUMENT_LLVMNATIVE = 5,
@@ -431,9 +430,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
 
-    if (lto_mode && plusplus_mode)
-      cc_params[cc_par_cnt++] = "-lc++";  // needed by fuzzbench, early
-
     if (lto_mode && have_instr_env) {
 
       cc_params[cc_par_cnt++] = "-Xclang";
@@ -564,12 +560,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (lto_mode && !have_c) {
 
       u8 *ld_path = strdup(AFL_REAL_LD);
-      if (!*ld_path) ld_path = "ld.lld";
+      if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); }
+      if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
       cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path);
 #else
       cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path);
 #endif
+      free(ld_path);
 
       cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
 
@@ -588,9 +586,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
       if (instrument_mode == INSTRUMENT_PCGUARD) {
 
 #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
-  #ifdef __ANDROID__
+  #if defined __ANDROID__ || ANDROID
         cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
-        instrument_mode != INSTRUMENT_LLVMNATIVE;
+        instrument_mode = INSTRUMENT_LLVMNATIVE;
   #else
         if (have_instr_list) {
 
@@ -639,12 +637,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
-        if (instrument_mode == INSTRUMENT_CFG)
-          cc_params[cc_par_cnt++] =
-              alloc_printf("%s/libLLVMInsTrim.so", obj_path);
-        else
-          cc_params[cc_par_cnt++] =
-              alloc_printf("%s/afl-llvm-pass.so", obj_path);
+        cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
 
       }
 
@@ -825,6 +818,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
+  if (getenv("AFL_USE_LSAN")) {
+
+    cc_params[cc_par_cnt++] = "-fsanitize=leak";
+    cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h";
+    cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()";
+
+  }
+
   if (getenv("AFL_USE_CFISAN")) {
 
     if (!lto_mode) {
@@ -1223,6 +1224,14 @@ int main(int argc, char **argv, char **envp) {
 
     if (strncmp(argv[i], "--afl", 5) == 0) {
 
+      if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
+
+        passthrough = 1;
+        argv[i] = "-g";  // we have to overwrite it, -g is always good
+        continue;
+
+      }
+
       if (compiler_mode)
         WARNF(
             "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
@@ -1252,8 +1261,9 @@ int main(int argc, char **argv, char **envp) {
 
                  strcasecmp(ptr, "CFG") == 0) {
 
-        compiler_mode = LLVM;
-        instrument_mode = INSTRUMENT_CFG;
+        FATAL(
+            "InsTrim instrumentation was removed. Use a modern LLVM and "
+            "PCGUARD (default in afl-cc).\n");
 
       } else if (strcasecmp(ptr, "AFL") == 0 ||
 
@@ -1319,10 +1329,9 @@ int main(int argc, char **argv, char **envp) {
   if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
       getenv("INSTRIM_LIB")) {
 
-    if (instrument_mode == 0)
-      instrument_mode = INSTRUMENT_CFG;
-    else if (instrument_mode != INSTRUMENT_CFG)
-      FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
+    FATAL(
+        "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
+        "(default in afl-cc).\n");
 
   }
 
@@ -1409,17 +1418,9 @@ int main(int argc, char **argv, char **envp) {
       if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
           strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
 
-        if (instrument_mode == INSTRUMENT_LTO) {
-
-          instrument_mode = INSTRUMENT_CFG;
-          lto_mode = 1;
-
-        } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG)
-
-          instrument_mode = INSTRUMENT_CFG;
-        else
-          FATAL("main instrumentation mode already set with %s",
-                instrument_mode_string[instrument_mode]);
+        FATAL(
+            "InsTrim instrumentation was removed. Use a modern LLVM and "
+            "PCGUARD (default in afl-cc).\n");
 
       }
 
@@ -1428,7 +1429,7 @@ int main(int argc, char **argv, char **envp) {
         lto_mode = 1;
         if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
           instrument_mode = INSTRUMENT_LTO;
-        else if (instrument_mode != INSTRUMENT_CFG)
+        else
           FATAL("main instrumentation mode already set with %s",
                 instrument_mode_string[instrument_mode]);
 
@@ -1456,9 +1457,11 @@ int main(int argc, char **argv, char **envp) {
 
       }
 
-      if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0) {
+      if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
+          strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
+          strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
 
-        u8 *ptr3 = ptr2 + strlen("ctx-");
+        u8 *ptr3 = ptr2;
         while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
           ptr3++;
 
@@ -1494,7 +1497,7 @@ int main(int argc, char **argv, char **envp) {
 
       }
 
-      if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) {
+      if (strcasecmp(ptr2, "ctx") == 0) {
 
         instrument_opt_mode |= INSTRUMENT_OPT_CTX;
         setenv("AFL_LLVM_CTX", "1", 1);
@@ -1579,7 +1582,12 @@ int main(int argc, char **argv, char **envp) {
     else if (have_gcc_plugin)
       compiler_mode = GCC_PLUGIN;
     else if (have_gcc)
+#ifdef __APPLE__
+      // on OSX clang masquerades as GCC
+      compiler_mode = CLANG;
+#else
       compiler_mode = GCC;
+#endif
     else if (have_lto)
       compiler_mode = LTO;
     else
@@ -1601,7 +1609,12 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
-  if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; }
+  if (compiler_mode == CLANG) {
+
+    instrument_mode = INSTRUMENT_CLANG;
+    setenv(CLANG_ENV_VAR, "1", 1);  // used by afl-as
+
+  }
 
   if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
 
@@ -1635,18 +1648,13 @@ int main(int argc, char **argv, char **envp) {
         "   yes\n"
         "  [LLVM] llvm:             %s%s\n"
         "      PCGUARD              %s      yes yes     module yes yes    "
-        "extern\n"
+        "yes\n"
         "      CLASSIC              %s      no  yes     module yes yes    "
         "yes\n"
         "        - NORMAL\n"
         "        - CALLER\n"
         "        - CTX\n"
         "        - NGRAM-{2-16}\n"
-        "      INSTRIM                           no  yes     module yes yes "
-        "   yes\n"
-        "        - NORMAL\n"
-        "        - CALLER\n"
-        "        - NGRAM-{2-16}\n"
         "  [GCC_PLUGIN] gcc plugin: %s%s\n"
         "      CLASSIC              DEFAULT      no  yes     no     no  no     "
         "yes\n"
@@ -1697,9 +1705,7 @@ int main(int argc, char **argv, char **envp) {
         "  CTX:     CLASSIC + full callee context "
         "(instrumentation/README.ctx.md)\n"
         "  NGRAM-x: CLASSIC + previous path "
-        "((instrumentation/README.ngram.md)\n"
-        "  INSTRIM: Dominator tree (for LLVM <= 6.0) "
-        "(instrumentation/README.instrim.md)\n\n");
+        "((instrumentation/README.ngram.md)\n\n");
 
 #undef NATIVE_MSG
 
@@ -1749,7 +1755,8 @@ int main(int argc, char **argv, char **envp) {
           "  AFL_USE_ASAN: activate address sanitizer\n"
           "  AFL_USE_CFISAN: activate control flow sanitizer\n"
           "  AFL_USE_MSAN: activate memory sanitizer\n"
-          "  AFL_USE_UBSAN: activate undefined behaviour sanitizer\n");
+          "  AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
+          "  AFL_USE_LSAN: activate leak-checker sanitizer\n");
 
       if (have_gcc_plugin)
         SAYF(
@@ -1770,6 +1777,8 @@ int main(int argc, char **argv, char **envp) {
         SAYF(
             "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
             "variables:\n"
+            "  AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, "
+            "disables neverzero\n"
 
             COUNTER_BEHAVIOUR
 
@@ -1791,19 +1800,16 @@ int main(int argc, char **argv, char **envp) {
             "  AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
             "mutator)\n"
             "  AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
-            "    CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, "
-            "NGRAM-2 ..-16\n"
+            "    CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 "
+            "..-16\n"
             " You can also use the old environment variables instead:\n"
             "  AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
-            "  AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
-            "  AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed "
-            "(option to INSTRIM)\n"
             "  AFL_LLVM_CALLER: use single context sensitive coverage (for "
             "CLASSIC)\n"
             "  AFL_LLVM_CTX: use full context sensitive coverage (for "
             "CLASSIC)\n"
             "  AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
-            "CLASSIC & INSTRIM)\n");
+            "CLASSIC)\n");
 
 #ifdef AFL_CLANG_FLTO
       if (have_lto)
@@ -1825,6 +1831,12 @@ int main(int argc, char **argv, char **envp) {
             "If anything fails - be sure to read README.lto.md!\n");
 #endif
 
+      SAYF(
+          "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. "
+          "(this is helpful\n"
+          "in some build systems if you do not want to instrument "
+          "everything.\n");
+
     }
 
     SAYF(
@@ -1951,11 +1963,7 @@ int main(int argc, char **argv, char **envp) {
         "(requires LLVM 11 or higher)");
 #endif
 
-  if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG &&
-      instrument_opt_mode & INSTRUMENT_OPT_CTX)
-    FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX.");
-  else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
-    // we will drop CFG/INSTRIM in the future so do not advertise
+  if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
     FATAL(
         "CALLER, CTX and NGRAM instrumentation options can only be used with "
         "the LLVM CLASSIC instrumentation mode.");
@@ -2023,7 +2031,7 @@ int main(int argc, char **argv, char **envp) {
   if (!be_quiet && cmplog_mode)
     printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
 
-#ifndef __ANDROID__
+#if !defined(__ANDROID__) && !defined(ANDROID)
   ptr = find_object("afl-compiler-rt.o", argv[0]);
 
   if (!ptr) {
diff --git a/src/afl-common.c b/src/afl-common.c
index 37b4788c..c61ce3d8 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -70,31 +70,26 @@ void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) {
 
       *use_stdin = false;
 
-      if (prog_in[0] != 0) {  // not afl-showmap special case
+      /* Be sure that we're always using fully-qualified paths. */
 
-        u8 *n_arg;
+      *aa_loc = 0;
 
-        /* Be sure that we're always using fully-qualified paths. */
+      /* Construct a replacement argv value. */
+      u8 *n_arg;
 
-        *aa_loc = 0;
+      if (prog_in[0] == '/') {
 
-        /* Construct a replacement argv value. */
+        n_arg = alloc_printf("%s%s%s", argv[i], prog_in, aa_loc + 2);
 
-        if (prog_in[0] == '/') {
-
-          n_arg = alloc_printf("%s%s%s", argv[i], prog_in, aa_loc + 2);
-
-        } else {
-
-          n_arg = alloc_printf("%s%s/%s%s", argv[i], cwd, prog_in, aa_loc + 2);
-
-        }
+      } else {
 
-        ck_free(argv[i]);
-        argv[i] = n_arg;
+        n_arg = alloc_printf("%s%s/%s%s", argv[i], cwd, prog_in, aa_loc + 2);
 
       }
 
+      ck_free(argv[i]);
+      argv[i] = n_arg;
+
     }
 
     i++;
@@ -287,12 +282,19 @@ u8 *find_binary(u8 *fname) {
 
 u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
 
-  u8 *afl_path = NULL, *target_path, *own_copy;
+  u8 *afl_path = NULL, *target_path, *own_copy, *tmp;
+  int perm = X_OK;
+
+  if ((tmp = strrchr(fname, '.'))) {
+
+    if (!strcasecmp(tmp, ".so") || !strcasecmp(tmp, ".dylib")) { perm = R_OK; }
+
+  }
 
   if ((afl_path = getenv("AFL_PATH"))) {
 
     target_path = alloc_printf("%s/%s", afl_path, fname);
-    if (!access(target_path, X_OK)) {
+    if (!access(target_path, perm)) {
 
       return target_path;
 
@@ -316,7 +318,7 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
       target_path = alloc_printf("%s/%s", own_copy, fname);
       ck_free(own_copy);
 
-      if (!access(target_path, X_OK)) {
+      if (!access(target_path, perm)) {
 
         return target_path;
 
@@ -334,8 +336,17 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
 
   }
 
-  target_path = alloc_printf("%s/%s", BIN_PATH, fname);
-  if (!access(target_path, X_OK)) {
+  if (perm == X_OK) {
+
+    target_path = alloc_printf("%s/%s", BIN_PATH, fname);
+
+  } else {
+
+    target_path = alloc_printf("%s/%s", AFL_PATH, fname);
+
+  }
+
+  if (!access(target_path, perm)) {
 
     return target_path;
 
@@ -345,7 +356,15 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
 
   }
 
-  return find_binary(fname);
+  if (perm == X_OK) {
+
+    return find_binary(fname);
+
+  } else {
+
+    FATAL("Library '%s' not found", fname);
+
+  }
 
 }
 
@@ -460,9 +479,17 @@ void print_suggested_envs(char *mispelled_env) {
 
       size_t end = start + strcspn(afl_env + start, "_") + 1;
       memcpy(reduced, afl_env, start);
-      if (end < afl_env_len)
+      if (end < afl_env_len) {
+
         memcpy(reduced + start, afl_env + end, afl_env_len - end);
-      reduced[afl_env_len - end + start] = 0;
+
+      }
+
+      if (afl_env_len + start >= end) {
+
+        reduced[afl_env_len - end + start] = 0;
+
+      }
 
       int distance = string_distance_levenshtein(reduced, env_name);
       if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) {
@@ -1091,6 +1118,10 @@ u32 get_map_size(void) {
 
     if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); }
 
+  } else if (getenv("AFL_SKIP_BIN_CHECK")) {
+
+    map_size = MAP_SIZE;
+
   }
 
   return map_size;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index c2d552cd..3d472b36 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -42,6 +42,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
@@ -126,7 +127,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->last_run_timed_out = 0;
 
   fsrv_to->init_child_func = from->init_child_func;
-  // Note: do not copy ->add_extra_func
+  // Note: do not copy ->add_extra_func or ->persistent_record*
 
   list_append(&fsrv_list, fsrv_to);
 
@@ -364,6 +365,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   if (!be_quiet) { ACTF("Spinning up the fork server..."); }
 
+#ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(fsrv->persistent_record)) {
+
+    fsrv->persistent_record_data =
+        (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *));
+    fsrv->persistent_record_len =
+        (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32));
+
+    if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) {
+
+      FATAL("Unable to allocate memory for persistent replay.");
+
+    }
+
+  }
+
+#endif
+
   if (fsrv->use_fauxsrv) {
 
     /* TODO: Come up with some nice way to initialize this all */
@@ -397,7 +416,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     struct rlimit r;
 
-    if (!fsrv->cmplog_binary && fsrv->qemu_mode == false) {
+    if (!fsrv->cmplog_binary && fsrv->qemu_mode == false &&
+        fsrv->frida_mode == false) {
 
       unsetenv(CMPLOG_SHM_ENV_VAR);  // we do not want that in non-cmplog fsrv
 
@@ -431,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
     /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
        before the dump is complete. */
 
-    //    r.rlim_max = r.rlim_cur = 0;
-    //    setrlimit(RLIMIT_CORE, &r);                      /* Ignore errors */
+    if (!fsrv->debug) {
+
+      r.rlim_max = r.rlim_cur = 0;
+      setrlimit(RLIMIT_CORE, &r);                          /* Ignore errors */
+
+    }
 
     /* Isolate the process and configure standard descriptors. If out_file is
        specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
@@ -483,7 +507,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
 
-    /* Set sane defaults for ASAN if nothing else specified. */
+    /* Set sane defaults for ASAN if nothing else is specified. */
 
     if (!getenv("ASAN_OPTIONS"))
       setenv("ASAN_OPTIONS",
@@ -500,7 +524,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
              "handle_sigill=0",
              1);
 
-    /* Set sane defaults for UBSAN if nothing else specified. */
+    /* Set sane defaults for UBSAN if nothing else is specified. */
 
     if (!getenv("UBSAN_OPTIONS"))
       setenv("UBSAN_OPTIONS",
@@ -538,6 +562,16 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
            "handle_sigill=0",
            1);
 
+    /* LSAN, too, does not support abort_on_error=1. */
+
+    if (!getenv("LSAN_OPTIONS"))
+      setenv("LSAN_OPTIONS",
+            "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+            "fast_unwind_on_malloc=0:"
+            "symbolize=0:"
+            "print_suppressions=0",
+            1);
+
     fsrv->init_child_func(fsrv, argv);
 
     /* Use a distinctive bitmap signature to tell the parent about execv()
@@ -792,7 +826,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   if (fsrv->last_run_timed_out) {
 
-    FATAL("Timeout while initializing fork server (adjusting -t may help)");
+    FATAL(
+        "Timeout while initializing fork server (setting "
+        "AFL_FORKSRV_INIT_TMOUT may help)");
 
   }
 
@@ -1032,7 +1068,33 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
 
 void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 
-  if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) {
+#ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(fsrv->persistent_record)) {
+
+    fsrv->persistent_record_len[fsrv->persistent_record_idx] = len;
+    fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc(
+        (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx],
+        len);
+
+    if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) {
+
+      FATAL("allocating replay memory failed.");
+
+    }
+
+    memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len);
+
+    if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) {
+
+      fsrv->persistent_record_idx = 0;
+
+    }
+
+  }
+
+#endif
+
+  if (likely(fsrv->use_shmem_fuzz)) {
 
     if (unlikely(len > MAX_FILE)) len = MAX_FILE;
 
@@ -1146,6 +1208,26 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   }
 
+#ifdef AFL_PERSISTENT_RECORD
+  // end of persistent loop?
+  if (unlikely(fsrv->persistent_record &&
+               fsrv->persistent_record_pid != fsrv->child_pid)) {
+
+    fsrv->persistent_record_pid = fsrv->child_pid;
+    u32 idx, val;
+    if (unlikely(!fsrv->persistent_record_idx))
+      idx = fsrv->persistent_record - 1;
+    else
+      idx = fsrv->persistent_record_idx - 1;
+    val = fsrv->persistent_record_len[idx];
+    memset((void *)fsrv->persistent_record_len, 0,
+           fsrv->persistent_record * sizeof(u32));
+    fsrv->persistent_record_len[idx] = val;
+
+  }
+
+#endif
+
   if (fsrv->child_pid <= 0) {
 
     if (*stop_soon_p) { return 0; }
@@ -1238,12 +1320,47 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
   if (unlikely(
           /* A normal crash/abort */
           (WIFSIGNALED(fsrv->child_status)) ||
-          /* special handling for msan */
-          (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
+          /* special handling for msan and lsan */
+          (fsrv->uses_asan &&
+           (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
+            WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) ||
           /* the custom crash_exitcode was returned by the target */
           (fsrv->uses_crash_exitcode &&
            WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
 
+#ifdef AFL_PERSISTENT_RECORD
+    if (unlikely(fsrv->persistent_record)) {
+
+      char fn[PATH_MAX];
+      u32  i, writecnt = 0;
+      for (i = 0; i < fsrv->persistent_record; ++i) {
+
+        u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
+        u8 *data = fsrv->persistent_record_data[entry];
+        u32 len = fsrv->persistent_record_len[entry];
+        if (likely(len && data)) {
+
+          snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
+                   fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
+                   writecnt++);
+          int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+          if (fd >= 0) {
+
+            ck_write(fd, data, len, fn);
+            close(fd);
+
+          }
+
+        }
+
+      }
+
+      ++fsrv->persistent_record_cnt;
+
+    }
+
+#endif
+
     /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
     fsrv->last_kill_signal =
         WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 3d0228db..97f10e6f 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -397,7 +397,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
 
 /* Write a message accompanying the crash directory :-) */
 
-static void write_crash_readme(afl_state_t *afl) {
+void write_crash_readme(afl_state_t *afl) {
 
   u8    fn[PATH_MAX];
   s32   fd;
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 27c6c413..c2e9c80f 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -35,7 +35,7 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
   if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); }
 
-  if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) {
+  if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) {
 
     argv[0] = fsrv->cmplog_binary;
 
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 6091db15..584241d4 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -130,6 +130,20 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
 
     }
 
+    /* Skip [number] */
+
+    if (*lptr == '[') {
+
+      do {
+
+        ++lptr;
+
+      } while (*lptr >= '0' && *lptr <= '9');
+
+      if (*lptr == ']') { ++lptr; }
+
+    }
+
     /* Skip whitespace and = signs. */
 
     while (isspace(*lptr) || *lptr == '=') {
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 70a49a6b..88b5bc02 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
   u8  lockfile[PATH_MAX] = "";
   s32 i;
 
-  if (afl->afl_env.afl_no_affinity) {
+  if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) {
 
     if (afl->cpu_to_bind != -1) {
 
@@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
     if (!bind_cpu(afl, afl->cpu_to_bind)) {
 
-      FATAL(
-          "Could not bind to requested CPU %d! Make sure you passed a valid "
-          "-b.",
-          afl->cpu_to_bind);
+      if (afl->afl_env.afl_try_affinity) {
+
+        WARNF(
+            "Could not bind to requested CPU %d! Make sure you passed a valid "
+            "-b.",
+            afl->cpu_to_bind);
+
+      } else {
+
+        FATAL(
+            "Could not bind to requested CPU %d! Make sure you passed a valid "
+            "-b.",
+            afl->cpu_to_bind);
+
+      }
 
     }
 
@@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) {
          "Uh-oh, looks like all %d CPU cores on your system are allocated to\n"
          "    other instances of afl-fuzz (or similar CPU-locked tasks). "
          "Starting\n"
-         "    another fuzzer on this machine is probably a bad plan, but if "
-         "you are\n"
-         "    absolutely sure, you can set AFL_NO_AFFINITY and try again.\n",
-         afl->cpu_core_count);
-    FATAL("No more free CPU cores");
+         "    another fuzzer on this machine is probably a bad plan.\n"
+         "%s",
+         afl->cpu_core_count,
+         afl->afl_env.afl_try_affinity ? ""
+                                       : "    If you are sure, you can set "
+                                         "AFL_NO_AFFINITY and try again.\n");
+
+    if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); }
 
   }
 
@@ -823,7 +837,6 @@ void perform_dry_run(afl_state_t *afl) {
 
   struct queue_entry *q;
   u32                 cal_failures = 0, idx;
-  u8 *                skip_crashes = afl->afl_env.afl_skip_crashes;
   u8 *                use_mem;
 
   for (idx = 0; idx < afl->queued_paths; idx++) {
@@ -881,7 +894,7 @@ void perform_dry_run(afl_state_t *afl) {
 
       case FSRV_RUN_TMOUT:
 
-        if (afl->timeout_given) {
+        if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) {
 
           /* if we have a timeout but a timeout value was given then always
              skip. The '+' meaning has been changed! */
@@ -923,27 +936,6 @@ void perform_dry_run(afl_state_t *afl) {
 
         if (afl->crash_mode) { break; }
 
-        if (skip_crashes) {
-
-          if (afl->fsrv.uses_crash_exitcode) {
-
-            WARNF(
-                "Test case results in a crash or AFL_CRASH_EXITCODE %d "
-                "(skipping)",
-                (int)(s8)afl->fsrv.crash_exitcode);
-
-          } else {
-
-            WARNF("Test case results in a crash (skipping)");
-
-          }
-
-          q->cal_failed = CAL_CHANCES;
-          ++cal_failures;
-          break;
-
-        }
-
         if (afl->fsrv.mem_limit) {
 
           u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
@@ -1036,20 +1028,24 @@ void perform_dry_run(afl_state_t *afl) {
 
         }
 
-        /* Remove from fuzzing queue but keep for splicing */
+        if (afl->afl_env.afl_exit_on_seed_issues) {
 
-        struct queue_entry *p = afl->queue;
+          FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits.");
 
-        if (!p->was_fuzzed) {
+        }
 
-          p->was_fuzzed = 1;
+        /* Remove from fuzzing queue but keep for splicing */
+
+        if (!q->was_fuzzed) {
+
+          q->was_fuzzed = 1;
           --afl->pending_not_fuzzed;
           --afl->active_paths;
 
         }
 
-        p->disabled = 1;
-        p->perf_score = 0;
+        q->disabled = 1;
+        q->perf_score = 0;
 
         u32 i = 0;
         while (unlikely(i < afl->queued_paths && afl->queue_buf[i] &&
@@ -1113,14 +1109,12 @@ void perform_dry_run(afl_state_t *afl) {
 
     if (cal_failures == afl->queued_paths) {
 
-      FATAL("All test cases time out%s, giving up!",
-            skip_crashes ? " or crash" : "");
+      FATAL("All test cases time out or crash, giving up!");
 
     }
 
-    WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures,
-          ((double)cal_failures) * 100 / afl->queued_paths,
-          skip_crashes ? " or crashes" : "");
+    WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.",
+          cal_failures, ((double)cal_failures) * 100 / afl->queued_paths);
 
     if (cal_failures * 5 > afl->queued_paths) {
 
@@ -1288,9 +1282,13 @@ void pivot_inputs(afl_state_t *afl) {
 
       if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) {
 
-        struct queue_entry *s = afl->queue_buf[src_id];
+        if (src_id < afl->queued_paths) {
 
-        if (s) { q->depth = s->depth + 1; }
+          struct queue_entry *s = afl->queue_buf[src_id];
+
+          if (s) { q->depth = s->depth + 1; }
+
+        }
 
         if (afl->max_depth < q->depth) { afl->max_depth = q->depth; }
 
@@ -2025,7 +2023,7 @@ void setup_dirs_fds(afl_state_t *afl) {
 
     fprintf(
         afl->fsrv.plot_file,
-        "# unix_time, cycles_done, cur_path, paths_total, "
+        "# relative_time, cycles_done, cur_path, paths_total, "
         "pending_total, pending_favs, map_size, unique_crashes, "
         "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
 
@@ -2490,6 +2488,18 @@ void check_asan_opts(afl_state_t *afl) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "symbolize=0")) {
+
+      FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+    }
+
+  }
+
 }
 
 /* Handle stop signal (Ctrl-C, etc). */
@@ -2692,7 +2702,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
 #endif                                                       /* ^!__APPLE__ */
 
-  if (!afl->fsrv.qemu_mode && !afl->unicorn_mode &&
+  if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
       !afl->non_instrumented_mode &&
       !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
@@ -2708,11 +2718,15 @@ void check_binary(afl_state_t *afl, u8 *fname) {
          "    When source code is not available, you may be able to leverage "
          "QEMU\n"
          "    mode support. Consult the README.md for tips on how to enable "
-         "this.\n"
+         "this.\n\n"
+
+         "    If your target is an instrumented binary (e.g. with zafl, "
+         "retrowrite,\n"
+         "    etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n"
 
          "    (It is also possible to use afl-fuzz as a traditional, "
-         "non-instrumented fuzzer.\n"
-         "    For that, you can use the -n option - but expect much worse "
+         "non-instrumented\n"
+         "    fuzzer. For that use the -n option - but expect much worse "
          "results.)\n",
          doc_path);
 
@@ -2720,7 +2734,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
   }
 
-  if ((afl->fsrv.qemu_mode) &&
+  if ((afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
       memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
@@ -2735,7 +2749,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
   }
 
   if (memmem(f_data, f_len, "__asan_init", 11) ||
-      memmem(f_data, f_len, "__msan_init", 11)) {
+      memmem(f_data, f_len, "__msan_init", 11) ||
+      memmem(f_data, f_len, "__lsan_init", 11)) {
 
     afl->fsrv.uses_asan = 1;
 
@@ -2755,9 +2770,18 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
     WARNF("AFL_PERSISTENT is no longer supported and may misbehave!");
 
+  } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) {
+
+    OKF("FRIDA Persistent mode configuration options detected.");
+    setenv(PERSIST_ENV_VAR, "1", 1);
+    afl->persistent_mode = 1;
+
+    afl->shmem_testcase_mode = 1;
+
   }
 
-  if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+  if (afl->fsrv.frida_mode ||
+      memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
 
     OKF(cPIN "Deferred forkserver binary detected.");
     setenv(DEFER_ENV_VAR, "1", 1);
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index a47b4f5f..e27d6fae 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -308,9 +308,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
 u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
                     struct custom_mutator *mutator) {
 
-  u8  needs_write = 0, fault = 0;
+  u8  fault = 0;
   u32 trim_exec = 0;
   u32 orig_len = q->len;
+  u32 out_len = 0;
+  u8 *out_buf = NULL;
 
   u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
 
@@ -397,27 +399,33 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
     if (likely(retlen && cksum == q->exec_cksum)) {
 
-      q->len = retlen;
-      memcpy(in_buf, retbuf, retlen);
-
       /* Let's save a clean trace, which will be needed by
-         update_bitmap_score once we're done with the trimming stuff. */
+         update_bitmap_score once we're done with the trimming stuff.
+         Use out_buf NULL check to make this only happen once per trim. */
 
-      if (!needs_write) {
+      if (!out_buf) {
 
-        needs_write = 1;
         memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
                afl->fsrv.map_size);
 
       }
 
+      if (afl_realloc((void **)&out_buf, retlen) == NULL) {
+
+        FATAL("can not allocate memory for trim");
+
+      }
+
+      out_len = retlen;
+      memcpy(out_buf, retbuf, retlen);
+
       /* Tell the custom mutator that the trimming was successful */
       afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
 
       if (afl->not_on_tty && afl->debug) {
 
         SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)",
-             afl->stage_cur, afl->stage_max, q->len);
+             afl->stage_cur, afl->stage_max, out_len);
 
       }
 
@@ -450,16 +458,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
   }
 
-  if (afl->not_on_tty && afl->debug) {
-
-    SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
-
-  }
-
-  /* If we have made changes to in_buf, we also need to update the on-disk
+  /* If we have made changes, we also need to update the on-disk
      version of the test case. */
 
-  if (needs_write) {
+  if (out_buf) {
 
     s32 fd;
 
@@ -469,16 +471,28 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
     if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
 
-    ck_write(fd, in_buf, q->len, q->fname);
+    ck_write(fd, out_buf, out_len, q->fname);
     close(fd);
 
+    /* Update the queue's knowledge of length as soon as we write the file.
+       We do this here so that exit/error cases that *don't* update the file
+       also don't update q->len. */
+    q->len = out_len;
+
     memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
     update_bitmap_score(afl, q);
 
   }
 
+  if (afl->not_on_tty && afl->debug) {
+
+    SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
+
+  }
+
 abort_trimming:
 
+  if (out_buf) afl_free(out_buf);
   afl->bytes_trim_out += q->len;
   return fault;
 
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 4e8154cd..c3ce2edd 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -561,8 +561,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
       if (afl->cmplog_lvl == 3 ||
           (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
+          afl->queue_cur->favored ||
           !(afl->fsrv.total_execs % afl->queued_paths) ||
-          get_cur_time() - afl->last_path_time > 300000) {
+          get_cur_time() - afl->last_path_time > 300000) {  // 300 seconds
 
         if (input_to_state_stage(afl, in_buf, out_buf, len)) {
 
@@ -1997,25 +1998,28 @@ havoc_stage:
   /* We essentially just do several thousand runs (depending on perf_score)
      where we take the input file and make random stacked tweaks. */
 
+#define MAX_HAVOC_ENTRY 59                                      /* 55 to 60 */
+
   u32 r_max, r;
 
-  r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+  r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) +
+          (afl->a_extras_cnt ? 4 : 0);
 
   if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
 
     /* add expensive havoc cases here, they are activated after a full
        cycle without finds happened */
 
-    r_max++;
+    r_max += 4;
 
   }
 
-  if (unlikely(get_cur_time() - afl->last_path_time > 5000 &&
+  if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ &&
                afl->ready_for_splicing_count > 1)) {
 
     /* add expensive havoc cases here if there is no findings in the last 5s */
 
-    r_max++;
+    r_max += 4;
 
   }
 
@@ -2069,7 +2073,7 @@ havoc_stage:
 
       switch ((r = rand_below(afl, r_max))) {
 
-        case 0:
+        case 0 ... 3: {
 
           /* Flip a single bit somewhere. Spooky! */
 
@@ -2080,7 +2084,9 @@ havoc_stage:
           FLIP_BIT(out_buf, rand_below(afl, temp_len << 3));
           break;
 
-        case 1:
+        }
+
+        case 4 ... 7: {
 
           /* Set byte to interesting value. */
 
@@ -2092,63 +2098,77 @@ havoc_stage:
               interesting_8[rand_below(afl, sizeof(interesting_8))];
           break;
 
-        case 2:
+        }
+
+        case 8 ... 9: {
 
           /* Set word to interesting value, randomly choosing endian. */
 
           if (temp_len < 2) { break; }
 
-          if (rand_below(afl, 2)) {
-
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
-                interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)];
+          *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
+              interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)];
 
-          } else {
+          break;
+
+        }
+
+        case 10 ... 11: {
+
+          /* Set word to interesting value, randomly choosing endian. */
+
+          if (temp_len < 2) { break; }
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE");
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE");
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16(
-                interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]);
-
-          }
+          *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16(
+              interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]);
 
           break;
 
-        case 3:
+        }
+
+        case 12 ... 13: {
 
           /* Set dword to interesting value, randomly choosing endian. */
 
           if (temp_len < 4) { break; }
 
-          if (rand_below(afl, 2)) {
-
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
-                interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)];
+          *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
+              interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)];
 
-          } else {
+          break;
+
+        }
+
+        case 14 ... 15: {
+
+          /* Set dword to interesting value, randomly choosing endian. */
+
+          if (temp_len < 4) { break; }
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE");
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE");
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32(
-                interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]);
-
-          }
+          *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32(
+              interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]);
 
           break;
 
-        case 4:
+        }
+
+        case 16 ... 19: {
 
           /* Randomly subtract from byte. */
 
@@ -2159,7 +2179,9 @@ havoc_stage:
           out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX);
           break;
 
-        case 5:
+        }
+
+        case 20 ... 23: {
 
           /* Randomly add to byte. */
 
@@ -2170,139 +2192,165 @@ havoc_stage:
           out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX);
           break;
 
-        case 6:
+        }
 
-          /* Randomly subtract from word, random endian. */
+        case 24 ... 25: {
 
-          if (temp_len < 2) { break; }
+          /* Randomly subtract from word, little endian. */
 
-          if (rand_below(afl, 2)) {
+          if (temp_len < 2) { break; }
 
-            u32 pos = rand_below(afl, temp_len - 1);
+          u32 pos = rand_below(afl, temp_len - 1);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+          *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
 
-          } else {
+          break;
 
-            u32 pos = rand_below(afl, temp_len - 1);
-            u16 num = 1 + rand_below(afl, ARITH_MAX);
+        }
+
+        case 26 ... 27: {
+
+          /* Randomly subtract from word, big endian. */
+
+          if (temp_len < 2) { break; }
+
+          u32 pos = rand_below(afl, temp_len - 1);
+          u16 num = 1 + rand_below(afl, ARITH_MAX);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos,
-                     num);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos,
+                   num);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + pos) =
-                SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num);
-
-          }
+          *(u16 *)(out_buf + pos) =
+              SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num);
 
           break;
 
-        case 7:
+        }
 
-          /* Randomly add to word, random endian. */
+        case 28 ... 29: {
 
-          if (temp_len < 2) { break; }
+          /* Randomly add to word, little endian. */
 
-          if (rand_below(afl, 2)) {
+          if (temp_len < 2) { break; }
 
-            u32 pos = rand_below(afl, temp_len - 1);
+          u32 pos = rand_below(afl, temp_len - 1);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+          *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
 
-          } else {
+          break;
+
+        }
+
+        case 30 ... 31: {
 
-            u32 pos = rand_below(afl, temp_len - 1);
-            u16 num = 1 + rand_below(afl, ARITH_MAX);
+          /* Randomly add to word, big endian. */
+
+          if (temp_len < 2) { break; }
+
+          u32 pos = rand_below(afl, temp_len - 1);
+          u16 num = 1 + rand_below(afl, ARITH_MAX);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos,
-                     num);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos,
+                   num);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u16 *)(out_buf + pos) =
-                SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num);
-
-          }
+          *(u16 *)(out_buf + pos) =
+              SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num);
 
           break;
 
-        case 8:
+        }
 
-          /* Randomly subtract from dword, random endian. */
+        case 32 ... 33: {
 
-          if (temp_len < 4) { break; }
+          /* Randomly subtract from dword, little endian. */
 
-          if (rand_below(afl, 2)) {
+          if (temp_len < 4) { break; }
 
-            u32 pos = rand_below(afl, temp_len - 3);
+          u32 pos = rand_below(afl, temp_len - 3);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+          *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
 
-          } else {
+          break;
+
+        }
+
+        case 34 ... 35: {
+
+          /* Randomly subtract from dword, big endian. */
+
+          if (temp_len < 4) { break; }
 
-            u32 pos = rand_below(afl, temp_len - 3);
-            u32 num = 1 + rand_below(afl, ARITH_MAX);
+          u32 pos = rand_below(afl, temp_len - 3);
+          u32 num = 1 + rand_below(afl, ARITH_MAX);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos,
-                     num);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos,
+                   num);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + pos) =
-                SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num);
-
-          }
+          *(u32 *)(out_buf + pos) =
+              SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num);
 
           break;
 
-        case 9:
+        }
 
-          /* Randomly add to dword, random endian. */
+        case 36 ... 37: {
 
-          if (temp_len < 4) { break; }
+          /* Randomly add to dword, little endian. */
 
-          if (rand_below(afl, 2)) {
+          if (temp_len < 4) { break; }
 
-            u32 pos = rand_below(afl, temp_len - 3);
+          u32 pos = rand_below(afl, temp_len - 3);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+          *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
 
-          } else {
+          break;
+
+        }
+
+        case 38 ... 39: {
 
-            u32 pos = rand_below(afl, temp_len - 3);
-            u32 num = 1 + rand_below(afl, ARITH_MAX);
+          /* Randomly add to dword, big endian. */
+
+          if (temp_len < 4) { break; }
+
+          u32 pos = rand_below(afl, temp_len - 3);
+          u32 num = 1 + rand_below(afl, ARITH_MAX);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos,
-                     num);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos,
+                   num);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            *(u32 *)(out_buf + pos) =
-                SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num);
-
-          }
+          *(u32 *)(out_buf + pos) =
+              SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num);
 
           break;
 
-        case 10:
+        }
+
+        case 40 ... 43: {
 
           /* Just set a random byte to a random value. Because,
              why not. We use XOR with 1-255 to eliminate the
@@ -2315,67 +2363,64 @@ havoc_stage:
           out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255);
           break;
 
-        case 11 ... 12: {
-
-          /* Delete bytes. We're making this a bit more likely
-             than insertion (the next option) in hopes of keeping
-             files reasonably small. */
+        }
 
-          u32 del_from, del_len;
+        case 44 ... 46: {
 
-          if (temp_len < 2) { break; }
-
-          /* Don't delete too much. */
+          if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
 
-          del_len = choose_block_len(afl, temp_len - 1);
+            /* Clone bytes. */
 
-          del_from = rand_below(afl, temp_len - del_len + 1);
+            u32 clone_len = choose_block_len(afl, temp_len);
+            u32 clone_from = rand_below(afl, temp_len - clone_len + 1);
+            u32 clone_to = rand_below(afl, temp_len);
 
 #ifdef INTROSPECTION
-          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from,
-                   del_len);
-          strcat(afl->mutation, afl->m_tmp);
+            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u",
+                     "clone", clone_from, clone_to, clone_len);
+            strcat(afl->mutation, afl->m_tmp);
 #endif
-          memmove(out_buf + del_from, out_buf + del_from + del_len,
-                  temp_len - del_from - del_len);
+            u8 *new_buf =
+                afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
+            if (unlikely(!new_buf)) { PFATAL("alloc"); }
 
-          temp_len -= del_len;
+            /* Head */
 
-          break;
+            memcpy(new_buf, out_buf, clone_to);
 
-        }
+            /* Inserted part */
 
-        case 13:
+            memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
 
-          if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+            /* Tail */
+            memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
+                   temp_len - clone_to);
 
-            /* Clone bytes (75%) or insert a block of constant bytes (25%). */
+            out_buf = new_buf;
+            afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+            temp_len += clone_len;
 
-            u8  actually_clone = rand_below(afl, 4);
-            u32 clone_from, clone_to, clone_len;
-            u8 *new_buf;
+          }
 
-            if (likely(actually_clone)) {
+          break;
 
-              clone_len = choose_block_len(afl, temp_len);
-              clone_from = rand_below(afl, temp_len - clone_len + 1);
+        }
 
-            } else {
+        case 47: {
 
-              clone_len = choose_block_len(afl, HAVOC_BLK_XL);
-              clone_from = 0;
+          if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
 
-            }
+            /* Insert a block of constant bytes (25%). */
 
-            clone_to = rand_below(afl, temp_len);
+            u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL);
+            u32 clone_to = rand_below(afl, temp_len);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u",
-                     actually_clone ? "clone" : "insert", clone_from, clone_to,
-                     clone_len);
+            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u",
+                     "insert", clone_to, clone_len);
             strcat(afl->mutation, afl->m_tmp);
 #endif
-            new_buf =
+            u8 *new_buf =
                 afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
             if (unlikely(!new_buf)) { PFATAL("alloc"); }
 
@@ -2385,18 +2430,10 @@ havoc_stage:
 
             /* Inserted part */
 
-            if (likely(actually_clone)) {
-
-              memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
-
-            } else {
-
-              memset(new_buf + clone_to,
-                     rand_below(afl, 2) ? rand_below(afl, 256)
-                                        : out_buf[rand_below(afl, temp_len)],
-                     clone_len);
-
-            }
+            memset(new_buf + clone_to,
+                   rand_below(afl, 2) ? rand_below(afl, 256)
+                                      : out_buf[rand_below(afl, temp_len)],
+                   clone_len);
 
             /* Tail */
             memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
@@ -2410,47 +2447,79 @@ havoc_stage:
 
           break;
 
-        case 14: {
+        }
 
-          /* Overwrite bytes with a randomly selected chunk (75%) or fixed
-             bytes (25%). */
+        case 48 ... 50: {
 
-          u32 copy_from, copy_to, copy_len;
+          /* Overwrite bytes with a randomly selected chunk bytes. */
 
           if (temp_len < 2) { break; }
 
-          copy_len = choose_block_len(afl, temp_len - 1);
+          u32 copy_len = choose_block_len(afl, temp_len - 1);
+          u32 copy_from = rand_below(afl, temp_len - copy_len + 1);
+          u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+          if (likely(copy_from != copy_to)) {
+
+#ifdef INTROSPECTION
+            snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_COPY-%u-%u-%u",
+                     copy_from, copy_to, copy_len);
+            strcat(afl->mutation, afl->m_tmp);
+#endif
+            memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
+
+          }
+
+          break;
+
+        }
+
+        case 51: {
 
-          copy_from = rand_below(afl, temp_len - copy_len + 1);
-          copy_to = rand_below(afl, temp_len - copy_len + 1);
+          /* Overwrite bytes with fixed bytes. */
 
-          if (likely(rand_below(afl, 4))) {
+          if (temp_len < 2) { break; }
 
-            if (likely(copy_from != copy_to)) {
+          u32 copy_len = choose_block_len(afl, temp_len - 1);
+          u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
 
 #ifdef INTROSPECTION
-              snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                       " OVERWRITE_COPY-%u-%u-%u", copy_from, copy_to,
-                       copy_len);
-              strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u",
+                   copy_to, copy_len);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-              memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
+          memset(out_buf + copy_to,
+                 rand_below(afl, 2) ? rand_below(afl, 256)
+                                    : out_buf[rand_below(afl, temp_len)],
+                 copy_len);
 
-            }
+          break;
 
-          } else {
+        }
+
+        // increase from 4 up to 8?
+        case 52 ... MAX_HAVOC_ENTRY: {
+
+          /* Delete bytes. We're making this a bit more likely
+             than insertion (the next option) in hopes of keeping
+             files reasonably small. */
+
+          if (temp_len < 2) { break; }
+
+          /* Don't delete too much. */
+
+          u32 del_len = choose_block_len(afl, temp_len - 1);
+          u32 del_from = rand_below(afl, temp_len - del_len + 1);
 
 #ifdef INTROSPECTION
-            snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                     " OVERWRITE_FIXED-%u-%u-%u", copy_from, copy_to, copy_len);
-            strcat(afl->mutation, afl->m_tmp);
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from,
+                   del_len);
+          strcat(afl->mutation, afl->m_tmp);
 #endif
-            memset(out_buf + copy_to,
-                   rand_below(afl, 2) ? rand_below(afl, 256)
-                                      : out_buf[rand_below(afl, temp_len)],
-                   copy_len);
+          memmove(out_buf + del_from, out_buf + del_from + del_len,
+                  temp_len - del_from - del_len);
 
-          }
+          temp_len -= del_len;
 
           break;
 
@@ -2458,93 +2527,101 @@ havoc_stage:
 
         default:
 
-          if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) {
+          r -= (MAX_HAVOC_ENTRY + 1);
 
-            /* Values 15 and 16 can be selected only if there are any extras
-               present in the dictionaries. */
+          if (afl->extras_cnt) {
 
-            if (r == 15) {
-
-              /* Overwrite bytes with an extra. */
-
-              if (!afl->extras_cnt ||
-                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+            if (r < 2) {
 
-                /* No user-specified extras or odds in our favor. Let's use an
-                   auto-detected one. */
+              /* Use the dictionary. */
 
-                u32 use_extra = rand_below(afl, afl->a_extras_cnt);
-                u32 extra_len = afl->a_extras[use_extra].len;
+              u32 use_extra = rand_below(afl, afl->extras_cnt);
+              u32 extra_len = afl->extras[use_extra].len;
 
-                if (extra_len > temp_len) { break; }
+              if (extra_len > temp_len) { break; }
 
-                u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+              u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+              snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_OVERWRITE-%u-%u",
+                       insert_at, extra_len);
+              strcat(afl->mutation, afl->m_tmp);
 #endif
-                memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
-                       extra_len);
+              memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+                     extra_len);
 
-              } else {
-
-                /* No auto extras or odds in our favor. Use the dictionary. */
+              break;
 
-                u32 use_extra = rand_below(afl, afl->extras_cnt);
-                u32 extra_len = afl->extras[use_extra].len;
+            } else if (r < 4) {
 
-                if (extra_len > temp_len) { break; }
+              u32 use_extra = rand_below(afl, afl->extras_cnt);
+              u32 extra_len = afl->extras[use_extra].len;
+              if (temp_len + extra_len >= MAX_FILE) { break; }
 
-                u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+              u8 *ptr = afl->extras[use_extra].data;
+              u32 insert_at = rand_below(afl, temp_len + 1);
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+              snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u",
+                       insert_at, extra_len);
+              strcat(afl->mutation, afl->m_tmp);
 #endif
-                memcpy(out_buf + insert_at, afl->extras[use_extra].data,
-                       extra_len);
 
-              }
+              out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+              if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+              /* Tail */
+              memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+                      temp_len - insert_at);
+
+              /* Inserted part */
+              memcpy(out_buf + insert_at, ptr, extra_len);
+              temp_len += extra_len;
 
               break;
 
-            } else {  // case 16
+            } else {
 
-              u32 use_extra, extra_len,
-                  insert_at = rand_below(afl, temp_len + 1);
-              u8 *ptr;
+              r -= 4;
 
-              /* Insert an extra. Do the same dice-rolling stuff as for the
-                 previous case. */
+            }
 
-              if (!afl->extras_cnt ||
-                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+          }
 
-                use_extra = rand_below(afl, afl->a_extras_cnt);
-                extra_len = afl->a_extras[use_extra].len;
-                ptr = afl->a_extras[use_extra].data;
-#ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
-#endif
+          if (afl->a_extras_cnt) {
 
-              } else {
+            if (r < 2) {
 
-                use_extra = rand_below(afl, afl->extras_cnt);
-                extra_len = afl->extras[use_extra].len;
-                ptr = afl->extras[use_extra].data;
+              /* Use the dictionary. */
+
+              u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+              u32 extra_len = afl->a_extras[use_extra].len;
+
+              if (extra_len > temp_len) { break; }
+
+              u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u",
-                         insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+              snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                       " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+              strcat(afl->mutation, afl->m_tmp);
 #endif
+              memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+                     extra_len);
 
-              }
+              break;
+
+            } else if (r < 4) {
 
+              u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+              u32 extra_len = afl->a_extras[use_extra].len;
               if (temp_len + extra_len >= MAX_FILE) { break; }
 
+              u8 *ptr = afl->a_extras[use_extra].data;
+              u32 insert_at = rand_below(afl, temp_len + 1);
+#ifdef INTROSPECTION
+              snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                       " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
+              strcat(afl->mutation, afl->m_tmp);
+#endif
+
               out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
               if (unlikely(!out_buf)) { PFATAL("alloc"); }
 
@@ -2554,103 +2631,97 @@ havoc_stage:
 
               /* Inserted part */
               memcpy(out_buf + insert_at, ptr, extra_len);
-
               temp_len += extra_len;
 
               break;
 
-            }
+            } else {
 
-          } else {
+              r -= 4;
 
-            /*
-                        switch (r) {
+            }
 
-                          case 15:  // fall through
-                          case 16:
-                          case 17: {*/
+          }
 
-            /* Overwrite bytes with a randomly selected chunk from another
-               testcase or insert that chunk. */
+          /* Splicing otherwise if we are still here.
+             Overwrite bytes with a randomly selected chunk from another
+             testcase or insert that chunk. */
 
-            /* Pick a random queue entry and seek to it. */
+          /* Pick a random queue entry and seek to it. */
 
-            u32 tid;
-            do {
+          u32 tid;
+          do {
 
-              tid = rand_below(afl, afl->queued_paths);
+            tid = rand_below(afl, afl->queued_paths);
 
-            } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+          } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
 
-            /* Get the testcase for splicing. */
-            struct queue_entry *target = afl->queue_buf[tid];
-            u32                 new_len = target->len;
-            u8 *                new_buf = queue_testcase_get(afl, target);
+          /* Get the testcase for splicing. */
+          struct queue_entry *target = afl->queue_buf[tid];
+          u32                 new_len = target->len;
+          u8 *                new_buf = queue_testcase_get(afl, target);
 
-            if ((temp_len >= 2 && rand_below(afl, 2)) ||
-                temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+          if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) {
 
-              /* overwrite mode */
+            /* overwrite mode */
 
-              u32 copy_from, copy_to, copy_len;
+            u32 copy_from, copy_to, copy_len;
 
-              copy_len = choose_block_len(afl, new_len - 1);
-              if (copy_len > temp_len) copy_len = temp_len;
+            copy_len = choose_block_len(afl, new_len - 1);
+            if (copy_len > temp_len) copy_len = temp_len;
 
-              copy_from = rand_below(afl, new_len - copy_len + 1);
-              copy_to = rand_below(afl, temp_len - copy_len + 1);
+            copy_from = rand_below(afl, new_len - copy_len + 1);
+            copy_to = rand_below(afl, temp_len - copy_len + 1);
 
 #ifdef INTROSPECTION
-              snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                       " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
-                       copy_len, target->fname);
-              strcat(afl->mutation, afl->m_tmp);
+            snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                     " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
+                     copy_len, target->fname);
+            strcat(afl->mutation, afl->m_tmp);
 #endif
-              memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+            memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
 
-            } else {
+          } else {
 
-              /* insert mode */
+            /* insert mode */
 
-              u32 clone_from, clone_to, clone_len;
+            u32 clone_from, clone_to, clone_len;
 
-              clone_len = choose_block_len(afl, new_len);
-              clone_from = rand_below(afl, new_len - clone_len + 1);
-              clone_to = rand_below(afl, temp_len + 1);
+            clone_len = choose_block_len(afl, new_len);
+            clone_from = rand_below(afl, new_len - clone_len + 1);
+            clone_to = rand_below(afl, temp_len + 1);
 
-              u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
-                                         temp_len + clone_len + 1);
-              if (unlikely(!temp_buf)) { PFATAL("alloc"); }
+            u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+                                       temp_len + clone_len + 1);
+            if (unlikely(!temp_buf)) { PFATAL("alloc"); }
 
 #ifdef INTROSPECTION
-              snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                       " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
-                       clone_len, target->fname);
-              strcat(afl->mutation, afl->m_tmp);
+            snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                     " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
+                     clone_len, target->fname);
+            strcat(afl->mutation, afl->m_tmp);
 #endif
-              /* Head */
-
-              memcpy(temp_buf, out_buf, clone_to);
-
-              /* Inserted part */
+            /* Head */
 
-              memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+            memcpy(temp_buf, out_buf, clone_to);
 
-              /* Tail */
-              memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
-                     temp_len - clone_to);
+            /* Inserted part */
 
-              out_buf = temp_buf;
-              afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
-              temp_len += clone_len;
+            memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
 
-            }
+            /* Tail */
+            memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+                   temp_len - clone_to);
 
-            break;
+            out_buf = temp_buf;
+            afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+            temp_len += clone_len;
 
           }
 
-          // end of default:
+          break;
+
+          // end of default
 
       }
 
@@ -2940,13 +3011,13 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
     u8 res = trim_case(afl, afl->queue_cur, in_buf);
     orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
 
-    if (res == FSRV_RUN_ERROR) {
+    if (unlikely(res == FSRV_RUN_ERROR)) {
 
       FATAL("Unable to execute target application");
 
     }
 
-    if (afl->stop_soon) {
+    if (unlikely(afl->stop_soon)) {
 
       ++afl->cur_skipped_paths;
       goto abandon_entry;
@@ -2990,7 +3061,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
       if (afl->cmplog_lvl == 3 ||
           (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
           !(afl->fsrv.total_execs % afl->queued_paths) ||
-          get_cur_time() - afl->last_path_time > 300000) {
+          get_cur_time() - afl->last_path_time > 300000) {  // 300 seconds
 
         if (input_to_state_stage(afl, in_buf, out_buf, len)) {
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 8760194c..3aa97635 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
         PyObject_GetAttrString(py_module, "introspection");
     py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
     if (!py_functions[PY_FUNC_DEINIT])
-      FATAL("deinit function not found in python module");
+      WARNF("deinit function not found in python module");
 
     for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
 
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index e5f51a6c..811e805c 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -478,7 +478,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
         u8 *fname_orig = NULL;
 
         /* At the initialization stage, queue_cur is NULL */
-        if (afl->queue_cur) fname_orig = afl->queue_cur->fname;
+        if (afl->queue_cur && !afl->syncing_party) {
+
+          fname_orig = afl->queue_cur->fname;
+
+        }
 
         el->afl_custom_queue_new_entry(el->data, fname, fname_orig);
 
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 9bfbf95b..22fd0621 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -437,8 +437,8 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
 
   if (taint) {
 
-    if (afl->colorize_success &&
-        (len / positions == 1 && positions > CMPLOG_POSITIONS_MAX &&
+    if (afl->colorize_success && afl->cmplog_lvl < 3 &&
+        (positions > CMPLOG_POSITIONS_MAX && len / positions == 1 &&
          afl->active_paths / afl->colorize_success > CMPLOG_CORPUS_PERCENT)) {
 
 #ifdef _DEBUG
@@ -1749,6 +1749,12 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
 
 #endif
 
+#ifdef _DEBUG
+      if (o->v0 != orig_o->v0 || o->v1 != orig_o->v1)
+        fprintf(stderr, "key=%u idx=%u o0=%llu v0=%llu o1=%llu v1=%llu\n", key,
+                idx, orig_o->v0, o->v0, orig_o->v1, o->v1);
+#endif
+
       // even for u128 and _ExtInt we do cmp_extend_encoding() because
       // if we got here their own special trials failed and it might just be
       // a cast from e.g. u64 to u128 from the input data.
@@ -2365,6 +2371,24 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
 
       status = 0;
 
+#ifdef _DEBUG
+      int w;
+      fprintf(stderr, "key=%u idx=%u len=%u o0=", key, idx,
+              SHAPE_BYTES(h->shape));
+      for (w = 0; w < SHAPE_BYTES(h->shape); ++w)
+        fprintf(stderr, "%02x", orig_o->v0[w]);
+      fprintf(stderr, " v0=");
+      for (w = 0; w < SHAPE_BYTES(h->shape); ++w)
+        fprintf(stderr, "%02x", o->v0[w]);
+      fprintf(stderr, " o1=");
+      for (w = 0; w < SHAPE_BYTES(h->shape); ++w)
+        fprintf(stderr, "%02x", orig_o->v1[w]);
+      fprintf(stderr, " v1=");
+      for (w = 0; w < SHAPE_BYTES(h->shape); ++w)
+        fprintf(stderr, "%02x", o->v1[w]);
+      fprintf(stderr, "\n");
+#endif
+
       if (unlikely(rtn_extend_encoding(
               afl, o->v0, o->v1, orig_o->v0, orig_o->v1, SHAPE_BYTES(h->shape),
               idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) {
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 83133dad..2c3e8a1b 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -107,27 +107,21 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
         new_size =
             el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
 
-      }
-
-      new_mem = new_buf;
-
-    });
-
-    if (unlikely(!new_buf && (new_size <= 0))) {
+        if (unlikely(!new_buf && new_size <= 0)) {
 
-      FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size);
+          FATAL("Custom_post_process failed (ret: %lu)",
+                (long unsigned)new_size);
 
-    } else if (likely(new_buf)) {
+        }
 
-      /* everything as planned. use the new data. */
-      afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size);
+        new_mem = new_buf;
 
-    } else {
+      }
 
-      /* custom mutators do not has a custom_post_process function */
-      afl_fsrv_write_to_testcase(&afl->fsrv, mem, len);
+    });
 
-    }
+    /* everything as planned. use the potentially new data. */
+    afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size);
 
   } else {
 
@@ -188,22 +182,22 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
         new_size =
             el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
 
-        if (unlikely(!new_buf || (new_size <= 0))) {
+        if (unlikely(!new_buf || new_size <= 0)) {
 
           FATAL("Custom_post_process failed (ret: %lu)",
                 (long unsigned)new_size);
 
         }
 
-      }
+        new_mem = new_buf;
 
-      new_mem = new_buf;
+      }
 
     });
 
   }
 
-  if (afl->fsrv.shmem_fuzz) {
+  if (likely(afl->fsrv.use_shmem_fuzz)) {
 
     if (!post_process_skipped) {
 
@@ -211,9 +205,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
 
       memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size);
 
-    }
-
-    else {
+    } else {
 
       memcpy(afl->fsrv.shmem_fuzz, mem, skip_at);
 
@@ -244,7 +236,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
 
     return;
 
-  } else if (afl->fsrv.out_file) {
+  } else if (unlikely(!afl->fsrv.use_stdin)) {
 
     if (unlikely(afl->no_unlink)) {
 
@@ -279,7 +271,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
 
   }
 
-  if (!afl->fsrv.out_file) {
+  if (afl->fsrv.use_stdin) {
 
     if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); }
     lseek(fd, 0, SEEK_SET);
@@ -412,7 +404,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
         }
 
         var_detected = 1;
-        afl->stage_max = CAL_CYCLES_LONG;
+        afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG;
 
       } else {
 
@@ -712,6 +704,7 @@ void sync_fuzzers(afl_state_t *afl) {
   if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0);
 
   afl->last_sync_time = get_cur_time();
+  afl->last_sync_cycle = afl->queue_cycle;
 
 }
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 0ddf8cf3..0658070e 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -99,10 +99,11 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
   afl->cal_cycles = CAL_CYCLES;
   afl->cal_cycles_long = CAL_CYCLES_LONG;
   afl->hang_tmout = EXEC_TIMEOUT;
+  afl->exit_on_time = 0;
   afl->stats_update_freq = 1;
   afl->stats_avg_exec = 0;
   afl->skip_deterministic = 1;
-  afl->cmplog_lvl = 1;
+  afl->cmplog_lvl = 2;
 #ifndef NO_SPLICING
   afl->use_splicing = 1;
 #endif
@@ -187,6 +188,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_exit_when_done =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_EXIT_ON_TIME",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_exit_on_time =
+                (u8 *)get_afl_env(afl_environment_variables[i]);
+
           } else if (!strncmp(env, "AFL_NO_AFFINITY",
 
                               afl_environment_variable_len)) {
@@ -194,12 +202,18 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_no_affinity =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_TRY_AFFINITY",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_try_affinity =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_SKIP_CRASHES",
 
                               afl_environment_variable_len)) {
 
-            afl->afl_env.afl_skip_crashes =
-                (u8 *)get_afl_env(afl_environment_variables[i]);
+            // we should mark this obsolete in a few versions
 
           } else if (!strncmp(env, "AFL_HANG_TMOUT",
 
@@ -292,6 +306,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_autoresume =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_PERSISTENT_RECORD",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_persistent_record =
+                get_afl_env(afl_environment_variables[i]);
+
           } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
 
                               afl_environment_variable_len)) {
@@ -299,6 +320,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->cycle_schedules = afl->afl_env.afl_cycle_schedules =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_EXIT_ON_SEED_ISSUES",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_exit_on_seed_issues =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW",
 
                               afl_environment_variable_len)) {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 2c814d90..4884b942 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -179,6 +179,8 @@ void load_stats_file(afl_state_t *afl) {
 
   }
 
+  if (afl->unique_crashes) { write_crash_readme(afl); }
+
   return;
 
 }
@@ -355,18 +357,19 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
                             double eps) {
 
-  if (unlikely(afl->stop_soon) ||
-      unlikely(afl->plot_prev_qp == afl->queued_paths &&
-               afl->plot_prev_pf == afl->pending_favored &&
-               afl->plot_prev_pnf == afl->pending_not_fuzzed &&
-               afl->plot_prev_ce == afl->current_entry &&
-               afl->plot_prev_qc == afl->queue_cycle &&
-               afl->plot_prev_uc == afl->unique_crashes &&
-               afl->plot_prev_uh == afl->unique_hangs &&
-               afl->plot_prev_md == afl->max_depth &&
-               afl->plot_prev_ed == afl->fsrv.total_execs) ||
-      unlikely(!afl->queue_cycle) ||
-      unlikely(get_cur_time() - afl->start_time <= 60)) {
+  if (unlikely(!afl->force_ui_update &&
+               (afl->stop_soon ||
+                (afl->plot_prev_qp == afl->queued_paths &&
+                 afl->plot_prev_pf == afl->pending_favored &&
+                 afl->plot_prev_pnf == afl->pending_not_fuzzed &&
+                 afl->plot_prev_ce == afl->current_entry &&
+                 afl->plot_prev_qc == afl->queue_cycle &&
+                 afl->plot_prev_uc == afl->unique_crashes &&
+                 afl->plot_prev_uh == afl->unique_hangs &&
+                 afl->plot_prev_md == afl->max_depth &&
+                 afl->plot_prev_ed == afl->fsrv.total_execs) ||
+                !afl->queue_cycle ||
+                get_cur_time() - afl->start_time <= 60000))) {
 
     return;
 
@@ -384,14 +387,14 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 
   /* Fields in the file:
 
-     unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed,
+     relative_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed,
      favored_not_fuzzed, unique_crashes, unique_hangs, max_depth,
      execs_per_sec, edges_found */
 
   fprintf(afl->fsrv.plot_file,
           "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
           "%u\n",
-          (afl->prev_run_time + get_cur_time() - afl->start_time),
+          ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
           afl->queue_cycle - 1, afl->current_entry, afl->queued_paths,
           afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
           afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
@@ -531,7 +534,8 @@ void show_stats(afl_state_t *afl) {
 
   /* Roughly every minute, update fuzzer stats and save auto tokens. */
 
-  if (cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000) {
+  if (unlikely(afl->force_ui_update ||
+               cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000)) {
 
     afl->stats_last_stats_ms = cur_ms;
     write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio,
@@ -543,7 +547,8 @@ void show_stats(afl_state_t *afl) {
 
   if (unlikely(afl->afl_env.afl_statsd)) {
 
-    if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) {
+    if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms >
+                                             STATSD_UPDATE_SEC * 1000)) {
 
       /* reset counter, even if send failed. */
       afl->statsd_last_send_ms = cur_ms;
@@ -555,7 +560,8 @@ void show_stats(afl_state_t *afl) {
 
   /* Every now and then, write plot data. */
 
-  if (cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000) {
+  if (unlikely(afl->force_ui_update ||
+               cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000)) {
 
     afl->stats_last_plot_ms = cur_ms;
     maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec);
@@ -564,14 +570,24 @@ void show_stats(afl_state_t *afl) {
 
   /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
 
-  if (!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
-      !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done) {
+  if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
+               !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) {
 
     afl->stop_soon = 2;
 
   }
 
-  if (afl->total_crashes && afl->afl_env.afl_bench_until_crash) {
+  /* AFL_EXIT_ON_TIME. */
+
+  if (unlikely(afl->last_path_time && !afl->non_instrumented_mode &&
+               afl->afl_env.afl_exit_on_time &&
+               (cur_ms - afl->last_path_time) > afl->exit_on_time)) {
+
+    afl->stop_soon = 2;
+
+  }
+
+  if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) {
 
     afl->stop_soon = 2;
 
@@ -583,7 +599,7 @@ void show_stats(afl_state_t *afl) {
 
   /* If we haven't started doing things, bail out. */
 
-  if (!afl->queue_cur) { return; }
+  if (unlikely(!afl->queue_cur)) { return; }
 
   /* Compute some mildly useful bitmap stats. */
 
@@ -602,7 +618,7 @@ void show_stats(afl_state_t *afl) {
 
   SAYF(TERM_HOME);
 
-  if (afl->term_too_small) {
+  if (unlikely(afl->term_too_small)) {
 
     SAYF(cBRI
          "Your terminal is too small to display the UI.\n"
@@ -861,9 +877,13 @@ void show_stats(afl_state_t *afl) {
        " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
        " path geometry " bSTG bH5 bH2 bVL "\n");
 
-  if (afl->skip_deterministic) {
+  if (unlikely(afl->custom_only)) {
+
+    strcpy(tmp, "disabled (custom-mutator-only mode)");
+
+  } else if (likely(afl->skip_deterministic)) {
 
-    strcpy(tmp, "n/a, n/a, n/a");
+    strcpy(tmp, "disabled (default, enable with -D)");
 
   } else {
 
@@ -881,7 +901,7 @@ void show_stats(afl_state_t *afl) {
                 "    levels : " cRST "%-10s" bSTG       bV "\n",
        tmp, u_stringify_int(IB(0), afl->max_depth));
 
-  if (!afl->skip_deterministic) {
+  if (unlikely(!afl->skip_deterministic)) {
 
     sprintf(tmp, "%s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]),
@@ -897,7 +917,7 @@ void show_stats(afl_state_t *afl) {
                 "   pending : " cRST "%-10s" bSTG       bV "\n",
        tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed));
 
-  if (!afl->skip_deterministic) {
+  if (unlikely(!afl->skip_deterministic)) {
 
     sprintf(tmp, "%s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]),
@@ -913,7 +933,7 @@ void show_stats(afl_state_t *afl) {
                 "  pend fav : " cRST "%-10s" bSTG       bV "\n",
        tmp, u_stringify_int(IB(0), afl->pending_favored));
 
-  if (!afl->skip_deterministic) {
+  if (unlikely(!afl->skip_deterministic)) {
 
     sprintf(tmp, "%s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]),
@@ -929,7 +949,7 @@ void show_stats(afl_state_t *afl) {
                 " own finds : " cRST "%-10s" bSTG       bV "\n",
        tmp, u_stringify_int(IB(0), afl->queued_discovered));
 
-  if (!afl->skip_deterministic) {
+  if (unlikely(!afl->skip_deterministic)) {
 
     sprintf(tmp, "%s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]),
@@ -939,6 +959,14 @@ void show_stats(afl_state_t *afl) {
             u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]),
             u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]));
 
+  } else if (unlikely(!afl->extras_cnt || afl->custom_only)) {
+
+    strcpy(tmp, "n/a");
+
+  } else {
+
+    strcpy(tmp, "havoc mode");
+
   }
 
   SAYF(bV bSTOP "  dictionary : " cRST "%-36s " bSTG bV bSTOP
@@ -974,35 +1002,57 @@ void show_stats(afl_state_t *afl) {
                   : cRST),
        tmp);
 
-  if (afl->shm.cmplog_mode) {
+  if (unlikely(afl->afl_env.afl_python_module)) {
 
-    sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s",
+    sprintf(tmp, "%s/%s,",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]),
-            u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]),
-            u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),
-            u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]),
-            u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]),
-            u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]),
-            u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]),
-            u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS]));
+            u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]));
+
+  } else {
 
-    SAYF(bV bSTOP "   custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n",
-         tmp);
+    strcpy(tmp, "unused,");
+
+  }
+
+  if (unlikely(afl->afl_env.afl_custom_mutator_library)) {
+
+    strcat(tmp, " ");
+    strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]));
+    strcat(tmp, "/");
+    strcat(tmp, u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON]));
+    strcat(tmp, ",");
 
   } else {
 
-    sprintf(tmp, "%s/%s, %s/%s",
-            u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]),
-            u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]),
-            u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),
-            u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]));
+    strcat(tmp, " unused,");
 
-    SAYF(bV bSTOP "   py/custom : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n",
-         tmp);
+  }
+
+  if (unlikely(afl->shm.cmplog_mode)) {
+
+    strcat(tmp, " ");
+    strcat(tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]));
+    strcat(tmp, "/");
+    strcat(tmp, u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]));
+    strcat(tmp, ", ");
+    strcat(tmp, u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]));
+    strcat(tmp, "/");
+    strcat(tmp, u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS]));
+
+  } else {
+
+    strcat(tmp, " unused, unused");
 
   }
 
-  if (!afl->bytes_trim_out) {
+  SAYF(bV bSTOP "py/custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n",
+       tmp);
+
+  if (likely(afl->disable_trim)) {
+
+    sprintf(tmp, "disabled, ");
+
+  } else if (unlikely(!afl->bytes_trim_out)) {
 
     sprintf(tmp, "n/a, ");
 
@@ -1015,12 +1065,13 @@ void show_stats(afl_state_t *afl) {
 
   }
 
-  if (!afl->blocks_eff_total) {
+  if (likely(afl->skip_deterministic)) {
 
-    u8 tmp2[128];
+    strcat(tmp, "disabled");
 
-    sprintf(tmp2, "n/a");
-    strcat(tmp, tmp2);
+  } else if (unlikely(!afl->blocks_eff_total)) {
+
+    strcat(tmp, "n/a");
 
   } else {
 
@@ -1044,7 +1095,7 @@ void show_stats(afl_state_t *afl) {
   //
   //} else {
 
-  SAYF(bV bSTOP "        trim : " cRST "%-36s " bSTG bV RESET_G1, tmp);
+  SAYF(bV bSTOP "    trim/eff : " cRST "%-36s " bSTG bV RESET_G1, tmp);
 
   //}
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index d70ffd31..5bdb4c8d 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -35,6 +35,10 @@
   #include <sys/shm.h>
 #endif
 
+#ifdef __APPLE__
+  #include <sys/qos.h>
+#endif
+
 #ifdef PROFILING
 extern u64 time_spent_working;
 #endif
@@ -109,6 +113,7 @@ static void usage(u8 *argv0, int more_help) {
       "maximum.\n"
       "  -m megs       - memory limit for child process (%u MB, 0 = no limit "
       "[default])\n"
+      "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine "
@@ -126,7 +131,7 @@ static void usage(u8 *argv0, int more_help) {
       "it.\n"
       "                  if using QEMU, just use -c 0.\n"
       "  -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
-      "                  1=small files (default), 2=larger files, 3=all "
+      "                  1=small files, 2=larger files (default), 3=all "
       "files,\n"
       "                  A=arithmetic solving, T=transformational solving.\n\n"
       "Fuzzing behavior settings:\n"
@@ -175,6 +180,14 @@ static void usage(u8 *argv0, int more_help) {
   #define DYN_COLOR
 #endif
 
+#ifdef AFL_PERSISTENT_RECORD
+  #define PERSISTENT_MSG                                                 \
+    "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
+    "out/crashes\n"
+#else
+  #define PERSISTENT_MSG
+#endif
+
     SAYF(
       "Environment variables used:\n"
       "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
@@ -195,6 +208,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
       "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
       "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
+      "AFL_EXIT_ON_TIME: exit when no new paths are found within the specified time period\n"
       "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n"
       "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
       "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
@@ -210,6 +224,7 @@ static void usage(u8 *argv0, int more_help) {
       "                    then they are randomly selected instead all of them being\n"
       "                    used. Defaults to 200.\n"
       "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
+      "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n"
       "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
       "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
       "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
@@ -222,12 +237,15 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_PATH: path to AFL support binaries\n"
       "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
       "AFL_QUIET: suppress forkserver status messages\n"
+
+      PERSISTENT_MSG
+
       "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_TARGET_ENV: pass extra environment variables to target\n"
       "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
-      "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n"
+      "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n"
       "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
-      "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
+      //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
       "AFL_STATSD: enables StatsD metrics collection\n"
       "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n"
       "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
@@ -253,7 +271,13 @@ static void usage(u8 *argv0, int more_help) {
   SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
        (char *)PYTHON_VERSION);
 #else
-  SAYF("Compiled without python module support\n");
+  SAYF("Compiled without python module support.\n");
+#endif
+
+#ifdef AFL_PERSISTENT_RECORD
+  SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
+#else
+  SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
 #endif
 
 #ifdef USEMMAP
@@ -263,27 +287,27 @@ static void usage(u8 *argv0, int more_help) {
 #endif
 
 #ifdef ASAN_BUILD
-  SAYF("Compiled with ASAN_BUILD\n\n");
+  SAYF("Compiled with ASAN_BUILD.\n");
 #endif
 
 #ifdef NO_SPLICING
-  SAYF("Compiled with NO_SPLICING\n\n");
+  SAYF("Compiled with NO_SPLICING.\n");
 #endif
 
 #ifdef PROFILING
-  SAYF("Compiled with PROFILING\n\n");
+  SAYF("Compiled with PROFILING.\n");
 #endif
 
 #ifdef INTROSPECTION
-  SAYF("Compiled with INTROSPECTION\n\n");
+  SAYF("Compiled with INTROSPECTION.\n");
 #endif
 
 #ifdef _DEBUG
-  SAYF("Compiled with _DEBUG\n\n");
+  SAYF("Compiled with _DEBUG.\n");
 #endif
 
 #ifdef _AFL_DOCUMENT_MUTATIONS
-  SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS\n\n");
+  SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
 #endif
 
   SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
@@ -309,17 +333,63 @@ static int stricmp(char const *a, char const *b) {
 
 }
 
+static void fasan_check_afl_preload(char *afl_preload) {
+
+  char   first_preload[PATH_MAX + 1] = {0};
+  char * separator = strchr(afl_preload, ':');
+  size_t first_preload_len = PATH_MAX;
+  char * basename;
+  char   clang_runtime_prefix[] = "libclang_rt.asan-";
+
+  if (separator != NULL && (separator - afl_preload) < PATH_MAX) {
+
+    first_preload_len = separator - afl_preload;
+
+  }
+
+  strncpy(first_preload, afl_preload, first_preload_len);
+
+  basename = strrchr(first_preload, '/');
+  if (basename == NULL) {
+
+    basename = first_preload;
+
+  } else {
+
+    basename = basename + 1;
+
+  }
+
+  if (strncmp(basename, clang_runtime_prefix,
+              sizeof(clang_runtime_prefix) - 1) != 0) {
+
+    FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD");
+
+  }
+
+  if (access(first_preload, R_OK) != 0) {
+
+    FATAL("Address Sanitizer DSO not found");
+
+  }
+
+  OKF("Found ASAN DSO: %s", first_preload);
+
+}
+
 /* Main entry point */
 
 int main(int argc, char **argv_orig, char **envp) {
 
-  s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/;
+  s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
   u64 prev_queued = 0;
   u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
       map_size = get_map_size();
   u8 *extras_dir[4];
   u8  mem_limit_given = 0, exit_1 = 0, debug = 0,
      extras_dir_cnt = 0 /*, have_p = 0*/;
+  char * afl_preload;
+  char * frida_afl_preload = NULL;
   char **use_argv;
 
   struct timeval  tv;
@@ -363,7 +433,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   while ((opt = getopt(
               argc, argv,
-              "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
+              "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
 
     switch (opt) {
 
@@ -755,6 +825,19 @@ int main(int argc, char **argv_orig, char **envp) {
         afl->use_banner = optarg;
         break;
 
+      case 'O':                                               /* FRIDA mode */
+
+        if (afl->fsrv.frida_mode) {
+
+          FATAL("Multiple -O options not supported");
+
+        }
+
+        afl->fsrv.frida_mode = 1;
+        if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; }
+
+        break;
+
       case 'Q':                                                /* QEMU mode */
 
         if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
@@ -831,6 +914,14 @@ int main(int argc, char **argv_orig, char **envp) {
               break;
             case '3':
               afl->cmplog_lvl = 3;
+
+              if (!afl->disable_trim) {
+
+                ACTF("Deactivating trimming due CMPLOG level 3");
+                afl->disable_trim = 1;
+
+              }
+
               break;
             case 'a':
             case 'A':
@@ -1023,6 +1114,30 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (unlikely(afl->afl_env.afl_persistent_record)) {
+
+  #ifdef AFL_PERSISTENT_RECORD
+
+    afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
+
+    if (afl->fsrv.persistent_record < 2) {
+
+      FATAL(
+          "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is "
+          "100 or 1000.");
+
+    }
+
+  #else
+
+    FATAL(
+        "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in "
+        "config.h!");
+
+  #endif
+
+  }
+
   if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
 
   OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
@@ -1085,6 +1200,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (afl->non_instrumented_mode) {
 
     if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
+    if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); }
     if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
     if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
 
@@ -1181,6 +1297,13 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (afl->afl_env.afl_exit_on_time) {
+
+    u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time);
+    afl->exit_on_time = (u64)exit_on_time * 1000;
+
+  }
+
   if (afl->afl_env.afl_max_det_extras) {
 
     s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
@@ -1289,6 +1412,34 @@ int main(int argc, char **argv_orig, char **envp) {
 
       /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
 
+    } else if (afl->fsrv.frida_mode) {
+
+      afl_preload = getenv("AFL_PRELOAD");
+      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+      OKF("Injecting %s ...", frida_binary);
+      if (afl_preload) {
+
+        if (afl->fsrv.frida_asan) {
+
+          OKF("Using Frida Address Sanitizer Mode");
+
+          fasan_check_afl_preload(afl_preload);
+
+          setenv("ASAN_OPTIONS", "detect_leaks=false", 1);
+
+        }
+
+        u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+        OKF("Injecting %s ...", frida_binary);
+        frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+        ck_free(frida_binary);
+
+        setenv("LD_PRELOAD", frida_afl_preload, 1);
+        setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
+      }
+
     } else {
 
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
@@ -1296,6 +1447,25 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+  } else if (afl->fsrv.frida_mode) {
+
+    if (afl->fsrv.frida_asan) {
+
+      OKF("Using Frida Address Sanitizer Mode");
+      FATAL(
+          "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida "
+          "Address Sanitizer Mode");
+
+    } else {
+
+      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+      OKF("Injecting %s ...", frida_binary);
+      setenv("LD_PRELOAD", frida_binary, 1);
+      setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+      ck_free(frida_binary);
+
+    }
+
   }
 
   if (getenv("AFL_LD_PRELOAD")) {
@@ -1479,7 +1649,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) {
+    if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode &&
+        !afl->non_instrumented_mode) {
 
       check_binary(afl, afl->cmplog_binary);
 
@@ -1489,6 +1660,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
   check_binary(afl, argv[optind]);
 
+  #ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(afl->fsrv.persistent_record)) {
+
+    if (!getenv(PERSIST_ENV_VAR)) {
+
+      FATAL(
+          "Target binary is not compiled in persistent mode, "
+          "AFL_PERSISTENT_RECORD makes no sense.");
+
+    }
+
+    afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
+
+  }
+
+  #endif
+
   if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
 
   afl->start_time = get_cur_time();
@@ -1513,7 +1701,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) {
+  if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
+      afl->fsrv.frida_mode || afl->unicorn_mode) {
 
     map_size = afl->fsrv.map_size = MAP_SIZE;
     afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
@@ -1533,10 +1722,10 @@ int main(int argc, char **argv_orig, char **envp) {
       afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
 
   if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
-      !afl->unicorn_mode) {
+      !afl->unicorn_mode && !afl->fsrv.frida_mode &&
+      !afl->afl_env.afl_skip_bin_check) {
 
-    if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode &&
-        !afl->fsrv.qemu_mode && !afl->unicorn_mode) {
+    if (map_size <= DEFAULT_SHMEM_SIZE) {
 
       afl->fsrv.map_size = DEFAULT_SHMEM_SIZE;  // dummy temporary value
       char vbuf[16];
@@ -1587,13 +1776,15 @@ int main(int argc, char **argv_orig, char **envp) {
     // TODO: this is semi-nice
     afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
     afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
+    afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
     afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
     afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
 
     if ((map_size <= DEFAULT_SHMEM_SIZE ||
          afl->cmplog_fsrv.map_size < map_size) &&
         !afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
-        !afl->unicorn_mode) {
+        !afl->fsrv.frida_mode && !afl->unicorn_mode &&
+        !afl->afl_env.afl_skip_bin_check) {
 
       afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
       char vbuf[16];
@@ -1649,7 +1840,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (extras_dir_cnt) {
 
-    for (i = 0; i < extras_dir_cnt; i++) {
+    for (u8 i = 0; i < extras_dir_cnt; i++) {
 
       load_extras(afl, extras_dir[i]);
 
@@ -1773,6 +1964,14 @@ int main(int argc, char **argv_orig, char **envp) {
                   runs_in_current_cycle > afl->queued_paths) ||
                  (afl->old_seed_selection && !afl->queue_cur))) {
 
+      if (unlikely((afl->last_sync_cycle < afl->queue_cycle ||
+                    (!afl->queue_cycle && afl->afl_env.afl_import_first)) &&
+                   afl->sync_id)) {
+
+        sync_fuzzers(afl);
+
+      }
+
       ++afl->queue_cycle;
       runs_in_current_cycle = (u32)-1;
       afl->cur_skipped_paths = 0;
@@ -1793,6 +1992,13 @@ int main(int argc, char **argv_orig, char **envp) {
 
         if (unlikely(seek_to)) {
 
+          if (unlikely(seek_to >= afl->queued_paths)) {
+
+            // This should never happen.
+            FATAL("BUG: seek_to location out of bounds!\n");
+
+          }
+
           afl->current_entry = seek_to;
           afl->queue_cur = afl->queue_buf[seek_to];
           seek_to = 0;
@@ -1811,8 +2017,10 @@ int main(int argc, char **argv_orig, char **envp) {
       /* If we had a full queue cycle with no new finds, try
          recombination strategies next. */
 
-      if (unlikely(afl->queued_paths == prev_queued &&
-                   (get_cur_time() - afl->start_time) >= 3600)) {
+      if (unlikely(afl->queued_paths == prev_queued
+                   /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >=
+                      3600 */
+                   )) {
 
         if (afl->use_splicing) {
 
@@ -1858,13 +2066,10 @@ int main(int argc, char **argv_orig, char **envp) {
               break;
             case 4:
               afl->expand_havoc = 5;
-              if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = 3;
+              // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl =
+              // 3;
               break;
             case 5:
-              // if not in sync mode, enable deterministic mode?
-              // if (!afl->sync_id) afl->skip_deterministic = 0;
-              afl->expand_havoc = 6;
-            case 6:
               // nothing else currently
               break;
 
@@ -1886,6 +2091,13 @@ int main(int argc, char **argv_orig, char **envp) {
 
       }
 
+  #ifdef INTROSPECTION
+      fprintf(afl->introspection_file,
+              "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n",
+              afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc,
+              afl->queued_paths);
+  #endif
+
       if (afl->cycle_schedules) {
 
         /* we cannot mix non-AFLfast schedules with others */
@@ -1923,7 +2135,7 @@ int main(int argc, char **argv_orig, char **envp) {
         }
 
         // we must recalculate the scores of all queue entries
-        for (i = 0; i < (s32)afl->queued_paths; i++) {
+        for (u32 i = 0; i < afl->queued_paths; i++) {
 
           if (likely(!afl->queue_buf[i]->disabled)) {
 
@@ -1937,13 +2149,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
       prev_queued = afl->queued_paths;
 
-      if (afl->sync_id && afl->queue_cycle == 1 &&
-          afl->afl_env.afl_import_first) {
-
-        sync_fuzzers(afl);
-
-      }
-
     }
 
     ++runs_in_current_cycle;
@@ -2023,12 +2228,10 @@ int main(int argc, char **argv_orig, char **envp) {
   }
 
   write_bitmap(afl);
-  maybe_update_plot_file(afl, 0, 0, 0);
   save_auto(afl);
 
 stop_fuzzing:
 
-  write_stats_file(afl, 0, 0, 0, 0);
   afl->force_ui_update = 1;  // ensure the screen is reprinted
   show_stats(afl);           // print the screen one last time
 
@@ -2074,6 +2277,8 @@ stop_fuzzing:
 
   }
 
+  if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
   fclose(afl->fsrv.plot_file);
   destroy_queue(afl);
   destroy_extras(afl);
@@ -2091,6 +2296,14 @@ stop_fuzzing:
   }
 
   afl_fsrv_deinit(&afl->fsrv);
+
+  /* remove tmpfile */
+  if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) {
+
+    (void)unlink(afl->fsrv.out_file);
+
+  }
+
   if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
   ck_free(afl->fsrv.target_path);
   ck_free(afl->fsrv.out_file);
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
index 0a978653..1ce97649 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -73,8 +73,8 @@ static u32 ld_param_cnt = 1;        /* Number of params to 'ld'             */
    so we exploit this property to keep the code "simple". */
 static void edit_params(int argc, char **argv) {
 
-  u32 i, instrim = 0, gold_pos = 0, gold_present = 0, rt_present = 0,
-         rt_lto_present = 0, inst_present = 0;
+  u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0,
+         inst_present = 0;
   char *ptr;
 
   ld_params = ck_alloc(4096 * sizeof(u8 *));
@@ -186,17 +186,18 @@ static void edit_params(int argc, char **argv) {
 
   }
 
-  if (getenv("AFL_LLVM_INSTRIM"))
-    instrim = 1;
-  else if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) &&
-           (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))
-    instrim = 1;
+  if (getenv("AFL_LLVM_INSTRIM") ||
+      ((ptr = getenv("AFL_LLVM_INSTRUMENT")) &&
+       (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0)))
+    FATAL(
+        "InsTrim was removed because it is not effective. Use a modern LLVM "
+        "and PCGUARD (which is the default in afl-cc).\n");
 
   if (debug)
     DEBUGF(
-        "passthrough=%s instrim=%u, gold_pos=%u, gold_present=%s "
+        "passthrough=%s, gold_pos=%u, gold_present=%s "
         "inst_present=%s rt_present=%s rt_lto_present=%s\n",
-        passthrough ? "true" : "false", instrim, gold_pos,
+        passthrough ? "true" : "false", gold_pos,
         gold_present ? "true" : "false", inst_present ? "true" : "false",
         rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
 
@@ -230,12 +231,8 @@ static void edit_params(int argc, char **argv) {
 
       if (!inst_present) {
 
-        if (instrim)
-          ld_params[ld_param_cnt++] =
-              alloc_printf("-mllvm=-load=%s/afl-llvm-lto-instrim.so", afl_path);
-        else
-          ld_params[ld_param_cnt++] = alloc_printf(
-              "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path);
+        ld_params[ld_param_cnt++] = alloc_printf(
+            "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path);
 
       }
 
@@ -301,13 +298,12 @@ int main(int argc, char **argv) {
 
     SAYF(
         "\n"
-        "This is a helper application for afl-clang-lto. It is a wrapper "
-        "around GNU "
-        "llvm's 'lld',\n"
-        "executed by the toolchain whenever using "
-        "afl-clang-lto/afl-clang-lto++.\n"
+        "This is a helper application for afl-clang-lto.\n"
+        "It is a wrapper around llvm's 'lld' in case afl-clang-lto cannot be "
+        "used.\n"
+        "Note that the target still has to be compiled with -flto=full!\n"
         "You probably don't want to run this program directly but rather pass "
-        "it as LD parameter to configure scripts\n\n"
+        "it as LD\nparameter to e.g. configure scripts.\n\n"
 
         "Environment variables:\n"
         "  AFL_LD_PASSTHROUGH   do not link+optimize == no instrumentation\n"
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 077c9248..96b72dd9 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -52,6 +52,7 @@
 #include <fcntl.h>
 #include <limits.h>
 
+#include <dirent.h>
 #include <sys/wait.h>
 #include <sys/time.h>
 #ifndef USEMMAP
@@ -72,22 +73,22 @@ static u8 *in_data,                    /* Input data                        */
 static u64 total;                      /* tuple content information         */
 static u32 tcnt, highest;              /* tuple content information         */
 
-static u32 in_len,                     /* Input data length                 */
-    arg_offset;                        /* Total number of execs             */
+static u32 in_len;                     /* Input data length                 */
 
 static u32 map_size = MAP_SIZE;
 
-static u8 quiet_mode,                  /* Hide non-essential messages?      */
+static bool quiet_mode,                /* Hide non-essential messages?      */
     edges_only,                        /* Ignore hit counts?                */
     raw_instr_output,                  /* Do not apply AFL filters          */
     cmin_mode,                         /* Generate output in afl-cmin mode? */
     binary_mode,                       /* Write output as a binary map      */
     keep_cores,                        /* Allow coredumps?                  */
-    remove_shm = 1,                    /* remove shmem?                     */
+    remove_shm = true,                 /* remove shmem?                     */
     collect_coverage,                  /* collect coverage                  */
     have_coverage,                     /* have coverage?                    */
     no_classify,                       /* do not classify counts            */
-    debug;                             /* debug mode                        */
+    debug,                             /* debug mode                        */
+    print_filenames;                   /* print the current filename        */
 
 static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_crashed;                     /* Child crashed?                    */
@@ -234,6 +235,9 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
   if (cmin_mode &&
       (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
 
+    // create empty file to prevent error messages in afl-cmin
+    fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+    close(fd);
     return ret;
 
   }
@@ -321,11 +325,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
   if (fsrv->trace_bits[0] == 1) {
 
     fsrv->trace_bits[0] = 0;
-    have_coverage = 1;
+    have_coverage = true;
 
   } else {
 
-    have_coverage = 0;
+    have_coverage = false;
 
   }
 
@@ -336,11 +340,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
   if (!fsrv->last_run_timed_out && !stop_soon &&
       WIFSIGNALED(fsrv->child_status)) {
 
-    child_crashed = 1;
+    child_crashed = true;
 
   } else {
 
-    child_crashed = 0;
+    child_crashed = false;
 
   }
 
@@ -376,6 +380,13 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
 
 static u32 read_file(u8 *in_file) {
 
+  if (print_filenames) {
+
+    SAYF("Processing %s\n", in_file);
+    fflush(stdout);
+
+  }
+
   struct stat st;
   s32         fd = open(in_file, O_RDONLY);
 
@@ -387,7 +398,18 @@ static u32 read_file(u8 *in_file) {
 
   }
 
-  in_len = st.st_size;
+  if (st.st_size > MAX_FILE) {
+
+    WARNF("Input file '%s' is too large, only reading %u bytes.", in_file,
+          MAX_FILE);
+    in_len = MAX_FILE;
+
+  } else {
+
+    in_len = st.st_size;
+
+  }
+
   in_data = ck_alloc_nozero(in_len);
 
   ck_read(fd, in_data, in_len, in_file);
@@ -505,11 +527,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
   if (fsrv->trace_bits[0] == 1) {
 
     fsrv->trace_bits[0] = 0;
-    have_coverage = 1;
+    have_coverage = true;
 
   } else {
 
-    have_coverage = 0;
+    have_coverage = false;
 
   }
 
@@ -519,7 +541,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
 
   if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) {
 
-    child_crashed = 1;
+    child_crashed = true;
 
   }
 
@@ -549,15 +571,17 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
 static void handle_stop_sig(int sig) {
 
   (void)sig;
-  stop_soon = 1;
+  stop_soon = true;
   afl_fsrv_killall();
 
 }
 
 /* Do basic preparations - persistent fds, filenames, etc. */
 
-static void set_up_environment(afl_forkserver_t *fsrv) {
+static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
 
+  char *afl_preload;
+  char *frida_afl_preload = NULL;
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -571,6 +595,13 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
          "handle_sigill=0",
          0);
 
+  setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0:"
+         "symbolize=0:"
+         "print_suppressions=0",
+          0);
+
   setenv("UBSAN_OPTIONS",
          "halt_on_error=1:"
          "abort_on_error=1:"
@@ -601,6 +632,25 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
       /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
 
+    } else if (fsrv->frida_mode) {
+
+      afl_preload = getenv("AFL_PRELOAD");
+      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+      if (afl_preload) {
+
+        frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+      } else {
+
+        frida_afl_preload = alloc_printf("%s", frida_binary);
+
+      }
+
+      ck_free(frida_binary);
+
+      setenv("LD_PRELOAD", frida_afl_preload, 1);
+      setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
     } else {
 
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
@@ -608,8 +658,17 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
     }
 
+  } else if (fsrv->frida_mode) {
+
+    u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+    setenv("LD_PRELOAD", frida_binary, 1);
+    setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+    ck_free(frida_binary);
+
   }
 
+  if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
 }
 
 /* Setup signal handlers, duh. */
@@ -656,6 +715,7 @@ static void usage(u8 *argv0) {
       "Execution control settings:\n"
       "  -t msec       - timeout for each run (none)\n"
       "  -m megs       - memory limit for child process (%u MB)\n"
+      "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use Unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n"
@@ -694,6 +754,8 @@ static void usage(u8 *argv0) {
       "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
       "size the target was compiled for\n"
       "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+      "AFL_PRINT_FILENAMES: If set, the filename currently processed will be "
+      "printed to stdout\n"
       "AFL_QUIET: do not print extra informational output\n",
       argv0, MEM_LIMIT, doc_path);
 
@@ -707,14 +769,17 @@ int main(int argc, char **argv_orig, char **envp) {
 
   // TODO: u64 mem_limit = MEM_LIMIT;                  /* Memory limit (MB) */
 
-  s32    opt, i;
-  u8     mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+  s32  opt, i;
+  bool mem_limit_given = false, timeout_given = false, unicorn_mode = false,
+       use_wine = false;
   char **use_argv;
 
   char **argv = argv_cpy_dup(argc, argv_orig);
 
   afl_forkserver_t fsrv_var = {0};
-  if (getenv("AFL_DEBUG")) { debug = 1; }
+  if (getenv("AFL_DEBUG")) { debug = true; }
+  if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; }
+
   fsrv = &fsrv_var;
   afl_fsrv_init(fsrv);
   map_size = get_map_size();
@@ -722,19 +787,19 @@ int main(int argc, char **argv_orig, char **envp) {
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
-  if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; }
+  if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrsh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) {
 
     switch (opt) {
 
       case 's':
-        no_classify = 1;
+        no_classify = true;
         break;
 
       case 'C':
-        collect_coverage = 1;
-        quiet_mode = 1;
+        collect_coverage = true;
+        quiet_mode = true;
         break;
 
       case 'i':
@@ -753,7 +818,7 @@ int main(int argc, char **argv_orig, char **envp) {
         u8 suffix = 'M';
 
         if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
-        mem_limit_given = 1;
+        mem_limit_given = true;
 
         if (!optarg) { FATAL("Wrong usage of -m"); }
 
@@ -814,7 +879,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 't':
 
         if (timeout_given) { FATAL("Multiple -t options not supported"); }
-        timeout_given = 1;
+        timeout_given = true;
 
         if (!optarg) { FATAL("Wrong usage of -t"); }
 
@@ -836,12 +901,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
         if (edges_only) { FATAL("Multiple -e options not supported"); }
         if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); }
-        edges_only = 1;
+        edges_only = true;
         break;
 
       case 'q':
 
-        quiet_mode = 1;
+        quiet_mode = true;
         break;
 
       case 'Z':
@@ -849,8 +914,8 @@ int main(int argc, char **argv_orig, char **envp) {
         /* This is an undocumented option to write data in the syntax expected
            by afl-cmin. Nobody else should have any use for this. */
 
-        cmin_mode = 1;
-        quiet_mode = 1;
+        cmin_mode = true;
+        quiet_mode = true;
         break;
 
       case 'A':
@@ -858,25 +923,33 @@ int main(int argc, char **argv_orig, char **envp) {
         at_file = optarg;
         break;
 
+      case 'O':                                               /* FRIDA mode */
+
+        if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
+
+        fsrv->frida_mode = true;
+
+        break;
+
       case 'Q':
 
         if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
 
-        fsrv->qemu_mode = 1;
+        fsrv->qemu_mode = true;
         break;
 
       case 'U':
 
         if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
 
-        unicorn_mode = 1;
+        unicorn_mode = true;
         break;
 
       case 'W':                                           /* Wine+QEMU mode */
 
         if (use_wine) { FATAL("Multiple -W options not supported"); }
-        fsrv->qemu_mode = 1;
-        use_wine = 1;
+        fsrv->qemu_mode = true;
+        use_wine = true;
 
         break;
 
@@ -885,20 +958,20 @@ int main(int argc, char **argv_orig, char **envp) {
         /* Secret undocumented mode. Writes output in raw binary format
            similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
 
-        binary_mode = 1;
+        binary_mode = true;
         break;
 
       case 'c':
 
         if (keep_cores) { FATAL("Multiple -c options not supported"); }
-        keep_cores = 1;
+        keep_cores = true;
         break;
 
       case 'r':
 
         if (raw_instr_output) { FATAL("Multiple -r options not supported"); }
         if (edges_only) { FATAL("-e and -r are mutually exclusive"); }
-        raw_instr_output = 1;
+        raw_instr_output = true;
         break;
 
       case 'h':
@@ -944,7 +1017,7 @@ int main(int argc, char **argv_orig, char **envp) {
   shm.cmplog_mode = 0;
   setup_signal_handlers();
 
-  set_up_environment(fsrv);
+  set_up_environment(fsrv, argv);
 
   fsrv->target_path = find_binary(argv[optind]);
   fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
@@ -958,10 +1031,27 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (in_dir) {
 
-    detect_file_args(argv + optind, "", &fsrv->use_stdin);
+    /* If we don't have a file name chosen yet, use a safe default. */
+    u8 *use_dir = ".";
+
+    if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+      use_dir = get_afl_env("TMPDIR");
+      if (!use_dir) { use_dir = "/tmp"; }
+
+    }
+
+    stdin_file = at_file ? strdup(at_file)
+                         : (char *)alloc_printf("%s/.afl-showmap-temp-%u",
+                                                use_dir, (u32)getpid());
+    unlink(stdin_file);
+
+    // If @@ are in the target args, replace them and also set use_stdin=false.
+    detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
 
   } else {
 
+    // If @@ are in the target args, replace them and also set use_stdin=false.
     detect_file_args(argv + optind, at_file, &fsrv->use_stdin);
 
   }
@@ -986,20 +1076,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  i = 0;
-  while (use_argv[i] != NULL && !arg_offset) {
-
-    if (strcmp(use_argv[i], "@@") == 0) { arg_offset = i; }
-    i++;
-
-  }
-
   shm_fuzz = ck_alloc(sizeof(sharedmem_t));
 
   /* initialize cmplog_mode */
   shm_fuzz->cmplog_mode = 0;
   u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
-  shm_fuzz->shmemfuzz_mode = 1;
+  shm_fuzz->shmemfuzz_mode = true;
   if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
 #ifdef USEMMAP
   setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
@@ -1008,7 +1090,7 @@ int main(int argc, char **argv_orig, char **envp) {
   setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
   ck_free(shm_str);
 #endif
-  fsrv->support_shmem_fuzz = 1;
+  fsrv->support_shmem_fuzz = true;
   fsrv->shmem_fuzz_len = (u32 *)map;
   fsrv->shmem_fuzz = map + sizeof(u32);
 
@@ -1025,6 +1107,9 @@ int main(int argc, char **argv_orig, char **envp) {
                                  : 0);
     be_quiet = save_be_quiet;
 
+    fsrv->kill_signal =
+        parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+
     if (new_map_size) {
 
       // only reinitialize when it makes sense
@@ -1051,8 +1136,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (in_dir) {
 
-    DIR *          dir_in, *dir_out = NULL;
-    struct dirent *dir_ent;
+    DIR *           dir_in, *dir_out = NULL;
+    struct dirent **file_list;
+
     //    int            done = 0;
     u8 infile[PATH_MAX], outfile[PATH_MAX];
     u8 wait_for_gdb = 0;
@@ -1060,7 +1146,7 @@ int main(int argc, char **argv_orig, char **envp) {
     struct stat statbuf;
 #endif
 
-    if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1;
+    if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
 
     fsrv->dev_null_fd = open("/dev/null", O_RDWR);
     if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@@ -1077,12 +1163,6 @@ int main(int argc, char **argv_orig, char **envp) {
       ck_free(dn);
     if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
 
-    if (!(dir_in = opendir(in_dir))) {
-
-      PFATAL("cannot open directory %s", in_dir);
-
-    }
-
     if (!collect_coverage) {
 
       if (!(dir_out = opendir(out_file))) {
@@ -1099,36 +1179,17 @@ int main(int argc, char **argv_orig, char **envp) {
 
       if ((coverage_map = (u8 *)malloc(map_size)) == NULL)
         FATAL("coult not grab memory");
-      edges_only = 0;
-      raw_instr_output = 1;
+      edges_only = false;
+      raw_instr_output = true;
 
     }
 
-    u8 *use_dir = ".";
-
-    if (access(use_dir, R_OK | W_OK | X_OK)) {
-
-      use_dir = get_afl_env("TMPDIR");
-      if (!use_dir) { use_dir = "/tmp"; }
-
-    }
-
-    stdin_file = at_file ? strdup(at_file)
-                         : (char *)alloc_printf("%s/.afl-showmap-temp-%u",
-                                                use_dir, (u32)getpid());
-    unlink(stdin_file);
     atexit(at_exit_handler);
     fsrv->out_file = stdin_file;
     fsrv->out_fd =
         open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
     if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
 
-    if (arg_offset && use_argv[arg_offset] != stdin_file) {
-
-      use_argv[arg_offset] = strdup(stdin_file);
-
-    }
-
     if (get_afl_env("AFL_DEBUG")) {
 
       int j = optind;
@@ -1156,9 +1217,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    fsrv->kill_signal =
-        parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
-
     if (getenv("AFL_CRASH_EXITCODE")) {
 
       long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
@@ -1187,7 +1245,16 @@ int main(int argc, char **argv_orig, char **envp) {
     if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
       shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
 
-    while ((dir_ent = readdir(dir_in))) {
+    int file_count = scandir(in_dir, &file_list, NULL, alphasort);
+    if (file_count < 0) {
+
+      PFATAL("Failed to read from input dir at %s\n", in_dir);
+
+    }
+
+    for (int i = 0; i < file_count; i++) {
+
+      struct dirent *dir_ent = file_list[i];
 
       if (dir_ent->d_name[0] == '.') {
 
@@ -1234,9 +1301,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+    free(file_list);
+    file_list = NULL;
+
     if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); }
 
-    closedir(dir_in);
     if (dir_out) { closedir(dir_out); }
 
     if (collect_coverage) {
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index fc974262..6656712a 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -640,9 +640,11 @@ static void handle_stop_sig(int sig) {
 
 /* Do basic preparations - persistent fds, filenames, etc. */
 
-static void set_up_environment(afl_forkserver_t *fsrv) {
+static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
 
-  u8 *x;
+  u8 *  x;
+  char *afl_preload;
+  char *frida_afl_preload = NULL;
 
   fsrv->dev_null_fd = open("/dev/null", O_RDWR);
   if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@@ -712,6 +714,18 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "symbolize=0")) {
+
+      FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
+
+    }
+
+  }
+
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -749,12 +763,38 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
                          "handle_sigfpe=0:"
                          "handle_sigill=0", 0);
 
+  setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0:"
+         "symbolize=0:"
+         "print_suppressions=0",
+         0);
+
   if (get_afl_env("AFL_PRELOAD")) {
 
     if (fsrv->qemu_mode) {
 
       /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
 
+    } else if (fsrv->frida_mode) {
+
+      afl_preload = getenv("AFL_PRELOAD");
+      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+      if (afl_preload) {
+
+        frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
+
+      } else {
+
+        frida_afl_preload = alloc_printf("%s", frida_binary);
+
+      }
+
+      ck_free(frida_binary);
+
+      setenv("LD_PRELOAD", frida_afl_preload, 1);
+      setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
+
     } else {
 
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
@@ -762,8 +802,17 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
     }
 
+  } else if (fsrv->frida_mode) {
+
+    u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
+    setenv("LD_PRELOAD", frida_binary, 1);
+    setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
+    ck_free(frida_binary);
+
   }
 
+  if (frida_afl_preload) { ck_free(frida_afl_preload); }
+
 }
 
 /* Setup signal handlers, duh. */
@@ -804,6 +853,7 @@ static void usage(u8 *argv0) {
       "  -f file       - input file read by the tested program (stdin)\n"
       "  -t msec       - timeout for each run (%u ms)\n"
       "  -m megs       - memory limit for child process (%u MB)\n"
+      "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine "
@@ -859,7 +909,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWHh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeOQUWHh")) > 0) {
 
     switch (opt) {
 
@@ -971,6 +1021,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'O':                                               /* FRIDA mode */
+
+        if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
+
+        fsrv->frida_mode = 1;
+
+        break;
+
       case 'Q':
 
         if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
@@ -1054,7 +1112,7 @@ int main(int argc, char **argv_orig, char **envp) {
   atexit(at_exit_handler);
   setup_signal_handlers();
 
-  set_up_environment(fsrv);
+  set_up_environment(fsrv, argv);
 
   fsrv->target_path = find_binary(argv[optind]);
   fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
diff --git a/test/test-all.sh b/test/test-all.sh
index 8df4bef9..0c189727 100755
--- a/test/test-all.sh
+++ b/test/test-all.sh
@@ -14,6 +14,8 @@
 
 . ./test-qemu-mode.sh
 
+. ./test-frida-mode.sh
+
 . ./test-unicorn-mode.sh
 
 . ./test-custom-mutators.sh
diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh
index bae4220f..5d679a82 100755
--- a/test/test-custom-mutators.sh
+++ b/test/test-custom-mutators.sh
@@ -5,7 +5,7 @@
 $ECHO "$BLUE[*] Testing: custom mutator"
 test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
   # normalize path
-  CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../utils/custom_mutators;pwd)
+  CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd)
   test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
     unset AFL_CC
     # Compile the vulnerable program for single mutator
@@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
       }
     }
     # Compile the custom mutator
-    cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
-    cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
+    cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
+    cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
     test -e test-custom-mutator -a -e ./libexamplemutator.so && {
       # Create input directory
       mkdir -p in
diff --git a/test/test-frida-mode.sh b/test/test-frida-mode.sh
new file mode 100755
index 00000000..b47d016a
--- /dev/null
+++ b/test/test-frida-mode.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+. ./test-pre.sh
+
+$ECHO "$BLUE[*] Testing: frida_mode"
+test -z "$AFL_CC" && {
+  if type gcc >/dev/null; then
+    export AFL_CC=gcc
+  else
+    if type clang >/dev/null; then
+      export AFL_CC=clang
+    fi
+  fi
+}
+
+test -e ../afl-frida-trace.so && {
+  cc -no-pie -o test-instr ../test-instr.c
+  cc -o test-compcov test-compcov.c
+  test -e test-instr -a -e test-compcov && {
+    {
+      mkdir -p in
+      echo 00000 > in/in
+      $ECHO "$GREY[*] running afl-fuzz for frida_mode, this will take approx 10 seconds"
+      {
+        ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr >>errors 2>&1
+      } >>errors 2>&1
+      test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+        $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode"
+        RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+      } || {
+        echo CUT------------------------------------------------------------------CUT
+        cat errors
+        echo CUT------------------------------------------------------------------CUT
+        $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode"
+        CODE=1
+      }
+      rm -f errors
+
+      test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+        $ECHO "$GREY[*] running afl-fuzz for frida_mode cmplog, this will take approx 10 seconds"
+        {
+          ../afl-fuzz -m none -V10 -O -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+        } >>errors 2>&1
+        test -n "$( ls out/default/queue/id:000003* 2>/dev/null )" && {
+          $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode cmplog"
+        } || {
+          echo CUT------------------------------------------------------------------CUT
+          cat errors
+          echo CUT------------------------------------------------------------------CUT
+          $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode cmplog"
+          CODE=1
+        }
+        rm -f errors
+      } || {
+       $ECHO "$YELLOW[-] not an intel or arm platform, cannot test frida_mode cmplog"
+      }
+
+      test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+        $ECHO "$GREY[*] running afl-fuzz for persistent frida_mode, this will take approx 10 seconds"
+        {
+          #if file test-instr | grep -q "32-bit"; then
+          #else
+          #fi
+          export AFL_FRIDA_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'`
+          $ECHO "Info: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
+          env|grep AFL_|sort
+          file test-instr
+          ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr
+          unset AFL_FRIDA_PERSISTENT_ADDR
+        } >>errors 2>&1
+        test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
+          $ECHO "$GREEN[+] afl-fuzz is working correctly with persistent frida_mode"
+          RUNTIMEP=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
+          test -n "$RUNTIME" -a -n "$RUNTIMEP" && {
+            DIFF=`expr $RUNTIMEP / $RUNTIME`
+            test "$DIFF" -gt 1 && { # must be at least twice as fast
+              $ECHO "$GREEN[+] persistent frida_mode was noticeable faster than standard frida_mode"
+            } || {
+              $ECHO "$YELLOW[-] persistent frida_mode was not noticeable faster than standard frida_mode"
+            }
+          } || {
+            $ECHO "$YELLOW[-] we got no data on executions performed? weird!"
+          }
+        } || {
+          echo CUT------------------------------------------------------------------CUT
+          cat errors
+          echo CUT------------------------------------------------------------------CUT
+          $ECHO "$RED[!] afl-fuzz is not working correctly with persistent frida_mode"
+          CODE=1
+        }
+        rm -rf in out errors
+      } || {
+       $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent frida_mode"
+      }
+
+    }
+  } || {
+    $ECHO "$RED[!] gcc compilation of test targets failed - what is going on??"
+    CODE=1
+  }
+
+  rm -f test-instr test-compcov
+} || {
+  $ECHO "$YELLOW[-] frida_mode is not compiled, cannot test"
+  INCOMPLETE=1
+}
+
+. ./test-post.sh
diff --git a/test/test-llvm.sh b/test/test-llvm.sh
index 3ef36b37..1152cc4e 100755
--- a/test/test-llvm.sh
+++ b/test/test-llvm.sh
@@ -43,10 +43,41 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
     $ECHO "$RED[!] llvm_mode failed"
     CODE=1
   }
+  AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_THREADSAFE_INST=1 ../afl-clang-fast -o test-instr.ts ../test-instr.c > /dev/null 2>&1
+  test -e test-instr.ts && {
+    $ECHO "$GREEN[+] llvm_mode threadsafe compilation succeeded"
+    echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.0 -r -- ./test-instr.ts > /dev/null 2>&1
+    AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.1 -r -- ./test-instr.ts < /dev/null > /dev/null 2>&1
+    test -e test-instr.ts.0 -a -e test-instr.ts.1 && {
+      diff test-instr.ts.0 test-instr.ts.1 > /dev/null 2>&1 && {
+        $ECHO "$RED[!] llvm_mode threadsafe instrumentation should be different on different input but is not"
+        CODE=1
+      } || {
+        $ECHO "$GREEN[+] llvm_mode threadsafe instrumentation present and working correctly"
+        TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.ts 2>&1 | grep Captur | awk '{print$3}'`
+        test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && {
+          $ECHO "$GREEN[+] llvm_mode run reported $TUPLES threadsafe instrumented locations which is fine"
+        } || {
+          $ECHO "$RED[!] llvm_mode threadsafe instrumentation produces weird numbers: $TUPLES"
+          CODE=1
+        }
+        test "$TUPLES" -lt 3 && SKIP=1
+        true
+      }
+    } || {
+      $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed"
+      CODE=1
+    }
+    rm -f test-instr.ts.0 test-instr.ts.1
+  } || {
+    $ECHO "$RED[!] llvm_mode (threadsafe) failed"
+    CODE=1
+  }
   ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1
   test -e test-instr.so && {
     $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded"
-    ../afl-clang-fast -o test-dlopen.plain test-dlopen.c -ldl > /dev/null 2>&1
+    test `uname -s` = 'Linux' && LIBS=-ldl :
+    ../afl-clang-fast -o test-dlopen.plain test-dlopen.c ${LIBS} > /dev/null 2>&1
     test -e test-dlopen.plain && {
       $ECHO "$GREEN[+] llvm_mode test-dlopen compilation succeeded"
       echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ./test-dlopen.plain > /dev/null 2>&1
@@ -81,6 +112,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
       CODE=1
     }
     rm -f test-dlopen.plain test-dlopen.plain.0 test-dlopen.plain.1 test-instr.so
+    unset LIBS
   } || {
     $ECHO "$RED[!] llvm_mode shared object with -z defs compilation failed"
     CODE=1
@@ -166,27 +198,6 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
   }
   rm -f test-instr.plain
 
-  # now for the special llvm_mode things
-  test -e ../libLLVMInsTrim.so && {
-    AFL_LLVM_INSTRUMENT=CFG AFL_LLVM_INSTRIM_LOOPHEAD=1 ../afl-clang-fast -o test-instr.instrim ../test-instr.c > /dev/null 2>test.out
-    test -e test-instr.instrim && {
-      TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.instrim 2>&1 | grep Captur | awk '{print$3}'`
-      test "$TUPLES" -gt 1 -a "$TUPLES" -lt 5 && {
-        $ECHO "$GREEN[+] llvm_mode InsTrim reported $TUPLES instrumented locations which is fine"
-      } || {
-        $ECHO "$RED[!] llvm_mode InsTrim instrumentation produces weird numbers: $TUPLES"
-        CODE=1
-      }
-      rm -f test-instr.instrim test.out
-    } || {
-      cat test.out
-      $ECHO "$RED[!] llvm_mode InsTrim compilation failed"
-      CODE=1
-    }
-  } || {
-    $ECHO "$YELLOW[-] llvm_mode InsTrim not compiled, cannot test"
-    INCOMPLETE=1
-  }
   AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1
   test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && {
     grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && {
diff --git a/test/test-performance.sh b/test/test-performance.sh
index cd9f6caf..d61e2f2a 100755
--- a/test/test-performance.sh
+++ b/test/test-performance.sh
@@ -18,6 +18,7 @@ export AFL_QUIET=1
 export AFL_PATH=`pwd`/..
 
 unset AFL_EXIT_WHEN_DONE
+unset AFL_EXIT_ON_TIME
 unset AFL_SKIP_CPUFREQ
 unset AFL_DEBUG
 unset AFL_HARDEN
diff --git a/test/test-pre.sh b/test/test-pre.sh
index 85ac320b..7819da47 100755
--- a/test/test-pre.sh
+++ b/test/test-pre.sh
@@ -62,6 +62,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || {
 test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; }
 
 export AFL_EXIT_WHEN_DONE=1
+export AFL_EXIT_ON_TIME=60
 export AFL_SKIP_CPUFREQ=1
 export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
 unset AFL_NO_X86
@@ -71,6 +72,7 @@ unset AFL_HARDEN
 unset AFL_USE_ASAN
 unset AFL_USE_MSAN
 unset AFL_USE_UBSAN
+unset AFL_USE_LSAN
 unset AFL_TMPDIR
 unset AFL_CC
 unset AFL_PRELOAD
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index d9ae5590..ffcf3b4c 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-fb2fc9f2
+019b871539fe9ed3f41d882385a8b02c243d49ad
diff --git a/unicorn_mode/helper_scripts/ida_context_loader.py b/unicorn_mode/helper_scripts/ida_context_loader.py
index 31d47a90..d7984c77 100644
--- a/unicorn_mode/helper_scripts/ida_context_loader.py
+++ b/unicorn_mode/helper_scripts/ida_context_loader.py
@@ -34,13 +34,11 @@ import ida_segment
 
 
 class ContextLoaderError(Exception):
-    """Base "catch all" exception for this script
-    """
+    """Base "catch all" exception for this script"""
 
 
 class ArchNotSupportedError(ContextLoaderError):
-    """Exception raised if the input file CPU architecture isn't supported fully
-    """
+    """Exception raised if the input file CPU architecture isn't supported fully"""
 
 
 def parse_mapping_index(filepath: str):
@@ -51,13 +49,16 @@ def parse_mapping_index(filepath: str):
     """
 
     if filepath is None:
-        raise ContextLoaderError('_index.json file was not selected')
+        raise ContextLoaderError("_index.json file was not selected")
 
     try:
-        with open(filepath, 'rb') as _file:
+        with open(filepath, "rb") as _file:
             return json.load(_file)
     except Exception as ex:
-        raise ContextLoaderError('Failed to parse json file {}'.format(filepath)) from ex
+        raise ContextLoaderError(
+            "Failed to parse json file {}".format(filepath)
+        ) from ex
+
 
 def get_input_name():
     """Get the name of the input file
@@ -68,19 +69,21 @@ def get_input_name():
     input_filepath = ida_nalt.get_input_file_path()
     return Path(input_filepath).name
 
+
 def write_segment_bytes(start: int, filepath: str):
-    """"Read data from context file and write it to the IDA segment
+    """ "Read data from context file and write it to the IDA segment
 
     :param start: Start address
     :param filepath: Path to context file
     """
 
-    with open(filepath, 'rb') as _file:
+    with open(filepath, "rb") as _file:
         data = _file.read()
 
     decompressed_data = zlib.decompress(data)
     ida_bytes.put_bytes(start, decompressed_data)
 
+
 def create_segment(context_dir: str, segment: dict, is_be: bool):
     """Create segment in IDA and map in the data from the file
 
@@ -90,23 +93,30 @@ def create_segment(context_dir: str, segment: dict, is_be: bool):
     """
 
     input_name = get_input_name()
-    if Path(segment['name']).name != input_name:
+    if Path(segment["name"]).name != input_name:
         ida_seg = idaapi.segment_t()
-        ida_seg.start_ea = segment['start']
-        ida_seg.end_ea = segment['end']
+        ida_seg.start_ea = segment["start"]
+        ida_seg.end_ea = segment["end"]
         ida_seg.bitness = 1 if is_be else 0
-        if segment['permissions']['r']:
+        if segment["permissions"]["r"]:
             ida_seg.perm |= ida_segment.SEGPERM_READ
-        if segment['permissions']['w']:
+        if segment["permissions"]["w"]:
             ida_seg.perm |= ida_segment.SEGPERM_WRITE
-        if segment['permissions']['x']:
+        if segment["permissions"]["x"]:
             ida_seg.perm |= ida_segment.SEGPERM_EXEC
-            idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'CODE', idaapi.ADDSEG_OR_DIE)
+            idaapi.add_segm_ex(
+                ida_seg, Path(segment["name"]).name, "CODE", idaapi.ADDSEG_OR_DIE
+            )
         else:
-            idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'DATA', idaapi.ADDSEG_OR_DIE)
+            idaapi.add_segm_ex(
+                ida_seg, Path(segment["name"]).name, "DATA", idaapi.ADDSEG_OR_DIE
+            )
+
+    if segment["content_file"]:
+        write_segment_bytes(
+            segment["start"], PurePath(context_dir, segment["content_file"])
+        )
 
-    if segment['content_file']:
-        write_segment_bytes(segment['start'], PurePath(context_dir, segment['content_file']))
 
 def create_segments(index: dict, context_dir: str):
     """Iterate segments in index JSON, create the segment in IDA, and map in the data from the file
@@ -117,9 +127,10 @@ def create_segments(index: dict, context_dir: str):
 
     info = idaapi.get_inf_structure()
     is_be = info.is_be()
-    for segment in index['segments']:
+    for segment in index["segments"]:
         create_segment(context_dir, segment, is_be)
 
+
 def rebase_program(index: dict):
     """Rebase the program to the offset specified in the context _index.json
 
@@ -128,20 +139,21 @@ def rebase_program(index: dict):
 
     input_name = get_input_name()
     new_base = None
-    for segment in index['segments']:
-        if not segment['name']:
+    for segment in index["segments"]:
+        if not segment["name"]:
             continue
 
-        segment_name = Path(segment['name']).name
+        segment_name = Path(segment["name"]).name
         if input_name == segment_name:
-            new_base = segment['start']
+            new_base = segment["start"]
             break
 
     if not new_base:
-        raise ContextLoaderError('Input file is not in _index.json')
+        raise ContextLoaderError("Input file is not in _index.json")
 
     current_base = idaapi.get_imagebase()
-    ida_segment.rebase_program(new_base-current_base, 8)
+    ida_segment.rebase_program(new_base - current_base, 8)
+
 
 def get_pc_by_arch(index: dict) -> int:
     """Queries the input file CPU architecture and attempts to lookup the address of the program
@@ -153,13 +165,14 @@ def get_pc_by_arch(index: dict) -> int:
 
     progctr = None
     info = idaapi.get_inf_structure()
-    if info.procname == 'metapc':
+    if info.procname == "metapc":
         if info.is_64bit():
-            progctr = index['regs']['rax']
+            progctr = index["regs"]["rax"]
         elif info.is_32bit():
-            progctr = index['regs']['eax']
+            progctr = index["regs"]["eax"]
     return progctr
 
+
 def write_reg_info(index: dict):
     """Write register info as line comment at instruction pointed to by the program counter and
     change focus to that location
@@ -167,17 +180,19 @@ def write_reg_info(index: dict):
     :param index: _index.json JSON data
     """
 
-    cmt = ''
-    for reg, val in index['regs'].items():
+    cmt = ""
+    for reg, val in index["regs"].items():
         cmt += f"{reg.ljust(6)} : {hex(val)}\n"
 
     progctr = get_pc_by_arch(index)
     if progctr is None:
         raise ArchNotSupportedError(
-            'Architecture not fully supported, skipping register status comment')
+            "Architecture not fully supported, skipping register status comment"
+        )
     ida_bytes.set_cmt(progctr, cmt, 0)
     ida_kernwin.jumpto(progctr)
 
+
 def main(filepath):
     """Main - parse _index.json input and map context files into the database
 
@@ -193,5 +208,6 @@ def main(filepath):
     except ContextLoaderError as ex:
         print(ex)
 
-if __name__ == '__main__':
-    main(ida_kernwin.ask_file(1, '*.json', 'Import file name'))
+
+if __name__ == "__main__":
+    main(ida_kernwin.ask_file(1, "*.json", "Import file name"))
diff --git a/unicorn_mode/samples/speedtest/c/Makefile b/unicorn_mode/samples/speedtest/c/Makefile
index ce784d4f..46789954 100644
--- a/unicorn_mode/samples/speedtest/c/Makefile
+++ b/unicorn_mode/samples/speedtest/c/Makefile
@@ -29,7 +29,11 @@ MYCC = $(__CC:$(_UNIQ)$(CROSS)=$(CROSS)gcc)
 
 .PHONY: all clean
 
-all: fuzz
+all: ../target harness
+
+afl-fuzz: ../../../../afl-fuzz
+../../../../afl-fuzz:
+	$(MAKE) -C ../../../../ afl-fuzz
 
 clean:
 	rm -rf *.o harness harness-debug
@@ -49,6 +53,6 @@ harness-debug: harness-debug.o
 ../target:
 	$(MAKE) -C ..
 
-fuzz: ../target harness
+fuzz: all afl-fuzz
 	rm -rf ./output
-	SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@
+	SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@
diff --git a/unicorn_mode/samples/speedtest/python/Makefile b/unicorn_mode/samples/speedtest/python/Makefile
index 4282c6cb..c0c64269 100644
--- a/unicorn_mode/samples/speedtest/python/Makefile
+++ b/unicorn_mode/samples/speedtest/python/Makefile
@@ -1,8 +1,15 @@
-all: fuzz
+.PHONY: all fuzz
+
+all: ../target
+
+afl-fuzz: ../../../../afl-fuzz
+../../../../afl-fuzz:
+	$(MAKE) -C ../../../../ afl-fuzz
+
 
 ../target:
 	$(MAKE) -C ..
 
-fuzz: ../target
+fuzz: all afl-fuzz
 	rm -rf ./ouptput
 	../../../../afl-fuzz -s 1 -U -i ../sample_inputs -o ./output -- python3 harness.py @@
diff --git a/unicorn_mode/samples/speedtest/rust/Makefile b/unicorn_mode/samples/speedtest/rust/Makefile
index fe18d6ee..46934c93 100644
--- a/unicorn_mode/samples/speedtest/rust/Makefile
+++ b/unicorn_mode/samples/speedtest/rust/Makefile
@@ -1,4 +1,10 @@
-all: fuzz
+.PHONY: all fuzz
+
+all: ../target ./target/release/unicornafl_harness
+
+afl-fuzz: ../../../../afl-fuzz
+../../../../afl-fuzz:
+	$(MAKE) -C ../../../../ afl-fuzz
 
 clean:
 	cargo clean
@@ -12,6 +18,6 @@ clean:
 ../target:
 	$(MAKE) -c ..
 
-fuzz: ../target ./target/release/unicornafl_harness
+fuzz: all afl-fuzz
 	rm -rf ./output
-	SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@
+	SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject fb2fc9f25df32f17f6b6b859e4dbd70f9a857e0
+Subproject 019b871539fe9ed3f41d882385a8b02c243d49a
diff --git a/utils/README.md b/utils/README.md
index 336b6b6c..b157424f 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -32,7 +32,8 @@ Here's a quick overview of the stuff you can find in this directory:
                            with additional gdb metadata.
 
   - custom_mutators      - examples for the afl++ custom mutator interface in
-                           C and Python
+                           C and Python. Note: They were moved to
+                           ../custom_mutators/examples/
 
   - distributed_fuzzing  - a sample script for synchronizing fuzzer instances
                            across multiple machines (see parallel_fuzzing.md).
diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c
index 711d8f33..e49d6f42 100644
--- a/utils/afl_frida/afl-frida.c
+++ b/utils/afl_frida/afl-frida.c
@@ -111,7 +111,7 @@ inline static void afl_maybe_log(guint64 current_pc) {
 
 }
 
-#if GUM_NATIVE_CPU == GUM_CPU_AMD64
+#ifdef __x86_64__
 
 static const guint8 afl_maybe_log_code[] = {
 
@@ -177,7 +177,7 @@ void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
       if (instr->address >= range->code_start &&
           instr->address <= range->code_end) {
 
-#if GUM_NATIVE_CPU == GUM_CPU_AMD64
+#ifdef __x86_64__
         GumX86Writer *cw = output->writer.x86;
         if (range->current_log_impl == 0 ||
             !gum_x86_writer_can_branch_directly_between(
diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c
index 0dfae658..60f174ee 100644
--- a/utils/afl_network_proxy/afl-network-server.c
+++ b/utils/afl_network_proxy/afl-network-server.c
@@ -45,7 +45,6 @@
 
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <sys/shm.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/resource.h>
@@ -53,7 +52,9 @@
 #include <netinet/ip6.h>
 #include <arpa/inet.h>
 #include <sys/mman.h>
-#include <sys/shm.h>
+#ifndef USEMMAP
+  #include <sys/shm.h>
+#endif
 #include <sys/socket.h>
 #include <netdb.h>
 
diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c
index aa7a361a..6006e238 100644
--- a/utils/afl_proxy/afl-proxy.c
+++ b/utils/afl_proxy/afl-proxy.c
@@ -70,6 +70,10 @@ static void __afl_map_shm(void) {
   char *id_str = getenv(SHM_ENV_VAR);
   char *ptr;
 
+  /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then
+     uncomment the following: */
+
+  /*
   if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
 
     u32 val = atoi(ptr);
@@ -77,6 +81,8 @@ static void __afl_map_shm(void) {
 
   }
 
+  */
+
   if (__afl_map_size > MAP_SIZE) {
 
     if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
@@ -189,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
   /* report that we are starting the target */
   if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
 
-  if (status < 1)
-    return 0;
-  else
-    return status;
+  return status;
 
 }
 
@@ -210,7 +213,7 @@ int main(int argc, char *argv[]) {
 
   /* This is were the testcase data is written into */
   u8  buf[1024];  // this is the maximum size for a test case! set it!
-  u32 len;
+  s32 len;
 
   /* here you specify the map size you need that you are reporting to
      afl-fuzz.  Any value is fine as long as it can be divided by 32. */
@@ -222,10 +225,20 @@ int main(int argc, char *argv[]) {
 
   while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
 
-    /* here you have to create the magic that feeds the buf/len to the
-       target and write the coverage to __afl_area_ptr */
+    if (len > 4) {  // the minimum data size you need for the target
+
+      /* here you have to create the magic that feeds the buf/len to the
+         target and write the coverage to __afl_area_ptr */
 
-    // ... the magic ...
+      // ... the magic ...
+
+      // remove this, this is just to make afl-fuzz not complain when run
+      if (buf[0] == 0xff)
+        __afl_area_ptr[1] = 1;
+      else
+        __afl_area_ptr[2] = 2;
+
+    }
 
     /* report the test case is done and wait for the next */
     __afl_end_testcase();
diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile
index c1a087d7..ad99b893 100644
--- a/utils/aflpp_driver/GNUmakefile
+++ b/utils/aflpp_driver/GNUmakefile
@@ -7,7 +7,7 @@ ifneq "" "$(LLVM_BINDIR)"
   LLVM_BINDIR := $(LLVM_BINDIR)/
 endif
 
-CFLAGS := -O3 -funroll-loops -g
+CFLAGS := -O3 -funroll-loops -g -fPIC
 
 all:	libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
 
@@ -26,17 +26,17 @@ debug:
 	ar ru libAFLDriver.a afl-performance.o aflpp_driver.o
 
 aflpp_qemu_driver.o:	aflpp_qemu_driver.c
-	$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
+	-$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
 
 libAFLQemuDriver.a:	aflpp_qemu_driver.o
-	ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
-	cp -vf libAFLQemuDriver.a ../../
+	-ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
+	-cp -vf libAFLQemuDriver.a ../../
 
 aflpp_qemu_driver_hook.so:	aflpp_qemu_driver_hook.o
-	$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so
+	-test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built."
 
 aflpp_qemu_driver_hook.o:	aflpp_qemu_driver_hook.c
-	$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c
+	-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built."
 
 test:	debug
 	#clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c
diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md
new file mode 100644
index 00000000..f03c2fe3
--- /dev/null
+++ b/utils/aflpp_driver/README.md
@@ -0,0 +1,36 @@
+# afl++ drivers
+
+## aflpp_driver
+
+aflpp_driver is used to compile directly libfuzzer `LLVMFuzzerTestOneInput()`
+targets.
+
+Just do `afl-clang-fast++ -o fuzz fuzzer_harness.cc libAFLDriver.a [plus required linking]`.
+
+You can also sneakily do this little trick: 
+If this is the clang compile command to build for libfuzzer:
+  `clang++ -o fuzz -fsanitize=fuzzer fuzzer_harness.cc -lfoo`
+then just switch `clang++` with `afl-clang-fast++` and our compiler will
+magically insert libAFLDriver.a :)
+
+To use shared-memory testcases, you need nothing to do.
+To use stdin testcases give `-` as the only command line parameter.
+To use file input testcases give `@@` as the only command line parameter.
+
+IMPORTANT: if you use `afl-cmin` or `afl-cmin.bash` then either pass `-`
+or `@@` as command line parameters.
+
+## aflpp_qemu_driver
+
+aflpp_qemu_driver is used for libfuzzer `LLVMFuzzerTestOneInput()` targets that
+are to be fuzzed in qemu_mode. So we compile them with clang/clang++, without
+-fsantize=fuzzer or afl-clang-fast, and link in libAFLQemuDriver.a:
+
+`clang++ -o fuzz fuzzer_harness.cc libAFLQemuDriver.a [plus required linking]`.
+
+
+Then just do (where the name of the binary is `fuzz`):
+```
+AFL_QEMU_PERSISTENT_ADDR=0x$(nm fuzz | grep "T LLVMFuzzerTestOneInput" | awk '{print $1}')
+AFL_QEMU_PERSISTENT_HOOK=/path/to/aflpp_qemu_driver_hook.so afl-fuzz -Q ... -- ./fuzz`
+```
diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c
index ad781e64..c094c425 100644
--- a/utils/aflpp_driver/aflpp_driver.c
+++ b/utils/aflpp_driver/aflpp_driver.c
@@ -174,11 +174,17 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
 static int ExecuteFilesOnyByOne(int argc, char **argv) {
 
   unsigned char *buf = (unsigned char *)malloc(MAX_FILE);
+
   for (int i = 1; i < argc; i++) {
 
-    int fd = open(argv[i], O_RDONLY);
-    if (fd == -1) continue;
+    int fd = 0;
+
+    if (strcmp(argv[i], "-") != 0) { fd = open(argv[i], O_RDONLY); }
+
+    if (fd == -1) { continue; }
+
     ssize_t length = read(fd, buf, MAX_FILE);
+
     if (length > 0) {
 
       printf("Reading %zu bytes from %s\n", length, argv[i]);
@@ -187,7 +193,7 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
 
     }
 
-    close(fd);
+    if (fd > 0) { close(fd); }
 
   }
 
@@ -199,15 +205,19 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
 int main(int argc, char **argv) {
 
   printf(
-      "======================= INFO =========================\n"
+      "============================== INFO ================================\n"
       "This binary is built for afl++.\n"
+      "To use with afl-cmin or afl-cmin.bash pass '-' as single command line "
+      "option\n"
       "To run the target function on individual input(s) execute this:\n"
       "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
       "To fuzz with afl-fuzz execute this:\n"
       "  afl-fuzz [afl-flags] -- %s [-N]\n"
       "afl-fuzz will run N iterations before re-spawning the process (default: "
       "INT_MAX)\n"
-      "======================================================\n",
+      "For stdin input processing, pass '-' as single command line option.\n"
+      "For file input processing, pass '@@' as single command line option.\n"
+      "===================================================================\n",
       argv[0], argv[0]);
 
   if (getenv("AFL_GDB")) {
@@ -237,22 +247,35 @@ int main(int argc, char **argv) {
   memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
   memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
          sizeof(AFL_DEFER_FORKSVR));
+
   int N = INT_MAX;
-  if (argc == 2 && argv[1][0] == '-')
+
+  if (argc == 2 && !strcmp(argv[1], "-")) {
+
+    __afl_sharedmem_fuzzing = 0;
+    __afl_manual_init();
+    return ExecuteFilesOnyByOne(argc, argv);
+
+  } else if (argc == 2 && argv[1][0] == '-') {
+
     N = atoi(argv[1] + 1);
-  else if (argc == 2 && (N = atoi(argv[1])) > 0)
+
+  } else if (argc == 2 && (N = atoi(argv[1])) > 0) {
+
     printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
-  else if (argc > 1) {
+
+  } else if (argc > 1) {
 
     __afl_sharedmem_fuzzing = 0;
-    __afl_manual_init();
+
+    if (argc == 2) { __afl_manual_init(); }
+
     return ExecuteFilesOnyByOne(argc, argv);
 
   }
 
   assert(N > 0);
 
-  //  if (!getenv("AFL_DRIVER_DONT_DEFER"))
   __afl_manual_init();
 
   // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
@@ -271,6 +294,7 @@ int main(int argc, char **argv) {
       fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
     fprintf(stderr, "\n");
 #endif
+
     if (*__afl_fuzz_len) {
 
       num_runs++;
diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
index 823cc42d..2979fadc 100644
--- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c
+++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
@@ -1,21 +1,30 @@
+#include "../../qemu_mode/qemuafl/qemuafl/api.h"
+
 #include <stdint.h>
 #include <string.h>
 
 #define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+#define h2g(x) ((uint64_t)(x)-guest_base)
 
-#define REGS_RDI 7
-#define REGS_RSI 6
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
 
-void afl_persistent_hook(uint64_t *regs, uint64_t guest_base,
-                         uint8_t *input_buf, uint32_t input_len) {
+  // In this example the register RDI is pointing to the memory location
+  // of the target buffer, and the length of the input is in RSI.
+  // This can be seen with a debugger, e.g. gdb (and "disass main")
 
-  memcpy(g2h(regs[REGS_RDI]), input_buf, input_len);
-  regs[REGS_RSI] = input_len;
+  memcpy(g2h(regs->rdi), input_buf, input_buf_len);
+  regs->rsi = input_buf_len;
 
 }
 
+#undef g2h
+#undef h2g
+
 int afl_persistent_hook_init(void) {
 
+  // 1 for shared memory input (faster), 0 for normal input (you have to use
+  // read(), input_buf will be NULL)
   return 1;
 
 }
diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py
new file mode 100644
index 00000000..f64e3fae
--- /dev/null
+++ b/utils/autodict_ql/autodict-ql.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+# AutoDict-QL - Optimal Token Generation for Fuzzing
+# Part of AFL++ Project
+# Developed and Maintained by Arash Ale Ebrahim (@Microsvuln)
+# Usage : python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]
+# CURRENT_DIR = full of your current Dir
+# CODEQL_DATABASE_PATH = Full path to your CodeQL database
+# TOKEN_PATH = Folder name of the newly generated tokens
+# Example : python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens
+# Just pass the tokens folder to the -x flag of your fuzzer
+
+import os
+import string
+import binascii
+import codecs
+import errno
+import struct
+import argparse
+import shutil
+import subprocess
+
+from binascii import unhexlify
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project ---------------------------------------------------------------------------  Example usage : python2 thisfile.py outdir str.txt"
+        )
+    )
+
+    # parser.add_argument("tokenpath",
+    # help="Destination directory for tokens")
+    parser.add_argument("cur", help="Current Path")
+    parser.add_argument("db", help="CodeQL database Path")
+    parser.add_argument("tokenpath", help="Destination directory for tokens")
+
+    return parser.parse_args()
+
+
+def static_analysis(file, file2, cur, db):
+    with open(cur + "/" + file, "w") as f:
+        print(cur + "/" + file)
+        stream = os.popen("codeql query run " + cur + "/" + file2 + " -d " + db)
+        output = stream.read()
+        f.write(output)
+        f.close()
+
+
+def copy_tokens(cur, tokenpath):
+    subprocess.call(
+        ["mv " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."],
+        shell=True,
+    )
+    subprocess.call(
+        ["mv " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."],
+        shell=True,
+    )
+    subprocess.call(
+        ["mv " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."],
+        shell=True,
+    )
+    subprocess.call(
+        ["mv " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."], shell=True
+    )
+    subprocess.call(
+        ["mv " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."],
+        shell=True,
+    )
+    subprocess.call(
+        ["rm -rf strcmp-strs memcmp-strs strncmp-strs lits strtool-strs"], shell=True
+    )
+    subprocess.call(["rm *.out"], shell=True)
+    subprocess.call(["find " + tokenpath + " -size 0 -delete"], shell=True)
+
+
+def codeql_analysis(cur, db):
+    static_analysis("litout.out", "litool.ql", cur, db)
+    static_analysis("strcmp-strings.out", "strcmp-str.ql", cur, db)
+    static_analysis("strncmp-strings.out", "strncmp-str.ql", cur, db)
+    static_analysis("memcmp-strings.out", "memcmp-str.ql", cur, db)
+    static_analysis("strtool-strings.out", "strtool.ql", cur, db)
+    start_autodict(0, cur)
+
+
+def start_autodict(tokenpath, cur):
+    command = ["python3", cur + "/litan.py", cur + "/lits/", cur + "/litout.out"]
+    worker1 = subprocess.Popen(command)
+    print(worker1.communicate())
+
+    command1 = [
+        "python3",
+        cur + "/strcmp-strings.py",
+        cur + "/strcmp-strs/",
+        cur + "/strcmp-strings.out",
+    ]
+    worker2 = subprocess.Popen(command1)
+    print(worker2.communicate())
+
+    command2 = [
+        "python3",
+        cur + "/strncmp-strings.py",
+        cur + "/strncmp-strs/",
+        cur + "/strncmp-strings.out",
+    ]
+    worker3 = subprocess.Popen(command2)
+    print(worker3.communicate())
+
+    command5 = [
+        "python3",
+        cur + "/memcmp-strings.py",
+        cur + "/memcmp-strs/",
+        cur + "/memcmp-strings.out",
+    ]
+    worker6 = subprocess.Popen(command5)
+    print(worker6.communicate())
+
+    command8 = [
+        "python3",
+        cur + "/stan-strings.py",
+        cur + "/strtool-strs/",
+        cur + "/strtool-strings.out",
+    ]
+    worker9 = subprocess.Popen(command8)
+    print(worker9.communicate())
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.tokenpath)
+    # copy_tokens(args.cur, args.tokenpath)
+    codeql_analysis(args.cur, args.db)
+    copy_tokens(args.cur, args.tokenpath)
+    # start_autodict(args.tokenpath, args.cur)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/build-codeql.sh b/utils/autodict_ql/build-codeql.sh
new file mode 100644
index 00000000..6ae4b362
--- /dev/null
+++ b/utils/autodict_ql/build-codeql.sh
@@ -0,0 +1,17 @@
+cd ~
+if [ -d "codeql-home" ]; then
+    echo "Exist !"
+    exit 1
+fi
+mkdir codeql-home
+cd codeql-home
+git clone https://github.com/github/codeql.git codeql-repo
+git clone https://github.com/github/codeql-go.git
+wget https://github.com/github/codeql-cli-binaries/releases/download/v2.4.6/codeql-linux64.zip
+unzip codeql-linux64.zip 
+mv codeql codeql-cli
+export "PATH=~/codeql-home/codeql-cli/:$PATH"
+echo "export PATH=~/codeql-home/codeql-cli/:$PATH" >> ~/.bashrc
+codeql resolve languages
+codeql resolve qlpacks
+codeql
diff --git a/utils/autodict_ql/litan.py b/utils/autodict_ql/litan.py
new file mode 100644
index 00000000..7033d363
--- /dev/null
+++ b/utils/autodict_ql/litan.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+# Autodict-QL - Optimal token generation for fuzzing
+# Part of AFL++ Project
+# Author : Microsvuln - Arash.vre@gmail.com
+import string
+import os
+import binascii
+import codecs
+import struct
+import errno
+import argparse
+import re
+import base64
+from binascii import unhexlify
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project -------  Example usage : python2 thisfile.py outdir o.txt"
+        )
+    )
+    parser.add_argument(
+        "corpdir", help="The path to the corpus directory to generate files."
+    )
+    parser.add_argument(
+        "infile",
+        help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt",
+    )
+    return parser.parse_args()
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno == errno.EEXIST:
+            # print "[-] Directory exists, specify another directory"
+            exit(1)
+
+
+def do_analysis1(corpdir, infile):
+    with open(infile, "rb") as f:
+        lines = f.readlines()[1:]
+        f.close()
+        new_lst = []
+        n = 1
+        for i, num in enumerate(lines):
+            if i != 0:
+                new_lst.append(num)
+                str1 = str(num)
+                print("num is " + str1)
+                str1 = str1.rstrip("\n\n")
+                # str1 = str1.replace("0x","");
+                str1 = str1.replace("|", "")
+                str1 = str1.rstrip("\r\n")
+                str1 = str1.rstrip("\n")
+                str1 = str1.replace(" ", "")
+                # str1 = str1.translate(None, string.punctuation)
+                translator = str.maketrans("", "", string.punctuation)
+                str1 = str1.translate(translator)
+                str1 = str1[1:]
+                str1 = str1[:-1]
+                print("After cleanup : " + str1)
+                if (
+                    (str1 != "0")
+                    and (str1 != "ffffffff")
+                    and (str1 != "fffffffe")
+                    or (len(str1) == 4)
+                    or (len(str1) == 8)
+                ):
+                    print("first : " + str1)
+                    if len(str1) > 8:
+                        str1 = str1[:-1]
+                    elif len(str1) == 5:
+                        str1 = str1 = "0"
+                    try:
+                        # str1 = str1.decode("hex")
+                        with open(corpdir + "/lit-seed{0}".format(n), "w") as file:
+                            str1 = str1.replace("0x", "")
+                            print(str1)
+                            str1 = int(str1, base=16)
+                            str1 = str1.to_bytes(4, byteorder="little")
+                            file.write(str(str1))
+                            file.close()
+                            with open(corpdir + "/lit-seed{0}".format(n), "r") as q:
+                                a = q.readline()
+                                a = a[1:]
+                                print(
+                                    "AFL++ Autodict-QL by Microsvuln : Writing Token :"
+                                    + str(a)
+                                )
+                                q.close()
+                                with open(
+                                    corpdir + "/lit-seed{0}".format(n), "w"
+                                ) as w1:
+                                    w1.write(str(a))
+                                    print("Done!")
+                                    w1.close()
+                    except:
+                        print("Error!")
+                    n = n + 1
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.corpdir)
+    do_analysis1(args.corpdir, args.infile)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/litool.ql b/utils/autodict_ql/litool.ql
new file mode 100644
index 00000000..76f429c1
--- /dev/null
+++ b/utils/autodict_ql/litool.ql
@@ -0,0 +1,10 @@
+import cpp
+
+class HexOrOctLiteral extends Literal{
+    HexOrOctLiteral(){
+      (this instanceof HexLiteral) or (this instanceof OctalLiteral)
+    }
+}
+
+from HexOrOctLiteral lit
+select lit.getValueText()
diff --git a/utils/autodict_ql/memcmp-str.ql b/utils/autodict_ql/memcmp-str.ql
new file mode 100644
index 00000000..830c9cac
--- /dev/null
+++ b/utils/autodict_ql/memcmp-str.ql
@@ -0,0 +1,8 @@
+import cpp 
+
+/// function :  memcmp trace
+
+from FunctionCall fucall, Expr size
+where
+    fucall.getTarget().hasName("memcmp")
+select fucall.getArgument(_).getValueText()	
\ No newline at end of file
diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py
new file mode 100644
index 00000000..270a697c
--- /dev/null
+++ b/utils/autodict_ql/memcmp-strings.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# Autodict-QL - Optimal token generation for fuzzing
+# Part of AFL++ Project
+# Author : Microsvuln - Arash.vre@gmail.com
+
+import os
+import string
+import binascii
+import codecs
+import errno
+import struct
+import argparse
+import re
+from binascii import unhexlify
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project ---------------------------------------------------------------------------  Example usage : python2 thisfile.py outdir str.txt"
+        )
+    )
+    parser.add_argument(
+        "corpdir", help="The path to the corpus directory to generate strings."
+    )
+    parser.add_argument(
+        "infile",
+        help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
+    )
+
+    return parser.parse_args()
+
+
+def do_string_analysis(corpdir, infile1):
+    with open(infile1, "r") as f1:
+        lines = f1.readlines()[1:]
+        f1.close()
+        new_lst1 = []
+        n = 1
+        for i, num1 in enumerate(lines):
+            if i != 0:
+                new_lst1.append(num1)
+                # print("num : %s" % num1)
+                str11 = str(num1)
+                str11 = str11.replace("|", "")
+                str11 = str11.replace("\n", "")
+                str11 = str11.lstrip()
+                str11 = str11.rstrip()
+                str11 = str(str11)
+                if (
+                    (" " in str11)
+                    or (")" in str11)
+                    or ("(" in str11)
+                    or ("<" in str11)
+                    or (">" in str11)
+                ):
+                    print("Space / Paranthesis String : %s" % str11)
+                else:
+                    with open(corpdir + "/memcmp-str{0}".format(n), "w") as file:
+                        file.write(str11)
+                        print(
+                            "AFL++ Autodict-QL by Microsvuln : Writing Token : %s"
+                            % str11
+                        )
+                        n = n + 1
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.corpdir)
+    do_string_analysis(args.corpdir, args.infile)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/qlpack.yml b/utils/autodict_ql/qlpack.yml
new file mode 100644
index 00000000..28892f24
--- /dev/null
+++ b/utils/autodict_ql/qlpack.yml
@@ -0,0 +1,3 @@
+name: autodict
+version: 0.0.0
+libraryPathDependencies: codeql-cpp
diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md
new file mode 100644
index 00000000..9170f552
--- /dev/null
+++ b/utils/autodict_ql/readme.md
@@ -0,0 +1,100 @@
+# Autodict-QL - Optimal Token Generation for Fuzzing
+
+## What is this?
+
+`Autodict-QL` is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses CodeQL (a powerful semantic code analysis engine) to fetch information from a code base.
+
+Tokens are useful when you perform fuzzing on different parsers. The AFL++ `-x` switch enables the usage of dictionaries through your fuzzing campaign. If you are not familiar with Dictionaries in fuzzing, take a look [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries) .
+
+
+## Why CodeQL ?
+We basically developed this plugin on top of the CodeQL engine because it gives the user scripting features, it's easier and it's independent of the LLVM system. This means that a user can write his CodeQL scripts or modify the current scripts to improve or change the token generation algorithms based on different program analysis concepts.
+
+
+## CodeQL scripts
+Currently, we pushed some scripts as defaults for Token generation. In addition, we provide every CodeQL script as an standalone script because it's easier to modify or test.
+
+Currently we provided the following CodeQL scripts :
+
+`strcmp-str.ql` is used to extract strings that are related to the `strcmp` function.
+
+`strncmp-str.ql` is used to extract the strings from the `strncmp` function.
+
+`memcmp-str.ql` is used to extract the strings from the `memcmp` function.
+
+`litool.ql` extracts Magic numbers as Hexadecimal format.
+
+`strtool.ql` extracts strings with uses of a regex and dataflow concept to capture the string comparison functions. If `strcmp` is rewritten in a project as Mystrcmp or something like strmycmp, then this script can catch the arguments and these are valuable tokens.
+
+You can write other CodeQL scripts to extract possible effective tokens if you think they can be useful.
+
+
+## Usage
+
+Before you proceed to installation make sure that you have the following packages by installing them :
+```shell
+sudo apt install build-essential libtool-bin python3-dev python3 automake git vim wget -y
+```
+The usage of Autodict-QL is pretty easy. But let's describe it as:
+
+1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system.
+Do the following :
+```shell
+# chmod +x codeql-build.sh
+# ./codeql-build.sh
+# source ~/.bashrc
+# codeql 
+```
+Then you should get:
+
+```shell
+Usage: codeql <command> <argument>...
+Create and query CodeQL databases, or work with the QL language.
+
+GitHub makes this program freely available for the analysis of open-source software and certain other uses, but it is
+not itself free software. Type codeql --license to see the license terms.
+
+      --license              Show the license terms for the CodeQL toolchain.
+Common options:
+  -h, --help                 Show this help text.
+  -v, --verbose              Incrementally increase the number of progress messages printed.
+  -q, --quiet                Incrementally decrease the number of progress messages printed.
+Some advanced options have been hidden; try --help -v for a fuller view.
+Commands:
+  query     Compile and execute QL code.
+  bqrs      Get information from .bqrs files.
+  database  Create, analyze and process CodeQL databases.
+  dataset   [Plumbing] Work with raw QL datasets.
+  test      Execute QL unit tests.
+  resolve   [Deep plumbing] Helper commands to resolve disk locations etc.
+  execute   [Deep plumbing] Low-level commands that need special JVM options.
+  version   Show the version of the CodeQL toolchain.
+  generate  Generate formatted QL documentation.
+  github    Commands useful for interacting with the GitHub API through CodeQL.
+```
+
+2. Compile your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard.
+	- First you need to create a CodeQL database of the project codebase, suppose we want to compile `libxml` with codeql. Go to libxml and issue the following commands:
+		- `./configure --disable-shared`
+		- `codeql create database libxml-db --language=cpp --command=make`
+			- Now you have the CodeQL database of the project :-)
+3. The final step is to update the CodeQL database you created in step 2 (Suppose we are in `aflplusplus/utils/autodict_ql/` directory):
+	- `codeql database upgrade /home/user/libxml/libxml-db`
+4. Everything is set! Now you should issue the following to get the tokens:
+	- `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]`
+		- example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py $PWD /home/user/libxml/libxml-db tokens`
+			- This will create the final `tokens` dir for you and you are done, then pass the tokens path to AFL++'s `-x` flag.
+5. Done! 
+
+
+## More on dictionaries and tokens
+Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extract useful tokens, in addition with LTO instrumentation mode, this dict2file is automatically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. In addition it's independent from LLVM system.
+On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file formats and specifications. For example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionaries, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generate dictionaries based on the target.
+
+I've personally prefered to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manually generated dictionaries as `Autodict-QL` and `dict2file` are working based on the target.
+In overall, fuzzing with dictionaries and well-generated tokens will give better results.
+
+There are 2 important points to remember :
+
+- If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chances to discover new bugs.
+- Do not forget to set `AFL_MAX_DET_EXTRAS` at least to the number of generated dictionaries. If you forget to set this environment variable, then AFL++ uses just 200 tokens and use the rest of them only probabilistically. So this will guarantee that your tokens will be used by AFL++.
diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py
new file mode 100644
index 00000000..81cb0b97
--- /dev/null
+++ b/utils/autodict_ql/stan-strings.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# Autodict-QL - Optimal token generation for fuzzing
+# Part of AFL++ Project
+# Author : Microsvuln - Arash.vre@gmail.com
+
+import os
+import string
+import binascii
+import codecs
+import errno
+import struct
+import argparse
+import re
+from binascii import unhexlify
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project ---------------------------------------------------------------------------  Example usage : python2 thisfile.py outdir str.txt"
+        )
+    )
+    parser.add_argument(
+        "corpdir", help="The path to the corpus directory to generate strings."
+    )
+    parser.add_argument(
+        "infile",
+        help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
+    )
+
+    return parser.parse_args()
+
+
+def do_string_analysis(corpdir, infile1):
+    with open(infile1, "r") as f1:
+        lines = f1.readlines()[1:]
+        f1.close()
+        new_lst1 = []
+        n = 1
+        for i, num1 in enumerate(lines):
+            if i != 0:
+                new_lst1.append(num1)
+                # print("num : %s" % num1)
+                str11 = str(num1)
+                str11 = str11.replace("|", "")
+                str11 = str11.replace("\n", "")
+                str11 = str11.lstrip()
+                str11 = str11.rstrip()
+                str11 = str(str11)
+                if (
+                    (" " in str11)
+                    or (")" in str11)
+                    or ("(" in str11)
+                    or ("<" in str11)
+                    or (">" in str11)
+                ):
+                    print("Space / Paranthesis String : %s" % str11)
+                else:
+                    with open(corpdir + "/seed-str{0}".format(n), "w") as file:
+                        file.write(str11)
+                        print(
+                            "AFL++ Autodict-QL by Microsvuln : Writing Token : %s"
+                            % str11
+                        )
+                        n = n + 1
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.corpdir)
+    do_string_analysis(args.corpdir, args.infile)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/strcmp-str.ql b/utils/autodict_ql/strcmp-str.ql
new file mode 100644
index 00000000..83ffadaf
--- /dev/null
+++ b/utils/autodict_ql/strcmp-str.ql
@@ -0,0 +1,8 @@
+import cpp 
+
+/// function : strcmp
+
+from FunctionCall fucall, Expr size
+where
+    fucall.getTarget().hasName("strcmp")
+select fucall.getArgument(_).getValueText()
\ No newline at end of file
diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py
new file mode 100644
index 00000000..9c2520c9
--- /dev/null
+++ b/utils/autodict_ql/strcmp-strings.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# Autodict-QL - Optimal token generation for fuzzing
+# Part of AFL++ Project
+# Author : Microsvuln - Arash.vre@gmail.com
+
+import os
+import string
+import binascii
+import codecs
+import errno
+import struct
+import argparse
+import re
+from binascii import unhexlify
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project ---------------------------------------------------------------------------  Example usage : python2 thisfile.py outdir str.txt"
+        )
+    )
+    parser.add_argument(
+        "corpdir", help="The path to the corpus directory to generate strings."
+    )
+    parser.add_argument(
+        "infile",
+        help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
+    )
+
+    return parser.parse_args()
+
+
+def do_string_analysis(corpdir, infile1):
+    with open(infile1, "r") as f1:
+        lines = f1.readlines()[1:]
+        f1.close()
+        new_lst1 = []
+        n = 1
+        for i, num1 in enumerate(lines):
+            if i != 0:
+                new_lst1.append(num1)
+                # print("num : %s" % num1)
+                str11 = str(num1)
+                str11 = str11.replace("|", "")
+                str11 = str11.replace("\n", "")
+                str11 = str11.lstrip()
+                str11 = str11.rstrip()
+                str11 = str(str11)
+                if (
+                    (" " in str11)
+                    or (")" in str11)
+                    or ("(" in str11)
+                    or ("<" in str11)
+                    or (">" in str11)
+                ):
+                    print("Space / Paranthesis String : %s" % str11)
+                else:
+                    with open(corpdir + "/strcmp-str{0}".format(n), "w") as file:
+                        file.write(str11)
+                        print(
+                            "AFL++ Autodict-QL by Microsvuln : Writing Token : %s"
+                            % str11
+                        )
+                        n = n + 1
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.corpdir)
+    do_string_analysis(args.corpdir, args.infile)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/strncmp-str.ql b/utils/autodict_ql/strncmp-str.ql
new file mode 100644
index 00000000..dbb952e5
--- /dev/null
+++ b/utils/autodict_ql/strncmp-str.ql
@@ -0,0 +1,8 @@
+import cpp 
+
+/// function : strncmp
+
+from FunctionCall fucall, Expr size
+where
+    fucall.getTarget().hasName("strncmp")
+select fucall.getArgument(_).getValueText()
\ No newline at end of file
diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py
new file mode 100644
index 00000000..6206b4c4
--- /dev/null
+++ b/utils/autodict_ql/strncmp-strings.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# Autodict-QL - Optimal token generation for fuzzing
+# Part of AFL++ Project
+# Author : Microsvuln - Arash.vre@gmail.com
+
+import os
+import string
+import binascii
+import codecs
+import errno
+import struct
+import argparse
+import re
+from binascii import unhexlify
+
+
+def ensure_dir(dir):
+    try:
+        os.makedirs(dir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description=(
+            "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project ---------------------------------------------------------------------------  Example usage : python2 thisfile.py outdir str.txt"
+        )
+    )
+    parser.add_argument(
+        "corpdir", help="The path to the corpus directory to generate strings."
+    )
+    parser.add_argument(
+        "infile",
+        help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
+    )
+
+    return parser.parse_args()
+
+
+def do_string_analysis(corpdir, infile1):
+    with open(infile1, "r") as f1:
+        lines = f1.readlines()[1:]
+        f1.close()
+        new_lst1 = []
+        n = 1
+        for i, num1 in enumerate(lines):
+            if i != 0:
+                new_lst1.append(num1)
+                # print("num : %s" % num1)
+                str11 = str(num1)
+                str11 = str11.replace("|", "")
+                str11 = str11.replace("\n", "")
+                str11 = str11.lstrip()
+                str11 = str11.rstrip()
+                str11 = str(str11)
+                if (
+                    (" " in str11)
+                    or (")" in str11)
+                    or ("(" in str11)
+                    or ("<" in str11)
+                    or (">" in str11)
+                ):
+                    print("Space / Paranthesis String : %s" % str11)
+                else:
+                    with open(corpdir + "/strncmp-str{0}".format(n), "w") as file:
+                        file.write(str11)
+                        print(
+                            "AFL++ Autodict-QL by Microsvuln : Writing Token : %s"
+                            % str11
+                        )
+                        n = n + 1
+
+
+def main():
+    args = parse_args()
+    ensure_dir(args.corpdir)
+    do_string_analysis(args.corpdir, args.infile)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/utils/autodict_ql/strtool.ql b/utils/autodict_ql/strtool.ql
new file mode 100644
index 00000000..253d1555
--- /dev/null
+++ b/utils/autodict_ql/strtool.ql
@@ -0,0 +1,24 @@
+import cpp
+import semmle.code.cpp.dataflow.DataFlow
+class StringLiteralNode extends DataFlow::Node {
+  StringLiteralNode() { this.asExpr() instanceof StringLiteral }
+}
+class CmpArgNode extends DataFlow::Node {
+   CmpArgNode() {
+    exists(FunctionCall fc |
+      fc.getTarget().getName().regexpMatch(".*(str|mem|strn|b)*(cmp|str)*") and
+      fc.getArgument(0) = this.asExpr() 
+    )
+ or
+    exists(FunctionCall fc |
+      fc.getTarget().getName().regexpMatch(".*(str|mem|strn|b)*(cmp|str)*") and
+      fc.getArgument(1) = this.asExpr()
+    )
+  }
+}
+
+from StringLiteralNode src, CmpArgNode arg
+where
+  DataFlow::localFlow(src, arg)
+
+select src.asExpr().(StringLiteral).toString()
\ No newline at end of file
diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh
index a752458d..4d75430e 100755
--- a/utils/crash_triage/triage_crashes.sh
+++ b/utils/crash_triage/triage_crashes.sh
@@ -90,12 +90,15 @@ for crash in $DIR/crashes/id:*; do
 
   for a in $@; do
 
-    if [ "$a" = "@@" ] ; then
-      use_args="$use_args $crash"
+    case "$a" in
+      *@@*)
       unset use_stdio
-    else
+      use_args="$use_args `printf %s "$a" | sed -e 's<@@<'$crash'<g'`"
+      ;;
+      *)
       use_args="$use_args $a"
-    fi
+      ;;
+    esac
 
   done
 
diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c
index 1b247c86..dde78f7b 100644
--- a/utils/libdislocator/libdislocator.so.c
+++ b/utils/libdislocator/libdislocator.so.c
@@ -144,8 +144,8 @@ typedef struct {
 
 /* Configurable stuff (use AFL_LD_* to set): */
 
-static u32 max_mem = MAX_ALLOC;         /* Max heap usage to permit         */
-static u8  alloc_verbose,               /* Additional debug messages        */
+static size_t max_mem = MAX_ALLOC;      /* Max heap usage to permit         */
+static u8     alloc_verbose,            /* Additional debug messages        */
     hard_fail,                          /* abort() when max_mem exceeded?   */
     no_calloc_over,                     /* abort() on calloc() overflows?   */
     align_allocations;                  /* Force alignment to sizeof(void*) */
@@ -154,7 +154,7 @@ static u8  alloc_verbose,               /* Additional debug messages        */
   #define __thread
   #warning no thread support available
 #endif
-static __thread size_t total_mem;       /* Currently allocated mem          */
+static _Atomic size_t total_mem;        /* Currently allocated mem          */
 
 static __thread u32 call_depth;         /* To avoid recursion via fprintf() */
 static u32          alloc_canary;
@@ -172,9 +172,9 @@ static void *__dislocator_alloc(size_t len) {
 
   if (total_mem + len > max_mem || total_mem + len < total_mem) {
 
-    if (hard_fail) FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024);
+    if (hard_fail) FATAL("total allocs exceed %zu MB", max_mem / 1024 / 1024);
 
-    DEBUGF("total allocs exceed %u MB, returning NULL", max_mem / 1024 / 1024);
+    DEBUGF("total allocs exceed %zu MB, returning NULL", max_mem / 1024 / 1024);
 
     return NULL;
 
@@ -500,19 +500,20 @@ size_t malloc_usable_size(const void *ptr) {
 
 __attribute__((constructor)) void __dislocator_init(void) {
 
-  u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB");
+  char *tmp = getenv("AFL_LD_LIMIT_MB");
 
   if (tmp) {
 
-    u8 *tok;
-    s32 mmem = (s32)strtol((char *)tmp, (char **)&tok, 10);
-    if (*tok != '\0' || errno == ERANGE) FATAL("Bad value for AFL_LD_LIMIT_MB");
+    char *             tok;
+    unsigned long long mmem = strtoull(tmp, &tok, 10);
+    if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024)
+      FATAL("Bad value for AFL_LD_LIMIT_MB");
     max_mem = mmem * 1024 * 1024;
 
   }
 
   alloc_canary = ALLOC_CANARY;
-  tmp = (u8 *)getenv("AFL_RANDOM_ALLOC_CANARY");
+  tmp = getenv("AFL_RANDOM_ALLOC_CANARY");
 
   if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary));
 
diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp
index b2066cc8..182a014b 100755
--- a/utils/qbdi_mode/template.cpp
+++ b/utils/qbdi_mode/template.cpp
@@ -25,7 +25,7 @@
 #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
   #define INC_AFL_AREA(loc)           \
     asm volatile(                     \
-        "incb (%0, %1, 1)\n"          \
+        "addb $1, (%0, %1, 1)\n"      \
         "adcb $0, (%0, %1, 1)\n"      \
         : /* no out */                \
         : "r"(afl_area_ptr), "r"(loc) \
diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c
index f4a8ae59..14b2ed85 100644
--- a/utils/qemu_persistent_hook/read_into_rdi.c
+++ b/utils/qemu_persistent_hook/read_into_rdi.c
@@ -3,12 +3,12 @@
 #include <stdio.h>
 #include <string.h>
 
-void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
-                         uint8_t *input_buf, uint32_t input_buf_len) {
-\
 #define g2h(x) ((void *)((unsigned long)(x) + guest_base))
 #define h2g(x) ((uint64_t)(x)-guest_base)
 
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+
   // In this example the register RDI is pointing to the memory location
   // of the target buffer, and the length of the input is in RSI.
   // This can be seen with a debugger, e.g. gdb (and "disass main")
@@ -19,11 +19,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
   memcpy(g2h(regs->rdi), input_buf, input_buf_len);
   regs->rsi = input_buf_len;
 
+}
+
 #undef g2h
 #undef h2g
 
-}
-
 int afl_persistent_hook_init(void) {
 
   // 1 for shared memory input (faster), 0 for normal input (you have to use