about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile11
-rw-r--r--README.md27
-rw-r--r--TODO.md1
-rw-r--r--docs/Changelog.md12
-rw-r--r--docs/FAQ.md113
-rw-r--r--examples/aflpp_driver/GNUmakefile2
-rw-r--r--examples/aflpp_driver/aflpp_driver.c26
-rw-r--r--examples/aflpp_driver/aflpp_driver_test.c16
-rw-r--r--include/afl-fuzz.h17
-rw-r--r--include/alloc-inl.h114
-rw-r--r--include/config.h10
-rw-r--r--include/forkserver.h4
-rw-r--r--llvm_mode/GNUmakefile9
-rw-r--r--llvm_mode/LLVMInsTrim.so.cc8
-rw-r--r--llvm_mode/README.instrument_list.md18
-rw-r--r--llvm_mode/afl-clang-fast.c122
-rw-r--r--llvm_mode/afl-ld-lto.c2
-rw-r--r--llvm_mode/afl-llvm-common.cc357
-rw-r--r--llvm_mode/afl-llvm-common.h1
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc174
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc9
-rw-r--r--llvm_mode/afl-llvm-rt.o.c151
-rw-r--r--llvm_mode/cmplog-instructions-pass.cc6
-rw-r--r--llvm_mode/cmplog-routines-pass.cc6
-rw-r--r--llvm_mode/compare-transform-pass.so.cc10
-rw-r--r--llvm_mode/split-compares-pass.so.cc6
-rw-r--r--llvm_mode/split-switches-pass.so.cc6
-rw-r--r--src/afl-forkserver.c39
-rw-r--r--src/afl-fuzz-bitmap.c9
-rw-r--r--src/afl-fuzz-extras.c58
-rw-r--r--src/afl-fuzz-one.c35
-rw-r--r--src/afl-fuzz-redqueen.c15
-rw-r--r--src/afl-fuzz-run.c10
-rw-r--r--src/afl-fuzz-state.c5
-rw-r--r--src/afl-showmap.c104
-rwxr-xr-xtest/test-basic.sh6
-rwxr-xr-xtest/test-post.sh2
-rwxr-xr-xtest/test-pre.sh1
38 files changed, 864 insertions, 658 deletions
diff --git a/GNUmakefile b/GNUmakefile
index fe5f8c03..3c5e10ed 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -97,7 +97,13 @@ ifneq "$(shell uname -m)" "x86_64"
  endif
 endif
 
-CFLAGS     ?= -O3 -funroll-loops $(CFLAGS_OPT)
+ifdef DEBUG
+  $(info Compiling DEBUG version of binaries)
+  CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror
+else
+  CFLAGS     ?= -O3 -funroll-loops $(CFLAGS_OPT)
+endif
+
 override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
 			  -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
 			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
@@ -305,6 +311,7 @@ help:
 	@echo "=========================================="
 	@echo STATIC - compile AFL++ static
 	@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
+	@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
 	@echo PROFILING - compile afl-fuzz with profiling information
 	@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
 	@echo "=========================================="
@@ -590,6 +597,8 @@ install: all $(MANPAGES)
 	if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
 	if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
 	if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
+	if [ -f libAFLDriver.a ]; then install -m 644 libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
+	if [ -f libAFLQemuDriver.a ]; then install -m 644 libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
 
 	set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
 	set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
diff --git a/README.md b/README.md
index 18983832..97c0a0d7 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,7 @@ These build options exist:
 
 * STATIC - compile AFL++ static
 * ASAN_BUILD - compiles with memory sanitizer for debug purposes
+* DEBUG - no optimization, -ggdb3, all warnings and -Werror
 * PROFILING - compile with profiling information (gprof)
 * NO_PYTHON - disable python support
 * AFL_NO_X86 - if compiling on non-intel/amd platforms
@@ -509,8 +510,8 @@ fuzz your target.
 
 On the same machine - due to the design of how afl++ works - there is a maximum
 number of CPU cores/threads that are useful, use more and the overall performance
-degrades instead. This value depends on the target and the limit is between 48
-and 96 cores/threads per machine.
+degrades instead. This value depends on the target, and the limit is between 32
+and 64 cores/threads per machine.
 
 There should be one main fuzzer (`-M main` option) and as many secondary
 fuzzers (eg `-S variant1`) as you have cores that you use.
@@ -562,11 +563,18 @@ To have only the summary use the `-s` switch e.g.: `afl-whatsup -s output/`
 The `paths found` value is a bad indicator how good the coverage is.
 
 A better indicator - if you use default llvm instrumentation with at least
-version 9 - to use `afl-showmap` on the target with all inputs of the
-queue/ directory one after another and collecting the found edge IDs (`-o N.out`),
-removing the counters of the edge IDs, making them unique - and there you have
-the total number of found instrumented edges.
-
+version 9 - is to use `afl-showmap` with the collect coverage option `-C` on
+the output directory:
+```
+$ afl-showmap -C -i out -o /dev/null -- ./target -params @@
+...
+[*] Using SHARED MEMORY FUZZING feature.
+[*] Target map size: 9960
+[+] Processed 7849 input files.
+[+] Captured 4331 tuples (highest value 255, total values 67130596) in '/dev/nul
+l'.
+[+] A coverage of 4331 edges were achieved out of 9960 existing (43.48%) with 7849 input files.
+```
 It is even better to check out the exact lines of code that have been reached -
 and which have not been found so far.
 
@@ -580,6 +588,11 @@ then terminate it. The main node will pick it up and make it available to the
 other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
 free core.
 
+Note that you in nearly all cases you can never reach full coverage. A lot of
+functionality is usually behind options that were not activated or fuzz e.g.
+if you fuzz a library to convert image formats and your target is the png to
+tiff API then you will not touch any of the other library APIs and features.
+
 #### e) How long to fuzz a target?
 
 This is a difficult question.
diff --git a/TODO.md b/TODO.md
index e81b82a3..e74fa1d5 100644
--- a/TODO.md
+++ b/TODO.md
@@ -4,6 +4,7 @@
 
  - AFL_MAP_SIZE for qemu_mode and unicorn_mode
  - CPU affinity for many cores? There seems to be an issue > 96 cores
+ - afl-plot to support multiple plot_data
 
 ## Further down the road
 
diff --git a/docs/Changelog.md b/docs/Changelog.md
index edcdac58..55b0c7dd 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -12,6 +12,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
 ### Version ++2.66d (devel)
   - Support for improved afl++ snapshot module:
     https://github.com/AFLplusplus/AFL-Snapshot-LKM
+  - Due to the instrumentation needing more memory, the initial memory sizes
+    for -m have been increased
   - afl-fuzz:
      - added -F option to allow -M main fuzzers to sync to foreign fuzzers,
        e.g. honggfuzz or libfuzzer
@@ -19,7 +21,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
      - eliminated CPU affinity race condition for -S/-M runs
      - expanded havoc mode added, on no cycle finds add extra splicing and
        MOpt into the mix
-     - fixed a bug in redqueen for strings
+     - fixed a bug in redqueen for strings and made deterministic with -s
   - llvm_mode:
      - now supports llvm 12!
      - support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous
@@ -29,9 +31,15 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
      - added neverzero counting to trace-pc/pcgard
      - fixes for laf-intel float splitting (thanks to mark-griffin for
        reporting)
+     - fixes for llvm 4.0
+     - skipping ctors and ifuncs for instrumentation
      - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR
             for a fixed map address (eg. 0x10000)
-     - LTO: skipping ctors and ifuncs in fix map address instrumentation
+     - LTO: improved stability for persistent mode, no other instrumentation
+            has that advantage
+     - LTO: fixed autodict for long strings
+     - LTO: laf-intel and redqueen/cmplog are now applied at link time
+            to prevent llvm optimizing away the splits
      - LTO: autodictionary mode is a default
      - LTO: instrim instrumentation disabled, only classic support used
             as it is always better
diff --git a/docs/FAQ.md b/docs/FAQ.md
index e690635a..93a87a72 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -2,14 +2,39 @@
 
 ## Contents
 
-  1. [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
-  2. [What is an edge?](#what-is-an-edge)
-  3. [Why is my stability below 100%?](#why-is-my-stability-below-100)
-  4. [How can I improve the stability value](#how-can-i-improve-the-stability-value)
+  * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl)
+  * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
+  * [How do I fuzz a network service?](#how-to-fuzz-a-network-service)
+  * [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program)
+  * [What is an edge?](#what-is-an-edge)
+  * [Why is my stability below 100%?](#why-is-my-stability-below-100)
+  * [How can I improve the stability value](#how-can-i-improve-the-stability-value)
 
 If you find an interesting or important question missing, submit it via
 [https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues)
 
+## What is the difference between afl and afl++?
+
+American Fuzzy Lop (AFL) was developed by MichaƂ "lcamtuf" Zalewski starting in
+2013/2014, and when he left Google end of 2017 he stopped developing it.
+
+At the end of 2019 the Google fuzzing team took over maintance of AFL, however
+it is only accepting PR from the community and is not developing enhancements
+anymore.
+
+In the second quarter of 2019, 1 1/2 years after no further development of
+AFL had happened and it became clear there would be none coming, afl++
+was born, where initially first community patches were collected and applied
+for bugs and enhancements. Then from various AFL spin-offs - mostly academic
+research - features were integrated. This already resulted in a much advanced
+AFL.
+
+Until the end of 2019 the afl++ team had grown to four active developers which
+then implemented their own research and feature, making it now by far the most
+flexible and feature rich guided fuzzer available as open source.
+And in independent fuzzing benchmarks it is one of the best fuzzers available,
+e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html)
+
 ## How to improve the fuzzing speed
 
   1. use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
@@ -20,6 +45,43 @@ If you find an interesting or important question missing, submit it via
   6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem
   7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads)
 
+## How do I fuzz a network service?
+
+The short answer is - you cannot, at least "out of the box".
+
+Using network has a slow-down of x10-20 on the fuzzing speed, does not scale,
+and finally usually it is more than one initial data packet but a back-and-forth
+which is totally unsupported by most coverage aware fuzzers.
+
+The established method to fuzz network services is to modify the source code
+to read from a file or stdin (fd 0) (or even faster via shared memory, combine
+this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md)
+and you have a performance gain of x10 instead of a performance loss of over
+x10 - that is a x100 difference!
+
+If modifying the source is not an option (e.g. because you only have a binary
+and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD
+to emulate the network. This is also much faster than network would be.
+See [examples/socket_fuzzing/](../examples/socket_fuzzing/)
+
+There is an outdated afl++ branch that implements networking if you are
+desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - 
+however a better option is AFLnet ([https://github.com/aflnet/aflnet](https://github.com/aflnet/aflnet))
+which allows you to define network state with different type of data packets.
+
+## How do I fuzz a GUI program?
+
+If the GUI program can read the fuzz data from a file (via the command line,
+a fixed location or via an environment variable) without needing any user
+interaction then then yes.
+
+Otherwise it is not possible without modifying the source code - which is a
+very good idea anyway as the GUI functionality is a huge CPU/time overhead
+for the fuzzing.
+
+So create a new `main()` that just reads the test case and calls the
+functionality for processing the input that the GUI program is using.
+
 ## What is an "edge"
 
 A program contains `functions`, `functions` contain the compiled machine code.
@@ -62,15 +124,15 @@ code example above):
 ```
 Every line between two blocks is an `edge`.
 
-## Why is my stability below 100
+## Why is my stability below 100%
 
 Stability is measured by how many percent of the edges in the target are
 "stable". Sending the same input again and again should take the exact same
 path through the target every time. If that is the case, the stability is 100%.
 
-If however randomness happens, e.g. a thread reading from shared memory,
+If however randomness happens, e.g. a thread reading other external data,
 reaction to timing, etc. then in some of the re-executions with the same data
-will result in the edge information being different accross runs.
+the result in the edge information will be different accross runs.
 Those edges that change are then flagged "unstable".
 
 The more "unstable" edges, the more difficult for afl++ to identify valid new
@@ -83,9 +145,25 @@ improve the stability.
 
 ## How can I improve the stability value
 
+For fuzzing a 100% stable target that covers all edges is the best.
+A 90% stable target that covers all edges is however better than a 100% stable
+target that ignores 10% of the edges.
+
+With instability you basically have a partial coverage loss on an edge, with
+ignore you have a full loss on that edge.
+
+There are functions that are unstable, but also provide value to coverage, eg
+init functions that use fuzz data as input for example.
+If however it is a function that has nothing to do with the input data is the
+source, e.g. checking jitter, or is a hash map function etc. then it should
+not be instrumented.
+
+To be able to make this decision the following process will allow you to
+identify the functions with variable edges so you can make this decision.
+
 Four steps are required to do this and requires quite some knowledge of
 coding and/or disassembly and it is only effectively possible with
-afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
+afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
 
   1. First step: Identify which edge ID numbers are unstable
 
@@ -96,9 +174,9 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
   2. Second step: Find the responsible function.
 
      a) For LTO instrumented binaries this can be documented during compile
-        time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/afile`.
-        This file will have one assigned edge ID and the corresponding function
-        per line.
+        time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`.
+        This file will have one assigned edge ID and the corresponding
+        function per line.
 
      b) For PCGUARD instrumented binaries it is much more difficult. Here you
         can either modify the __sanitizer_cov_trace_pc_guard function in
@@ -112,6 +190,10 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
         on start, check to which memory address the edge ID value is written
         and set a write breakpoint to that address (`watch 0x.....`).
 
+     c) in all other instrumentation types this is not possible. So just
+        recompile with the the two mentioned above. This is just for
+        identifying the functions that have unstable edges.
+
   3. Third step: create a text file with the filenames/functions
 
      Identify which source code files contain the functions that you need to
@@ -122,6 +204,15 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
      If PCGUARD is used, then you need to follow this guide (needs llvm 12+!):
      [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
 
+     Only deny those functions from instrumentation that provide no value
+     for coverage - that is if it does not process any fuzz data directly
+     or indirectly (e.g. hash maps, thread management etc.).
+     If however a function directly or indirectly handles fuzz data then you
+     should not put the function in a deny instrumentation list and rather
+     live with the instability it comes with.
+
   4. Fourth step: recompile the target
 
      Recompile, fuzz it, be happy :)
+
+     This link explains this process for [Fuzzbench](https://github.com/google/fuzzbench/issues/677)
diff --git a/examples/aflpp_driver/GNUmakefile b/examples/aflpp_driver/GNUmakefile
index b118a8b5..57e74be7 100644
--- a/examples/aflpp_driver/GNUmakefile
+++ b/examples/aflpp_driver/GNUmakefile
@@ -16,6 +16,7 @@ aflpp_driver.o:	aflpp_driver.c
 
 libAFLDriver.a:	aflpp_driver.o
 	ar ru libAFLDriver.a aflpp_driver.o
+	cp -vf libAFLDriver.a ../../
 
 debug:
 	$(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
@@ -29,6 +30,7 @@ aflpp_qemu_driver.o:	aflpp_qemu_driver.c
 
 libAFLQemuDriver.a:	aflpp_qemu_driver.o
 	ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
+	cp -vf libAFLQemuDriver.a ../../
 
 aflpp_qemu_driver_hook.so:	aflpp_qemu_driver_hook.o
 	$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so
diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c
index 7d388799..ff5446e9 100644
--- a/examples/aflpp_driver/aflpp_driver.c
+++ b/examples/aflpp_driver/aflpp_driver.c
@@ -109,8 +109,6 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both.
 int                   __afl_sharedmem_fuzzing = 1;
 extern unsigned int * __afl_fuzz_len;
 extern unsigned char *__afl_fuzz_ptr;
-extern unsigned char *__afl_area_ptr;
-// extern struct cmp_map *__afl_cmp_map;
 
 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
@@ -248,28 +246,8 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
 
 }
 
-__attribute__((constructor(1))) void __afl_protect(void) {
-
-  setenv("__AFL_DEFER_FORKSRV", "1", 1);
-  __afl_area_ptr = (unsigned char *)mmap(
-      (void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE,
-      MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-  if ((uint64_t)__afl_area_ptr == -1)
-    __afl_area_ptr = (unsigned char *)mmap((void *)0x10000, MAX_DUMMY_SIZE,
-                                           PROT_READ | PROT_WRITE,
-                                           MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-  if ((uint64_t)__afl_area_ptr == -1)
-    __afl_area_ptr =
-        (unsigned char *)mmap(NULL, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE,
-                              MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-  // __afl_cmp_map = (struct cmp_map *)__afl_area_ptr;
-
-}
-
 int main(int argc, char **argv) {
 
-  fprintf(stderr, "dummy map is at %p\n", __afl_area_ptr);
-
   printf(
       "======================= INFO =========================\n"
       "This binary is built for afl++.\n"
@@ -307,8 +285,6 @@ int main(int argc, char **argv) {
   else if (argc > 1) {
 
     __afl_sharedmem_fuzzing = 0;
-    munmap(__afl_area_ptr, MAX_DUMMY_SIZE);  // we need to free 0x10000
-    __afl_area_ptr = NULL;
     __afl_manual_init();
     return ExecuteFilesOnyByOne(argc, argv);
 
@@ -317,8 +293,6 @@ int main(int argc, char **argv) {
   assert(N > 0);
 
   //  if (!getenv("AFL_DRIVER_DONT_DEFER"))
-  munmap(__afl_area_ptr, MAX_DUMMY_SIZE);
-  __afl_area_ptr = NULL;
   __afl_manual_init();
 
   // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
diff --git a/examples/aflpp_driver/aflpp_driver_test.c b/examples/aflpp_driver/aflpp_driver_test.c
index e4567bbf..ddc3effb 100644
--- a/examples/aflpp_driver/aflpp_driver_test.c
+++ b/examples/aflpp_driver/aflpp_driver_test.c
@@ -4,6 +4,16 @@
 
 #include "hash.h"
 
+void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
+
+  if (Data[0] == 'F')
+    if (Data[1] == 'A')
+      if (Data[2] == '$')
+        if (Data[3] == '$')
+          if (Data[4] == '$') abort();
+
+}
+
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
 
   fprintf(stderr, "FUNC crc: %016llx len: %lu\n",
@@ -13,11 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
 
   if (Size < 5) return 0;
 
-  if (Data[0] == 'F')
-    if (Data[1] == 'A')
-      if (Data[2] == '$')
-        if (Data[3] == '$')
-          if (Data[4] == '$') abort();
+  crashme(Data, Size);
 
   return 0;
 
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 51ab0e85..ca7d10fe 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -172,6 +172,14 @@ struct extra_data {
 
 };
 
+struct auto_extra_data {
+
+  u8  data[MAX_AUTO_EXTRA];             /* Dictionary token data            */
+  u32 len;                              /* Dictionary token length          */
+  u32 hit_cnt;                          /* Use count in the corpus          */
+
+};
+
 /* Fuzzing stages */
 
 enum {
@@ -571,8 +579,9 @@ typedef struct afl_state {
   struct extra_data *extras;            /* Extra tokens to fuzz with        */
   u32                extras_cnt;        /* Total number of tokens read      */
 
-  struct extra_data *a_extras;          /* Automatically selected extras    */
-  u32                a_extras_cnt;      /* Total number of tokens available */
+  struct auto_extra_data
+      a_extras[MAX_AUTO_EXTRAS];        /* Automatically selected extras    */
+  u32 a_extras_cnt;                     /* Total number of tokens available */
 
   /* afl_postprocess API - Now supported via custom mutators */
 
@@ -608,8 +617,6 @@ typedef struct afl_state {
   u32 document_counter;
 #endif
 
-  void *maybe_add_auto;
-
   /* statistics file */
   double last_bitmap_cvg, last_stability, last_eps;
 
@@ -911,7 +918,7 @@ u8 has_new_bits(afl_state_t *, u8 *);
 
 void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
 void load_extras(afl_state_t *, u8 *);
-void maybe_add_auto(void *, u8 *, u32);
+void maybe_add_auto(afl_state_t *, u8 *, u32);
 void save_auto(afl_state_t *);
 void load_auto(afl_state_t *);
 void destroy_extras(afl_state_t *);
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
index 832b2de4..306cc622 100644
--- a/include/alloc-inl.h
+++ b/include/alloc-inl.h
@@ -177,43 +177,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
 
 }
 
-/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
-   or NULL inputs. */
-
-static inline void *DFL_ck_memdup(void *mem, u32 size) {
-
-  void *ret;
-
-  if (!mem || !size) { return NULL; }
-
-  ALLOC_CHECK_SIZE(size);
-  ret = malloc(size);
-  ALLOC_CHECK_RESULT(ret, size);
-
-  return memcpy(ret, mem, size);
-
-}
-
-/* Create a buffer with a block of text, appending a NUL terminator at the end.
-   Returns NULL for zero-sized or NULL inputs. */
-
-static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
-
-  u8 *ret;
-
-  if (!mem || !size) { return NULL; }
-
-  ALLOC_CHECK_SIZE(size);
-  ret = (u8 *)malloc(size + 1);
-  ALLOC_CHECK_RESULT(ret, size);
-
-  memcpy(ret, mem, size);
-  ret[size] = 0;
-
-  return ret;
-
-}
-
   /* In non-debug mode, we just do straightforward aliasing of the above
      functions to user-visible names such as ck_alloc(). */
 
@@ -222,8 +185,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
   #define ck_realloc DFL_ck_realloc
   #define ck_realloc_block DFL_ck_realloc_block
   #define ck_strdup DFL_ck_strdup
-  #define ck_memdup DFL_ck_memdup
-  #define ck_memdup_str DFL_ck_memdup_str
   #define ck_free DFL_ck_free
 
   #define alloc_report()
@@ -489,55 +450,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
 
 }
 
-/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
-   or NULL inputs. */
-
-static inline void *DFL_ck_memdup(void *mem, u32 size) {
-
-  void *ret;
-
-  if (!mem || !size) return NULL;
-
-  ALLOC_CHECK_SIZE(size);
-  ret = malloc(size + ALLOC_OFF_TOTAL);
-  ALLOC_CHECK_RESULT(ret, size);
-
-  ret += ALLOC_OFF_HEAD;
-
-  ALLOC_C1(ret) = ALLOC_MAGIC_C1;
-  ALLOC_S(ret) = size;
-  ALLOC_C2(ret) = ALLOC_MAGIC_C2;
-
-  return memcpy(ret, mem, size);
-
-}
-
-/* Create a buffer with a block of text, appending a NUL terminator at the end.
-   Returns NULL for zero-sized or NULL inputs. */
-
-static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
-
-  u8 *ret;
-
-  if (!mem || !size) return NULL;
-
-  ALLOC_CHECK_SIZE(size);
-  ret = malloc(size + ALLOC_OFF_TOTAL + 1);
-  ALLOC_CHECK_RESULT(ret, size);
-
-  ret += ALLOC_OFF_HEAD;
-
-  ALLOC_C1(ret) = ALLOC_MAGIC_C1;
-  ALLOC_S(ret) = size;
-  ALLOC_C2(ret) = ALLOC_MAGIC_C2;
-
-  memcpy(ret, mem, size);
-  ret[size] = 0;
-
-  return ret;
-
-}
-
   #ifndef DEBUG_BUILD
 
     /* In non-debug mode, we just do straightforward aliasing of the above
@@ -548,8 +460,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
     #define ck_realloc DFL_ck_realloc
     #define ck_realloc_block DFL_ck_realloc_block
     #define ck_strdup DFL_ck_strdup
-    #define ck_memdup DFL_ck_memdup
-    #define ck_memdup_str DFL_ck_memdup_str
     #define ck_free DFL_ck_free
 
     #define alloc_report()
@@ -713,24 +623,6 @@ static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
 
 }
 
-static inline void *TRK_ck_memdup(void *mem, u32 size, const char *file,
-                                  const char *func, u32 line) {
-
-  void *ret = DFL_ck_memdup(mem, size);
-  TRK_alloc_buf(ret, file, func, line);
-  return ret;
-
-}
-
-static inline void *TRK_ck_memdup_str(void *mem, u32 size, const char *file,
-                                      const char *func, u32 line) {
-
-  void *ret = DFL_ck_memdup_str(mem, size);
-  TRK_alloc_buf(ret, file, func, line);
-  return ret;
-
-}
-
 static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
                                u32 line) {
 
@@ -754,12 +646,6 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
 
     #define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
 
-    #define ck_memdup(_p1, _p2) \
-      TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
-
-    #define ck_memdup_str(_p1, _p2) \
-      TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
-
     #define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
 
   #endif                                                   /* ^!DEBUG_BUILD */
diff --git a/include/config.h b/include/config.h
index 344a368f..a978a27c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -70,21 +70,21 @@
 
 #ifndef __NetBSD__
   #ifndef WORD_SIZE_64
-    #define MEM_LIMIT 25
-  #else
     #define MEM_LIMIT 50
+  #else
+    #define MEM_LIMIT 75
   #endif                                                  /* ^!WORD_SIZE_64 */
 #else /* NetBSD's kernel needs more space for stack, see discussion for issue \
          #165 */
-  #define MEM_LIMIT 200
+  #define MEM_LIMIT 250
 #endif
 /* Default memory limit when running in QEMU mode (MB): */
 
-#define MEM_LIMIT_QEMU 200
+#define MEM_LIMIT_QEMU 250
 
 /* Default memory limit when running in Unicorn mode (MB): */
 
-#define MEM_LIMIT_UNICORN 200
+#define MEM_LIMIT_UNICORN 250
 
 /* Number of calibration cycles per every new test case (and for test
    cases that show variable behavior): */
diff --git a/include/forkserver.h b/include/forkserver.h
index 717493db..0a7390ed 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -89,9 +89,9 @@ typedef struct afl_forkserver {
   /* Function to kick off the forkserver child */
   void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
 
-  u8 *function_opt;                     /* for autodictionary: afl ptr      */
+  u8 *afl_ptr;                          /* for autodictionary: afl ptr      */
 
-  void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len);
+  void (*autodict_func)(void *afl_ptr, u8 *mem, u32 len);
 
 } afl_forkserver_t;
 
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 0fa9b12e..fb4e8537 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -206,6 +206,9 @@ AFL_CLANG_FUSELD=
 ifeq "$(LLVM_LTO)" "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
+    ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+      AFL_CLANG_LDPATH=1
+    endif
   else
     $(warn -fuse-ld is not working, cannot enable LTO mode)
     LLVM_LTO = 0
@@ -218,7 +221,9 @@ CFLAGS_SAFE     := -Wall -g -Wno-pointer-sign -I ../include/ \
                    -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
                    -DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
                    -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-                   -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
+                   -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
+                   -DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \
+                   -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
                    -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
 override CFLAGS += $(CFLAGS_SAFE)
 
@@ -236,7 +241,7 @@ endif
 ifneq "$(LLVM_CONFIG)" ""
   CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
 endif
-CLANG_CPPFL  = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS)
+CLANG_CPPFL  = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
 CLANG_LFL    = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
 
 
diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc
index 4d8c4719..206e2682 100644
--- a/llvm_mode/LLVMInsTrim.so.cc
+++ b/llvm_mode/LLVMInsTrim.so.cc
@@ -94,7 +94,7 @@ struct InsTrim : public ModulePass {
 
   }
 
-#if LLVM_VERSION_MAJOR >= 4 || \
+#if LLVM_VERSION_MAJOR > 4 || \
     (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
   #define AFL_HAVE_VECTOR_INTRINSICS 1
 #endif
@@ -144,7 +144,7 @@ struct InsTrim : public ModulePass {
 #ifdef AFL_HAVE_VECTOR_INTRINSICS
     unsigned int ngram_size = 0;
     /* Decide previous location vector size (must be a power of two) */
-    VectorType *PrevLocTy;
+    VectorType *PrevLocTy = NULL;
 
     if (ngram_size_str)
       if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
@@ -194,7 +194,7 @@ struct InsTrim : public ModulePass {
         new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
                            GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
     GlobalVariable *AFLPrevLoc;
-    GlobalVariable *AFLContext;
+    GlobalVariable *AFLContext = NULL;
     LoadInst *      PrevCtx = NULL;  // for CTX sensitive coverage
 
     if (ctx_str)
@@ -256,6 +256,8 @@ struct InsTrim : public ModulePass {
     u64 total_rs = 0;
     u64 total_hs = 0;
 
+    scanForDangerousFunctions(&M);
+
     for (Function &F : M) {
 
       if (debug) {
diff --git a/llvm_mode/README.instrument_list.md b/llvm_mode/README.instrument_list.md
index d4739dda..1fc06414 100644
--- a/llvm_mode/README.instrument_list.md
+++ b/llvm_mode/README.instrument_list.md
@@ -14,13 +14,13 @@ disturbance by uninteresting code being exercised.
 
 For this purpose, a "partial instrumentation" support en par with llvm sancov
 is provided by afl++ that allows you to specify on a source file and function
-level which should be compiled with or without instrumentation.
+level which function should be compiled with or without instrumentation.
 
 Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead:
 https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
 
-the llvm sancov list format is fully supported by afl++, however afl++ has
-more flexbility.
+The llvm sancov list format is fully supported by afl++, however afl++ has
+more flexibility.
 
 ## 2) Building the LLVM module
 
@@ -35,13 +35,13 @@ The only required change is that you need to set either the environment variable
 AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename.
 
 That file then contains the filenames or functions that should be instrumented
-(AFL_LLVM_ALLOWLIST) or should specifically NOT instrumentd (AFL_LLVM_DENYLIST).
+(AFL_LLVM_ALLOWLIST) or should specifically NOT be instrumented (AFL_LLVM_DENYLIST).
 
 For matching, the function/filename that is being compiled must end in the
-function/filename entry contained in this the instrument file list (to avoid
+function/filename entry contained in this instrument file list (to avoid
 breaking the matching when absolute paths are used during compilation).
 
-**NOTE:** In optimization functions might be inlined and then not match!
+**NOTE:** In builds with optimization enabled functions might be inlined and would not match!
 
 For example if your source tree looks like this:
 ```
@@ -52,7 +52,7 @@ project/feature_b/b1.cpp
 project/feature_b/b2.cpp
 ```
 
-and you only want to test feature_a, then create a the instrument file list file containing:
+and you only want to test feature_a, then create a instrument file list file containing:
 ```
 feature_a/a1.cpp
 feature_a/a2.cpp
@@ -69,7 +69,7 @@ exists somewhere else in the project directories.
 You can also specify function names. Note that for C++ the function names
 must be mangled to match!
 
-afl++ is intelligent to identify if an entry is a filename or a function.
+afl++ is able to identify if an entry is a filename or a function.
 However if you want to be sure (and compliant to the sancov allow/blocklist
 format), you can specify source file entries like this:
 ```
@@ -79,7 +79,7 @@ and function entries like this:
 ```
 fun: MallocFoo
 ```
-Note that whitespace is ignored and comments (`# foo`) supported.
+Note that whitespace is ignored and comments (`# foo`) are supported.
 
 ## 4) UNIX-style pattern matching
 You can add UNIX-style pattern matching in the the instrument file list entries.
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index efaba122..99b17430 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -246,33 +246,60 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   // laf
   if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
 
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/split-switches-pass.so", obj_path);
+    if (lto_mode) {
+
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path);
+
+    } else {
+
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/split-switches-pass.so", obj_path);
+
+    }
 
   }
 
   if (getenv("LAF_TRANSFORM_COMPARES") ||
       getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
 
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/compare-transform-pass.so", obj_path);
+    if (lto_mode) {
+
+      cc_params[cc_par_cnt++] = alloc_printf(
+          "-Wl,-mllvm=-load=%s/compare-transform-pass.so", obj_path);
+
+    } else {
+
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/compare-transform-pass.so", obj_path);
+
+    }
 
   }
 
   if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
       getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
 
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/split-compares-pass.so", obj_path);
+    if (lto_mode) {
+
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/split-compares-pass.so", obj_path);
+
+    } else {
+
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/split-compares-pass.so", obj_path);
+
+    }
 
   }
 
@@ -282,24 +309,37 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   unsetenv("AFL_LD_CALLER");
   if (cmplog_mode) {
 
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/cmplog-routines-pass.so", obj_path);
+    if (lto_mode) {
 
-    // reuse split switches from laf
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/split-switches-pass.so", obj_path);
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path);
+      cc_params[cc_par_cnt++] =
+          alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path);
+      cc_params[cc_par_cnt++] = alloc_printf(
+          "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path);
 
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] = "-load";
-    cc_params[cc_par_cnt++] = "-Xclang";
-    cc_params[cc_par_cnt++] =
-        alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
+    } else {
+
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/cmplog-routines-pass.so", obj_path);
+
+      // reuse split switches from laf
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/split-switches-pass.so", obj_path);
+
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
+
+    }
 
     cc_params[cc_par_cnt++] = "-fno-inline";
 
@@ -312,8 +352,17 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     else
       setenv("AFL_LLVM_LTO_AUTODICTIONARY", "1", 1);
 
+#if defined(AFL_CLANG_LDPATH) && LLVM_VERSION_MAJOR >= 12
+    u8 *ld_ptr = strrchr(AFL_REAL_LD, '/');
+    if (!ld_ptr) ld_ptr = "ld.lld";
+    cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_ptr);
+    cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", AFL_REAL_LD);
+#else
     cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
+#endif
+
     cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
+
     /*
         The current LTO instrim mode is not good, so we disable it
         if (instrument_mode == INSTRUMENT_CFG)
@@ -321,6 +370,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
               alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so",
        obj_path); else
     */
+
     cc_params[cc_par_cnt++] = alloc_printf(
         "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
     cc_params[cc_par_cnt++] = lto_flag;
@@ -329,8 +379,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     if (instrument_mode == INSTRUMENT_PCGUARD) {
 
+#if LLVM_VERSION_MAJOR > 4 ||   \
+    (LLVM_VERSION_MAJOR == 4 && \
+     (LLVM_VERSION_MINOR > 0 || LLVM_VERSION_PATCH >= 1))
       cc_params[cc_par_cnt++] =
           "-fsanitize-coverage=trace-pc-guard";  // edge coverage by default
+#else
+      FATAL("pcguard instrumentation requires llvm 4.0.1+");
+#endif
 
     } else {
 
@@ -965,6 +1021,10 @@ int main(int argc, char **argv, char **envp) {
 #ifdef AFL_CLANG_FLTO
     SAYF(
         "\nafl-clang-lto specific environment variables:\n"
+        "AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), e.g. "
+        "0x10000\n"
+        "AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
+        "functions they are in into this file\n"
         "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
         "global var\n"
         "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
diff --git a/llvm_mode/afl-ld-lto.c b/llvm_mode/afl-ld-lto.c
index 1b59bb4a..771e2d0d 100644
--- a/llvm_mode/afl-ld-lto.c
+++ b/llvm_mode/afl-ld-lto.c
@@ -278,7 +278,7 @@ int main(int argc, char **argv) {
 
   if (debug) {
 
-    (void)getcwd(thecwd, sizeof(thecwd));
+    if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, ".");
 
     SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd);
     for (i = 0; i < argc; i++)
diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc
index 0b50c547..d9e63bd3 100644
--- a/llvm_mode/afl-llvm-common.cc
+++ b/llvm_mode/afl-llvm-common.cc
@@ -67,8 +67,11 @@ bool isIgnoreFunction(const llvm::Function *F) {
       "__libc_csu",
       "__asan",
       "__msan",
+      "__cmplog",
+      "__sancov",
       "msan.",
       "LLVMFuzzer",
+      "__decide_deferred",
       "maybe_duplicate_stderr",
       "discard_output",
       "close_stdout",
@@ -253,101 +256,63 @@ void initInstrumentList() {
 
 }
 
-bool isInInstrumentList(llvm::Function *F) {
-
-  // is this a function with code? If it is external we dont instrument it
-  // anyway and cant be in the the instrument file list. Or if it is ignored.
-  if (!F->size() || isIgnoreFunction(F)) return false;
-
-  // if we do not have a the instrument file list return true
-  if (!allowListFiles.empty() || !allowListFunctions.empty()) {
-
-    if (!allowListFunctions.empty()) {
-
-      std::string instFunction = F->getName().str();
-
-      for (std::list<std::string>::iterator it = allowListFunctions.begin();
-           it != allowListFunctions.end(); ++it) {
-
-        /* We don't check for filename equality here because
-         * filenames might actually be full paths. Instead we
-         * check that the actual filename ends in the filename
-         * specified in the list. We also allow UNIX-style pattern
-         * matching */
-
-        if (instFunction.length() >= it->length()) {
-
-          if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
-
-            if (debug)
-              SAYF(cMGN "[D] " cRST
-                        "Function %s is in the allow function list, "
-                        "instrumenting ... \n",
-                   instFunction.c_str());
-            return true;
-
-          }
-
-        }
-
-      }
+void scanForDangerousFunctions(llvm::Module *M) {
 
-    }
+  if (!M) return;
 
-    if (!allowListFiles.empty()) {
+#if LLVM_VERSION_MAJOR > 3 || \
+    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
 
-      // let's try to get the filename for the function
-      auto                 bb = &F->getEntryBlock();
-      BasicBlock::iterator IP = bb->getFirstInsertionPt();
-      IRBuilder<>          IRB(&(*IP));
-      DebugLoc             Loc = IP->getDebugLoc();
+  for (GlobalIFunc &IF : M->ifuncs()) {
 
-#if LLVM_VERSION_MAJOR >= 4 || \
-    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
-      if (Loc) {
+    StringRef ifunc_name = IF.getName();
+    Constant *r = IF.getResolver();
+    StringRef r_name = cast<Function>(r->getOperand(0))->getName();
+    if (!be_quiet)
+      fprintf(stderr,
+              "Info: Found an ifunc with name %s that points to resolver "
+              "function %s, we will not instrument this, putting it into the "
+              "block list.\n",
+              ifunc_name.str().c_str(), r_name.str().c_str());
+    denyListFunctions.push_back(r_name.str());
 
-        DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
-
-        unsigned int instLine = cDILoc->getLine();
-        StringRef    instFilename = cDILoc->getFilename();
+  }
 
-        if (instFilename.str().empty()) {
+  GlobalVariable *GV = M->getNamedGlobal("llvm.global_ctors");
+  if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
 
-          /* If the original location is empty, try using the inlined location
-           */
-          DILocation *oDILoc = cDILoc->getInlinedAt();
-          if (oDILoc) {
+    ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
 
-            instFilename = oDILoc->getFilename();
-            instLine = oDILoc->getLine();
+    if (InitList) {
 
-          }
+      for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
 
-        }
+        if (ConstantStruct *CS =
+                dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
 
-        /* Continue only if we know where we actually are */
-        if (!instFilename.str().empty()) {
+          if (CS->getNumOperands() >= 2) {
 
-          for (std::list<std::string>::iterator it = allowListFiles.begin();
-               it != allowListFiles.end(); ++it) {
+            if (CS->getOperand(1)->isNullValue())
+              break;  // Found a null terminator, stop here.
 
-            /* We don't check for filename equality here because
-             * filenames might actually be full paths. Instead we
-             * check that the actual filename ends in the filename
-             * specified in the list. We also allow UNIX-style pattern
-             * matching */
+            ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
+            int          Priority = CI ? CI->getSExtValue() : 0;
 
-            if (instFilename.str().length() >= it->length()) {
+            Constant *FP = CS->getOperand(1);
+            if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
+              if (CE->isCast()) FP = CE->getOperand(0);
+            if (Function *F = dyn_cast<Function>(FP)) {
 
-              if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
-                  0) {
+              if (!F->isDeclaration() &&
+                  strncmp(F->getName().str().c_str(), "__afl", 5) != 0) {
 
-                if (debug)
-                  SAYF(cMGN "[D] " cRST
-                            "Function %s is in the allowlist (%s), "
-                            "instrumenting ... \n",
-                       F->getName().str().c_str(), instFilename.str().c_str());
-                return true;
+                if (!be_quiet)
+                  fprintf(stderr,
+                          "Info: Found constructor function %s with prio "
+                          "%u, we will not instrument this, putting it into a "
+                          "block list.\n",
+                          F->getName().str().c_str(), Priority);
+                denyListFunctions.push_back(F->getName().str());
 
               }
 
@@ -361,63 +326,67 @@ bool isInInstrumentList(llvm::Function *F) {
 
     }
 
-#else
-      if (!Loc.isUnknown()) {
+  }
 
-        DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
+#endif
 
-        unsigned int instLine = cDILoc.getLineNumber();
-        StringRef    instFilename = cDILoc.getFilename();
+}
 
-        (void)instLine;
-        /* Continue only if we know where we actually are */
-        if (!instFilename.str().empty()) {
+static std::string getSourceName(llvm::Function *F) {
 
-          for (std::list<std::string>::iterator it = allowListFiles.begin();
-               it != allowListFiles.end(); ++it) {
+  // let's try to get the filename for the function
+  auto                 bb = &F->getEntryBlock();
+  BasicBlock::iterator IP = bb->getFirstInsertionPt();
+  IRBuilder<>          IRB(&(*IP));
+  DebugLoc             Loc = IP->getDebugLoc();
 
-            /* We don't check for filename equality here because
-             * filenames might actually be full paths. Instead we
-             * check that the actual filename ends in the filename
-             * specified in the list. We also allow UNIX-style pattern
-             * matching */
+#if LLVM_VERSION_MAJOR >= 4 || \
+    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
+  if (Loc) {
 
-            if (instFilename.str().length() >= it->length()) {
+    DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
 
-              if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
-                  0) {
+    StringRef instFilename = cDILoc->getFilename();
 
-                return true;
+    if (instFilename.str().empty()) {
 
-              }
+      /* If the original location is empty, try using the inlined location
+       */
+      DILocation *oDILoc = cDILoc->getInlinedAt();
+      if (oDILoc) { instFilename = oDILoc->getFilename(); }
 
-            }
+    }
 
-          }
+    return instFilename.str();
 
-        }
+  }
 
-      }
+#else
+  if (!Loc.isUnknown()) {
 
-    }
+    DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
+
+    StringRef instFilename = cDILoc.getFilename();
+
+    /* Continue only if we know where we actually are */
+    return instFilename.str();
+
+  }
 
 #endif
-    else {
 
-      // we could not find out the location. in this case we say it is not
-      // in the the instrument file list
-      if (!be_quiet)
-        WARNF(
-            "No debug information found for function %s, will not be "
-            "instrumented (recompile with -g -O[1-3]).",
-            F->getName().str().c_str());
-      return false;
+  return std::string("");
 
-    }
+}
 
-    return false;
+bool isInInstrumentList(llvm::Function *F) {
 
-  }
+  bool return_default = true;
+
+  // is this a function with code? If it is external we don't instrument it
+  // anyway and it can't be in the instrument file list. Or if it is it is
+  // ignored.
+  if (!F->size() || isIgnoreFunction(F)) return false;
 
   if (!denyListFiles.empty() || !denyListFunctions.empty()) {
 
@@ -455,62 +424,75 @@ bool isInInstrumentList(llvm::Function *F) {
 
     if (!denyListFiles.empty()) {
 
-      // let's try to get the filename for the function
-      auto                 bb = &F->getEntryBlock();
-      BasicBlock::iterator IP = bb->getFirstInsertionPt();
-      IRBuilder<>          IRB(&(*IP));
-      DebugLoc             Loc = IP->getDebugLoc();
+      std::string source_file = getSourceName(F);
 
-#if LLVM_VERSION_MAJOR >= 4 || \
-    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
-      if (Loc) {
+      if (!source_file.empty()) {
 
-        DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
+        for (std::list<std::string>::iterator it = denyListFiles.begin();
+             it != denyListFiles.end(); ++it) {
 
-        unsigned int instLine = cDILoc->getLine();
-        StringRef    instFilename = cDILoc->getFilename();
+          /* We don't check for filename equality here because
+           * filenames might actually be full paths. Instead we
+           * check that the actual filename ends in the filename
+           * specified in the list. We also allow UNIX-style pattern
+           * matching */
 
-        if (instFilename.str().empty()) {
+          if (source_file.length() >= it->length()) {
 
-          /* If the original location is empty, try using the inlined location
-           */
-          DILocation *oDILoc = cDILoc->getInlinedAt();
-          if (oDILoc) {
+            if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
 
-            instFilename = oDILoc->getFilename();
-            instLine = oDILoc->getLine();
+              return false;
+
+            }
 
           }
 
         }
 
-        /* Continue only if we know where we actually are */
-        if (!instFilename.str().empty()) {
+      } else {
 
-          for (std::list<std::string>::iterator it = denyListFiles.begin();
-               it != denyListFiles.end(); ++it) {
+        // we could not find out the location. in this case we say it is not
+        // in the instrument file list
+        if (!be_quiet)
+          WARNF(
+              "No debug information found for function %s, will be "
+              "instrumented (recompile with -g -O[1-3]).",
+              F->getName().str().c_str());
 
-            /* We don't check for filename equality here because
-             * filenames might actually be full paths. Instead we
-             * check that the actual filename ends in the filename
-             * specified in the list. We also allow UNIX-style pattern
-             * matching */
+      }
 
-            if (instFilename.str().length() >= it->length()) {
+    }
 
-              if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
-                  0) {
+  }
 
-                if (debug)
-                  SAYF(cMGN "[D] " cRST
-                            "Function %s is in the denylist (%s), not "
-                            "instrumenting ... \n",
-                       F->getName().str().c_str(), instFilename.str().c_str());
-                return false;
+  // if we do not have a instrument file list return true
+  if (!allowListFiles.empty() || !allowListFunctions.empty()) {
 
-              }
+    return_default = false;
 
-            }
+    if (!allowListFunctions.empty()) {
+
+      std::string instFunction = F->getName().str();
+
+      for (std::list<std::string>::iterator it = allowListFunctions.begin();
+           it != allowListFunctions.end(); ++it) {
+
+        /* We don't check for filename equality here because
+         * filenames might actually be full paths. Instead we
+         * check that the actual filename ends in the filename
+         * specified in the list. We also allow UNIX-style pattern
+         * matching */
+
+        if (instFunction.length() >= it->length()) {
+
+          if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
+
+            if (debug)
+              SAYF(cMGN "[D] " cRST
+                        "Function %s is in the allow function list, "
+                        "instrumenting ... \n",
+                   instFunction.c_str());
+            return true;
 
           }
 
@@ -520,35 +502,31 @@ bool isInInstrumentList(llvm::Function *F) {
 
     }
 
-#else
-      if (!Loc.isUnknown()) {
-
-        DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
-
-        unsigned int instLine = cDILoc.getLineNumber();
-        StringRef instFilename = cDILoc.getFilename();
+    if (!allowListFiles.empty()) {
 
-        (void)instLine;
-        /* Continue only if we know where we actually are */
-        if (!instFilename.str().empty()) {
+      std::string source_file = getSourceName(F);
 
-          for (std::list<std::string>::iterator it = denyListFiles.begin();
-               it != denyListFiles.end(); ++it) {
+      if (!source_file.empty()) {
 
-            /* We don't check for filename equality here because
-             * filenames might actually be full paths. Instead we
-             * check that the actual filename ends in the filename
-             * specified in the list. We also allow UNIX-style pattern
-             * matching */
+        for (std::list<std::string>::iterator it = allowListFiles.begin();
+             it != allowListFiles.end(); ++it) {
 
-            if (instFilename.str().length() >= it->length()) {
+          /* We don't check for filename equality here because
+           * filenames might actually be full paths. Instead we
+           * check that the actual filename ends in the filename
+           * specified in the list. We also allow UNIX-style pattern
+           * matching */
 
-              if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
-                  0) {
+          if (source_file.length() >= it->length()) {
 
-                return false;
+            if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
 
-              }
+              if (debug)
+                SAYF(cMGN "[D] " cRST
+                          "Function %s is in the allowlist (%s), "
+                          "instrumenting ... \n",
+                     F->getName().str().c_str(), source_file.c_str());
+              return true;
 
             }
 
@@ -556,29 +534,24 @@ bool isInInstrumentList(llvm::Function *F) {
 
         }
 
-      }
+      } else {
 
-    }
+        // we could not find out the location. In this case we say it is not
+        // in the instrument file list
+        if (!be_quiet)
+          WARNF(
+              "No debug information found for function %s, will not be "
+              "instrumented (recompile with -g -O[1-3]).",
+              F->getName().str().c_str());
+        return false;
 
-#endif
-    else {
-
-      // we could not find out the location. in this case we say it is not
-      // in the the instrument file list
-      if (!be_quiet)
-        WARNF(
-            "No debug information found for function %s, will be "
-            "instrumented (recompile with -g -O[1-3]).",
-            F->getName().str().c_str());
-      return true;
+      }
 
     }
 
-    return true;
-
   }
 
-  return true;  // not reached
+  return return_default;
 
 }
 
diff --git a/llvm_mode/afl-llvm-common.h b/llvm_mode/afl-llvm-common.h
index 5b96be43..a1561d9c 100644
--- a/llvm_mode/afl-llvm-common.h
+++ b/llvm_mode/afl-llvm-common.h
@@ -37,6 +37,7 @@ bool                   isIgnoreFunction(const llvm::Function *F);
 void                   initInstrumentList();
 bool                   isInInstrumentList(llvm::Function *F);
 unsigned long long int calculateCollisions(uint32_t edges);
+void                   scanForDangerousFunctions(llvm::Module *M);
 
 #ifndef IS_EXTERN
   #define IS_EXTERN
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index fd8e48a7..300951fb 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -103,6 +103,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
   std::vector<std::string>         dictionary;
   std::vector<CallInst *>          calls;
   DenseMap<Value *, std::string *> valueMap;
+  std::vector<BasicBlock *>        BlockList;
   char *                           ptr;
   FILE *                           documentFile = NULL;
 
@@ -150,7 +151,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
       map_addr = 0;
 
-    } else if (map_addr == 0) {
+    } else if (getenv("AFL_LLVM_MAP_DYNAMIC")) {
 
       FATAL(
           "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
@@ -217,79 +218,9 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
   }
 
-    */
-
-  std::vector<std::string> module_block_list;
-
-  if (map_addr) {
-
-    for (GlobalIFunc &IF : M.ifuncs()) {
-
-      StringRef ifunc_name = IF.getName();
-      Constant *r = IF.getResolver();
-      StringRef r_name = cast<Function>(r->getOperand(0))->getName();
-      if (!be_quiet)
-        fprintf(stderr,
-                "Warning: Found an ifunc with name %s that points to resolver "
-                "function %s, we cannot instrument this, putting it into a "
-                "block list.\n",
-                ifunc_name.str().c_str(), r_name.str().c_str());
-      module_block_list.push_back(r_name.str());
-
-    }
-
-    GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors");
-    if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
-
-      ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
-
-      if (InitList) {
-
-        for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
-
-          if (ConstantStruct *CS =
-                  dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
-
-            if (CS->getNumOperands() >= 2) {
-
-              if (CS->getOperand(1)->isNullValue())
-                break;  // Found a null terminator, stop here.
-
-              ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
-              int          Priority = CI ? CI->getSExtValue() : 0;
-
-              Constant *FP = CS->getOperand(1);
-              if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
-                if (CE->isCast()) FP = CE->getOperand(0);
-              if (Function *F = dyn_cast<Function>(FP)) {
-
-                if (!F->isDeclaration() &&
-                    strncmp(F->getName().str().c_str(), "__afl", 5) != 0 &&
-                    Priority <= 5) {
-
-                  if (!be_quiet)
-                    fprintf(stderr,
-                            "Warning: Found constructor function %s with prio "
-                            "%u, we cannot instrument this, putting it into a "
-                            "block list.\n",
-                            F->getName().str().c_str(), Priority);
-                  module_block_list.push_back(F->getName().str());
-
-                }
-
-              }
-
-            }
-
-          }
-
-        }
-
-      }
-
-    }
+  */
 
-  }
+  scanForDangerousFunctions(&M);
 
   /* Instrument all the things! */
 
@@ -307,26 +238,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
     if (F.size() < function_minimum_size) continue;
     if (isIgnoreFunction(&F)) continue;
 
-    if (module_block_list.size()) {
-
-      for (auto bname : module_block_list) {
-
-        std::string fname = F.getName().str();
-
-        if (fname.compare(bname) == 0) {
-
-          if (!be_quiet)
-            WARNF(
-                "Skipping instrumentation of dangerous early running function "
-                "%s",
-                fname.c_str());
-
-        }
-
-      }
-
-    }
-
     // the instrument file list check
     AttributeList Attrs = F.getAttributes();
     if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {
@@ -380,14 +291,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
           if ((callInst = dyn_cast<CallInst>(&IN))) {
 
-            bool    isStrcmp = true;
-            bool    isMemcmp = true;
-            bool    isStrncmp = true;
-            bool    isStrcasecmp = true;
-            bool    isStrncasecmp = true;
-            bool    isIntMemcpy = true;
-            bool    addedNull = false;
-            uint8_t optLen = 0;
+            bool   isStrcmp = true;
+            bool   isMemcmp = true;
+            bool   isStrncmp = true;
+            bool   isStrcasecmp = true;
+            bool   isStrncasecmp = true;
+            bool   isIntMemcpy = true;
+            bool   addedNull = false;
+            size_t optLen = 0;
 
             Function *Callee = callInst->getCalledFunction();
             if (!Callee) continue;
@@ -400,6 +311,24 @@ bool AFLLTOPass::runOnModule(Module &M) {
             isStrncasecmp &= !FuncName.compare("strncasecmp");
             isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
 
+            /* we do something different here, putting this BB and the
+               successors in a block map */
+            if (!FuncName.compare("__afl_persistent_loop")) {
+
+              BlockList.push_back(&BB);
+              /*
+                            for (succ_iterator SI = succ_begin(&BB), SE =
+                 succ_end(&BB); SI != SE; ++SI) {
+
+                              BasicBlock *succ = *SI;
+                              BlockList.push_back(succ);
+
+                            }
+
+              */
+
+            }
+
             if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
                 !isStrncasecmp && !isIntMemcpy)
               continue;
@@ -617,18 +546,27 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
             // add null byte if this is a string compare function and a null
             // was not already added
-            if (addedNull == false && !isMemcmp) {
+            if (!isMemcmp) {
+
+              if (addedNull == false) {
 
-              thestring.append("\0", 1);  // add null byte
-              optLen++;
+                thestring.append("\0", 1);  // add null byte
+                optLen++;
+
+              }
+
+              // ensure we do not have garbage
+              size_t offset = thestring.find('\0', 0);
+              if (offset + 1 < optLen) optLen = offset + 1;
+              thestring = thestring.substr(0, optLen);
 
             }
 
             if (!be_quiet) {
 
               std::string outstring;
-              fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
-                      (unsigned int)thestring.length());
+              fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
+                      thestring.length());
               for (uint8_t i = 0; i < thestring.length(); i++) {
 
                 uint8_t c = thestring[i];
@@ -686,13 +624,35 @@ bool AFLLTOPass::runOnModule(Module &M) {
       do {
 
         --i;
-        BasicBlock *              newBB;
+        BasicBlock *              newBB = NULL;
         BasicBlock *              origBB = &(*InsBlocks[i]);
         std::vector<BasicBlock *> Successors;
         Instruction *             TI = origBB->getTerminator();
         uint32_t                  fs = origBB->getParent()->size();
         uint32_t                  countto;
 
+        if (BlockList.size()) {
+
+          int skip = 0;
+          for (uint32_t k = 0; k < BlockList.size(); k++) {
+
+            if (origBB == BlockList[k]) {
+
+              if (debug)
+                fprintf(
+                    stderr,
+                    "DEBUG: Function %s skipping BB with/after __afl_loop\n",
+                    F.getName().str().c_str());
+              skip = 1;
+
+            }
+
+          }
+
+          if (skip) continue;
+
+        }
+
         for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
              SI != SE; ++SI) {
 
diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc
index 618abe48..a791d720 100644
--- a/llvm_mode/afl-llvm-pass.so.cc
+++ b/llvm_mode/afl-llvm-pass.so.cc
@@ -112,7 +112,7 @@ uint64_t PowerOf2Ceil(unsigned in) {
 #endif
 
 /* #if LLVM_VERSION_STRING >= "4.0.1" */
-#if LLVM_VERSION_MAJOR >= 4 || \
+#if LLVM_VERSION_MAJOR > 4 || \
     (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
   #define AFL_HAVE_VECTOR_INTRINSICS 1
 #endif
@@ -194,7 +194,7 @@ bool AFLCoverage::runOnModule(Module &M) {
 
 #ifdef AFL_HAVE_VECTOR_INTRINSICS
   /* Decide previous location vector size (must be a power of two) */
-  VectorType *PrevLocTy;
+  VectorType *PrevLocTy = NULL;
 
   if (ngram_size_str)
     if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
@@ -236,7 +236,7 @@ bool AFLCoverage::runOnModule(Module &M) {
       new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
                          GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
   GlobalVariable *AFLPrevLoc;
-  GlobalVariable *AFLContext;
+  GlobalVariable *AFLContext = NULL;
 
   if (ctx_str)
 #ifdef __ANDROID__
@@ -292,11 +292,12 @@ bool AFLCoverage::runOnModule(Module &M) {
   ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
   ConstantInt *One = ConstantInt::get(Int8Ty, 1);
 
-  LoadInst *PrevCtx;  // CTX sensitive coverage
+  LoadInst *PrevCtx = NULL;  // CTX sensitive coverage
 
   /* Instrument all the things! */
 
   int inst_blocks = 0;
+  scanForDangerousFunctions(&M);
 
   for (auto &F : M) {
 
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index a567593e..d00fd26f 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -35,6 +35,8 @@
 #include <string.h>
 #include <assert.h>
 #include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
 #include <errno.h>
 
 #include <sys/mman.h>
@@ -52,8 +54,6 @@
    Basically, we need to make sure that the forkserver is initialized after
    the LLVM-generated runtime initialization pass, not before. */
 
-#define CONST_PRIO 5
-
 #ifndef MAP_FIXED_NOREPLACE
   #ifdef MAP_EXCL
     #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
@@ -62,6 +62,8 @@
   #endif
 #endif
 
+#define CTOR_PRIO 3
+
 #include <sys/mman.h>
 #include <fcntl.h>
 
@@ -75,11 +77,7 @@
   #define MAP_INITIAL_SIZE MAP_SIZE
 #endif
 
-#ifdef AFL_REAL_LD
-u8 __afl_area_initial[MAP_INITIAL_SIZE];
-#else
-u8                  __afl_area_initial[MAP_SIZE];
-#endif
+u8   __afl_area_initial[MAP_INITIAL_SIZE];
 u8 * __afl_area_ptr = __afl_area_initial;
 u8 * __afl_dictionary;
 u8 * __afl_fuzz_ptr;
@@ -109,6 +107,10 @@ struct cmp_map *__afl_cmp_map;
 
 static u8 is_persistent;
 
+/* Are we in sancov mode? */
+
+static u8 _is_sancov;
+
 /* Error reporting to forkserver controller */
 
 void send_forkserver_error(int error) {
@@ -186,7 +188,7 @@ static void __afl_map_shm_fuzz() {
 static void __afl_map_shm(void) {
 
   // we we are not running in afl ensure the map exists
-  if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
+  if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_initial; }
 
   char *id_str = getenv(SHM_ENV_VAR);
 
@@ -194,8 +196,8 @@ static void __afl_map_shm(void) {
 
     if (__afl_final_loc % 8)
       __afl_final_loc = (((__afl_final_loc + 7) >> 3) << 3);
-
     __afl_map_size = __afl_final_loc;
+
     if (__afl_final_loc > MAP_SIZE) {
 
       char *ptr;
@@ -205,10 +207,12 @@ static void __afl_map_shm(void) {
 
         if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
 
-          fprintf(stderr,
-                  "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
-                  "be able to run this instrumented program!\n",
-                  __afl_final_loc);
+          if (!getenv("AFL_QUIET"))
+            fprintf(stderr,
+                    "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u "
+                    "to be able to run this instrumented program!\n",
+                    __afl_final_loc);
+
           if (id_str) {
 
             send_forkserver_error(FS_ERROR_MAP_SIZE);
@@ -218,10 +222,11 @@ static void __afl_map_shm(void) {
 
         } else {
 
-          fprintf(stderr,
-                  "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
-                  "be able to run this instrumented program!\n",
-                  __afl_final_loc);
+          if (!getenv("AFL_QUIET"))
+            fprintf(stderr,
+                    "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u "
+                    "to be able to run this instrumented program!\n",
+                    __afl_final_loc);
 
         }
 
@@ -237,13 +242,25 @@ static void __afl_map_shm(void) {
 
   if (getenv("AFL_DEBUG"))
     fprintf(stderr,
-            "DEBUG: id_str %s, __afl_map_addr 0x%llx, 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);
+            "DEBUG: id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
+            "__afl_map_addr 0x%llx, MAP_SIZE %u, __afl_final_loc %u, "
+            "max_size_forkserver %u/0x%x\n",
+            id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
+            __afl_area_initial, __afl_map_addr, MAP_SIZE, __afl_final_loc,
+            FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
 
   if (id_str) {
 
+    if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) {
+
+      if (__afl_map_addr)
+        munmap((void *)__afl_map_addr, __afl_final_loc);
+      else
+        free(__afl_area_ptr);
+      __afl_area_ptr = __afl_area_initial;
+
+    }
+
 #ifdef USEMMAP
     const char *   shm_file_path = id_str;
     int            shm_fd = -1;
@@ -312,11 +329,14 @@ static void __afl_map_shm(void) {
 
     __afl_area_ptr[0] = 1;
 
-  } else if (__afl_map_addr) {
+  } else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
+
+             __afl_map_addr) {
 
     __afl_area_ptr =
         mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
              MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
     if (__afl_area_ptr == MAP_FAILED) {
 
       fprintf(stderr, "can not aquire mmap for address %p\n",
@@ -325,6 +345,14 @@ static void __afl_map_shm(void) {
 
     }
 
+  } else if (_is_sancov && __afl_area_ptr != __afl_area_initial) {
+
+    free(__afl_area_ptr);
+    __afl_area_ptr = NULL;
+    if (__afl_final_loc > MAP_INITIAL_SIZE)
+      __afl_area_ptr = malloc(__afl_final_loc);
+    if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
+
   }
 
   id_str = getenv(CMPLOG_SHM_ENV_VAR);
@@ -842,9 +870,22 @@ void __afl_manual_init(void) {
 
   static u8 init_done;
 
+  if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
+
+    init_done = 1;
+    is_persistent = 0;
+    __afl_sharedmem_fuzzing = 0;
+    if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_initial;
+
+    if (getenv("AFL_DEBUG"))
+      fprintf(stderr,
+              "DEBUG: disabled instrumentation because of "
+              "AFL_DISABLE_LLVM_INSTRUMENTATION\n");
+
+  }
+
   if (!init_done) {
 
-    __afl_map_shm();
     __afl_start_forkserver();
     init_done = 1;
 
@@ -852,11 +893,11 @@ void __afl_manual_init(void) {
 
 }
 
-/* Proper initialization routine. */
+/* Initialization of the forkserver - latest possible */
 
-__attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
+__attribute__((constructor())) void __afl_auto_init(void) {
 
-  is_persistent = !!getenv(PERSIST_ENV_VAR);
+  if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
 
   if (getenv(DEFER_ENV_VAR)) return;
 
@@ -864,6 +905,57 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
 
 }
 
+/* Initialization of the shmem - earliest possible because of LTO fixed mem. */
+
+__attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
+
+  is_persistent = !!getenv(PERSIST_ENV_VAR);
+
+  if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
+
+  __afl_map_shm();
+
+}
+
+/* preset __afl_area_ptr #2 */
+
+__attribute__((constructor(1))) void __afl_auto_second(void) {
+
+  if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
+  u8 *ptr;
+
+  if (__afl_final_loc) {
+
+    if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial)
+      free(__afl_area_ptr);
+
+    if (__afl_map_addr)
+      ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_final_loc,
+                       PROT_READ | PROT_WRITE,
+                       MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+    else
+      ptr = (u8 *)malloc(__afl_final_loc);
+
+    if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
+
+  }
+
+}
+
+/* preset __afl_area_ptr #1 - at constructor level 0 global variables have
+   not been set */
+
+__attribute__((constructor(0))) void __afl_auto_first(void) {
+
+  if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
+  u8 *ptr;
+
+  ptr = (u8 *)malloc(1024000);
+
+  if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
+
+}
+
 /* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
    It remains non-operational in the traditional, plugin-backed LLVM mode.
    For more info about 'trace-pc-guard', see llvm_mode/README.md.
@@ -874,7 +966,7 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
 void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
 
   // For stability analysis, if you want to know to which function unstable
-  // edge IDs belong to - uncomment, recompile+install llvm_mode, recompile
+  // edge IDs belong - uncomment, recompile+install llvm_mode, recompile
   // the target. libunwind and libbacktrace are better solutions.
   // Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture
   // the backtrace output
@@ -912,7 +1004,8 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
 
 #else
 
-  __afl_area_ptr[*guard] = __afl_area_ptr[*guard] + 1 + (__afl_area_ptr[*guard] == 255 ? 1 : 0);
+  __afl_area_ptr[*guard] =
+      __afl_area_ptr[*guard] + 1 + (__afl_area_ptr[*guard] == 255 ? 1 : 0);
 
 #endif
 
@@ -927,6 +1020,8 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
   u32   inst_ratio = 100;
   char *x;
 
+  _is_sancov = 1;
+
   if (getenv("AFL_DEBUG")) {
 
     fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
diff --git a/llvm_mode/cmplog-instructions-pass.cc b/llvm_mode/cmplog-instructions-pass.cc
index 7c48d906..d5de3dbb 100644
--- a/llvm_mode/cmplog-instructions-pass.cc
+++ b/llvm_mode/cmplog-instructions-pass.cc
@@ -284,3 +284,9 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPass(
 static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
 
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+    registerCmpLogInstructionsPass);
+#endif
+
diff --git a/llvm_mode/cmplog-routines-pass.cc b/llvm_mode/cmplog-routines-pass.cc
index a0f8f64f..c44f38c4 100644
--- a/llvm_mode/cmplog-routines-pass.cc
+++ b/llvm_mode/cmplog-routines-pass.cc
@@ -204,3 +204,9 @@ static RegisterStandardPasses RegisterCmpLogRoutinesPass(
 static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
 
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+    registerCmpLogRoutinesPass);
+#endif
+
diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc
index bed3597a..acdd0f3b 100644
--- a/llvm_mode/compare-transform-pass.so.cc
+++ b/llvm_mode/compare-transform-pass.so.cc
@@ -137,7 +137,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
           bool isStrcasecmp = processStrcasecmp;
           bool isStrncasecmp = processStrncasecmp;
           bool isIntMemcpy = true;
-          bool indirect = false;
 
           Function *Callee = callInst->getCalledFunction();
           if (!Callee) continue;
@@ -264,8 +263,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
             }
 
-            if ((HasStr1 || HasStr2)) indirect = true;
-
           }
 
           if (isIntMemcpy) continue;
@@ -278,7 +275,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
               Str1 = StringRef(*val);
               HasStr1 = true;
-              indirect = true;
               // fprintf(stderr, "loaded1 %s\n", Str1.str().c_str());
 
             } else {
@@ -288,7 +284,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
                 Str2 = StringRef(*val);
                 HasStr2 = true;
-                indirect = true;
                 // fprintf(stderr, "loaded2 %s\n", Str2.str().c_str());
 
               }
@@ -585,3 +580,8 @@ static RegisterStandardPasses RegisterCompTransPass(
 static RegisterStandardPasses RegisterCompTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass);
 
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterCompTransPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass);
+#endif
+
diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc
index 3630bd8c..617b55de 100644
--- a/llvm_mode/split-compares-pass.so.cc
+++ b/llvm_mode/split-compares-pass.so.cc
@@ -1342,3 +1342,9 @@ static RegisterStandardPasses RegisterSplitComparesPass(
 static RegisterStandardPasses RegisterSplitComparesTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
 
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+    registerSplitComparesPass);
+#endif
+
diff --git a/llvm_mode/split-switches-pass.so.cc b/llvm_mode/split-switches-pass.so.cc
index f025df77..a79d4114 100644
--- a/llvm_mode/split-switches-pass.so.cc
+++ b/llvm_mode/split-switches-pass.so.cc
@@ -439,3 +439,9 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass(
 static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
     PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
 
+#if LLVM_VERSION_MAJOR >= 11
+static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
+    registerSplitSwitchesTransPass);
+#endif
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 6819fc8a..25983f26 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -58,6 +58,8 @@ static list_t fsrv_list = {.element_prealloc_count = 0};
 
 static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
+  if (fsrv->qemu_mode) setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
+
   execv(fsrv->target_path, argv);
 
 }
@@ -122,8 +124,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   Returns the time passed to read.
   If the wait times out, returns timeout_ms + 1;
   Returns 0 if an error occurred (fd closed, signal, ...); */
-static u32 __attribute__ ((hot)) read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms,
-                          volatile u8 *stop_soon_p) {
+static u32 __attribute__((hot))
+read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms, volatile u8 *stop_soon_p) {
 
   fd_set readfds;
   FD_ZERO(&readfds);
@@ -322,7 +324,7 @@ static void report_error_and_exit(int error) {
    cloning a stopped child. So, we just execute once, and then send commands
    through a pipe. The other part of this logic is in afl-as.h / llvm_mode */
 
-void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
+void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
                     volatile u8 *stop_soon_p, u8 debug_child_output) {
 
   int st_pipe[2], ctl_pipe[2];
@@ -628,13 +630,19 @@ void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
       if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
 
-        if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) {
+        if (fsrv->autodict_func == NULL || fsrv->afl_ptr == NULL) {
 
           // this is not afl-fuzz - we deny and return
-          if (fsrv->use_shmem_fuzz)
+          if (fsrv->use_shmem_fuzz) {
+
             status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
-          else
+
+          } else {
+
             status = (FS_OPT_ENABLED);
+
+          }
+
           if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
 
             FATAL("Writing to forkserver failed.");
@@ -647,11 +655,16 @@ void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
         if (!be_quiet) { ACTF("Using AUTODICT feature."); }
 
-        if (fsrv->use_shmem_fuzz)
+        if (fsrv->use_shmem_fuzz) {
+
           status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
-        else
+
+        } else {
+
           status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
 
+        }
+
         if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
 
           FATAL("Writing to forkserver failed.");
@@ -670,7 +683,8 @@ void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
         }
 
-        u32 len = status, offset = 0, count = 0;
+        u32 offset = 0, count = 0;
+        u32 len = status;
         u8 *dict = ck_alloc(len);
         if (dict == NULL) {
 
@@ -701,8 +715,8 @@ void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
         while (offset < (u32)status &&
                (u8)dict[offset] + offset < (u32)status) {
 
-          fsrv->function_ptr(fsrv->function_opt, dict + offset + 1,
-                             (u8)dict[offset]);
+          fsrv->autodict_func(fsrv->afl_ptr, dict + offset + 1,
+                              (u8)dict[offset]);
           offset += (1 + dict[offset]);
           count++;
 
@@ -861,7 +875,8 @@ void __attribute__ ((hot)) afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
         "    - the target was compiled with afl-clang-lto and a constructor "
         "was\n"
         "      instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
-        "your problem\n\n"
+        "your \n"
+        "      problem\n\n"
 
         "    - Less likely, there is a horrible bug in the fuzzer. If other "
         "options\n"
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index f6389c06..1b9df624 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -57,7 +57,7 @@ void write_bitmap(afl_state_t *afl) {
    This function is called after every exec() on a fairly large buffer, so
    it needs to be fast. We do this in 32-bit and 64-bit flavors. */
 
-u8 __attribute__ ((hot)) has_new_bits(afl_state_t *afl, u8 *virgin_map) {
+u8 __attribute__((hot)) has_new_bits(afl_state_t *afl, u8 *virgin_map) {
 
 #ifdef WORD_SIZE_64
 
@@ -347,7 +347,7 @@ void init_count_class16(void) {
 
 #ifdef WORD_SIZE_64
 
-void __attribute__ ((hot)) classify_counts(afl_forkserver_t *fsrv) {
+void __attribute__((hot)) classify_counts(afl_forkserver_t *fsrv) {
 
   u64 *mem = (u64 *)fsrv->trace_bits;
 
@@ -376,7 +376,7 @@ void __attribute__ ((hot)) classify_counts(afl_forkserver_t *fsrv) {
 
 #else
 
-void __attribute__ ((hot)) classify_counts(afl_forkserver_t *fsrv) {
+void __attribute__((hot)) classify_counts(afl_forkserver_t *fsrv) {
 
   u32 *mem = (u32 *)fsrv->trace_bits;
 
@@ -534,7 +534,8 @@ static void write_crash_readme(afl_state_t *afl) {
    save or queue the input test case for further analysis if so. Returns 1 if
    entry is saved, 0 otherwise. */
 
-u8 __attribute__ ((hot)) save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
+u8 __attribute__((hot))
+save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
   if (unlikely(len == 0)) { return 0; }
 
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 097871c8..17f02984 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -25,23 +25,28 @@
 
 #include "afl-fuzz.h"
 
-/* Helper function for load_extras. */
+/* helper function for auto_extras qsort */
+static int compare_auto_extras_len(const void *ae1, const void *ae2) {
+
+  return ((struct auto_extra_data *)ae1)->len -
+         ((struct auto_extra_data *)ae2)->len;
+
+}
 
-static int compare_extras_len(const void *p1, const void *p2) {
+/* descending order */
 
-  struct extra_data *e1 = (struct extra_data *)p1,
-                    *e2 = (struct extra_data *)p2;
+static int compare_auto_extras_use_d(const void *ae1, const void *ae2) {
 
-  return e1->len - e2->len;
+  return ((struct auto_extra_data *)ae2)->hit_cnt -
+         ((struct auto_extra_data *)ae1)->hit_cnt;
 
 }
 
-static int compare_extras_use_d(const void *p1, const void *p2) {
+/* Helper function for load_extras. */
 
-  struct extra_data *e1 = (struct extra_data *)p1,
-                    *e2 = (struct extra_data *)p2;
+static int compare_extras_len(const void *e1, const void *e2) {
 
-  return e2->hit_cnt - e1->hit_cnt;
+  return ((struct extra_data *)e1)->len - ((struct extra_data *)e2)->len;
 
 }
 
@@ -354,14 +359,10 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
 }
 
 /* Maybe add automatic extra. */
-/* Ugly hack: afl state is transfered as u8* because we import data via
-   afl-forkserver.c - which is shared with other afl tools that do not
-   have the afl state struct */
 
-void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
+void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) {
 
-  afl_state_t *afl = (afl_state_t *)afl_tmp;
-  u32          i;
+  u32 i;
 
   /* Allow users to specify that they don't want auto dictionaries. */
 
@@ -375,7 +376,7 @@ void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
 
   }
 
-  if (i == len) { return; }
+  if (i == len || unlikely(len > MAX_AUTO_EXTRA)) { return; }
 
   /* Reject builtin interesting values. */
 
@@ -452,10 +453,7 @@ void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
 
   if (afl->a_extras_cnt < MAX_AUTO_EXTRAS) {
 
-    afl->a_extras = ck_realloc_block(
-        afl->a_extras, (afl->a_extras_cnt + 1) * sizeof(struct extra_data));
-
-    afl->a_extras[afl->a_extras_cnt].data = ck_memdup(mem, len);
+    memcpy(afl->a_extras[afl->a_extras_cnt].data, mem, len);
     afl->a_extras[afl->a_extras_cnt].len = len;
     ++afl->a_extras_cnt;
 
@@ -463,9 +461,7 @@ void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
 
     i = MAX_AUTO_EXTRAS / 2 + rand_below(afl, (MAX_AUTO_EXTRAS + 1) / 2);
 
-    ck_free(afl->a_extras[i].data);
-
-    afl->a_extras[i].data = ck_memdup(mem, len);
+    memcpy(afl->a_extras[i].data, mem, len);
     afl->a_extras[i].len = len;
     afl->a_extras[i].hit_cnt = 0;
 
@@ -475,13 +471,13 @@ sort_a_extras:
 
   /* First, sort all auto extras by use count, descending order. */
 
-  qsort(afl->a_extras, afl->a_extras_cnt, sizeof(struct extra_data),
-        compare_extras_use_d);
+  qsort(afl->a_extras, afl->a_extras_cnt, sizeof(struct auto_extra_data),
+        compare_auto_extras_use_d);
 
   /* Then, sort the top USE_AUTO_EXTRAS entries by size. */
 
   qsort(afl->a_extras, MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt),
-        sizeof(struct extra_data), compare_extras_len);
+        sizeof(struct auto_extra_data), compare_auto_extras_len);
 
 }
 
@@ -544,7 +540,7 @@ void load_auto(afl_state_t *afl) {
 
     if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) {
 
-      maybe_add_auto((u8 *)afl, tmp, len);
+      maybe_add_auto(afl, tmp, len);
 
     }
 
@@ -579,13 +575,5 @@ void destroy_extras(afl_state_t *afl) {
 
   ck_free(afl->extras);
 
-  for (i = 0; i < afl->a_extras_cnt; ++i) {
-
-    ck_free(afl->a_extras[i].data);
-
-  }
-
-  ck_free(afl->a_extras);
-
 }
 
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 452c5298..0a4be320 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -95,7 +95,7 @@ static u32 choose_block_len(afl_state_t *afl, u32 limit) {
 
     default:
 
-      if (rand_below(afl, 10)) {
+      if (likely(rand_below(afl, 10))) {
 
         min_value = HAVOC_BLK_MEDIUM;
         max_value = HAVOC_BLK_LARGE;
@@ -421,7 +421,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
     if (((afl->queue_cur->was_fuzzed > 0 || afl->queue_cur->fuzz_level > 0) ||
          !afl->queue_cur->favored) &&
-        rand_below(afl, 100) < SKIP_TO_NEW_PROB) {
+        likely(rand_below(afl, 100) < SKIP_TO_NEW_PROB)) {
 
       return 1;
 
@@ -438,11 +438,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
     if (afl->queue_cycle > 1 &&
         (afl->queue_cur->fuzz_level == 0 || afl->queue_cur->was_fuzzed)) {
 
-      if (rand_below(afl, 100) < SKIP_NFAV_NEW_PROB) { return 1; }
+      if (likely(rand_below(afl, 100) < SKIP_NFAV_NEW_PROB)) { return 1; }
 
     } else {
 
-      if (rand_below(afl, 100) < SKIP_NFAV_OLD_PROB) { return 1; }
+      if (likely(rand_below(afl, 100) < SKIP_NFAV_OLD_PROB)) { return 1; }
 
     }
 
@@ -526,8 +526,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
    * TRIMMING *
    ************/
 
-  if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
-      !afl->disable_trim) {
+  if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
+               !afl->disable_trim)) {
 
     u8 res = trim_case(afl, afl->queue_cur, in_buf);
 
@@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   if (unlikely(perf_score == 0)) { goto abandon_entry; }
 
-  if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
+  if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) {
 
     if (input_to_state_stage(afl, in_buf, out_buf, len,
                              afl->queue_cur->exec_cksum)) {
@@ -591,8 +591,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
   /* Skip deterministic fuzzing if exec path checksum puts this out of scope
      for this main instance. */
 
-  if (afl->main_node_max && (afl->queue_cur->exec_cksum % afl->main_node_max) !=
-                                afl->main_node_id - 1) {
+  if (unlikely(afl->main_node_max &&
+               (afl->queue_cur->exec_cksum % afl->main_node_max) !=
+                   afl->main_node_id - 1)) {
 
     goto custom_mutator_stage;
 
@@ -681,7 +682,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
 
-          maybe_add_auto((u8 *)afl, a_collect, a_len);
+          maybe_add_auto(afl, a_collect, a_len);
 
         }
 
@@ -692,7 +693,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
 
-          maybe_add_auto((u8 *)afl, a_collect, a_len);
+          maybe_add_auto(afl, a_collect, a_len);
 
         }
 
@@ -2131,7 +2132,7 @@ havoc_stage:
             u32 clone_from, clone_to, clone_len;
             u8 *new_buf;
 
-            if (actually_clone) {
+            if (likely(actually_clone)) {
 
               clone_len = choose_block_len(afl, temp_len);
               clone_from = rand_below(afl, temp_len - clone_len + 1);
@@ -2154,7 +2155,7 @@ havoc_stage:
 
             /* Inserted part */
 
-            if (actually_clone) {
+            if (likely(actually_clone)) {
 
               memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
 
@@ -2194,7 +2195,7 @@ havoc_stage:
           copy_from = rand_below(afl, temp_len - copy_len + 1);
           copy_to = rand_below(afl, temp_len - copy_len + 1);
 
-          if (rand_below(afl, 4)) {
+          if (likely(rand_below(afl, 4))) {
 
             if (copy_from != copy_to) {
 
@@ -2753,7 +2754,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   orig_perf = perf_score = calculate_score(afl, afl->queue_cur);
 
-  if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
+  if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) {
 
     if (input_to_state_stage(afl, in_buf, out_buf, len,
                              afl->queue_cur->exec_cksum)) {
@@ -2882,7 +2883,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
 
-          maybe_add_auto((u8 *)afl, a_collect, a_len);
+          maybe_add_auto(afl, a_collect, a_len);
 
         }
 
@@ -2893,7 +2894,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) {
 
-          maybe_add_auto((u8 *)afl, a_collect, a_len);
+          maybe_add_auto(afl, a_collect, a_len);
 
         }
 
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 9716be95..f21dd0b0 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -151,7 +151,8 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) {
       /* Discard if the mutations change the paths or if it is too decremental
         in speed */
       if (cksum != exec_cksum ||
-          (stop_us - start_us > 2 * afl->queue_cur->exec_us)) {
+          ((stop_us - start_us > 2 * afl->queue_cur->exec_us) &&
+           likely(!afl->fixed_seed))) {
 
         ranges = add_range(ranges, rng->start, rng->start + s / 2);
         ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
@@ -499,7 +500,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
 
   }
 
-  maybe_add_auto((u8 *)afl, (u8 *)&v, shape);
+  maybe_add_auto(afl, (u8 *)&v, shape);
 
   u64 rev;
   switch (shape) {
@@ -508,15 +509,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
       break;
     case 2:
       rev = SWAP16((u16)v);
-      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
+      maybe_add_auto(afl, (u8 *)&rev, shape);
       break;
     case 4:
       rev = SWAP32((u32)v);
-      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
+      maybe_add_auto(afl, (u8 *)&rev, shape);
       break;
     case 8:
       rev = SWAP64(v);
-      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
+      maybe_add_auto(afl, (u8 *)&rev, shape);
       break;
 
   }
@@ -771,8 +772,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
       if (afl->pass_stats[key].total == 0) {
 
-        maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape));
-        maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape));
+        maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape));
+        maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape));
 
       }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 97fcb3c8..d3f823c9 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -38,8 +38,8 @@ u64 time_spent_working = 0;
 /* Execute target application, monitoring for timeouts. Return status
    information. The called program will update afl->fsrv->trace_bits. */
 
-fsrv_run_result_t __attribute__ ((hot)) fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
-                                  u32 timeout) {
+fsrv_run_result_t __attribute__((hot))
+fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
 
 #ifdef PROFILING
   static u64      time_spent_start = 0;
@@ -72,7 +72,8 @@ fsrv_run_result_t __attribute__ ((hot)) fuzz_run_target(afl_state_t *afl, afl_fo
    old file is unlinked and a new one is created. Otherwise, afl->fsrv.out_fd is
    rewound and truncated. */
 
-void __attribute__ ((hot)) write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
+void __attribute__((hot))
+write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
 
 #ifdef _AFL_DOCUMENT_MUTATIONS
   s32  doc_fd;
@@ -858,7 +859,8 @@ abort_trimming:
    error conditions, returning 1 if it's time to bail out. This is
    a helper function for fuzz_one(). */
 
-u8 __attribute__ ((hot)) common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
+u8 __attribute__((hot))
+common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   u8 fault;
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index e2d62bc6..d4de91a4 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -112,8 +112,9 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
 
   afl->fsrv.use_stdin = 1;
   afl->fsrv.map_size = map_size;
-  afl->fsrv.function_opt = (u8 *)afl;
-  afl->fsrv.function_ptr = &maybe_add_auto;
+  // afl_state_t is not available in forkserver.c
+  afl->fsrv.afl_ptr = (void *)afl;
+  afl->fsrv.autodict_func = (void (*)(void *, u8 *, u32)) & maybe_add_auto;
 
   afl->cal_cycles = CAL_CYCLES;
   afl->cal_cycles_long = CAL_CYCLES_LONG;
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 0aa116e5..47c615d8 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -68,9 +68,11 @@ static char *stdin_file;               /* stdin file                        */
 static u8 *in_dir = NULL,              /* input folder                      */
     *out_file = NULL, *at_file = NULL;        /* Substitution string for @@ */
 
-static u8 *in_data;                    /* Input data                        */
+static u8 *in_data,                    /* Input data                        */
+    *coverage_map;                     /* Coverage map                      */
 
-static u32 total, highest;             /* tuple content information         */
+static u64 total;                      /* tuple content information         */
+static u32 tcnt, highest;              /* tuple content information         */
 
 static u32 in_len,                     /* Input data length                 */
     arg_offset;                        /* Total number of execs             */
@@ -83,7 +85,8 @@ static u8 quiet_mode,                  /* Hide non-essential messages?      */
     cmin_mode,                         /* Generate output in afl-cmin mode? */
     binary_mode,                       /* Write output as a binary map      */
     keep_cores,                        /* Allow coredumps?                  */
-    remove_shm = 1;                    /* remove shmem?                     */
+    remove_shm = 1,                    /* remove shmem?                     */
+    collect_coverage;                  /* collect coverage                  */
 
 static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_crashed;                     /* Child crashed?                    */
@@ -175,6 +178,25 @@ static void at_exit_handler(void) {
 
 }
 
+/* Analyze results. */
+
+static void analyze_results(afl_forkserver_t *fsrv) {
+
+  u32 i;
+  for (i = 0; i < map_size; i++) {
+
+    if (fsrv->trace_bits[i]) {
+
+      total += fsrv->trace_bits[i];
+      if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
+      if (!coverage_map[i]) { coverage_map[i] = 1; }
+
+    }
+
+  }
+
+}
+
 /* Write results. */
 
 static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
@@ -588,9 +610,14 @@ static void usage(u8 *argv0) {
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n\n"
       "Other settings:\n"
-      "  -i dir        - process all files in this directory, -o must be a "
+      "  -i dir        - process all files in this directory, must be combined "
+      "with -o.\n"
+      "                  With -C, -o is a file, without -C it must be a "
       "directory\n"
       "                  and each bitmap will be written there individually.\n"
+      "  -C            - collect coverage, writes all edges to -o and gives a "
+      "summary\n"
+      "                  Must be combined with -i.\n"
       "  -q            - sink program's output and don't show messages\n"
       "  -e            - show edge coverage only, ignore hit counts\n"
       "  -r            - show real tuple values instead of AFL filter values\n"
@@ -624,7 +651,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   s32    opt, i;
   u8     mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
-  u32    tcnt = 0;
   char **use_argv;
 
   char **argv = argv_cpy_dup(argc, argv_orig);
@@ -639,10 +665,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; }
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqZQUWbcrh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrh")) > 0) {
 
     switch (opt) {
 
+      case 'C':
+        collect_coverage = 1;
+        break;
+
       case 'i':
         if (in_dir) { FATAL("Multiple -i options not supported"); }
         in_dir = optarg;
@@ -820,6 +850,13 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (optind == argc || !out_file) { usage(argv[0]); }
 
+  if (in_dir) {
+
+    if (!out_file && !collect_coverage)
+      FATAL("for -i you need to specify either -C and/or -o");
+
+  }
+
   if (fsrv->qemu_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
   if (unicorn_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
 
@@ -910,7 +947,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (in_dir) {
 
-    DIR *          dir_in, *dir_out;
+    DIR *          dir_in, *dir_out = NULL;
     struct dirent *dir_ent;
     int            done = 0;
     u8             infile[PATH_MAX], outfile[PATH_MAX];
@@ -924,20 +961,43 @@ int main(int argc, char **argv_orig, char **envp) {
     fsrv->dev_null_fd = open("/dev/null", O_RDWR);
     if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
 
+    // if a queue subdirectory exists switch to that
+    u8 *dn = alloc_printf("%s/queue", in_dir);
+    if ((dir_in = opendir(dn)) != NULL) {
+
+      closedir(dir_in);
+      in_dir = dn;
+
+    } else
+
+      ck_free(dn);
+    if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
+
     if (!(dir_in = opendir(in_dir))) {
 
       PFATAL("cannot open directory %s", in_dir);
 
     }
 
-    if (!(dir_out = opendir(out_file))) {
+    if (!collect_coverage) {
+
+      if (!(dir_out = opendir(out_file))) {
+
+        if (mkdir(out_file, 0700)) {
 
-      if (mkdir(out_file, 0700)) {
+          PFATAL("cannot create output directory %s", out_file);
 
-        PFATAL("cannot create output directory %s", out_file);
+        }
 
       }
 
+    } else {
+
+      if ((coverage_map = (u8 *)malloc(map_size)) == NULL)
+        FATAL("coult not grab memory");
+      edges_only = 0;
+      raw_instr_output = 1;
+
     }
 
     u8 *use_dir = ".";
@@ -978,6 +1038,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     afl_fsrv_start(fsrv, use_argv, &stop_soon,
                    get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
+    map_size = fsrv->map_size;
 
     if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
       shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
@@ -1005,7 +1066,8 @@ int main(int argc, char **argv_orig, char **envp) {
       if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
 #endif
 
-      snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
+      if (!collect_coverage)
+        snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
 
       if (read_file(infile)) {
 
@@ -1019,7 +1081,10 @@ int main(int argc, char **argv_orig, char **envp) {
 
         showmap_run_target_forkserver(fsrv, in_data, in_len);
         ck_free(in_data);
-        tcnt = write_results_to_file(fsrv, outfile);
+        if (collect_coverage)
+          analyze_results(fsrv);
+        else
+          tcnt = write_results_to_file(fsrv, outfile);
 
       }
 
@@ -1030,6 +1095,13 @@ int main(int argc, char **argv_orig, char **envp) {
     closedir(dir_in);
     if (dir_out) { closedir(dir_out); }
 
+    if (collect_coverage) {
+
+      memcpy(fsrv->trace_bits, coverage_map, map_size);
+      tcnt = write_results_to_file(fsrv, out_file);
+
+    }
+
   } else {
 
     if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
@@ -1043,8 +1115,14 @@ int main(int argc, char **argv_orig, char **envp) {
   if (!quiet_mode) {
 
     if (!tcnt) { FATAL("No instrumentation detected" cRST); }
-    OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST,
+    OKF("Captured %u tuples (highest value %u, total values %llu) in "
+        "'%s'." cRST,
         tcnt, highest, total, out_file);
+    if (collect_coverage)
+      OKF("A coverage of %u edges were achieved out of %u existing (%.02f%%) "
+          "with %llu input files.",
+          tcnt, map_size, ((float)tcnt * 100) / (float)map_size,
+          fsrv->total_execs);
 
   }
 
diff --git a/test/test-basic.sh b/test/test-basic.sh
index 9e4b03c3..06c40efe 100755
--- a/test/test-basic.sh
+++ b/test/test-basic.sh
@@ -99,8 +99,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
             ;;
         esac
     } else {
-      $ECHO "$YELLOW[-] no bash available, cannot test afl-cmin.bash"
-      INCOMPLETE=1
+      $ECHO "$GRAY[*] no bash available, cannot test afl-cmin.bash"
     }
     fi
     ../afl-tmin -m ${MEM_LIMIT} -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
@@ -119,8 +118,9 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
   INCOMPLETE=1
  }
 } || {
- $ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc"
+ $ECHO "$GREY[[*] not an intel platform, skipped tests of afl-gcc"
  #this is not incomplete as this feature doesnt exist, so all good
+ AFL_TEST_COUNT=$((AFL_TEST_COUNT-1))
 }
 
 . ./test-post.sh
diff --git a/test/test-post.sh b/test/test-post.sh
index c1e22498..0911e2cd 100755
--- a/test/test-post.sh
+++ b/test/test-post.sh
@@ -4,7 +4,7 @@ AFL_TEST_DEPTH=$((AFL_TEST_DEPTH-1))
 if [ $AFL_TEST_DEPTH = 0 ]; then
 # All runs done :)
 
-$ECHO "$GREY[*] all test cases completed.$RESET"
+$ECHO "$GREY[*] $AFL_TEST_COUNT test cases completed.$RESET"
 test "$INCOMPLETE" = "0" && $ECHO "$GREEN[+] all test cases executed"
 test "$INCOMPLETE" = "1" && $ECHO "$YELLOW[-] not all test cases were executed"
 test "$CODE" = "0" && $ECHO "$GREEN[+] all tests were successful :-)$RESET"
diff --git a/test/test-pre.sh b/test/test-pre.sh
index 3e2d475d..e3393962 100755
--- a/test/test-pre.sh
+++ b/test/test-pre.sh
@@ -4,6 +4,7 @@
 # They may set an error code with $CODE=1
 # If tests are incomplete, they may set $INCOMPLETE=1
 
+AFL_TEST_COUNT=$((AFL_TEST_COUNT+1))
 AFL_TEST_DEPTH=$((AFL_TEST_DEPTH+1))
 
 if [ $AFL_TEST_DEPTH = 1 ]; then