about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-x.custom-format.py2
-rw-r--r--GNUmakefile38
-rw-r--r--TODO.md1
-rw-r--r--custom_mutators/aflpp_tritondse/README.md9
-rw-r--r--custom_mutators/aflpp_tritondse/aflpp_tritondse.py78
-rw-r--r--custom_mutators/symcc/README.md2
-rw-r--r--custom_mutators/symqemu/Makefile14
-rw-r--r--custom_mutators/symqemu/README.md19
-rw-r--r--custom_mutators/symqemu/symqemu.c424
-rw-r--r--docs/Changelog.md3
-rw-r--r--docs/env_variables.md8
-rw-r--r--frida_mode/src/lib/lib_apple.c4
-rw-r--r--include/afl-fuzz.h1
-rw-r--r--include/config.h2
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc4
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc4
-rw-r--r--instrumentation/afl-compiler-rt.o.c14
-rw-r--r--instrumentation/afl-llvm-common.h2
-rw-r--r--instrumentation/afl-llvm-lto-instrumentlist.so.cc2
-rw-r--r--instrumentation/cmplog-routines-pass.cc4
-rw-r--r--instrumentation/compare-transform-pass.so.cc2
-rw-r--r--instrumentation/split-compares-pass.so.cc2
-rw-r--r--qemu_mode/libcompcov/libcompcov.so.c6
-rw-r--r--src/afl-cc.c21
-rw-r--r--src/afl-common.c2
-rw-r--r--src/afl-fuzz-one.c1
-rw-r--r--src/afl-fuzz-redqueen.c32
-rw-r--r--src/afl-fuzz.c45
-rw-r--r--test-instr.c9
-rw-r--r--utils/afl_untracer/afl-untracer.c2
-rw-r--r--utils/libtokencap/libtokencap.so.c6
-rw-r--r--utils/socket_fuzzing/socketfuzz.c3
-rw-r--r--utils/target_intelligence/README.md61
33 files changed, 738 insertions, 89 deletions
diff --git a/.custom-format.py b/.custom-format.py
index 1295ce55..1d5c8839 100755
--- a/.custom-format.py
+++ b/.custom-format.py
@@ -24,7 +24,7 @@ import importlib.metadata
 
 # string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
 
-CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
+CURRENT_LLVM = os.getenv('LLVM_VERSION', 15)
 CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
 
 
diff --git a/GNUmakefile b/GNUmakefile
index 31374c10..4ecdae52 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -139,13 +139,13 @@ endif
 
 ifdef DEBUG
   $(info Compiling DEBUG version of binaries)
-  override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
+  override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror -Wno-error=format-truncation= $(CFLAGS_OPT)
 else
   CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
 endif
 
 override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
-			-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
+			-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" -Wno-format-truncation \
 			-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
 # -fstack-protector
 
@@ -180,13 +180,13 @@ AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
 
 ifneq "$(shell command -v python3m 2>/dev/null)" ""
   ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
-    PYTHON_INCLUDE  ?= $(shell python3m-config --includes)
-    PYTHON_VERSION  ?= $(strip $(shell python3m --version 2>&1))
+    PYTHON_INCLUDE  := $(shell python3m-config --includes)
+    PYTHON_VERSION  := $(strip $(shell python3m --version 2>&1))
     # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
     ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
-      PYTHON_LIB      ?= $(shell python3m-config --libs --embed --ldflags)
+      PYTHON_LIB      := $(shell python3m-config --libs --embed --ldflags)
     else
-      PYTHON_LIB      ?= $(shell python3m-config --ldflags)
+      PYTHON_LIB      := $(shell python3m-config --ldflags)
     endif
   endif
 endif
@@ -194,13 +194,13 @@ endif
 ifeq "$(PYTHON_INCLUDE)" ""
   ifneq "$(shell command -v python3 2>/dev/null)" ""
     ifneq "$(shell command -v python3-config 2>/dev/null)" ""
-      PYTHON_INCLUDE  ?= $(shell python3-config --includes)
-      PYTHON_VERSION  ?= $(strip $(shell python3 --version 2>&1))
+      PYTHON_INCLUDE  := $(shell python3-config --includes)
+      PYTHON_VERSION  := $(strip $(shell python3 --version 2>&1))
       # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
       ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
-        PYTHON_LIB      ?= $(shell python3-config --libs --embed --ldflags)
+        PYTHON_LIB      := $(shell python3-config --libs --embed --ldflags)
       else
-        PYTHON_LIB      ?= $(shell python3-config --ldflags)
+        PYTHON_LIB      := $(shell python3-config --ldflags)
       endif
     endif
   endif
@@ -209,9 +209,9 @@ endif
 ifeq "$(PYTHON_INCLUDE)" ""
   ifneq "$(shell command -v python 2>/dev/null)" ""
     ifneq "$(shell command -v python-config 2>/dev/null)" ""
-      PYTHON_INCLUDE  ?= $(shell python-config --includes)
-      PYTHON_LIB      ?= $(shell python-config --ldflags)
-      PYTHON_VERSION  ?= $(strip $(shell python --version 2>&1))
+      PYTHON_INCLUDE  := $(shell python-config --includes)
+      PYTHON_LIB      := $(shell python-config --ldflags)
+      PYTHON_VERSION  := $(strip $(shell python --version 2>&1))
     endif
   endif
 endif
@@ -220,9 +220,9 @@ endif
 ifeq "$(PYTHON_INCLUDE)" ""
   ifneq "$(shell command -v python3.7 2>/dev/null)" ""
     ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
-      PYTHON_INCLUDE  ?= $(shell python3.7-config --includes)
-      PYTHON_LIB      ?= $(shell python3.7-config --ldflags)
-      PYTHON_VERSION  ?= $(strip $(shell python3.7 --version 2>&1))
+      PYTHON_INCLUDE  := $(shell python3.7-config --includes)
+      PYTHON_LIB      := $(shell python3.7-config --ldflags)
+      PYTHON_VERSION  := $(strip $(shell python3.7 --version 2>&1))
     endif
   endif
 endif
@@ -231,9 +231,9 @@ endif
 ifeq "$(PYTHON_INCLUDE)" ""
   ifneq "$(shell command -v python2.7 2>/dev/null)" ""
     ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
-      PYTHON_INCLUDE  ?= $(shell python2.7-config --includes)
-      PYTHON_LIB      ?= $(shell python2.7-config --ldflags)
-      PYTHON_VERSION  ?= $(strip $(shell python2.7 --version 2>&1))
+      PYTHON_INCLUDE  := $(shell python2.7-config --includes)
+      PYTHON_LIB      := $(shell python2.7-config --ldflags)
+      PYTHON_VERSION  := $(strip $(shell python2.7 --version 2>&1))
     endif
   endif
 endif
diff --git a/TODO.md b/TODO.md
index 2efcefea..d6a2e6fd 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,6 +2,7 @@
 
 ## Should
 
+ - redo PCGUARD + LTO for llvm 15+
  - splicing selection weighted?
  - support persistent and deferred fork server in afl-showmap?
  - better autodetection of shifting runtime timeout values
diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md
index 8a5dd02b..033655d2 100644
--- a/custom_mutators/aflpp_tritondse/README.md
+++ b/custom_mutators/aflpp_tritondse/README.md
@@ -10,8 +10,13 @@
 ../../afl-cc -o ../../test-instr ../../test-instr.c
 mkdir -p in
 echo aaaa > in/in
-TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
+AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
 ```
 
 Note that this custom mutator works differently, new finds are synced
-after 10-60 seconds to the fuzzing instance.
+after 10-60 seconds to the fuzzing instance. This is necessary because only
+C/C++ custom mutators have access to the internal AFL++ state.
+
+Note that you should run first with `AFL_DEBUG` for 5-10 minutes and see if
+all important libraries and syscalls are hooked (look at `WARNING` and `CRITICAL`
+output during the run, best use with `AFL_NO_UI=1`)
diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
index e0219f0b..58b506b6 100644
--- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
+++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
@@ -22,14 +22,17 @@ config = None
 dse = None
 cycle = 0
 count = 0
+finding = 0
 hashes = set()
 format = SeedFormat.RAW
 
 def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
     global count
     global hashes
+    global finding
     if se.seed.hash not in hashes:
         hashes.add(se.seed.hash)
+        finding = 1
         filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash
         if not os.path.exists(filename):
             if is_debug:
@@ -47,6 +50,59 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
     #        file.write(se.seed.content)
 
 
+#def rtn_open(se: SymbolicExecutor, pstate: ProcessState, pc):
+#    """
+#    The open behavior.
+#    """
+#    logging.debug('open hooked')
+#
+#    # Get arguments
+#    arg0 = pstate.get_argument_value(0)  # const char *pathname
+#    flags = pstate.get_argument_value(1)  # int flags
+#    mode = pstate.get_argument_value(2)  # int mode
+#    arg0s = pstate.memory.read_string(arg0)
+#
+#    # Concretize the whole path name
+#    pstate.concretize_memory_bytes(arg0, len(arg0s)+1)  # Concretize the whole string + \0
+#
+#    # We use flags as concrete value
+#    pstate.concretize_argument(1)
+#
+#    # Use the flags to open the file in the write mode.
+#    mode = ""
+#    if (flags & 0xFF) == 0x00:   # O_RDONLY
+#        mode = "r"
+#    elif (flags & 0xFF) == 0x01: # O_WRONLY
+#        mode = "w"
+#    elif (flags & 0xFF) == 0x02: # O_RDWR
+#        mode = "r+"
+#
+#    if (flags & 0x0100): # O_CREAT
+#        mode += "x"
+#    if (flags & 0x0200): # O_APPEND
+#        mode = "a"  # replace completely value
+#
+#    if se.seed.is_file_defined(arg0s) and "r" in mode:  # input file and opened in reading
+#        logging.info(f"opening an input file: {arg0s}")
+#        # Program is opening an input
+#        data = se.seed.get_file_input(arg0s)
+#        filedesc = pstate.create_file_descriptor(arg0s, io.BytesIO(data))
+#        fd = filedesc.id
+#    else:
+#        # Try to open it as a regular file
+#        try:
+#            fd = open(arg0s, mode)  # use the mode here
+#            filedesc = pstate.create_file_descriptor(arg0s, fd)
+#            fd = filedesc.id
+#        except Exception as e:
+#            logging.debug(f"Failed to open {arg0s} {e}")
+#            fd = pstate.minus_one
+#
+#    pstate.write_register("rax", fd)  # write the return value
+#    pstate.cpu.program_counter = pstate.pop_stack_value()  # pop the return value
+#    se.skip_instruction()  # skip the current instruction so that the engine go straight fetching the next instruction
+
+
 def init(seed):
     global config
     global dse
@@ -64,6 +120,10 @@ def init(seed):
         is_debug = True
     except KeyError:
         pass
+    if is_debug:
+        logging.basicConfig(level=logging.WARNING)
+    else:
+        logging.basicConfig(level=logging.CRITICAL)
     try:
         foo = os.environ['AFL_CUSTOM_INFO_OUT']
         out_path = foo + '/../tritondse/queue'
@@ -115,10 +175,16 @@ def init(seed):
     dse = SymbolicExplorator(config, prog)
     # Add callbacks.
     dse.callback_manager.register_pre_execution_callback(pre_exec_hook)
+    #dse.callback_manager.register_function_callback("open", rtn_open)
 
 
-#def fuzz(buf, add_buf, max_size):
-#    return b""
+def fuzz(buf, add_buf, max_size):
+    global finding
+    finding = 1
+    while finding == 1:
+      finding = 0
+      dse.step()
+    return b""
 
 
 def queue_new_entry(filename_new_queue, filename_orig_queue):
@@ -141,8 +207,14 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
         dse.add_input_seed(seed)
         # Start exploration!
         #dse.step()
-        dse.explore()
+        #dse.explore()
     pass
 
+
+# we simulate just doing one single fuzz in the custom mutator
+def fuzz_count(buf):
+    return 1
+
+
 def splice_optout():
     pass
diff --git a/custom_mutators/symcc/README.md b/custom_mutators/symcc/README.md
index 364a348e..a6839a37 100644
--- a/custom_mutators/symcc/README.md
+++ b/custom_mutators/symcc/README.md
@@ -5,6 +5,8 @@ This uses the symcc to find new paths into the target.
 Note that this is a just a proof of concept example! It is better to use
 the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this.
 
+Also the symqemu custom mutator is better than this.
+
 To use this custom mutator follow the steps in the symcc repository 
 [https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/) 
 on how to build symcc and how to instrument a target binary (the same target
diff --git a/custom_mutators/symqemu/Makefile b/custom_mutators/symqemu/Makefile
new file mode 100644
index 00000000..958aec19
--- /dev/null
+++ b/custom_mutators/symqemu/Makefile
@@ -0,0 +1,14 @@
+
+ifdef DEBUG
+  CFLAGS += -DDEBUG
+endif
+
+all: symqemu-mutator.so
+
+CFLAGS	+= -O3 -funroll-loops
+
+symqemu-mutator.so: symqemu.c
+	$(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c
+
+clean:
+	rm -f symqemu-mutator.so *.o *~ core
diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md
new file mode 100644
index 00000000..c3071afc
--- /dev/null
+++ b/custom_mutators/symqemu/README.md
@@ -0,0 +1,19 @@
+# custum mutator: symqemu
+
+This uses the symcc to find new paths into the target.
+
+## How to build and use
+
+To use this custom mutator follow the steps in the symqemu repository 
+[https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/) 
+on how to build symqemu-x86_x64 and put it in your `PATH`.
+
+Just type `make` to build this custom mutator.
+
+```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...```
+
+## Options
+
+`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones.
+
+`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes.
diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c
new file mode 100644
index 00000000..73a1640a
--- /dev/null
+++ b/custom_mutators/symqemu/symqemu.c
@@ -0,0 +1,424 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "config.h"
+#include "debug.h"
+#include "afl-fuzz.h"
+#include "common.h"
+
+afl_state_t *afl_struct;
+static u32   debug = 0;
+static u32   found_items = 0;
+
+#define SYMQEMU_LOCATION "symqemu"
+
+#define DBG(x...) \
+  if (debug) { fprintf(stderr, x); }
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  u32          all;
+  u32          late;
+  u8          *mutator_buf;
+  u8          *out_dir;
+  u8          *target;
+  u8          *symqemu;
+  u8          *input_file;
+  u32          counter;
+  u32          seed;
+  u32          argc;
+  u8         **argv;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  if (getenv("AFL_DEBUG")) debug = 1;
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  char *path = getenv("PATH");
+  char *exec_name = "symqemu-x86_64";
+  char *token = strtok(path, ":");
+  char  exec_path[4096];
+
+  while (token != NULL && data->symqemu == NULL) {
+
+    snprintf(exec_path, sizeof(exec_path), "%s/%s", token, exec_name);
+    if (access(exec_path, X_OK) == 0) {
+
+      data->symqemu = (u8 *)strdup(exec_path);
+      break;
+
+    }
+
+    token = strtok(NULL, ":");
+
+  }
+
+  if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name);
+  DBG("Found %s\n", data->symqemu);
+
+  if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) {
+
+    WARNF(
+        "the symqemu module is not very effective with "
+        "AFL_CUSTOM_MUTATOR_ONLY.");
+
+  }
+
+  if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
+
+    free(data);
+    perror("mutator_buf alloc");
+    return NULL;
+
+  }
+
+  data->target = getenv("AFL_CUSTOM_INFO_PROGRAM");
+
+  u8 *path_tmp = getenv("AFL_CUSTOM_INFO_OUT");
+  u32 len = strlen(path_tmp) + 32;
+  u8 *symqemu_path = malloc(len);
+  data->out_dir = malloc(len);
+  snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION);
+  snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp);
+
+  (void)mkdir(symqemu_path, 0755);
+  (void)mkdir(data->out_dir, 0755);
+
+  setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
+
+  data->input_file = getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT");
+
+  u8 *tmp = NULL;
+  if ((tmp = getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) && *tmp) {
+
+    int argc = 0, index = 2;
+    for (u32 i = 0; i < strlen(tmp); ++i)
+      if (isspace(tmp[i])) ++argc;
+
+    data->argv = (u8 **)malloc((argc + 4) * sizeof(u8 **));
+    u8 *p = strdup(tmp);
+
+    do {
+
+      data->argv[index] = p;
+      while (*p && !isspace(*p))
+        ++p;
+      if (*p) {
+
+        *p++ = 0;
+        while (isspace(*p))
+          ++p;
+
+      }
+
+      if (strcmp(data->argv[index], "@@") == 0) {
+
+        if (!data->input_file) {
+
+          u32 ilen = strlen(symqemu_path) + 32;
+          data->input_file = malloc(ilen);
+          snprintf(data->input_file, ilen, "%s/.input", symqemu_path);
+
+        }
+
+        data->argv[index] = data->input_file;
+
+      }
+
+      DBG("%d: %s\n", index, data->argv[index]);
+      index++;
+
+    } while (*p);
+
+    data->argv[index] = NULL;
+    data->argc = index;
+
+  } else {
+
+    data->argv = (u8 **)malloc(8 * sizeof(u8 **));
+    data->argc = 2;
+    data->argv[2] = NULL;
+
+  }
+
+  data->argv[0] = data->symqemu;
+  data->argv[1] = data->target;
+  data->afl = afl;
+  data->seed = seed;
+  afl_struct = afl;
+
+  if (getenv("SYMQEMU_ALL")) { data->all = 1; }
+  if (getenv("SYMQEMU_LATE")) { data->late = 1; }
+  if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); }
+
+  DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir,
+      data->target,
+      data->input_file ? (char *)data->input_file : (char *)"<stdin>",
+      data->argc);
+
+  if (debug) {
+
+    fprintf(stderr, "[");
+    for (u32 i = 0; i <= data->argc; ++i)
+      fprintf(stderr, " \"%s\"",
+              data->argv[i] ? (char *)data->argv[i] : "<NULL>");
+    fprintf(stderr, " ]\n");
+
+  }
+
+  return data;
+
+}
+
+/* No need to receive a splicing item */
+void afl_custom_splice_optout(void *data) {
+
+  (void)(data);
+
+}
+
+/* Get unix time in milliseconds */
+
+inline u64 get_cur_time(void) {
+
+  struct timeval  tv;
+  struct timezone tz;
+
+  gettimeofday(&tv, &tz);
+
+  return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
+
+}
+
+u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) {
+
+  if (likely((!afl_struct->queue_cur->favored && !data->all) ||
+             afl_struct->queue_cur->was_fuzzed)) {
+
+    return 0;
+
+  }
+
+  if (likely(data->late)) {
+
+    if (unlikely(get_cur_time() - afl_struct->last_find_time <=
+                 10 * 60 * 1000)) {
+
+      return 0;
+
+    }
+
+  }
+
+  int         pipefd[2];
+  struct stat st;
+
+  if (afl_struct->afl_env.afl_no_ui) {
+
+    ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname);
+
+  }
+
+  if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) &&
+        st.st_size)) {
+
+    PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname);
+
+  }
+
+  if (afl_struct->fsrv.use_stdin) {
+
+    if (pipe(pipefd) == -1) {
+
+      PFATAL(
+          "Couldn't create a pipe for interacting with symqemu child process");
+
+    }
+
+  }
+
+  if (data->input_file) {
+
+    int     fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+    ssize_t s = write(fd, buf, buf_size);
+    close(fd);
+    DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file);
+
+  }
+
+  int pid = fork();
+
+  if (pid == -1) return 0;
+
+  if (likely(pid)) {
+
+    if (!data->input_file || afl_struct->fsrv.use_stdin) {
+
+      close(pipefd[0]);
+
+      if (fcntl(pipefd[1], F_GETPIPE_SZ)) {
+
+        fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
+
+      }
+
+      ck_write(pipefd[1], buf, buf_size, data->input_file);
+
+      close(pipefd[1]);
+
+    }
+
+    pid = waitpid(pid, NULL, 0);
+    DBG("symqemu finished executing!\n");
+
+  } else /* (pid == 0) */ {  // child
+
+    if (afl_struct->fsrv.use_stdin) {
+
+      close(pipefd[1]);
+      dup2(pipefd[0], 0);
+
+    }
+
+    DBG("exec=%s\n", data->target);
+    if (!debug) {
+
+      close(1);
+      close(2);
+      dup2(afl_struct->fsrv.dev_null_fd, 1);
+      dup2(afl_struct->fsrv.dev_null_fd, 2);
+
+    }
+
+    execvp((char *)data->argv[0], (char **)data->argv);
+    fprintf(stderr, "Executing: [");
+    for (u32 i = 0; i <= data->argc; ++i)
+      fprintf(stderr, " \"%s\"",
+              data->argv[i] ? (char *)data->argv[i] : "<NULL>");
+    fprintf(stderr, " ]\n");
+    FATAL("Failed to execute %s %s\n", data->argv[0], data->argv[1]);
+    exit(-1);
+
+  }
+
+  /* back in mother process */
+
+  struct dirent **nl;
+  s32             i, items = scandir(data->out_dir, &nl, NULL, NULL);
+  found_items = 0;
+  char source_name[4096];
+
+  if (items > 0) {
+
+    for (i = 0; i < (u32)items; ++i) {
+
+      // symqemu output files start with a digit
+      if (!isdigit(nl[i]->d_name[0])) continue;
+
+      struct stat st;
+      snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
+               nl[i]->d_name);
+      DBG("file=%s\n", source_name);
+
+      if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
+
+        ++found_items;
+
+      }
+
+      free(nl[i]);
+
+    }
+
+    free(nl);
+
+  }
+
+  DBG("Done, found %u items!\n", found_items);
+
+  return found_items;
+
+}
+
+size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
+                       u8 **out_buf, u8 *add_buf, size_t add_buf_size,
+                       size_t max_size) {
+
+  struct dirent **nl;
+  s32             done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL);
+  char            source_name[4096];
+
+  if (items > 0) {
+
+    for (i = 0; i < (u32)items; ++i) {
+
+      // symqemu output files start with a digit
+      if (!isdigit(nl[i]->d_name[0])) continue;
+
+      struct stat st;
+      snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
+               nl[i]->d_name);
+      DBG("file=%s\n", source_name);
+
+      if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
+
+        int fd = open(source_name, O_RDONLY);
+        if (fd < 0) { goto got_an_issue; }
+
+        ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
+        close(fd);
+
+        DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r);
+
+        if (r < 1) { goto got_an_issue; }
+
+        done = 1;
+        --found_items;
+        unlink(source_name);
+
+        *out_buf = data->mutator_buf;
+        return (u32)r;
+
+      }
+
+      free(nl[i]);
+
+    }
+
+    free(nl);
+
+  }
+
+got_an_issue:
+  *out_buf = NULL;
+  return 0;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->mutator_buf);
+  free(data);
+
+}
+
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 3602af50..e99747f6 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -23,6 +23,9 @@
   - qemu_mode:
     - Persistent mode +QASAN support for ppc32 tragets by @worksbutnottested
   - a new grammar custom mutator atnwalk was submitted by @voidptr127 !
+  - two new custom mutators are now available:
+    - TritonDSE in custom_mutators/aflpp_tritondse
+    - SymQEMU in custom_mutators/symqemu
 
 
 ### Version ++4.06c (release)
diff --git a/docs/env_variables.md b/docs/env_variables.md
index b1f23159..0f0869d2 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -619,6 +619,14 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
   - Setting `AFL_INST_LIBS` causes the translator to also instrument the code
     inside any dynamically linked libraries (notably including glibc).
 
+  - You can use `AFL_QEMU_INST_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to just
+    instrument specific memory locations, e.g. a specific library.
+    Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
+
+  - You can use `AFL_QEMU_EXCLUDE_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to **NOT**
+    instrument specific memory locations, e.g. a specific library.
+    Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
+
   - It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some
     of the basic blocks, which can be useful when dealing with very complex
     binaries.
diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c
index 634e0e30..d29d0303 100644
--- a/frida_mode/src/lib/lib_apple.c
+++ b/frida_mode/src/lib/lib_apple.c
@@ -17,8 +17,8 @@ static gboolean lib_get_main_module(const GumModuleDetails *details,
 
   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);
+      details->path, mach_task_self(), details->range->base_address,
+      GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
 
   FVERBOSE("Found main module: %s", module->name);
 
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 8fb7ecb1..beb2de2a 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -184,6 +184,7 @@ struct queue_entry {
       handicap,                         /* Number of queue cycles behind    */
       depth,                            /* Path depth                       */
       exec_cksum,                       /* Checksum of the execution trace  */
+      custom,                           /* Marker for custom mutators       */
       stats_mutated;                    /* stats: # of mutations performed  */
 
   u8 *trace_mini;                       /* Trace bytes, if kept             */
diff --git a/include/config.h b/include/config.h
index 764c29dc..194786f7 100644
--- a/include/config.h
+++ b/include/config.h
@@ -81,7 +81,7 @@
    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
+// #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
diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc
index b3b0d2cd..d7b03634 100644
--- a/instrumentation/SanitizerCoverageLTO.so.cc
+++ b/instrumentation/SanitizerCoverageLTO.so.cc
@@ -1478,8 +1478,8 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection(
 
   ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
   auto       Array = new GlobalVariable(
-            *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
-            Constant::getNullValue(ArrayTy), "__sancov_gen_");
+      *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
+      Constant::getNullValue(ArrayTy), "__sancov_gen_");
 
 #if LLVM_VERSION_MAJOR >= 13
   if (TargetTriple.supportsCOMDAT() &&
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index 41c38283..8fed2042 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -714,8 +714,8 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
 
   ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
   auto       Array = new GlobalVariable(
-            *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
-            Constant::getNullValue(ArrayTy), "__sancov_gen_");
+      *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
+      Constant::getNullValue(ArrayTy), "__sancov_gen_");
 
 #if LLVM_VERSION_MAJOR >= 13
   if (TargetTriple.supportsCOMDAT() &&
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index 5372fae0..3f8b519b 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -544,12 +544,12 @@ static void __afl_map_shm(void) {
 
     if (__afl_map_size && __afl_map_size > MAP_SIZE) {
 
-             u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
-             if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
+      u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
+      if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
 
-               fprintf(stderr, "FS_ERROR_MAP_SIZE\n");
-               send_forkserver_error(FS_ERROR_MAP_SIZE);
-               _exit(1);
+        fprintf(stderr, "FS_ERROR_MAP_SIZE\n");
+        send_forkserver_error(FS_ERROR_MAP_SIZE);
+        _exit(1);
 
       }
 
@@ -561,13 +561,13 @@ static void __afl_map_shm(void) {
 
     if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
 
-             if (__afl_map_addr)
+      if (__afl_map_addr)
         send_forkserver_error(FS_ERROR_MAP_ADDR);
       else
         send_forkserver_error(FS_ERROR_SHMAT);
 
       perror("shmat for map");
-             _exit(1);
+      _exit(1);
 
     }
 
diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h
index c9324460..23f67179 100644
--- a/instrumentation/afl-llvm-common.h
+++ b/instrumentation/afl-llvm-common.h
@@ -23,7 +23,7 @@ typedef long double max_align_t;
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #if LLVM_VERSION_MAJOR < 17
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+  #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #endif
 
 #if LLVM_VERSION_MAJOR > 3 || \
diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
index db5bd55e..61f97d77 100644
--- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc
+++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
@@ -45,7 +45,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
-//#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+// #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Passes/PassPlugin.h"
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/IR/PassManager.h"
diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc
index 39db5aa4..c3fbed8d 100644
--- a/instrumentation/cmplog-routines-pass.cc
+++ b/instrumentation/cmplog-routines-pass.cc
@@ -542,7 +542,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
     Value               *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
     Value               *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
     Value               *v3Pbitcast = IRB.CreateBitCast(
-                      v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
+        v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
     Value *v3Pcasted =
         IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
     args.push_back(v1Pcasted);
@@ -608,7 +608,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
     Value               *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
     Value               *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
     Value               *v3Pbitcast = IRB.CreateBitCast(
-                      v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
+        v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
     Value *v3Pcasted =
         IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
     args.push_back(v1Pcasted);
diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc
index efc99d20..5dd705cf 100644
--- a/instrumentation/compare-transform-pass.so.cc
+++ b/instrumentation/compare-transform-pass.so.cc
@@ -623,7 +623,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
         IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
         Value      *icmp = cur_lenchk_IRB.CreateICmpEQ(
-                 sizedValue, ConstantInt::get(sizedValue->getType(), i));
+            sizedValue, ConstantInt::get(sizedValue->getType(), i));
         cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
         cur_lenchk_bb->getTerminator()->eraseFromParent();
 
diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc
index 8a07610c..aec6758e 100644
--- a/instrumentation/split-compares-pass.so.cc
+++ b/instrumentation/split-compares-pass.so.cc
@@ -60,7 +60,7 @@ using namespace llvm;
 
 // uncomment this toggle function verification at each step. horribly slow, but
 // helps to pinpoint a potential problem in the splitting code.
-//#define VERIFY_TOO_MUCH 1
+// #define VERIFY_TOO_MUCH 1
 
 namespace {
 
diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c
index b6ee0019..b57e9701 100644
--- a/qemu_mode/libcompcov/libcompcov.so.c
+++ b/qemu_mode/libcompcov/libcompcov.so.c
@@ -68,7 +68,11 @@ static int debug_fd = -1;
 
 #define MAX_MAPPINGS 1024
 
-static struct mapping { void *st, *en; } __compcov_ro[MAX_MAPPINGS];
+static struct mapping {
+
+  void *st, *en;
+
+} __compcov_ro[MAX_MAPPINGS];
 
 static u32 __compcov_ro_cnt;
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 972ac8cd..84fe70ec 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -574,14 +574,15 @@ static void process_params(u32 argc, char **argv) {
 
       }
 
-      u8    *tmpbuf = malloc(st.st_size + 1), *ptr;
+      u8    *tmpbuf = malloc(st.st_size + 2), *ptr;
       char **args = malloc(sizeof(char *) * (st.st_size >> 1));
       int    count = 1, cont = 0, cont_act = 0;
 
-      while (fgets(tmpbuf, st.st_size, f)) {
+      while (fgets(tmpbuf, st.st_size + 1, f)) {
 
         ptr = tmpbuf;
-        // no leading whitespace
+        // fprintf(stderr, "1: %s\n", ptr);
+        //  no leading whitespace
         while (isspace(*ptr)) {
 
           ++ptr;
@@ -603,6 +604,8 @@ static void process_params(u32 argc, char **argv) {
 
         }
 
+        // fprintf(stderr, "2: %s\n", ptr);
+
         // remove whitespace at end
         while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
 
@@ -611,6 +614,7 @@ static void process_params(u32 argc, char **argv) {
 
         }
 
+        // fprintf(stderr, "3: %s\n", ptr);
         if (*ptr) {
 
           do {
@@ -933,10 +937,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-    //#if LLVM_MAJOR >= 13
-    //    // Use the old pass manager in LLVM 14 which the AFL++ passes still
-    //    use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
-    //#endif
+    // #if LLVM_MAJOR >= 13
+    //     // Use the old pass manager in LLVM 14 which the AFL++ passes still
+    //     use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
+    // #endif
 
     if (lto_mode && !have_c) {
 
@@ -1838,7 +1842,8 @@ int main(int argc, char **argv, char **envp) {
       }
 
       if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
-          strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
+          strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
+          strncasecmp(ptr2, "native", strlen("native")) == 0) {
 
         if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
           instrument_mode = INSTRUMENT_LLVMNATIVE;
diff --git a/src/afl-common.c b/src/afl-common.c
index a5c48e80..84ddefd8 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -949,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
 
 /* Get unix time in milliseconds */
 
-u64 get_cur_time(void) {
+inline u64 get_cur_time(void) {
 
   struct timeval  tv;
   struct timezone tz;
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index c6e9a295..5c71fc59 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -1912,6 +1912,7 @@ custom_mutator_stage:
 
   afl->stage_name = "custom mutator";
   afl->stage_short = "custom";
+  afl->stage_cur = 0;
   afl->stage_val_type = STAGE_VAL_NONE;
   bool has_custom_fuzz = false;
   u32  shift = unlikely(afl->custom_only) ? 7 : 8;
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 6e4a655b..d9dc50df 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -28,8 +28,8 @@
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
-//#define _DEBUG
-//#define CMPLOG_INTROSPECTION
+// #define _DEBUG
+// #define CMPLOG_INTROSPECTION
 
 // CMP attribute enum
 enum {
@@ -571,7 +571,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
 
 }
 
-//#ifdef CMPLOG_SOLVE_TRANSFORM
+// #ifdef CMPLOG_SOLVE_TRANSFORM
 static int strntoll(const char *str, size_t sz, char **end, int base,
                     long long *out) {
 
@@ -771,7 +771,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
 
 #endif
 
-//#endif
+// #endif
 
 static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
                               u64 pattern, u64 repl, u64 o_pattern,
@@ -803,8 +803,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
   //         o_pattern, pattern, repl, changed_val, idx, taint_len,
   //         hshape, attr);
 
-  //#ifdef CMPLOG_SOLVE_TRANSFORM
-  // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
+  // #ifdef CMPLOG_SOLVE_TRANSFORM
+  //  reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
   if (afl->cmplog_enable_transform && (lvl & LVL3)) {
 
     u8                *endptr;
@@ -1120,7 +1120,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  //#endif
+  // #endif
 
   // we only allow this for ascii2integer (above) so leave if this is the case
   if (unlikely(pattern == o_pattern)) { return 0; }
@@ -1275,7 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
   //       16 = modified float, 32 = modified integer (modified = wont match
   //                                                   in original buffer)
 
-  //#ifdef CMPLOG_SOLVE_ARITHMETIC
+  // #ifdef CMPLOG_SOLVE_ARITHMETIC
   if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
 
     return 0;
@@ -1440,8 +1440,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  //#endif                                           /*
-  // CMPLOG_SOLVE_ARITHMETIC
+  // #endif                                           /*
+  //  CMPLOG_SOLVE_ARITHMETIC
 
   return 0;
 
@@ -1948,9 +1948,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
 #ifndef CMPLOG_COMBINE
   (void)(cbuf);
 #endif
-  //#ifndef CMPLOG_SOLVE_TRANSFORM
-  //  (void)(changed_val);
-  //#endif
+  // #ifndef CMPLOG_SOLVE_TRANSFORM
+  //   (void)(changed_val);
+  // #endif
 
   if (afl->fsrv.total_execs - last_update > screen_update) {
 
@@ -2418,7 +2418,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
 
   }
 
-  //#endif
+  // #endif
 
   return 0;
 
@@ -2818,9 +2818,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
 
     } else if ((lvl & LVL1)
 
-               //#ifdef CMPLOG_SOLVE_TRANSFORM
+               // #ifdef CMPLOG_SOLVE_TRANSFORM
                || ((lvl & LVL3) && afl->cmplog_enable_transform)
-               //#endif
+               // #endif
     ) {
 
       if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 4339ddd2..4134b99e 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1746,16 +1746,6 @@ int main(int argc, char **argv_orig, char **envp) {
   check_if_tty(afl);
   if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
 
-  if (afl->afl_env.afl_custom_mutator_only) {
-
-    /* This ensures we don't proceed to havoc/splice */
-    afl->custom_only = 1;
-
-    /* Ensure we also skip all deterministic steps */
-    afl->skip_deterministic = 1;
-
-  }
-
   get_core_count(afl);
 
   atexit(at_exit);
@@ -1816,7 +1806,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  {
+  if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {
 
     u8 envbuf[8096] = "", tmpbuf[8096] = "";
     for (s32 i = optind + 1; i < argc; ++i) {
@@ -1847,10 +1837,41 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1);  // same as __AFL_OUT_DIR
+  if (!getenv("AFL_CUSTOM_INFO_OUT")) {
+
+    setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1);  // same as __AFL_OUT_DIR
+
+  }
 
   setup_custom_mutators(afl);
 
+  if (afl->afl_env.afl_custom_mutator_only) {
+
+    if (!afl->custom_mutators_count) {
+
+      if (afl->shm.cmplog_mode) {
+
+        WARNF(
+            "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
+            "pointless and only allowed now to allow experiments with CMPLOG.");
+
+      } else {
+
+        FATAL(
+            "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");
+
+      }
+
+    }
+
+    /* This ensures we don't proceed to havoc/splice */
+    afl->custom_only = 1;
+
+    /* Ensure we also skip all deterministic steps */
+    afl->skip_deterministic = 1;
+
+  }
+
   if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
 
     if (afl->custom_only) {
diff --git a/test-instr.c b/test-instr.c
index 1d9f2e6e..eda5189c 100644
--- a/test-instr.c
+++ b/test-instr.c
@@ -24,7 +24,7 @@
 
 int main(int argc, char **argv) {
 
-  int   fd = 0;
+  int   fd = 0, cnt;
   char  buff[8];
   char *buf = buff;
 
@@ -32,7 +32,6 @@ int main(int argc, char **argv) {
   if (argc == 2) {
 
     buf = argv[1];
-    printf("Input %s - ", buf);
 
   } else {
 
@@ -47,15 +46,19 @@ int main(int argc, char **argv) {
 
     }
 
-    if (read(fd, buf, sizeof(buf)) < 1) {
+    if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
 
       printf("Hum?\n");
       return 1;
 
     }
 
+    buf[cnt] = 0;
+
   }
 
+  if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf);
+
   // we support three input cases (plus a 4th if stdin is used but there is no
   // input)
   switch (buf[0]) {
diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c
index a18e314e..e1038212 100644
--- a/utils/afl_untracer/afl-untracer.c
+++ b/utils/afl_untracer/afl-untracer.c
@@ -288,7 +288,7 @@ library_list_t *find_library(char *name) {
 #pragma GCC optimize("O0")
 void        breakpoint(void) {
 
-         if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
+  if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
 
 }
 
diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c
index 299056ab..b21f3068 100644
--- a/utils/libtokencap/libtokencap.so.c
+++ b/utils/libtokencap/libtokencap.so.c
@@ -81,7 +81,11 @@ void *(*__libc_memmem)(const void *haystack, size_t haystack_len,
 
 #define MAX_MAPPINGS 1024
 
-static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS];
+static struct mapping {
+
+  void *st, *en;
+
+} __tokencap_ro[MAX_MAPPINGS];
 
 static u32   __tokencap_ro_cnt;
 static u8    __tokencap_ro_loaded;
diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c
index 3ec8383b..7497519e 100644
--- a/utils/socket_fuzzing/socketfuzz.c
+++ b/utils/socket_fuzzing/socketfuzz.c
@@ -23,7 +23,8 @@
 #include <errno.h>
 #include <stdio.h>
 #include <poll.h>
-//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: "
+// #include "logging.h" // switched from preeny_info() to fprintf(stderr, "Info:
+// "
 
 //
 // originals
diff --git a/utils/target_intelligence/README.md b/utils/target_intelligence/README.md
new file mode 100644
index 00000000..086c9e20
--- /dev/null
+++ b/utils/target_intelligence/README.md
@@ -0,0 +1,61 @@
+# Target Intelligence
+
+These are some ideas you can do so that your target that you are fuzzing can
+give helpful feedback to AFL++.
+
+## Add to the AFL++ dictionary from your target
+
+For this you target must be compiled for CMPLOG (`AFL_LLVM_CMPLOG=1`).
+
+Add in your source code:
+
+```
+__attribute__((weak)) void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len);
+__attribute__((weak)) void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr);
+
+int in_your_function(...) {
+
+  // to add two strings to the AFL++ dictionary:
+  if (__cmplog_rtn_hook_strn)
+    __cmplog_rtn_hook_strn(string1, length_of_string1, string2, length_of_string2);
+
+  // to add two 32 bit integers to the AFL++ dictionary:
+  if (__cmplog_ins_hook4)
+    __cmplog_ins_hook4(first_32_bit_var, second_32_bit_var, 0);
+
+}
+```
+
+Note that this only makes sense if these values are in-depth processed in the
+target in a way that AFL++ CMPLOG cannot uncover these, e.g. if these values
+are transformed by a matrix computation.
+
+Fixed values are always better to give to afl-fuzz via a `-x dictionary`.
+
+## Add inputs to AFL++ dictionary from your target
+
+If for whatever reason you want your target to propose new inputs to AFL++,
+then this is actually very easy.
+The environment variable `AFL_CUSTOM_INFO_OUT` contains the output directory
+of this run - including the fuzzer instance name (e.g. `default`), so if you
+run `afl-fuzz -o out -S foobar`, the value would be `out/foobar`).
+
+To show afl-fuzz an input it should consider just do the following:
+
+1. create the directory `$AFL_CUSTOM_INFO_OUT/../target/queue`
+2. create any new inputs you want afl-fuzz to notice in that directory with the
+   following naming convention: `id:NUMBER-OF-LENGTH-SIX-WITH-LEADING-ZEROES,whatever`
+   where that number has to be increasing.
+   e.g.:
+```
+   id:000000,first_file
+   id:000001,second_file
+   id:000002,third_file
+   etc.
+```
+
+Note that this will not work in nyx_mode because afl-fuzz cannot see inside the
+virtual machine.