about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile7
-rw-r--r--custom_mutators/examples/example.c2
-rw-r--r--custom_mutators/examples/post_library_gif.so.c13
-rw-r--r--custom_mutators/examples/post_library_png.so.c48
-rw-r--r--docs/Changelog.md6
-rw-r--r--docs/INSTALL.md10
-rw-r--r--docs/custom_mutators.md9
-rw-r--r--frida_mode/GNUmakefile2
-rw-r--r--frida_mode/README.md5
-rw-r--r--frida_mode/Scripting.md8
-rw-r--r--frida_mode/frida.map1
-rw-r--r--frida_mode/include/instrument.h3
-rw-r--r--frida_mode/src/instrument/instrument.c49
-rw-r--r--frida_mode/src/instrument/instrument_arm32.c19
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c39
-rw-r--r--frida_mode/src/instrument/instrument_coverage.c6
-rw-r--r--frida_mode/src/instrument/instrument_debug.c4
-rw-r--r--frida_mode/src/instrument/instrument_x64.c22
-rw-r--r--frida_mode/src/instrument/instrument_x86.c14
-rw-r--r--frida_mode/src/intercept.c4
-rw-r--r--frida_mode/src/js/api.js9
-rw-r--r--frida_mode/src/js/js_api.c5
-rw-r--r--frida_mode/ts/lib/afl.ts14
-rw-r--r--include/envs.h1
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc4
-rw-r--r--src/afl-fuzz-bitmap.c15
-rw-r--r--src/afl-fuzz-cmplog.c13
-rw-r--r--src/afl-fuzz-mutators.c18
-rw-r--r--src/afl-fuzz-python.c11
-rw-r--r--src/afl-fuzz-run.c85
-rw-r--r--src/afl-fuzz-state.c20
-rw-r--r--src/afl-fuzz.c4
32 files changed, 360 insertions, 110 deletions
diff --git a/GNUmakefile b/GNUmakefile
index b6865f0c..a64d511f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -367,15 +367,18 @@ help:
 	@echo Known build environment options:
 	@echo "=========================================="
 	@echo STATIC - compile AFL++ static
-	@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
+	@echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
+	@echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
 	@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
 	@echo PROFILING - compile afl-fuzz with profiling information
 	@echo INTROSPECTION - compile afl-fuzz with mutation introspection
 	@echo NO_PYTHON - disable python support
 	@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
 	@echo NO_NYX - disable building nyx mode dependencies
+	@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
+	@echo NO_UNICORN_ARM64 - disable building unicorn on arm64
 	@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
-	@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
+	@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
 	@echo "=========================================="
 	@echo e.g.: make ASAN_BUILD=1
 
diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c
index 5c174e10..3f299508 100644
--- a/custom_mutators/examples/example.c
+++ b/custom_mutators/examples/example.c
@@ -352,7 +352,7 @@ uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
  * @return if the file contents was modified return 1 (True), 0 (False)
  *         otherwise
  */
-uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
+uint8_t afl_custom_queue_new_entry(my_mutator_t  *data,
                                    const uint8_t *filename_new_queue,
                                    const uint8_t *filename_orig_queue) {
 
diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c
index aec05720..9cd224f4 100644
--- a/custom_mutators/examples/post_library_gif.so.c
+++ b/custom_mutators/examples/post_library_gif.so.c
@@ -72,6 +72,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "alloc-inl.h"
 
 /* Header that must be present at the beginning of every test case: */
 
@@ -127,9 +128,11 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
   }
 
   /* Allocate memory for new buffer, reusing previous allocation if
-     possible. */
+     possible. Note we have to use afl-fuzz's own realloc!
+     Note that you should only do this if you need to grow the buffer,
+     otherwise work with in_buf, and assign it to *out_buf instead. */
 
-  *out_buf = realloc(data->buf, len);
+  *out_buf = afl_realloc(out_buf, len);
 
   /* If we're out of memory, the most graceful thing to do is to return the
      original buffer and give up on modifying it. Let AFL handle OOM on its
@@ -142,9 +145,9 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
 
   }
 
-  /* Copy the original data to the new location. */
-
-  memcpy(*out_buf, in_buf, len);
+  if (len > strlen(HEADER))
+    memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
+           len - strlen(HEADER));
 
   /* Insert the new header. */
 
diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c
index 941f7e55..cd65b1bc 100644
--- a/custom_mutators/examples/post_library_png.so.c
+++ b/custom_mutators/examples/post_library_png.so.c
@@ -29,8 +29,8 @@
 #include <stdint.h>
 #include <string.h>
 #include <zlib.h>
-
 #include <arpa/inet.h>
+#include "alloc-inl.h"
 
 /* A macro to round an integer up to 4 kB. */
 
@@ -70,9 +70,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
                                unsigned int          len,
                                const unsigned char **out_buf) {
 
-  unsigned char *new_buf = (unsigned char *)in_buf;
-  unsigned int   pos = 8;
-
   /* Don't do anything if there's not enough room for the PNG header
      (8 bytes). */
 
@@ -83,6 +80,22 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
 
   }
 
+  /* This is not a good way to do it, if you do not need to grow the buffer
+     then just work with in_buf instead for speed reasons.
+     But we want to show how to grow a buffer, so this is how it's done: */
+
+  unsigned int   pos = 8;
+  unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
+
+  if (!new_buf) {
+
+    *out_buf = in_buf;
+    return len;
+
+  }
+
+  memcpy(new_buf, in_buf, len);
+
   /* Minimum size of a zero-length PNG chunk is 12 bytes; if we
      don't have that, we can bail out. */
 
@@ -111,33 +124,6 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
 
     if (real_cksum != file_cksum) {
 
-      /* First modification? Make a copy of the input buffer. Round size
-         up to 4 kB to minimize the number of reallocs needed. */
-
-      if (new_buf == in_buf) {
-
-        if (len <= data->size) {
-
-          new_buf = data->buf;
-
-        } else {
-
-          new_buf = realloc(data->buf, UP4K(len));
-          if (!new_buf) {
-
-            *out_buf = in_buf;
-            return len;
-
-          }
-
-          data->buf = new_buf;
-          data->size = UP4K(len);
-          memcpy(new_buf, in_buf, len);
-
-        }
-
-      }
-
       *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
 
     }
diff --git a/docs/Changelog.md b/docs/Changelog.md
index ff3907f0..05bbe827 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -9,6 +9,12 @@ 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 ++4.02a (dev)
+  - afl-fuzz:
+    - change post_process hook to allow returning NULL and 0 length to
+      tell afl-fuzz to skip this mutated input
+  - afl-cc:
+    - important fix for the default pcguard mode when LLVM IR vector
+      selects are produced, thanks to @juppytt for reporting!
   - gcc_plugin:
     - Adacore submitted CMPLOG support to the gcc_plugin! :-)
   - llvm_mode:
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index 312b41e9..4f2b7174 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -79,19 +79,23 @@ make STATIC=1
 These build options exist:
 
 * STATIC - compile AFL++ static
-* ASAN_BUILD - compiles with memory sanitizer for debug purposes
+* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
+* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for
+  debug purposes
 * DEBUG - no optimization, -ggdb3, all warnings and -Werror
-* PROFILING - compile with profiling information (gprof)
+* PROFILING - compile afl-fuzz with profiling information
 * INTROSPECTION - compile afl-fuzz with mutation introspection
 * NO_PYTHON - disable python support
 * NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
   normal fuzzing
 * NO_NYX - disable building nyx mode dependencies
+* NO_CORESIGHT - disable building coresight (arm64 only)
+* NO_UNICORN_ARM64 - disable building unicorn on arm64
 * AFL_NO_X86 - if compiling on non-intel/amd platforms
 * LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
   (e.g., Debian)
 
-e.g.: `make ASAN_BUILD=1`
+e.g.: `make LLVM_CONFIG=llvm-config-14`
 
 ## MacOS X on x86 and arm64 (M1)
 
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 7b4e0516..6f3353ec 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -38,6 +38,11 @@ performed with the custom mutator.
 
 ## 2) APIs
 
+**IMPORTANT NOTE**: If you use our C/C++ API and you want to increase the size
+of an **out_buf buffer, you have to use `afl_realloc()` for this, so include
+`include/alloc-inl.h` - otherwise afl-fuzz will crash when trying to free
+your buffers.
+
 C/C++:
 
 ```c
@@ -159,6 +164,10 @@ def deinit():  # optional for Python
     This can return any python object that implements the buffer protocol and
     supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
 
+    You can decide in the post_process mutator to not send the mutated data
+    to the target, e.g. if it is too short, too corrupted, etc. If so,
+    return a NULL buffer and zero length (or a 0 length string in Python).
+
 - `queue_new_entry` (optional):
 
     This methods is called after adding a new test case to the queue. If the
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile
index b9b47b62..bc7df6c0 100644
--- a/frida_mode/GNUmakefile
+++ b/frida_mode/GNUmakefile
@@ -116,7 +116,7 @@ ifndef OS
  $(error "Operating system unsupported")
 endif
 
-GUM_DEVKIT_VERSION=15.1.27
+GUM_DEVKIT_VERSION=15.2.1
 GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
 GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
 
diff --git a/frida_mode/README.md b/frida_mode/README.md
index 4025dba5..29f7968b 100644
--- a/frida_mode/README.md
+++ b/frida_mode/README.md
@@ -151,6 +151,7 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
 * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
   and their instrumented counterparts during block compilation.
 
+```
 Creating block for 0x7ffff7953313:
         0x7ffff7953313  mov qword ptr [rax], 0
         0x7ffff795331a  add rsp, 8
@@ -166,7 +167,7 @@ Generated block 0x7ffff75e98e2
 
 
   ***
-  ```
+```
 * `AFL_FRIDA_INST_CACHE_SIZE` - Set the size of the instrumentation cache used
 as a look-up table to cache real to instrumented address block translations.
 Default is 256Mb.
@@ -177,6 +178,8 @@ Default is 256Mb.
   a file.
 * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
   instrumentation (the default where available). Required to use
+* `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start
+  of each block.
   `AFL_FRIDA_INST_TRACE`.
 * `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
 instrumented address block translations.
diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md
index 8634860b..2b18e200 100644
--- a/frida_mode/Scripting.md
+++ b/frida_mode/Scripting.md
@@ -850,6 +850,14 @@ class Afl {
   static setInstrumentNoOptimize() {
       Afl.jsApiSetInstrumentNoOptimize();
   }
+  /**
+   * See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
+   * an argument.
+   */
+  public static setInstrumentRegsFile(file: string): void {
+    const buf = Memory.allocUtf8String(file);
+    Afl.jsApiSetInstrumentRegsFile(buf);
+  }
   /*
     * See `AFL_FRIDA_INST_SEED`
     */
diff --git a/frida_mode/frida.map b/frida_mode/frida.map
index 6726dbbd..8e956460 100644
--- a/frida_mode/frida.map
+++ b/frida_mode/frida.map
@@ -19,6 +19,7 @@
     js_api_set_instrument_libraries;
     js_api_set_instrument_instructions;
     js_api_set_instrument_no_optimize;
+    js_api_set_instrument_regs_file;
     js_api_set_instrument_seed;
     js_api_set_instrument_trace;
     js_api_set_instrument_trace_unique;
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
index cd480202..b85aa571 100644
--- a/frida_mode/include/instrument.h
+++ b/frida_mode/include/instrument.h
@@ -13,6 +13,7 @@ extern gboolean instrument_unique;
 extern guint64  instrument_hash_zero;
 extern char    *instrument_coverage_unstable_filename;
 extern gboolean instrument_coverage_insn;
+extern char *   instrument_regs_filename;
 
 extern gboolean instrument_use_fixed_seed;
 extern guint64  instrument_fixed_seed;
@@ -66,6 +67,8 @@ void instrument_cache_config(void);
 void instrument_cache_init(void);
 void instrument_cache_insert(gpointer real_address, gpointer code_address);
 void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
+void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data);
+void instrument_regs_format(int fd, char *format, ...);
 
 #endif
 
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index 9ee7db2d..93c498e8 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -1,3 +1,4 @@
+#include <fcntl.h>
 #include <unistd.h>
 #include <sys/shm.h>
 #include <sys/mman.h>
@@ -20,6 +21,8 @@
 #include "stats.h"
 #include "util.h"
 
+#define FRIDA_DEFAULT_MAP_SIZE (64UL << 10)
+
 gboolean instrument_tracing = false;
 gboolean instrument_optimize = false;
 gboolean instrument_unique = false;
@@ -30,6 +33,7 @@ gboolean instrument_use_fixed_seed = FALSE;
 guint64  instrument_fixed_seed = 0;
 char    *instrument_coverage_unstable_filename = NULL;
 gboolean instrument_coverage_insn = FALSE;
+char *   instrument_regs_filename = NULL;
 
 static GumStalkerTransformer *transformer = NULL;
 
@@ -37,6 +41,8 @@ static GumAddress previous_rip = 0;
 static GumAddress previous_end = 0;
 static u8        *edges_notified = NULL;
 
+static int regs_fd = -1;
+
 __thread guint64  instrument_previous_pc;
 __thread guint64 *instrument_previous_pc_addr = NULL;
 
@@ -230,6 +236,10 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
 
         }
 
+        if (unlikely(instrument_regs_filename != NULL)) {
+          gum_stalker_iterator_put_callout(iterator, instrument_write_regs,
+                                           (void *)(size_t)regs_fd, NULL);
+        }
       }
 
     }
@@ -240,8 +250,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
 
     }
 
-    instrument_debug_instruction(instr->address, instr->size, output);
-
     if (likely(!excluded)) {
 
       asan_instrument(instr, iterator);
@@ -266,7 +274,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
   instrument_flush(output);
   instrument_debug_end(output);
   instrument_coverage_end(instr->address + instr->size);
-
 }
 
 void instrument_config(void) {
@@ -279,6 +286,7 @@ void instrument_config(void) {
   instrument_coverage_unstable_filename =
       (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
   instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL);
+  instrument_regs_filename = getenv("AFL_FRIDA_INST_REGS_FILE");
 
   instrument_debug_config();
   instrument_coverage_config();
@@ -290,6 +298,8 @@ void instrument_config(void) {
 
 void instrument_init(void) {
 
+  if (__afl_map_size == MAP_SIZE) __afl_map_size = FRIDA_DEFAULT_MAP_SIZE;
+
   if (!instrument_is_coverage_optimize_supported()) instrument_optimize = false;
 
   FOKF(cBLU "Instrumentation" cRST " - " cGRN "optimize:" cYEL " [%c]",
@@ -390,6 +400,23 @@ void instrument_init(void) {
        instrument_hash_seed);
   instrument_hash_zero = instrument_get_offset_hash(0);
 
+  FOKF(cBLU "Instrumentation" cRST " - " cGRN "regs:" cYEL " [%s]",
+       instrument_regs_filename == NULL ? " " : instrument_regs_filename);
+
+  if (instrument_regs_filename != NULL) {
+    char *path =
+        g_canonicalize_filename(instrument_regs_filename, g_get_current_dir());
+
+    FOKF(cBLU "Instrumentation" cRST " - " cGRN "path:" cYEL " [%s]", path);
+
+    regs_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+
+    if (regs_fd < 0) { FFATAL("Failed to open regs file '%s'", path); }
+
+    g_free(path);
+  }
+
   asan_init();
   cmplog_init();
   instrument_coverage_init();
@@ -416,3 +443,19 @@ void instrument_on_fork() {
 
 }
 
+void instrument_regs_format(int fd, 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(fd, buffer, len));
+}
diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c
index 572b706c..73923326 100644
--- a/frida_mode/src/instrument/instrument_arm32.c
+++ b/frida_mode/src/instrument/instrument_arm32.c
@@ -80,5 +80,24 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
 
 }
 
+void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
+  int fd = (int)user_data;
+  instrument_regs_format(fd,
+                         "r0 : 0x%08x, r1 : 0x%08x, r2 : 0x%08x, r3 : 0x%08x\n",
+                         cpu_context->r[0], cpu_context->r[2],
+                         cpu_context->r[1], cpu_context->r[3]);
+  instrument_regs_format(fd,
+                         "r4 : 0x%08x, r5 : 0x%08x, r6 : 0x%08x, r7 : 0x%08x\n",
+                         cpu_context->r[4], cpu_context->r[5],
+                         cpu_context->r[6], cpu_context->r[7]);
+  instrument_regs_format(
+      fd, "r8 : 0x%08x, r9 : 0x%08x, r10: 0x%08x, r11: 0x%08x\n",
+      cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
+  instrument_regs_format(
+      fd, "r12: 0x%08x, sp : 0x%08x, lr : 0x%08x, pc : 0x%08x\n",
+      cpu_context->r12, cpu_context->sp, cpu_context->lr, cpu_context->pc);
+  instrument_regs_format(fd, "cpsr: 0x%08x\n\n", cpu_context->cpsr);
+}
+
 #endif
 
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
index afc20f42..9157f8f5 100644
--- a/frida_mode/src/instrument/instrument_arm64.c
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -272,9 +272,10 @@ void instrument_coverage_optimize(const cs_insn    *instr,
 
     GumAddressSpec spec = {.near_address = cw->code,
                            .max_distance = 1ULL << 30};
+    guint          page_size = gum_query_page_size();
 
     instrument_previous_pc_addr = gum_memory_allocate_near(
-        &spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
+        &spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
     *instrument_previous_pc_addr = instrument_hash_zero;
     FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
     FVERBOSE("code_addr: %p", cw->code);
@@ -405,5 +406,41 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
 
 }
 
+void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
+  int fd = (int)(size_t)user_data;
+  instrument_regs_format(
+      fd, "x0 : 0x%016x, x1 : 0x%016x, x2 : 0x%016x, x3 : 0x%016x\n",
+      cpu_context->x[0], cpu_context->x[1], cpu_context->x[2],
+      cpu_context->x[3]);
+  instrument_regs_format(
+      fd, "x4 : 0x%016x, x5 : 0x%016x, x6 : 0x%016x, x7 : 0x%016x\n",
+      cpu_context->x[4], cpu_context->x[5], cpu_context->x[6],
+      cpu_context->x[7]);
+  instrument_regs_format(
+      fd, "x8 : 0x%016x, x9 : 0x%016x, x10: 0x%016x, x11: 0x%016x\n",
+      cpu_context->x[8], cpu_context->x[9], cpu_context->x[10],
+      cpu_context->x[11]);
+  instrument_regs_format(
+      fd, "x12: 0x%016x, x13: 0x%016x, x14: 0x%016x, x15: 0x%016x\n",
+      cpu_context->x[12], cpu_context->x[13], cpu_context->x[14],
+      cpu_context->x[15]);
+  instrument_regs_format(
+      fd, "x16: 0x%016x, x17: 0x%016x, x18: 0x%016x, x19: 0x%016x\n",
+      cpu_context->x[16], cpu_context->x[17], cpu_context->x[18],
+      cpu_context->x[19]);
+  instrument_regs_format(
+      fd, "x20: 0x%016x, x21: 0x%016x, x22: 0x%016x, x23: 0x%016x\n",
+      cpu_context->x[20], cpu_context->x[21], cpu_context->x[22],
+      cpu_context->x[23]);
+  instrument_regs_format(
+      fd, "x24: 0x%016x, x25: 0x%016x, x26: 0x%016x, x27: 0x%016x\n",
+      cpu_context->x[24], cpu_context->x[25], cpu_context->x[26],
+      cpu_context->x[27]);
+  instrument_regs_format(
+      fd, "x28: 0x%016x, fp : 0x%016x, lr : 0x%016x, sp : 0x%016x\n",
+      cpu_context->x[28], cpu_context->fp, cpu_context->lr, cpu_context->sp);
+  instrument_regs_format(fd, "pc : 0x%016x\n\n", cpu_context->pc);
+}
+
 #endif
 
diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c
index 68842feb..07d4d622 100644
--- a/frida_mode/src/instrument/instrument_coverage.c
+++ b/frida_mode/src/instrument/instrument_coverage.c
@@ -317,6 +317,12 @@ static void coverage_write_events(void *key, void *value, void *user_data) {
 
   };
 
+#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+  evt.offset = __builtin_bswap32(evt.offset);
+  evt.length = __builtin_bswap16(evt.length);
+  evt.module = __builtin_bswap16(evt.module);
+#endif
+
   coverage_write(fd, &evt, sizeof(coverage_event_t));
 
 }
diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c
index d26f9cec..17245d65 100644
--- a/frida_mode/src/instrument/instrument_debug.c
+++ b/frida_mode/src/instrument/instrument_debug.c
@@ -63,14 +63,12 @@ static void instrument_disasm(guint8 *start, guint8 *end,
 
     count = cs_disasm(capstone, curr, size, GPOINTER_TO_SIZE(curr), 0, &insn);
     if (insn == NULL) {
-
       instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t* 0x%016" G_GSIZE_MODIFIER
                        "x\n",
-                       (uint64_t)curr, *(size_t *)curr);
+                       (uint64_t)(size_t)curr, *(size_t *)curr);
 
       len += sizeof(size_t);
       continue;
-
     }
 
     for (i = 0; i != count; i++) {
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
index bfafe067..9d754082 100644
--- a/frida_mode/src/instrument/instrument_x64.c
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -337,15 +337,14 @@ void instrument_coverage_optimize(const cs_insn    *instr,
                                   GumStalkerOutput *output) {
 
   GumX86Writer *cw = output->writer.x86;
-  /* guint64 area_offset =
-   * instrument_get_offset_hash(GUM_ADDRESS(instr->address)); */
   if (instrument_previous_pc_addr == NULL) {
 
     GumAddressSpec spec = {.near_address = cw->code,
                            .max_distance = 1ULL << 30};
+    guint          page_size = gum_query_page_size();
 
     instrument_previous_pc_addr = gum_memory_allocate_near(
-        &spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
+        &spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
     *instrument_previous_pc_addr = instrument_hash_zero;
     FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
     FVERBOSE("code_addr: %p", cw->code);
@@ -469,5 +468,22 @@ gpointer instrument_cur(GumStalkerOutput *output) {
 
 }
 
+void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
+  int fd = (int)(size_t)user_data;
+  instrument_regs_format(
+      fd, "rax: 0x%016x, rbx: 0x%016x, rcx: 0x%016x, rdx: 0x%016x\n",
+      cpu_context->rax, cpu_context->rbx, cpu_context->rcx, cpu_context->rdx);
+  instrument_regs_format(
+      fd, "rdi: 0x%016x, rsi: 0x%016x, rbp: 0x%016x, rsp: 0x%016x\n",
+      cpu_context->rdi, cpu_context->rsi, cpu_context->rbp, cpu_context->rsp);
+  instrument_regs_format(
+      fd, "r8 : 0x%016x, r9 : 0x%016x, r10: 0x%016x, r11: 0x%016x\n",
+      cpu_context->r8, cpu_context->r9, cpu_context->r10, cpu_context->r11);
+  instrument_regs_format(
+      fd, "r12: 0x%016x, r13: 0x%016x, r14: 0x%016x, r15: 0x%016x\n",
+      cpu_context->r12, cpu_context->r13, cpu_context->r14, cpu_context->r15);
+  instrument_regs_format(fd, "rip: 0x%016x\n\n", cpu_context->rip);
+}
+
 #endif
 
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
index 048daf32..eb0c7184 100644
--- a/frida_mode/src/instrument/instrument_x86.c
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -162,9 +162,10 @@ void instrument_coverage_optimize(const cs_insn    *instr,
 
     GumAddressSpec spec = {.near_address = cw->code,
                            .max_distance = 1ULL << 30};
+    guint          page_size = gum_query_page_size();
 
     instrument_previous_pc_addr = gum_memory_allocate_near(
-        &spec, sizeof(guint64), 0x1000, GUM_PAGE_READ | GUM_PAGE_WRITE);
+        &spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE);
     *instrument_previous_pc_addr = instrument_hash_zero;
     FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr);
     FVERBOSE("code_addr: %p", cw->code);
@@ -269,5 +270,16 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
 
 }
 
+void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) {
+  int fd = (int)(size_t)user_data;
+  instrument_regs_format(
+      fd, "eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n",
+      cpu_context->eax, cpu_context->ebx, cpu_context->ecx, cpu_context->edx);
+  instrument_regs_format(
+      fd, "esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n",
+      cpu_context->esi, cpu_context->edi, cpu_context->ebp, cpu_context->esp);
+  instrument_regs_format(fd, "eip: 0x%08x\n\n", cpu_context->eip);
+}
+
 #endif
 
diff --git a/frida_mode/src/intercept.c b/frida_mode/src/intercept.c
index 26d20c50..e9751848 100644
--- a/frida_mode/src/intercept.c
+++ b/frida_mode/src/intercept.c
@@ -7,8 +7,8 @@ void intercept_hook(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);
+  GumReplaceReturn ret = gum_interceptor_replace(interceptor, address,
+                                                 replacement, user_data, NULL);
   if (ret != GUM_REPLACE_OK) { FFATAL("gum_interceptor_attach: %d", ret); }
   gum_interceptor_end_transaction(interceptor);
 
diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js
index c1c9d36f..721ef82c 100644
--- a/frida_mode/src/js/api.js
+++ b/frida_mode/src/js/api.js
@@ -150,6 +150,14 @@ class Afl {
     static setInstrumentNoOptimize() {
         Afl.jsApiSetInstrumentNoOptimize();
     }
+    /**
+     * See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
+     * an argument.
+     */
+    static setInstrumentRegsFile(file) {
+        const buf = Memory.allocUtf8String(file);
+        Afl.jsApiSetInstrumentRegsFile(buf);
+    }
     /*
      * See `AFL_FRIDA_INST_SEED`
      */
@@ -322,6 +330,7 @@ Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument
 Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
 Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
 Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
+Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]);
 Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);
 Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
 Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
index 7cc8ffc7..d0c0aa60 100644
--- a/frida_mode/src/js/js_api.c
+++ b/frida_mode/src/js/js_api.c
@@ -156,6 +156,11 @@ __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
 
 }
 
+__attribute__((visibility("default"))) void js_api_set_instrument_regs_file(
+    char *path) {
+  instrument_regs_filename = g_strdup(path);
+}
+
 __attribute__((visibility("default"))) void js_api_set_instrument_seed(
     guint64 seed) {
 
diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts
index a858f074..455d4305 100644
--- a/frida_mode/ts/lib/afl.ts
+++ b/frida_mode/ts/lib/afl.ts
@@ -178,6 +178,15 @@ class Afl {
     Afl.jsApiSetInstrumentNoOptimize();
   }
 
+  /**
+   * See `AFL_FRIDA_INST_REGS_FILE`. This function takes a single `string` as
+   * an argument.
+   */
+  public static setInstrumentRegsFile(file: string): void {
+    const buf = Memory.allocUtf8String(file);
+    Afl.jsApiSetInstrumentRegsFile(buf);
+  }
+
   /*
    * See `AFL_FRIDA_INST_SEED`
    */
@@ -419,6 +428,11 @@ class Afl {
     "void",
     []);
 
+  private static readonly jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction(
+    "js_api_set_instrument_regs_file",
+    "void",
+    ["pointer"]);
+
   private static readonly jsApiSetInstrumentSeed = Afl.jsApiGetFunction(
     "js_api_set_instrument_seed",
     "void",
diff --git a/include/envs.h b/include/envs.h
index 9b8917f9..853edbd9 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -67,6 +67,7 @@ static char *afl_environment_variables[] = {
     "AFL_FRIDA_INST_NO_PREFETCH",
     "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
     "AFL_FRIDA_INST_RANGES",
+    "AFL_FRIDA_INST_REGS_FILE",
     "AFL_FRIDA_INST_SEED",
     "AFL_FRIDA_INST_TRACE",
     "AFL_FRIDA_INST_TRACE_UNIQUE",
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index d5f56aa8..e22c9ead 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -262,7 +262,7 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
 
 }  // namespace
 
-#if 1
+#if LLVM_VERSION_MAJOR >= 11                        /* use new pass manager */
 
 extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
 llvmGetPassPluginInfo() {
@@ -902,7 +902,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
           if (tt) {
 
             cnt_sel++;
-            cnt_sel_inc += tt->getElementCount().getKnownMinValue();
+            cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
 
           }
 
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 089f7bb5..b3a10bb7 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -647,8 +647,19 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
       if (afl->fsrv.exec_tmout < afl->hang_tmout) {
 
-        u8 new_fault;
-        len = write_to_testcase(afl, &mem, len, 0);
+        u8  new_fault;
+        u32 tmp_len = write_to_testcase(afl, &mem, len, 0);
+
+        if (likely(tmp_len)) {
+
+          len = tmp_len;
+
+        } else {
+
+          len = write_to_testcase(afl, &mem, len, 1);
+
+        }
+
         new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
         classify_counts(&afl->fsrv);
 
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 258d9ea7..d0c829e2 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -47,9 +47,18 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
 u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
-  u8 fault;
+  u8  fault;
+  u32 tmp_len = write_to_testcase(afl, (void **)&out_buf, len, 0);
 
-  write_to_testcase(afl, (void **)&out_buf, len, 0);
+  if (likely(tmp_len)) {
+
+    len = tmp_len;
+
+  } else {
+
+    len = write_to_testcase(afl, (void **)&out_buf, len, 1);
+
+  }
 
   fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index dd97a7d3..b9daebfa 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -430,13 +430,21 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
       retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
 
-      fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
-      ++afl->trim_execs;
+      if (unlikely(!retlen)) {
+
+        ++afl->trim_execs;
+
+      } else {
 
-      if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+        fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+        ++afl->trim_execs;
 
-      classify_counts(&afl->fsrv);
-      cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+        if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+
+        classify_counts(&afl->fsrv);
+        cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+      }
 
     }
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index a3d864c3..a43d80bb 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -535,7 +535,16 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
 
     Py_DECREF(py_value);
 
-    *out_buf = (u8 *)py->post_process_buf.buf;
+    if (unlikely(py->post_process_buf.len == 0)) {
+
+      *out_buf = NULL;
+
+    } else {
+
+      *out_buf = (u8 *)py->post_process_buf.buf;
+
+    }
+
     return py->post_process_buf.len;
 
   } else {
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 0f3be1a7..c0e72ae6 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -76,24 +76,6 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
 u32 __attribute__((hot))
 write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
 
-#ifdef _AFL_DOCUMENT_MUTATIONS
-  s32  doc_fd;
-  char fn[PATH_MAX];
-  snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
-           afl->document_counter++,
-           describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
-
-  if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
-      0) {
-
-    if (write(doc_fd, *mem, len) != len)
-      PFATAL("write to mutation file failed: %s", fn);
-    close(doc_fd);
-
-  }
-
-#endif
-
   if (unlikely(afl->custom_mutators_count)) {
 
     ssize_t new_size = len;
@@ -107,19 +89,38 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
         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_size = 0;
+          new_buf = new_mem;
+          // FATAL("Custom_post_process failed (ret: %lu)", (long
+          // unsigned)new_size);
 
-        }
+        } else {
 
-        new_mem = new_buf;
+          new_mem = new_buf;
+
+        }
 
       }
 
     });
 
+    if (unlikely(!new_size)) {
+
+      // perform dummy runs (fix = 1), but skip all others
+      if (fix) {
+
+        new_size = len;
+
+      } else {
+
+        return 0;
+
+      }
+
+    }
+
     if (unlikely(new_size < afl->min_length && !fix)) {
 
       new_size = afl->min_length;
@@ -153,6 +154,24 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
 
   }
 
+#ifdef _AFL_DOCUMENT_MUTATIONS
+  s32  doc_fd;
+  char fn[PATH_MAX];
+  snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
+           afl->document_counter++,
+           describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
+
+  if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
+      0) {
+
+    if (write(doc_fd, *mem, len) != len)
+      PFATAL("write to mutation file failed: %s", fn);
+    close(doc_fd);
+
+  }
+
+#endif
+
   return len;
 
 }
@@ -207,14 +226,18 @@ 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_size = 0;
+          new_buf = new_mem;
+          // FATAL("Custom_post_process failed (ret: %lu)", (long
+          // unsigned)new_size);
 
-        }
+        } else {
 
-        new_mem = new_buf;
+          new_mem = new_buf;
+
+        }
 
       }
 
@@ -969,7 +992,11 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   u8 fault;
 
-  len = write_to_testcase(afl, (void **)&out_buf, len, 0);
+  if (unlikely(len = write_to_testcase(afl, (void **)&out_buf, len, 0)) == 0) {
+
+    return 0;
+
+  }
 
   fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index cc4138ae..ddfd4b31 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -518,16 +518,6 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_no_crash_readme =
                 atoi((u8 *)get_afl_env(afl_environment_variables[i]));
 
-            if (afl->afl_env.afl_pizza_mode == 0) {
-
-              afl->afl_env.afl_pizza_mode = 1;
-
-            } else {
-
-              afl->pizza_is_served = 1;
-
-            }
-
           } else if (!strncmp(env, "AFL_SYNC_TIME",
 
                               afl_environment_variable_len)) {
@@ -607,6 +597,16 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
 
   }
 
+  if (afl->afl_env.afl_pizza_mode == 0) {
+
+    afl->afl_env.afl_pizza_mode = 1;
+
+  } else {
+
+    afl->pizza_is_served = 1;
+
+  }
+
   if (issue_detected) { sleep(2); }
 
 }
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 287f09df..2e151abb 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -167,8 +167,8 @@ static void usage(u8 *argv0, int more_help) {
       "                  See docs/README.MOpt.md\n"
       "  -c program    - enable CmpLog by specifying a binary compiled for "
       "it.\n"
-      "                  if using QEMU/FRIDA or if you the fuzzing target is "
-      "compiled"
+      "                  if using QEMU/FRIDA or the fuzzing target is "
+      "compiled\n"
       "                  for CmpLog then just use -c 0.\n"
       "  -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
       "                  1=small files, 2=larger files (default), 3=all "