about summary refs log tree commit diff
path: root/llvm_mode
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_mode')
-rw-r--r--llvm_mode/GNUmakefile115
-rw-r--r--llvm_mode/LLVMInsTrim.so.cc5
-rw-r--r--llvm_mode/README.md21
-rw-r--r--llvm_mode/README.neverzero.md10
-rw-r--r--llvm_mode/afl-clang-fast.c198
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc14
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc25
-rw-r--r--llvm_mode/afl-llvm-rt.o.c2
8 files changed, 256 insertions, 134 deletions
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 69b0875e..93886e47 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -38,7 +38,7 @@ else
   LLVM_CONFIG ?= llvm-config
 endif
 
-LLVMVER  = $(shell $(LLVM_CONFIG) --version 2>/dev/null )
+LLVMVER  = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
 LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-7]|^1[2-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_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
@@ -82,30 +82,79 @@ endif
 # this seems to be busted on some distros, so using the one in $PATH is
 # probably better.
 
-CC         ?= $(LLVM_BINDIR)/clang
-CXX        ?= $(LLVM_BINDIR)/clang++
+CC         = $(LLVM_BINDIR)/clang
+CXX        = $(LLVM_BINDIR)/clang++
 
+# llvm-config --bindir may not providing a valid path, so ...
 ifeq "$(shell test -e $(CC) || echo 1 )" "1"
-  # llvm-config --bindir may not providing a valid path, so ...
-  ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
-    # we found one in the local install directory, lets use these
-    CC         = $(BIN_DIR)/clang
-    CXX        = $(BIN_DIR)/clang++
-  else
-    # hope for the best
-    $(warning we have trouble finding clang/clang++ - llvm-config is not helping us)
-    CC         = clang
-    CXX        = clang++
+  # however we must ensure that this is not a "CC=gcc make"
+  ifeq "$(shell command -v $(CC) 2> /dev/null)" ""
+    # we do not have a valid CC variable so we try alternatives
+    ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
+      # we found one in the local install directory, lets use these
+      CC         = $(BIN_DIR)/clang
+    else
+      # hope for the best
+      $(warning we have trouble finding clang - llvm-config is not helping us)
+      CC         = clang
+    endif
+  endif
+endif
+# llvm-config --bindir may not providing a valid path, so ...
+ifeq "$(shell test -e $(CXX) || echo 1 )" "1"
+  # however we must ensure that this is not a "CC=gcc make"
+  ifeq "$(shell command -v $(CXX) 2> /dev/null)" ""
+    # we do not have a valid CC variable so we try alternatives
+    ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1"
+      # we found one in the local install directory, lets use these
+      CXX        = $(BIN_DIR)/clang++
+    else
+      # hope for the best
+      $(warning we have trouble finding clang++ - llvm-config is not helping us)
+      CXX        = clang++
+    endif
   endif
 endif
 
 # sanity check.
 # Are versions of clang --version and llvm-config --version equal?
-CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
+CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
 
-ifneq "$(CLANGVER)" "$(LLVMVER)"
-  CC = $(shell $(LLVM_CONFIG) --bindir)/clang
-  CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
+# I disable this because it does not make sense with what we did before (marc)
+# We did exactly set these 26 lines above with these values, and it would break
+# "CC=gcc make" etc. usages
+ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+  CC_SAVE := $(LLVM_BINDIR)/clang
+else
+  CC_SAVE := $(CC)
+endif
+ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" ""
+  CXX_SAVE := $(LLVM_BINDIR)/clang++
+else
+  CXX_SAVE := $(CXX)
+endif
+
+CLANG_BIN := $(CC_SAVE)
+CLANGPP_BIN := $(CXX_SAVE)
+
+ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang"
+  USE_BINDIR = 1
+else
+  ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++"
+    USE_BINDIR = 1
+  else
+    USE_BINDIR = 0
+  endif
+endif
+
+# On old platform we cannot compile with clang because std++ libraries are too
+# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX
+# variable we override the compiler variables here
+ifneq "$(REAL_CC)" ""
+CC         = $(REAL_CC)
+endif
+ifneq "$(REAL_CXX)" ""
+CXX        = $(REAL_CXX)
 endif
 
 # After we set CC/CXX we can start makefile magic tests
@@ -114,13 +163,13 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .te
 	CFLAGS_OPT = -march=native
 endif
 
-ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
         AFL_CLANG_FLTO ?= -flto=full
 else
- ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
         AFL_CLANG_FLTO ?= -flto=thin
  else
-  ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+  ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
         AFL_CLANG_FLTO ?= -flto
   endif
  endif
@@ -141,24 +190,11 @@ endif
 
 AFL_CLANG_FUSELD=
 ifneq "$(AFL_CLANG_FLTO)" ""
-ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
   AFL_CLANG_FUSELD=1
 endif
 endif
 
-CLANG_BIN = $(basename $(CC))
-CLANGPP_BIN = $(basename $(CXX))
-ifeq "$(shell test -e $(CLANG_BIN) || echo 1 )" "1"
-  CLANG_BIN = $(CC)
-  CLANGPP_BIN = $(CXX)
-endif
-
-ifeq "$(CC)" "$(LLVM_BINDIR)/clang"
-  USE_BINDIR = 1
-else
-  USE_BINDIR = 0
-endif
-
 CFLAGS          ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
 override CFLAGS += -Wall \
                -g -Wno-pointer-sign -I ../include/ \
@@ -166,7 +202,7 @@ override CFLAGS += -Wall \
                -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
                -DLLVM_VERSION=\"$(LLVMVER)\"  -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
                -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-               -DCLANG_BIN=\"$(CC)\" -DCLANGPP_BIN=\"$(CXX)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
+               -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
 ifdef AFL_TRACE_PC
   $(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
 endif
@@ -249,7 +285,6 @@ test_deps:
 	@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
 ifneq "$(CLANGVER)" "$(LLVMVER)"
 	@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
-	@echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang"
 else
 	@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
 endif
@@ -290,9 +325,9 @@ endif
 ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
 ifeq "$(LLVM_LTO)" "1"
 	$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
-	$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
-	@$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
-	@$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
+	$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
+	@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
+	@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
 endif
 
 # laf
@@ -323,7 +358,7 @@ endif
 
 test_build: $(PROGS)
 	@echo "[*] Testing the CC wrapper and instrumentation output..."
-	unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
+	unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
 	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
diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc
index 98263ef1..c78250eb 100644
--- a/llvm_mode/LLVMInsTrim.so.cc
+++ b/llvm_mode/LLVMInsTrim.so.cc
@@ -56,6 +56,7 @@ struct InsTrim : public ModulePass {
  protected:
   uint32_t function_minimum_size = 1;
   uint32_t debug = 0;
+  char *   skip_nozero = NULL;
 
  private:
   std::mt19937 generator;
@@ -112,6 +113,7 @@ struct InsTrim : public ModulePass {
     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) {
@@ -304,8 +306,7 @@ struct InsTrim : public ModulePass {
             NULL)  // with llvm 9 we make this the default as the bug in llvm is
                    // then fixed
 #else
-        if (1)  // with llvm 9 we make this the default as the bug in llvm is
-                // then fixed
+        if (!skip_nozero)
 #endif
         {
 
diff --git a/llvm_mode/README.md b/llvm_mode/README.md
index 607350fb..0bff1ff1 100644
--- a/llvm_mode/README.md
+++ b/llvm_mode/README.md
@@ -37,7 +37,26 @@ co-exists with the original code.
 
 The idea and much of the implementation comes from Laszlo Szekeres.
 
-## 2) How to use this
+## 2a) How to use this - short
+
+Set the `LLVM_CONFIG` variable to the clang version you want to use, e.g.
+```
+LLVM_CONFIG=llvm-config-9 make
+```
+In case you have your own compiled llvm version specify the full path:
+```
+LLVM_CONFIG=~/llvm-project/build/bin/llvm-config make
+```
+If you try to use a new llvm version on an old Linux this can fail because of
+old c++ libraries. In this case usually switching to gcc/g++ to compile
+llvm_mode will work:
+```
+LLVM_CONFIG=llvm-config-7 REAL_CC=gcc REAL_CXX=g++ make
+```
+It is highly recommended to use the newest clang version you can put your
+hands on :)
+
+## 2b) How to use this - long
 
 In order to leverage this mechanism, you need to have clang installed on your
 system. You should also make sure that the llvm-config tool is in your path
diff --git a/llvm_mode/README.neverzero.md b/llvm_mode/README.neverzero.md
index 1e406560..903e5bd3 100644
--- a/llvm_mode/README.neverzero.md
+++ b/llvm_mode/README.neverzero.md
@@ -20,8 +20,16 @@ This is implemented in afl-gcc, 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.
 
-If you want to enable this for llvm < 9 then set
+If you want to enable this for llvm versions below 9 then set
 
 ```
 export AFL_LLVM_NOT_ZERO=1
 ```
+
+In case you are on llvm 9 or greater and you do not want this behaviour then
+you can set:
+```
+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.
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 3de5fd7d..9f85e5c6 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -43,7 +43,7 @@ static u8 * obj_path;                  /* Path to runtime libraries         */
 static u8 **cc_params;                 /* Parameters passed to the real CC  */
 static u32  cc_par_cnt = 1;            /* Param count, including argv0      */
 static u8   llvm_fullpath[PATH_MAX];
-static u8   instrument_mode;
+static u8   instrument_mode, instrument_opt_mode, ngram_size;
 static u8 * lto_flag = AFL_CLANG_FLTO;
 static u8 * march_opt = CFLAGS_OPT;
 static u8   debug;
@@ -60,14 +60,15 @@ enum {
   INSTRUMENT_INSTRIM = 2,
   INSTRUMENT_CFG = 2,
   INSTRUMENT_LTO = 3,
-  INSTRUMENT_CTX = 4,
-  INSTRUMENT_NGRAM = 5  // + ngram value of 2-16 = 7 - 21
+  INSTRUMENT_OPT_CTX = 4,
+  INSTRUMENT_OPT_NGRAM = 8
 
 };
 
-char instrument_mode_string[6][16] = {
+char instrument_mode_string[10][16] = {
 
-    "DEFAULT", "PCGUARD", "CFG", "LTO", "CTX",
+    "CLASSIC", "PCGUARD", "CFG",   "LTO", "CTX", "",
+    "",        "",        "NGRAM", ""
 
 };
 
@@ -562,54 +563,6 @@ int main(int argc, char **argv, char **envp) {
   instrument_mode = INSTRUMENT_PCGUARD;
 #endif
 
-  if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) {
-
-    if (strncasecmp(ptr, "default", strlen("default")) == 0 ||
-        strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
-        strncasecmp(ptr, "classic", strlen("classic")) == 0)
-      instrument_mode = INSTRUMENT_DEFAULT;
-    if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
-        strncasecmp(ptr, "instrim", strlen("instrim")) == 0)
-      instrument_mode = INSTRUMENT_CFG;
-    else if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
-             strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0)
-      instrument_mode = INSTRUMENT_PCGUARD;
-    else if (strncasecmp(ptr, "lto", strlen("lto")) == 0)
-      instrument_mode = INSTRUMENT_LTO;
-    else if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) {
-
-      instrument_mode = INSTRUMENT_CTX;
-      setenv("AFL_LLVM_CTX", "1", 1);
-
-    } else if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) {
-
-      ptr += strlen("ngram");
-      while (*ptr && (*ptr < '0' || *ptr > '9'))
-        ptr++;
-      if (!*ptr)
-        if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL)
-          FATAL(
-              "you must set the NGRAM size with (e.g. for value 2) "
-              "AFL_LLVM_INSTRUMENT=ngram-2");
-      instrument_mode = INSTRUMENT_NGRAM + atoi(ptr);
-      if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
-          instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
-        FATAL(
-            "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
-            "(%u)",
-            NGRAM_SIZE_MAX);
-
-      ptr = alloc_printf("%u", instrument_mode - INSTRUMENT_NGRAM);
-      setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1);
-
-    } else if (strncasecmp(ptr, "classic", strlen("classic")) != 0 ||
-
-               strncasecmp(ptr, "default", strlen("default")) != 0 ||
-               strncasecmp(ptr, "afl", strlen("afl")) != 0)
-      FATAL("unknown AFL_LLVM_INSTRUMENT value: %s", ptr);
-
-  }
-
   if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
       getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
 
@@ -631,39 +584,116 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
-  if (getenv("AFL_LLVM_CTX")) {
+  if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
 
-    if (instrument_mode == 0)
-      instrument_mode = INSTRUMENT_CTX;
-    else if (instrument_mode != INSTRUMENT_CTX)
-      FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_CTX together");
+  if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+
+    instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
+    ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
+    if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
+      FATAL(
+          "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
+          "(%u)",
+          NGRAM_SIZE_MAX);
 
   }
 
-  if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+  if (getenv("AFL_LLVM_INSTRUMENT")) {
 
-    if (instrument_mode == 0) {
+    u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
 
-      instrument_mode = INSTRUMENT_NGRAM + atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
-      if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
-          instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
-        FATAL(
-            "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
-            "(%u)",
-            NGRAM_SIZE_MAX);
+    while (ptr) {
 
-    } else if (instrument_mode != INSTRUMENT_NGRAM)
+      if (strncasecmp(ptr, "default", strlen("default")) == 0 ||
+          strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
+          strncasecmp(ptr, "classic", strlen("classic")) == 0) {
 
-      FATAL(
-          "you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_NGRAM_SIZE "
-          "together");
+        if (!instrument_mode || instrument_mode == INSTRUMENT_DEFAULT)
+          instrument_mode = INSTRUMENT_DEFAULT;
+        else
+          FATAL("main instrumentation mode already set with %s",
+                instrument_mode_string[instrument_mode]);
+
+      }
+
+      if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
+          strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) {
+
+        if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
+          instrument_mode = INSTRUMENT_PCGUARD;
+        else
+          FATAL("main instrumentation mode already set with %s",
+                instrument_mode_string[instrument_mode]);
+
+      }
+
+      if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
+          strncasecmp(ptr, "instrim", strlen("instrim")) == 0) {
+
+        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]);
+
+      }
+
+      if (strncasecmp(ptr, "lto", strlen("lto")) == 0) {
+
+        if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
+          instrument_mode = INSTRUMENT_LTO;
+        else
+          FATAL("main instrumentation mode already set with %s",
+                instrument_mode_string[instrument_mode]);
+
+      }
+
+      if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) {
+
+        instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+        setenv("AFL_LLVM_CTX", "1", 1);
+
+      }
+
+      if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) {
+
+        ptr += strlen("ngram");
+        while (*ptr && (*ptr < '0' || *ptr > '9'))
+          ptr++;
+        if (!*ptr)
+          if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL)
+            FATAL(
+                "you must set the NGRAM size with (e.g. for value 2) "
+                "AFL_LLVM_INSTRUMENT=ngram-2");
+        ngram_size = atoi(ptr);
+        if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
+          FATAL(
+              "NGRAM instrumentation option must be between 2 and "
+              "NGRAM_SIZE_MAX "
+              "(%u)",
+              NGRAM_SIZE_MAX);
+        instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
+        ptr = alloc_printf("%u", ngram_size);
+        setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1);
+
+      }
+
+      ptr = strtok(NULL, ":,;");
+
+    }
 
   }
 
-  if (instrument_mode < INSTRUMENT_NGRAM)
+  if (!instrument_opt_mode)
     ptr = instrument_mode_string[instrument_mode];
+  else if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
+    ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]);
+  else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM)
+    ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode],
+                       ngram_size);
   else
-    ptr = alloc_printf("NGRAM-%u", instrument_mode - INSTRUMENT_NGRAM);
+    ptr = alloc_printf("%s + CTX + NGRAM-%u",
+                       instrument_mode_string[instrument_mode], ngram_size);
 
   if (strstr(argv[0], "afl-clang-lto") != NULL) {
 
@@ -685,9 +715,28 @@ int main(int argc, char **argv, char **envp) {
 
 #ifndef AFL_CLANG_FLTO
   if (instrument_mode == INSTRUMENT_LTO)
-    FATAL("instrumentation mode LTO specified but LLVM support not available");
+    FATAL(
+        "instrumentation mode LTO specified but LLVM support not available "
+        "(requires LLVM 11)");
 #endif
 
+  if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
+    /*&& instrument_mode != INSTRUMENT_CFG*/
+    FATAL(
+        "CTX and NGRAM instrumentation options can only be used with the "
+        "CLASSIC instrumentation mode!");
+
+  if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
+    FATAL(
+        "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
+        "together");
+
+  if (instrument_mode == INSTRUMENT_CFG &&
+      getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") == NULL && ngram_size)
+    FATAL(
+        "NGRAM option together with CFG/INSTRIM instrumentation mode can only "
+        "be used if AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK is set");
+
   if (argc < 2 || strcmp(argv[1], "-h") == 0) {
 
     if (instrument_mode != INSTRUMENT_LTO)
@@ -726,6 +775,7 @@ int main(int argc, char **argv, char **envp) {
         "AFL_HARDEN: adds code hardening to catch memory bugs\n"
         "AFL_INST_RATIO: percentage of branches to instrument\n"
         "AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
+        "AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
         "AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
         "AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to "
         "cascaded "
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index 118ada52..2811d98e 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -78,6 +78,8 @@ class AFLLTOPass : public ModulePass {
         FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
               ptr, MAP_SIZE - 1);
 
+    skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
+
   }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -111,6 +113,7 @@ class AFLLTOPass : public ModulePass {
   int      afl_global_id = 1, debug = 0, autodictionary = 0;
   uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
   uint64_t map_addr = 0x10000;
+  char *   skip_nozero = NULL;
 
 };
 
@@ -614,9 +617,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
           Value *Incr = IRB.CreateAdd(Counter, One);
 
-          auto cf = IRB.CreateICmpEQ(Incr, Zero);
-          auto carry = IRB.CreateZExt(cf, Int8Ty);
-          Incr = IRB.CreateAdd(Incr, carry);
+          if (skip_nozero) {
+
+            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));
 
diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc
index 9314c3d1..42a2f3af 100644
--- a/llvm_mode/afl-llvm-pass.so.cc
+++ b/llvm_mode/afl-llvm-pass.so.cc
@@ -84,7 +84,7 @@ class AFLCoverage : public ModulePass {
   uint32_t ngram_size = 0;
   uint32_t debug = 0;
   uint32_t map_size = MAP_SIZE;
-  char *   ctx_str = NULL;
+  char *   ctx_str = NULL, *skip_nozero = NULL;
 
 };
 
@@ -180,8 +180,9 @@ bool AFLCoverage::runOnModule(Module &M) {
 #if LLVM_VERSION_MAJOR < 9
   char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
 #endif
+  skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
 
-  unsigned PrevLocSize;
+  unsigned PrevLocSize = 0;
 
   char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
   if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
@@ -215,9 +216,6 @@ bool AFLCoverage::runOnModule(Module &M) {
   if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
 #endif
 
-  if (ctx_str && ngram_size_str)
-    FATAL("you must decide between NGRAM and CTX instrumentation");
-
   /* Get globals for the SHM region and the previous location. Note that
      __afl_prev_loc is thread-local. */
 
@@ -436,8 +434,10 @@ bool AFLCoverage::runOnModule(Module &M) {
         PrevLocTrans = IRB.CreateXorReduce(PrevLoc);
       else
 #endif
-          if (ctx_str)
-        PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLoc, PrevCtx), Int32Ty);
+        PrevLocTrans = PrevLoc;
+      if (ctx_str)
+        PrevLocTrans =
+            IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
       else
         PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
 
@@ -451,7 +451,9 @@ bool AFLCoverage::runOnModule(Module &M) {
       if (ngram_size)
         MapPtrIdx = IRB.CreateGEP(
             MapPtr,
-            IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, CurLoc), Int32Ty));
+            IRB.CreateZExt(
+                IRB.CreateXor(PrevLocTrans, IRB.CreateZExt(CurLoc, Int32Ty)),
+                Int32Ty));
       else
 #endif
         MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
@@ -467,6 +469,9 @@ bool AFLCoverage::runOnModule(Module &M) {
       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
@@ -482,12 +487,8 @@ bool AFLCoverage::runOnModule(Module &M) {
         auto carry = IRB.CreateZExt(cf, Int8Ty);
         Incr = IRB.CreateAdd(Incr, carry);
 
-#if LLVM_VERSION_MAJOR < 9
-
       }
 
-#endif
-
       IRB.CreateStore(Incr, MapPtrIdx)
           ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
 
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 8867ae36..722ca421 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -152,7 +152,7 @@ static void __afl_map_shm(void) {
 
   if (getenv("AFL_DEBUG"))
     fprintf(stderr,
-            "DEBUG: id_str %s, __afl_map_addr 0x%x, MAP_SIZE %u, "
+            "DEBUG: id_str %s, __afl_map_addr 0x%lx, MAP_SIZE %u, "
             "__afl_final_loc %u, max_size_forkserver %u/0x%x\n",
             id_str == NULL ? "<null>" : id_str, __afl_map_addr, MAP_SIZE,
             __afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);